Immich 跑在 2283,Vaultwarden 在 8222,Jellyfin 8096,Alist 5244,qBittorrent 8081,Portainer 9000。
六个端口,六个 IP:端口,我自己都记不住,更别说朋友了。他每次问我"那个看剧的地址是啥来着",我都得翻一下笔记。
还有个大问题:除了 Vaultwarden 强制要 https,其他都是 http。手机在外面连,运营商有时候会劫持 http 页面,弹广告。
这篇讲我怎么用 Nginx Proxy Manager 把这些服务统一收进 https 域名。
NPM 是干什么的
一句话:给不会写 nginx 配置的人用的反代面板。
网页上填几个空,就能把一个域名反代到内网端口,证书自动申请、自动续期。
它不是必须要用,但对不想天天改配置文件的人来说,省事。
一、先看端口冲突
NPM 要占 80 和 443 才能申请证书、才能正常反代。
我这台机器上,宝塔面板已经占了 80 和 443(主站 moxiaoa.com 就在上面跑)。
两种做法:
做法一:让 NPM 接管 80/443,主站也交给它管。
最干净。把宝塔站的 nginx 停掉,主站的反代规则搬到 NPM 里,之后所有域名统一在 NPM 上维护。
代价是主站要重新配一遍,而且宝塔面板的证书、伪静态这些都要跟着改。
做法二:主站不动,NPM 换端口,中间加一层转发。
我用的这个。原因是我主站已经跑了一个月,ssl 证书、301 规则、伪静态都在宝塔上配好了,搬过去风险大于收益。
具体是:
- 主站 nginx 继续占 80/443,负责 moxiaoa.com 和 moxiaoa.cn
- NPM 换到 8080/8443,只处理子域名(photo、vault、jelly 这些)
- 子域名的请求先到主站 nginx,再转发到 NPM
多了一跳,但主站零改动。
如果你机器上没有别的 web 服务占 80/443,直接用做法一,比我这套简单十倍。 我这是历史包袱,不是推荐方案。
下面按做法一(干净场景)写配置,最后一节说我这种复杂情况的处理。
下面按"机器上没有其他服务"的干净场景讲,最后再说我这种复杂情况的处理。
二、compose 配置
services:
npm:
container_name: nginx-proxy-manager
image: jc21/nginx-proxy-manager:latest
restart: unless-stopped
ports:
- "80:80"
- "443:443"
- "81:81"
volumes:
- /opt/docker/npm/data:/data
- /opt/docker/npm/letsencrypt:/etc/letsencrypt
environment:
- TZ=Asia/Shanghai
mem_limit: 512m
三个端口的分工:
| 端口 | 用途 |
|---|---|
| 80 | HTTP,也是 Let's Encrypt 验证用的 |
| 443 | HTTPS |
| 81 | 管理后台 |
启动后访问 http://服务器IP:81,默认账号:
- 邮箱:
admin@example.com - 密码:
changeme
第一次登录会强制改密码,改完进主界面。
三、加一个反代
点 Proxy Hosts → Add Proxy Host,填四个地方:
Details 页:
| 字段 | 填什么 |
|---|---|
| Domain Names | jelly.你的域名.com |
| Scheme | http |
| Forward Hostname / IP | 容器名或者宿主机内网 IP |
| Forward Port | 8096 |
| Block Common Exploits | 勾上 |
| Websockets Support | 勾上(Vaultwarden、Jellyfin 都需要) |
Forward Hostname 填什么,是这套东西的关键。
如果 NPM 和其他容器在同一个 docker 网络里,直接填容器名,比如 jellyfin。
如果不在同一个网络,填宿主机内网 IP,比如 192.168.1.50。
我一开始填了 localhost,结果反代一直 502——因为在 NPM 容器里,localhost 指的是容器自己,不是宿主机。
正确的做法:要么把 NPM 和其他服务放进同一个 docker 网络,要么填宿主机 IP。
我后来统一用了一个自定义网络:
docker network create apps
然后在每个服务的 compose 里加:
networks:
default:
external: true
name: apps
这样 NPM 和服务之间直接用容器名通信。
SSL 页:
- 选 "Request a new SSL Certificate"
- 勾上 "Force SSL"
- 勾上 "HTTP/2 Support"
- 填邮箱(证书到期提醒)
- 同意条款
点保存,NPM 会自动去 Let's Encrypt 申请证书。
四、证书申请失败的四种原因
这一步是最容易卡住的,我踩了三种。
原因一:DNS 没生效
域名要提前解析到服务器 IP,用 dig 或者 nslookup 确认。刚解析的域名要等几分钟到几小时。
dig +short jelly.你的域名.com
能返回你的服务器 IP 才去申请。
原因二:80 端口不通
Let's Encrypt 的 HTTP 验证要走 80 端口。如果 80 被防火墙拦了、或者被别的程序占了,验证就失败。
云服务器的安全组要放行 80 和 443。
原因三:申请次数限制
Let's Encrypt 同一个域名一周最多失败 5 次,超了要等一周。所以别反复试,先排查清楚再点。
我第一天不知道这个限制,失败三次之后不敢点了,第二天改好 DNS 才成功。
原因四:域名有 CAA 记录限制
少见,但遇到过。如果域名的 DNS 里配了 CAA 记录,只允许特定 CA 签发,Let's Encrypt 就会被拒。查一下:
dig CAA 你的域名.com
五、我实际的配置
我的主站(moxiaoa.com)已经在宝塔的 nginx 上跑着,占着 80/443,不想动。
所以我的方案是:
- 子域名(jelly、vault、photo 等)全部解析到同一台机器
- NPM 换端口到 8080/8443
- 在主站 nginx 里给子域名加一个 server 块,反代到 NPM 的 8080/8443
这样主站不受影响,子域名由 NPM 管理证书。
配置大概长这样:
server {
listen 80;
server_name jelly.moxiaoa.com vault.moxiaoa.com photo.moxiaoa.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name jelly.moxiaoa.com vault.moxiaoa.com photo.moxiaoa.com;
ssl_certificate /etc/letsencrypt/live/子域名/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/子域名/privkey.pem;
location / {
proxy_pass https://127.0.0.1:8443;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
说实话,这套配置比直接用 NPM 麻烦,但因为我主站在宝塔上,改来改去风险更大,就这样了。
如果你的机器是干净的,直接用 NPM 接管 80/443,比我这套简单十倍。
六、几个实用功能
1. 访问列表(Access List)
给不想公开的服务加个 HTTP Basic Auth:
Access Lists → Add → 填用户名密码 → 在 Proxy Host 里选择。
Portainer、qBittorrent 这种管理面板,加上一层,安全很多。
2. 自定义 location
Advanced 页可以加自定义 nginx 配置。比如给 Jellyfin 加 WebSocket 长连接超时:
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
3. 重定向规则
老域名跳新域名、http 跳 https,都能在界面上配。
七、踩坑提醒
坑一:改完配置要等几秒
NPM 改完配置会重新加载 nginx,大概 2-5 秒。改完立刻访问可能还是旧的。
坑二:镜像更新会重置配置吗
不会,配置在 /data 里。但大版本更新前一定要备份 /data 和 /letsencrypt,我见过更新后证书全丢的案例。
坑三:Let's Encrypt 证书 90 天到期
NPM 会自动续期,但前提是 80 端口一直通。如果哪天你把 80 关了,续期就失败。建议每月上去看一眼证书状态。
最后
装完 NPM,我朋友终于不用记端口了。他现在记的是三个地址:
photo.xxx.com看照片jelly.xxx.com看剧vault.xxx.com管密码
这才像个正经的家庭服务器。
下一篇写 Uptime Kuma——让这些服务挂了的时候,有人通知我。
---
如果你也在折腾这套服务,碰到卡住的地方,可以加我微信 lige0552 聊聊。白天要上班,消息回得慢,看到都会回。