外观
反向代理与 HTTPS
完成后,你的几个应用共用一个入口,用 https://应用.你的域名 访问,证书由代理自动申请和续期。你也清楚哪些端口会暴露出去,哪些永远不该开放。
先问:真的需要反向代理吗
| 你的情况 | 要不要 |
|---|---|
只在局域网用,浏览器用 http://NAS的IP:端口 就行 | 不需要,别给自己加复杂度 |
| 应用强制要求 HTTPS,例如 Vaultwarden,浏览器的加密接口只在 HTTPS 下可用 | 需要,哪怕只在局域网 |
| 想用域名,不想记端口 | 需要 |
| 想从外面访问 | 优先用 VPN,见远程访问:别把 NAS 直接暴露到公网、WireGuard、Tailscale 组网。非要对外开放,才用反向代理,并且只暴露具体的应用 |
反向代理就是一个门卫:所有请求先到它,它终止 HTTPS,再按域名转发给后面的应用。
text
浏览器 ──https://vault.example.com──▶ 反向代理(80、443)──http──▶ vaultwarden:80
──https://photos.example.com─▶ └──▶ immich:2283路由器上开了什么端口,就暴露了什么
- 影响范围:路由器把 80、443 转发给 NAS 后,全网的人都能访问代理后面的应用。应用的漏洞、弱密码都会被自动扫描。
- 前置条件:先只在局域网跑通,再考虑对外。每个对外的应用都有强密码,支持两步验证的打开它。系统和镜像保持更新,数据已有独立备份。你的宽带必须有公网 IP,运营商级 NAT(CGNAT)后面转发无效。
- 怎么回退:删掉路由器上的端口转发,外网入口立即关闭;在代理里停用对应的主机。
- 永远不要对外开放:OMV 的 Web 界面、SSH、SMB、NFS,以及代理自己的管理界面(例如 Nginx Proxy Manager 的 81 端口)。
先解决:OMV 占着 80 和 443
OMV 的 Web 界面默认监听 80。启用 HTTPS 后,还会监听 443。反向代理要用这两个端口,必须有一方让出来。设置在 系统 → 工作台 → 设置(System → Workbench → Settings):端口(Port)是 HTTP 端口,安全连接 里的 已启用SSL/TLS、证书、端口(HTTPS 端口,默认 443)、强制使用 SSL/TLS 管 HTTPS。
| 方案 | 做法 | 优点 | 缺点 |
|---|---|---|---|
| A. 把 OMV 界面挪走(推荐) | OMV 的 HTTP 端口改成别的,比如 8888,HTTPS 端口改成 8443 | 代理用标准的 80 和 443,最省事 | 以后访问 OMV 要写端口 |
| B. 代理换端口 | OMV 不动,代理容器映射成 8880:80 和 8443:443,路由器把外部的 80 转发到 8880、443 转发到 8443 | OMV 地址不变 | 局域网里直接访问要带端口。HTTP 质询申请证书时,路由器必须把外部 80 转到代理 |
| C. 代理独占一个 IP | 用 macvlan 网络给代理单独的局域网 IP | 都不用改端口 | 宿主机默认访问不到 macvlan 上的容器,wiki 的解决办法要手写网络配置,OMV 8 用 netplan,可能冲突,本站不教 |
OMV 官方也允许在它自己的 nginx 里另加站点(用 nginx_ensite 启用,不要改 OMV 自己的 nginx 文件),但配置和证书都要手写,本站不展开,容器方案更好维护。
改 OMV 的 Web 端口,写错就进不去界面
- 影响范围:保存并应用后,Web 界面立即换到新端口,当前页面会没反应,要用新地址重新打开,比如
http://<NAS的IP>:8888。收藏夹、脚本、别的设备上的链接都要改。 - 前置条件:先确认你能用 SSH 或本机控制台登录 OMV,这是你的后路。新端口别和其他服务冲突。
- 怎么回退:进不了界面时,在 OMV 的 shell 里以 root 身份运行
omv-firstaid,选Configure workbench,把 HTTP 端口改回 80,需要的话重设 HTTPS 的端口和证书。详见Web 界面安全。
部署 Nginx Proxy Manager
Nginx Proxy Manager(下文简称 NPM)有网页界面,内置 Let's Encrypt,新手最容易上手。插件示例里有 nginx-proxy-manager,带一个 MariaDB 容器。
- 先按上一节,选方案 A 把 OMV 界面端口改走并应用,用新端口重新登录。
- 在
服务 → Compose → 网络(Networks)页点 创建(Create),名字填proxy,驱动选bridge,保存。这是代理和应用共用的网络。 服务 → Compose → 文件→ 添加 → 从模板添加,选nginx-proxy-manager,添加,然后 编辑。- 对照 NPM 官方文档,做这几处修改:
- 示例的环境变量里,MariaDB 的 root 密码和用户密码都是
npm,一共出现在DB_MYSQL_PASSWORD、MYSQL_ROOT_PASSWORD、MYSQL_PASSWORD三处,全部换成同一个随机的强密码(数据库不对外映射端口,但别用默认值)。 - 数据路径用
sf占位符放进appdata,别放data(见写好 compose 文件)。 - 在 NPM 的容器上加入
proxy网络:服务里写networks: [default, proxy],文件末尾声明proxy是外部网络,写法见写好 compose 文件。别漏掉default:一旦写了networks,服务就只加入列出的网络,漏了它,NPM 就连不上同一个文件里的 MariaDB 容器。 - 端口保持
80:80、443:443、81:81。81 是管理界面,不要对外转发。
- 示例的环境变量里,MariaDB 的 root 密码和用户密码都是
- 保存,检查,上线。浏览器访问
http://<NAS的IP>:81。示例文件的注释里写了默认账号,登录后立即改邮箱和密码,登录页没有提示的话以 NPM 官方文档为准。
在 NPM 里添加应用:
- Hosts → Proxy Hosts,添加。域名填
vault.example.com。 - 转发主机名填应用的容器名,转发端口填应用容器内部的端口(不是你映射到 NAS 的端口)。例如 Vaultwarden 填
vaultwarden和80。 - SSL 页签申请证书(见下一节),勾选强制 SSL。
- 页面能打开但实时通知、上传异常时,打开 Websockets Support。界面文字以你的 NPM 版本为准。
应用那一侧同样要加入 proxy 网络,并且去掉对局域网的端口映射,让它只能通过代理访问:
yaml
services:
vaultwarden:
image: vaultwarden/server:latest
container_name: vaultwarden
environment:
DOMAIN: "https://vault.example.com"
volumes:
- ${{ sf:"appdata" }}/vaultwarden/data:/data
networks:
- proxy
restart: unless-stopped
networks:
proxy:
external: true容器名要在所有 compose 文件里唯一,代理靠容器名找到应用。DOMAIN 这类「告诉应用它的外部地址」的设置,每个应用都有自己的名字,代理后面页面异常多半是它没设对。
证书
| 方式 | 要什么 | 适合 |
|---|---|---|
| HTTP 质询 | 域名解析到你的公网 IP,外部的 80 端口能到达代理 | 对外开放的应用 |
| DNS 质询 | 域名在支持 API 的 DNS 服务商那里,填 API 令牌 | 只在局域网用的应用:不需要任何入站端口,域名甚至可以解析到 192.168.x.x |
NPM 的证书页面支持 DNS 质询,可选的 DNS 服务商以NPM 的 Certbot DNS 插件说明为准,这些插件由第三方维护,可能跟不上 Certbot 的更新。
局域网内用域名访问时,要让域名解析到 NAS 的局域网 IP:在路由器或局域网 DNS 里加一条记录。否则请求会绕到公网再回来,有些路由器不支持这样的回环。
另一个选择:Caddy
Caddy 用几行配置就能自动申请证书。插件示例里没有 Caddy,下面是按 Vaultwarden 官方文档的 Caddy 写法改过的最小例子:
yaml
services:
caddy:
image: caddy:2
container_name: caddy
restart: unless-stopped
ports:
- "80:80"
- "443:443"
- "443:443/udp"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- ${{ sf:"appdata" }}/caddy/data:/data
- ${{ sf:"appdata" }}/caddy/config:/config
networks:
- proxy
networks:
proxy:
external: trueCaddyfile 在 服务 → Compose → 配置(Configs)页创建,选中这个 compose 文件,文件名填 Caddyfile,内容:
text
vault.example.com {
reverse_proxy vaultwarden:80
}Caddy 官方镜像不含 DNS 质询模块,要用 DNS 质询需要自己构建带模块的 Caddy,见 Vaultwarden wiki 里的说明。
Traefik 也有示例,但示例开着 --api.insecure=true(仪表盘无需认证)、读写挂载了 docker.sock,还要你自己准备静态配置文件,新手不建议。
检查结果
- 在 OMV 的 shell 里(root)运行
ss -tulpn | grep -E ":80 |:443 ",占用 80 和 443 的是代理容器相关的进程,而不是 OMV 的 nginx。 - OMV 的 Web 界面在新端口上能正常登录。
- 在局域网里用
https://vault.example.com打开应用,浏览器显示有效证书,没有警告。 - 如果开放了外网:手机关掉 Wi-Fi 用流量访问,应当能打开;用同样的方法访问
http://你的公网IP:81,应当打不开。 - 在 NPM 的证书列表里看到到期时间,续期由 NPM 自动做。
常见问题
改了 OMV 端口,界面打不开了。 地址要带新端口。真的进不去,用 omv-firstaid 回退,见上面的警告。
NPM 启动失败,提示 80 或 443 已被占用。 OMV 的 nginx 还占着,确认端口修改已经应用,用 ss -tulpn 看谁在监听。
证书申请失败。 HTTP 质询:域名没解析到公网 IP、外部 80 没到达代理,或者在 CGNAT 后面。DNS 质询:API 令牌权限不足,或者 DNS 里有会干扰的通配符 CNAME 记录。Let's Encrypt 有申请频率限制,反复失败时先别连续重试。
访问时 502 Bad Gateway。 代理访问不到应用。检查:两边都加入了 proxy 网络;转发主机名是容器名;转发端口是容器内部端口;应用容器在运行。
页面能打开,但登录后跳转到 http:// 或循环重定向。 应用不知道自己在 HTTPS 后面。设置它的外部地址,例如 Vaultwarden 的 DOMAIN、Paperless-ngx 的 PAPERLESS_URL,Nextcloud AIO 要按官方的反向代理文档设置 APACHE_PORT。