这是「Docker 好项目」系列的第 2 期。每期挑一个真正能在自己服务器上跑起来、并且能解决具体问题的项目,给出能直接复制的配置。
上一期我们聊了怎么 7×24 盯着服务有没有挂,结尾留了一句「挂个反代 + HTTPS,成本几乎为零」。这一期就把这句话展开。
如果你现在访问自己的服务靠的是 http://服务器IP:3001、http://服务器IP:8080 这种地址,那有三个问题同时存在:记不住端口、没有 HTTPS 浏览器会标红、一个 IP 只能靠端口区分服务。
Nginx Proxy Manager(下面简称 NPM)就是一次性解决这三个问题的:给每个服务分配一个正经域名,自动签发并续期 Let's Encrypt 证书,全程在网页上点,不碰一行 Nginx 配置。

它到底能干什么
- 反向代理:把
blog.example.com指到内部某个端口,多个服务共用一个 IP - 免费 SSL:自动申请 Let's Encrypt 证书,到期前自动续期,不用管 certbot 定时任务
- 泛域名证书:支持 DNS 挑战方式签
*.example.com - 访问控制:给没有登录功能的面板加一层基础认证,或按 IP 段白名单
- 重定向 / 流转发:301/302 跳转,以及 TCP/UDP 端口转发(Streams)
- 自定义配置:每个反代条目都能塞原生 Nginx 指令
它不做的是:不做负载均衡的健康检查与权重调度、不做 WAF、不做 CDN 缓存。它是个人和小团队的反代管理层,不是企业级网关。
部署前准备:先确认这三件事
NPM 起不来的原因,九成出在这三步上,先自查:
1. 80 和 443 端口必须是空的
sudo ss -tlnp | grep -E ':80 |:443 '
用 1Panel 的同学特别注意:1Panel 默认会装 OpenResty,它已经把 80/443 占了,直接起 NPM 会报端口冲突。三个解法,选一个:
- 方案 A(推荐):就用 1Panel 自带的「网站 → 反向代理」,功能跟 NPM 重叠,不装 NPM
- 方案 B:在 1Panel 里停用 OpenResty,把 80/443 让给 NPM 统一管理
- 方案 C:继续用 OpenResty 做最外层,NPM 改用非标准端口(比如
8080:80、8443:443),代价是 Let's Encrypt 的 HTTP-01 验证会失效,得改用 DNS 挑战
2. 域名要指向这台服务器
去 DNS 服务商加一条 A 记录,指向服务器公网 IP。用 * 泛解析可以一次覆盖所有子域名:
| 类型 | 名称 | 值 |
|---|---|---|
| A | blog |
你的公网 IP |
| A | * |
你的公网 IP(可选,一次配齐) |
改完别急着操作,先确认解析已生效:
dig +short blog.你的域名
3. 云服务器要放行端口
华为云这类主机,安全组和系统防火墙是两层,都要开:80、443,以及管理界面的 81。安全组没开的话,外面根本连不进来,症状是「容器起来了但网页打不开」。
一键启动:docker-compose
mkdir -p /opt/nginx-proxy-manager && cd /opt/nginx-proxy-manager
新建 docker-compose.yml:
services:
nginx-proxy-manager:
image: jc21/nginx-proxy-manager:2.14.0
container_name: nginx-proxy-manager
restart: unless-stopped
ports:
- "80:80" # HTTP,Let's Encrypt 验证要用
- "443:443" # HTTPS
- "127.0.0.1:81:81" # 管理后台,只监听本机
volumes:
- ./data:/data
- ./letsencrypt:/etc/letsencrypt
environment:
- TZ=Asia/Shanghai
# 服务器不支持 IPv6 时打开,能避免证书验证卡住
# - DISABLE_IPV6=true
networks:
- proxy
networks:
proxy:
name: proxy
driver: bridge
启动:
docker compose up -d
docker compose logs -f nginx-proxy-manager
每个配置项为什么这么写
| 配置 | 说明 |
|---|---|
image: ...:2.14.0 |
官方示例常用 :latest,但建议 pin 具体版本。NPM 跨版本升级会改数据库结构,锁定版本才能随时重建 |
80:80 |
不能省。Let's Encrypt 的 HTTP-01 挑战要访问 80 端口,关掉就签不了证书 |
127.0.0.1:81:81 |
管理后台只绑本机。81 端口的默认账号是公开的,暴露到公网等于把路由和证书交给别人 |
./data:/data |
所有反代规则、账号、配置都在这,必须备份 |
./letsencrypt:/etc/letsencrypt |
证书存放位置,丢了要重新签发 |
DISABLE_IPV6 |
服务器没有 IPv6 时,NPM 可能尝试用 IPv6 去验证导致超时,国内云主机常见 |
networks: proxy |
建一个独立网络,后面让被代理的服务也加入进来,就能用容器名互相访问 |
早期教程里会让你再配一个 MariaDB 容器。现在不用了——NPM 默认用 SQLite,官方文档的标准 compose 已经不含数据库服务,个人使用完全够。
首次登录:第一件事是改密码
管理后台在 http://服务器IP:81。因为我们只绑了 127.0.0.1,从外面访问要用 SSH 隧道:
ssh -L 8181:127.0.0.1:81 root@你的服务器IP
然后本地浏览器打开 http://localhost:8181。
默认账号:
- 邮箱:
admin@example.com - 密码:
changeme
登录后立刻改掉。这两个值是公开写进文档的,不改等于门户大开。改完会被强制登出,用新密码重新登录。
顺便把邮箱改成你自己的——证书快过期时 Let's Encrypt 会往这个邮箱发通知。
加第一个反代:从域名到 HTTPS
假设 Uptime Kuma 跑在 3001 端口,想用 status.你的域名 访问。
第一步:让 Kuma 加入同一个网络
在 Uptime Kuma 的 compose 里加上:
services:
uptime-kuma:
# ... 原有配置不变
networks:
- proxy
networks:
proxy:
external: true # 用 NPM 已经建好的那个
然后 docker compose up -d 重建。
第二步:在 NPM 里添加
进后台 → Hosts → Proxy Hosts → Add Proxy Host:
Details 标签
| 字段 | 填什么 |
|---|---|
| Domain Names | status.你的域名 |
| Scheme | http(内部走明文就行,HTTPS 由 NPM 终结) |
| Forward Hostname / IP | uptime-kuma(容器名,前提是同一 Docker 网络) |
| Forward Port | 3001 |
| Block Common Exploits | 打开 |
| Websockets Support | 打开(Kuma 靠 WebSocket 实时刷新,不开数据不动) |
SSL 标签
| 字段 | 填什么 |
|---|---|
| SSL Certificate | Request a new SSL Certificate |
| Force SSL | 打开(HTTP 自动跳 HTTPS) |
| HTTP/2 Support | 打开 |
| 你的邮箱 | |
| 同意条款 | 勾上 |
点 Save,等 15~30 秒,条目变绿就是成功了。此时 https://status.你的域名 已经能用,有绿色小锁。
为什么用容器名而不是 IP:容器的 IP 每次重启都可能变,用容器名由 Docker 自己解析,永远不会指错。
三个真正好用的进阶功能
给没有登录的面板加把锁
很多自建面板(比如一些下载器、监控页)压根没有登录功能,直接暴露很危险。
Access Lists → Add Access List → 在 Authorization 页加用户名密码 → 保存 → 回到反代条目,在 Access List 下拉里选它。再访问就会先弹登录框。
按 IP 限制同理,适合只允许家里网络或 VPN 网段访问的场景。
改上传大小限制
默认上传限制很小,传大文件会 413 报错。在反代条目的 Advanced 标签里加:
client_max_body_size 512M;
proxy_read_timeout 300s;
WebSocket 手动补
有些服务在 Details 里勾了 Websockets 还不生效,去 Advanced 补上:
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
备份
只需要打包两个目录,规则和账号全在里面:
cd /opt/nginx-proxy-manager
tar czf npm-backup-$(date +%F).tar.gz data/ letsencrypt/
挂到 1Panel 的计划任务或 crontab 里,每周一次。恢复就是解压回去再 docker compose up -d。
踩坑清单
- 证书申请失败,先查三件事:DNS 是否生效、
80端口外网是否可达(可用curl -I http://你的域名从手机流量测)、安全组是否放行 - 端口 80 被运营商封了:家用宽带常见。改用 DNS 挑战签证书,需要在 SSL 设置里选 DNS Challenge 并填服务商 API
- 不要双层反代:OpenResty 套 NPM 再套服务,容易出 header 和 WebSocket 问题。NPM 应该是最外层做 SSL 终结的那一层
- 改配置后不生效:NPM 偶尔不会重载 Nginx,进后台重新 Save 一次对应条目即可
- 别把 81 暴露公网:这是最容易被扫到的入口,务必绑 127.0.0.1 或用 SSH 隧道
- 华为云安全组和系统防火墙是两层:只在服务器里 ufw 放行没用,控制台的安全组也要开
小结
NPM 属于「一旦用上就回不去」的基础设施:服务再多,也只需要记住域名,不用记端口;证书再也不用手动续。
适合:一台机器上跑多个自建服务、想要 HTTPS、不想手写 Nginx 配置的个人和小团队。 不适合:需要 WAF、精细负载均衡策略、多节点高可用的生产场景——那个层级该看 Traefik 或专业网关。
下期继续聊另一个 Docker 项目。
项目地址:https://github.com/NginxProxyManager/nginx-proxy-manager 官方文档:https://nginxproxymanager.com