跳到主要内容

Nginx Proxy Manager 反向代理

Halo 部署​

参见 使用 Docker Compose 部署

跳过 Halo 反向代理配置

「反向代理」 部分不进行操作,保证 Halo 服务运行无误即可。

简介​

Nginx Proxy Manager 是一个可视化的 Nginx 反向代理管理器,支持在 Web UI 上管理反向代理的网站,支持申请免费的 SSL 证书并自动续签。

接下来会介绍如何使用 Nginx Proxy Manager 来反向代理 Halo,以下的 Nginx 安装方式均来自于 Nginx Proxy Manager 官方文档。在开始之前,建议先阅读一遍官方文档,需要对其有一定的了解。

说明​

  • 此文档需要对 Docker 和 Docker Compose 有一定的熟悉程度,并且已经提前在服务器上安装
  • 在安装 Nginx Proxy Manager 之前,需要确保服务器没有其他占用了 80 和 443 端口的服务
  • 需要对 Vim 有一定的熟悉程度
  • 下文使用 NPM 简称 Nginx Proxy Manager

安装 Nginx Proxy Manager​

创建工作目录​

创建一个文件夹来存放 NPM 的 docker-compose.yml 文件:

mkdir npm && cd npm
vim docker-compose.yml

创建 docker-compose.yml​

将下面的内容复制到 docker-compose.yml 文件:

services:
npm:
image: "jc21/nginx-proxy-manager:latest"
networks:
- npm
restart: unless-stopped
ports:
- "80:80" # Nginx 的 80 端口
- "443:443" # Nginx 的 443 端口
- "81:81" # Nginx Proxy Manager 的管理端口
volumes:
- ./data:/data
- ./letsencrypt:/etc/letsencrypt

# 定义网络以便 NPM 与其他容器通信
networks:
npm:
name: npm
attachable: true
提前开放所需端口

配置中提到的 80、443、81 端口需要提前在服务器提供商开放端口。

启动 NPM​

docker compose up -d

创建管理员账户​

在服务正常启动的情况下,现在已经可以通过 http://{服务器公网 IP}:81 访问 NPM 的网页端了。

无法访问时检查 81 端口

如果无法通过端口访问到 NPM,可以检查是否在服务器提供商开放了 81 端口。

图 1  Nginx Proxy Manager 欢迎页
图 1 Nginx Proxy Manager 欢迎页

首次进入页面会提示创建管理员账户,需要注意的是:邮箱一定要是合法邮箱,后续涉及到 SSL 证书签发。

至此,我们已经完成了 Nginx Proxy Manager 的搭建,之后就可以用它给我们的 Halo 或者其他 Web 应用做反向代理了。

配置 Halo 的反向代理​

配置 Halo 的 Docker 编排​

将 npm 的网络加入到 Halo 的容器,之后就可以使用 Halo 的服务名作为 hostname 在 NPM 的内部进行反向代理了。

# 省略
networks:
# 加入 npm 网络
npm:
external: true
halo:

services:
halo:
image: registry.fit2cloud.com/halo/halo-pro:2.26
container_name: halo
restart: on-failure:3
volumes:
- ./halo2:/root/.halo2
networks:
# 加入 npm 网络
- npm
- halo
# 省略

配置完成之后,需要使用 docker compose up -d 命令重建 Halo 容器。

进入代理服务配置页面​

进入 NPM 仪表盘,点击代理服务进入代理服务配置页面。

图 2  Nginx Proxy Manager 仪表盘
图 2 Nginx Proxy Manager 仪表盘

添加代理配置​

图 3  添加反向代理
图 3 添加反向代理
  1. 域名:配置想要代理到 Halo 的域名,需要提前在域名服务商解析到当前服务器
  2. 协议:选择 http
  3. 转发主机名 / IP:填写 Halo 容器的服务名,比如上方示例中的 halo
  4. 转发端口:8090

以上配置为必须修改,界面中的其他配置可以按需选择,但其中的缓存资源不建议打开,可能不会完全遵守 Halo 的缓存策略。

配置完成之后,就可以尝试访问域名。

配置 SSL​

点击 SSL 选项卡,勾选 申请新证书 之后保存即可,同时建议勾选 强制 SSL,这样在访问 http 协议的地址时会自动跳转到 https 协议的地址。

图 4  配置 SSL 证书
图 4 配置 SSL 证书

至此,我们已经完成了在 Nginx Proxy Manager 配置 Halo 反向代理并添加 SSL 证书的全过程。

进阶配置:性能与安全(可选)​

前文已完成基础反向代理与 SSL,对大多数博客已经够用。本节介绍在 NPM 中追加性能优化与安全响应头配置,两个目标:

  • 性能:让 JavaScript、字体、JSON 等静态资源也参与 gzip 压缩;调大 proxy buffer 避免响应落盘
  • 安全:补齐 securityheaders.com 认可的安全响应头,默认可拿到 A 评级
通用反向代理优化

本节所有配置均为反代层通用优化,与具体主题无关,适用于任何 Halo 实例。

在 NPM 中添加自定义配置:

编辑 Halo 的代理记录​

进入 NPM 仪表盘,在 Hosts → Proxy Hosts 点开 Halo 的代理记录进行编辑。

打开高级设置​

切换到 Advanced 标签页。

添加自定义配置​

把下面的内容粘贴到 Custom Nginx Configuration 文本框。

保存配置​

保存后 NPM 会自动 reload nginx,无需重建容器。

推荐的自定义配置​

# ---- gzip 压缩:补齐 NPM 默认未覆盖的 JS、字体、JSON 等 MIME 类型 ----
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_min_length 1024;
gzip_types
text/css
text/javascript
application/javascript
application/x-javascript
application/json
application/xml
application/rss+xml
application/atom+xml
image/svg+xml
font/ttf
font/otf
font/woff
font/woff2;
# 若目录下存在 .gz 预压缩文件则优先使用
gzip_static on;

# ---- proxy buffer:避免较大响应被临时写入磁盘 ----
proxy_buffers 16 32k;
proxy_buffer_size 64k;
proxy_busy_buffers_size 128k;

# ---- 安全响应头:加 always 确保错误页也会返回 ----
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
# HSTS 请在确认 HTTPS 稳定运行后再启用,见下文说明
# add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;

# ---- RSS 路径别名:Halo 默认 RSS 为 /rss.xml ----
rewrite ^/rss$ /rss.xml permanent;
rewrite ^/feed$ /rss.xml permanent;
避免重复声明 text/html

gzip_types 不要再列 text/html,nginx 默认已经对其启用 gzip,重复声明会产生 duplicate MIME type 警告。

关于 HSTS​

Strict-Transport-Security 会告诉浏览器未来只能通过 HTTPS 访问当前域名。一旦启用且 max-age 较长,浏览器会缓存该策略直到过期,期间无法回退到 HTTP。因此建议:

  • 在 HTTPS 证书可正常续签、基础设施稳定运行 1–2 周后再启用
  • 先从 max-age=300(5 分钟)起步验证,确认无误再逐步调大到 63072000(2 年)
  • preload 表示提交到浏览器内置 HSTS 列表,提交后撤销非常困难,确有必要再加

验证配置是否生效​

# 查看安全响应头
curl -I https://your-halo-domain.example.com/ \
| grep -iE "x-content-type|x-frame|x-xss|referrer-policy|permissions-policy"

# 检查 JavaScript 是否启用了 gzip
curl -IH "Accept-Encoding: gzip" \
https://your-halo-domain.example.com/themes/<your-theme>/source/main.js \
| grep -i content-encoding

浏览器侧也可以在 DevTools → Network → Response Headers 中确认。

常见问题​

能拿到 securityheaders.com A+ 吗?​

上面的配置能稳定拿到 A 评级。追求 A+ 的硬指标是配置 Content-Security-Policy(CSP),在博客场景下收益较低:

  • 多数 Halo 主题依赖若干第三方 CDN(字体、评论系统、统计、表情等),每个都需要加入 CSP 白名单
  • 主题模板中常见内联脚本,需使用 'unsafe-inline'(会明显削弱 CSP 的价值)或改造为 nonce 模式
  • 管理后台「代码注入」功能注入的脚本同样受 CSP 约束,白名单收敛难度较高

如确有 A+ 需求,建议按以下路径落地:

  1. 先使用 Content-Security-Policy-Report-Only,不阻断页面,仅在浏览器控制台打印违规
  2. 观察 1–2 周,根据 violation 报告收敛白名单
  3. 白名单稳定后再转为生产 Content-Security-Policy

作为参考,GitHub 本身的 securityheaders.com 评级也是 A,对博客类站点而言 A 已足够。

NPM 界面中的「缓存资源」开关要开启吗?​

建议保持关闭。Halo 自身已通过 ETag、Last-Modified 等机制对静态资源提供合理的缓存策略,NPM 层再叠一层缓存可能导致主题升级或资源替换后不能立即生效。性能提升主要来自本节的 gzip 与 proxy buffer 优化。

为什么要调大 proxy buffer?​

NPM 默认的 proxy buffer 较小,当 Halo 返回的响应体超过 buffer 总量时,nginx 会把剩余数据临时写入磁盘后再转发。调大到 16 32k(共 512 KB)能覆盖绝大多数 HTML/JSON 响应,避免磁盘 I/O 成为瓶颈。