Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
116 changes: 116 additions & 0 deletions docs/getting-started/install/other/nginxproxymanager.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,3 +126,119 @@ docker compose up -d
![Nginx Proxy Manager SSL](/img/nginx-proxy-manager/npm-ssl.png)

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

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

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

- **性能**:让 JavaScript、字体、JSON 等静态资源也参与 gzip 压缩;调大 proxy buffer 避免响应落盘
- **安全**:补齐 [securityheaders.com](https://securityheaders.com) 认可的安全响应头,默认可拿到 A 评级

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

### 在 NPM 中找到自定义配置入口

1. 进入 NPM 仪表盘,在 Hosts → Proxy Hosts 点开 Halo 的代理记录进行编辑
2. 切换到 **Advanced** 标签页
3. 把下面的内容粘贴到 **Custom Nginx Configuration** 文本框
4. 保存后 NPM 会自动 reload nginx,无需重建容器

### 推荐的自定义配置

```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;
```

:::tip
`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 列表,**提交后撤销非常困难**,确有必要再加

### 验证配置是否生效

```bash
# 查看安全响应头
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 成为瓶颈。
Original file line number Diff line number Diff line change
Expand Up @@ -126,3 +126,119 @@ docker compose up -d
![Nginx Proxy Manager SSL](/img/nginx-proxy-manager/npm-ssl.png)

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

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

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

- **性能**:让 JavaScript、字体、JSON 等静态资源也参与 gzip 压缩;调大 proxy buffer 避免响应落盘
- **安全**:补齐 [securityheaders.com](https://securityheaders.com) 认可的安全响应头,默认可拿到 A 评级

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

### 在 NPM 中找到自定义配置入口

1. 进入 NPM 仪表盘,在 Hosts → Proxy Hosts 点开 Halo 的代理记录进行编辑
2. 切换到 **Advanced** 标签页
3. 把下面的内容粘贴到 **Custom Nginx Configuration** 文本框
4. 保存后 NPM 会自动 reload nginx,无需重建容器

### 推荐的自定义配置

```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;
```

:::tip
`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 列表,**提交后撤销非常困难**,确有必要再加

### 验证配置是否生效

```bash
# 查看安全响应头
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 成为瓶颈。
Loading