这是「Docker 好项目」系列的第 2 期。每期挑一个真正能在自己服务器上跑起来、并且能解决具体问题的项目,给出能直接复制的配置。

上一期我们聊了怎么 7×24 盯着服务有没有挂,结尾留了一句「挂个反代 + HTTPS,成本几乎为零」。这一期就把这句话展开。

如果你现在访问自己的服务靠的是 http://服务器IP:3001、http://服务器IP:8080 这种地址,那有三个问题同时存在:记不住端口、没有 HTTPS 浏览器会标红、一个 IP 只能靠端口区分服务。

Nginx Proxy Manager(下面简称 NPM)就是一次性解决这三个问题的:给每个服务分配一个正经域名,自动签发并续期 Let's Encrypt 证书,全程在网页上点,不碰一行 Nginx 配置。

Nginx Proxy Manager 管理界面

它到底能干什么

  • 反向代理:把 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 打开
Email 你的邮箱
同意条款 勾上

点 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