Nginx Proxy Manager 日常运维手册
Nginx Proxy Manager(NPM)v2.16.0 日常运维手册:巡检与健康检查、数据备份与迁移恢复实测、版本升级回滚、证书续期机制与六类故障排查实录,均已在 Ubuntu 22.04 实测通过
Nginx Proxy Manager 日常运维手册
目标:面向已按部署篇完成 Nginx Proxy Manager(NPM)v2.16.0 部署的运维人员,覆盖日常巡检、数据备份与迁移恢复、版本升级与回滚、证书续期机制、日志管理与典型故障排查六大场景,全部命令与回显均已在 Ubuntu 22.04 实测通过,故障案例均为真实发生并记录的排障实录。
一、环境信息
本章为全文实测基准,所有巡检、备份、升级、排障操作都在同一套 v2.16.0 实例上完成。
- 操作系统:Ubuntu 22.04(NPM v2.16.0 运行实例,部署基线见《Nginx Proxy Manager Docker Compose 部署指南》)
- 实例形态:编排部署于 /opt/npm(主服务与演示后端两个服务实例),数据挂载 /opt/npm/data 与 /opt/npm/letsencrypt,端口映射 8093/8094/8095/8096
- 实例数据:2 条代理主机(demo.local 挂自定义证书与强制 HTTPS、acl.local 挂访问控制)、1 条 404 主机、1 条 Stream、1 张自签证书、1 条 ACL
- 管理账号:admin@example.com(API 令牌已保存在本地 /opt/npm/token.txt,1 天有效期)
二、日常巡检与健康检查
日常巡检围绕四个层面:管理面是否存活、数据面配置是否合法、服务状态与资源占用、主机是否可正常转发。
2.1 管理面健康检查
无需认证的管理接口是最轻量的探活命令,可直接纳入监控拨测:
curl -s http://127.0.0.1:8094/api/
实测回显:
{"status":"OK","setup":true,"version":{"major":2,"minor":16,"revision":0}}
status:OK 即管理面存活;setup:true 表示元数据库完好;version 与预期版本一致说明没有意外升级。
2.2 数据面配置合法性检查
管理面存活不代表 Nginx 数据面配置合法,进入 NPM 服务实例执行标准检查命令:
nginx -t
实测回显:
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
test is successful 即当前全部生成配置可正常加载。若此命令报错,优先按第六章 Q1 排查。
2.3 服务监听与资源基准
确认 NPM 的四个业务/管理端口都在宿主机正常监听:
ss -ltn | grep -E ':(8093|8094|8095|8096)\b'
实测回显(4 个端口各有 IPv4/IPv6 两条监听记录):
LISTEN 0 4096 0.0.0.0:8093 0.0.0.0:*
LISTEN 0 4096 0.0.0.0:8094 0.0.0.0:*
LISTEN 0 4096 0.0.0.0:8095 0.0.0.0:*
LISTEN 0 4096 0.0.0.0:8096 0.0.0.0:*
LISTEN 0 4096 [::]:8093 [::]:*
LISTEN 0 4096 [::]:8094 [::]:*
LISTEN 0 4096 [::]:8095 [::]:*
LISTEN 0 4096 [::]:8096 [::]:*
资源基准(本实例实测):近空载时主服务常驻内存约 77 MiB、演示后端约 10 MiB,CPU 趋近 0。巡检时若内存持续增长或 CPU 长期高位,结合 6.1 节日志确认是否有异常流量或攻击特征。
2.4 业务转发抽检
抽查代表性主机是否仍正常转发(HTTP 主机 + HTTPS 主机各一条):
curl -s -o /dev/null -w 'acl.local HTTP=%{http_code}\n' -u admin:q1w2e3r4 -H "Host: acl.local" http://127.0.0.1:8093/
curl -sk -o /dev/null -w 'demo.local HTTPS=%{http_code}\n' --resolve demo.local:8095:127.0.0.1 https://demo.local:8095/
实测回显:
acl.local HTTP=200
demo.local HTTPS=200
两个 200 即全链路(Nginx → 转发模板 → 上游)健康;出现 401/502/404 时按第六章对应条目处理。
三、数据备份与恢复
NPM 的全部状态在 /data 与 /etc/letsencrypt 两个挂载目录(内容构成详见《Nginx Proxy Manager 2.16.0 配置参数详解》),本章给出可实际执行的备份与恢复流程,恢复流程已做完整的迁移实测。
3.1 备份:打包数据目录
最简单可靠的备份就是停机打包两个挂载目录(在线打包同样可行——SQLite 单文件在写入间隙拷贝一般一致,但生产环境建议低峰执行或先停止主服务实例):
mkdir -p /opt/backup
tar -czf /opt/backup/npm-data-$(date +%Y%m%d).tar.gz -C /opt/npm data letsencrypt
ls -lh /opt/backup/ && tar -tzf /opt/backup/npm-data-*.tar.gz | wc -l
实测回显(本实例全量数据,含全部主机/证书/日志):
total 20K
-rw-r--r-- 1 root root 19K 10月 18 15:25 npm-data-20261018.tar.gz
48
实测全量备份仅 19K、48 个对象——NPM 的状态极轻量,备份成本几乎可以忽略。必须保留的关键文件:database.sqlite(元数据)、keys.json(令牌签名密钥,实测权限 600,丢失后旧令牌全部失效)、custom_ssl/ 与 letsencrypt/(证书)。
3.2 恢复与迁移实测
以下演示「备份 → 在新位置恢复 → 用恢复的数据启动一套全新实例 → 全链路验证」的完整迁移流程(等价于迁移到新服务器的过程,仅需把备份包传到新服务器后执行相同步骤)。
第一步,解包备份到新目录:
mkdir -p /opt/restore && cd /opt/restore
tar -xzf /opt/backup/npm-data-20261018.tar.gz
ls -d data letsencrypt && ls data/database.sqlite data/keys.json
实测回显:
data
letsencrypt
data/database.sqlite
data/keys.json
第二步,用恢复出的数据启动实例。启动方式与全新部署完全一致(编排写法见《Nginx Proxy Manager Docker Compose 部署指南》),仅两处差异:数据目录挂载指向 /opt/restore/data 与 /opt/restore/letsencrypt(而不是 /opt/npm 下的原目录);实例需接入与上游后端互通的网络(本实测接入了原编排网络,使 demo 上游可达;跨主机迁移时使用目标机网络并把上游地址指向目标机的后端)。本实测实例监听 18093/18094/18095 三个临时端口以避免与原实例冲突。
第三步,全链路验证恢复效果(等 30 秒让服务完成初始化):
sleep 30 && curl -s http://127.0.0.1:18094/api/
TOKEN=$(cat /opt/npm/token.txt) && curl -s "http://127.0.0.1:18094/api/nginx/proxy-hosts" \
-H "Authorization: Bearer $TOKEN" \
| python3 -c "import json,sys; d=json.load(sys.stdin); print('restored_hosts:', [(h['id'], h['domain_names']) for h in d])"
curl -s -o /dev/null -w 'RESTORED_PROXY=%{http_code}\n' -H "Host: demo.local" http://127.0.0.1:18093/
curl -sk -o /dev/null -w 'RESTORED_HTTPS=%{http_code}\n' --resolve demo.local:18095:127.0.0.1 https://demo.local:18095/
实测回显:
{"status":"OK","setup":true,"version":{"major":2,"minor":16,"revision":0}}
restored_hosts: [(2, ['acl.local']), (1, ['demo.local'])]
RESTORED_PROXY=301
RESTORED_HTTPS=200
四项验证全部通过的结论:管理员与全部主机配置完整恢复(setup:true + 两条主机);旧 API 令牌继续有效(keys.json 随备份恢复);HTTP 强跳 301 与 HTTPS 200 说明证书绑定关系也完整还原。这正是日常演练迁移的标准动作:每次备份后可定期抽检一次恢复流程,确保备份真的可用。
3.3 备份自动化建议
将 3.1 节命令写入计划任务即可实现每日备份(示例:每天 02:30 备份并保留 14 天,写入 root 的 crontab):
30 2 * * * tar -czf /opt/backup/npm-data-$(date +\%Y\%m\%d).tar.gz -C /opt/npm data letsencrypt && find /opt/backup -name 'npm-data-*.tar.gz' -mtime +14 -delete
两点提醒:备份目录 /opt/backup 不放在 /opt/npm 内,避免被下次备份重复打包;跨机容灾则把 /opt/backup 同步到异地(rsync 或对象存储均可)。
四、版本升级与回滚
4.1 升级标准流程
三步:备份 → 变更版本标签 → 重建服务实例。
- 按 3.1 节完成备份(跨版本升级必须做,原因见 4.2 的回滚限制);
- 在部署编排中把主服务的版本标签(如 2.16.0)改为目标版本;
- 重建服务实例:编排检测到版本变化会自动拉取新版本并重建,数据目录不受影响,全程约半分钟(具体命令与实测回显见《Nginx Proxy Manager Docker Compose 部署指南》的升级操作)。
升级完成后立即执行第二章 2.1~2.4 的巡检命令确认健康。
4.2 回滚
编排形态下回滚就是把版本标签改回旧版本并重建服务实例。v2.16.0 之前的版本(如 2.12.x → 2.16.0 跨度)涉及元数据库自动迁移,迁移后数据库结构已变,直接回滚旧版本可能无法识别新库——这是回滚最大的坑。因此升级前务必备份(3.1 节),回滚时先恢复备份再启动旧版本,而不是仅改标签。
4.3 版本与标签策略
生产环境固定精确版本标签(如 2.16.0),升级动作显式化;latest/2 标签的自动漂移会让回滚失去基准(标签选型依据见《Nginx Proxy Manager 2.16.0 介绍与选型指南》)。关注官方 Releases 中的安全修复条目,v2.16.0 即包含多项安全修复(证书私钥权限、密码修改后旧令牌未失效等),遇到同类 CVE 应尽快跟进升级。
五、证书申请与续期机制
5.1 自动续期机制
NPM 内置 Certbot 5.8.0,续期由管理后端的定时器驱动。每次服务启动时日志可见续期器初始化(实测服务运行日志节选):
npm-2.16.0-app | [10/18/2026] [7:40:20 AM] [SSL ] › ℹ info Let's Encrypt Renewal Timer initialized
npm-2.16.0-app | [10/18/2026] [7:40:20 AM] [SSL ] › ℹ info Renewing SSL certs expiring within 30 days ...
npm-2.16.0-app | [10/18/2026] [7:40:20 AM] [IP Ranges] › ℹ info IP Ranges Renewal Timer initialized
npm-2.16.0-app | [10/18/2026] [7:40:20 AM] [SSL ] › ℹ info Completed SSL cert renew process
续期窗口为 30 天——运行实例内的续期模块源码参数为 renewBeforeExpirationBy: [30, "days"](/app/internal/certificate.js 实读核实),即后端每日检查一次,到期不足 30 天的 Let's Encrypt 证书自动触发 Certbot 续期(v2.16.0 起默认签发 ECDSA secp384r1 证书,全局参数文件 /etc/letsencrypt.ini 的逐项解读见《Nginx Proxy Manager 2.16.0 配置参数详解》)。续期要求与首次申请相同:HTTP 校验需域名公网可达且 80 端口开放,DNS 校验需凭据有效。
5.2 证书有效期巡检
通过证书列表接口批量核对有效期(自定义证书与 Let's Encrypt 证书同表):
TOKEN=$(cat /opt/npm/token.txt) && curl -s "http://127.0.0.1:8094/api/nginx/certificates" \
-H "Authorization: Bearer $TOKEN" \
| python3 -c "import json,sys; d=json.load(sys.stdin); [print(c['id'], c['provider'], c['nice_name'], c['domain_names'], 'expires_on:', c['expires_on']) for c in d]"
实测回显(本实例仅一张自签证书;生产环境应有 provider=letsencrypt 的记录):
1 other demo.local self-signed ['demo.local'] expires_on: 2027-10-18 07:18:51
巡检关注点:expires_on 距今不足 30 天且持续未变的 Let's Encrypt 证书,说明自动续期未成功,立即查 /data/logs/letsencrypt.log 定位原因(常见原因见第六章 Q2)。管理界面「SSL Certificates」页同样展示该信息与到期倒计时。
5.3 续期失败兜底
Let's Encrypt 申请/续期的完整过程都落在 /data/logs/letsencrypt.log(自动轮转出 .1 等历史文件)。实测一次申请失败的日志尾部(无效邮箱被 ACME 拒绝):
certbot.errors.Error: Unable to register an account with ACME server. The ACME server believes admin@example.com is an invalid email address. Please ensure it is a valid email and attempt registration again.
2026-10-18 07:25:05,396:ERROR:certbot._internal.log:Unable to register an account with ACME server. The ACME server believes admin@example.com is an invalid email address. Please ensure it is a valid email and attempt registration again.
调试签发流程时可设置环境变量 LE_STAGING=true 走 Let's Encrypt 测试环境,避免调试期触发正式环境限额(频率限制见官方文档)。
六、日志管理与排障
6.1 日志文件体系
全部日志集中在 /data/logs(宿主机 /opt/npm/data/logs),实测本实例日志总量与构成:
du -sh /opt/npm/data/logs && ls -lh /opt/npm/data/logs/proxy-host-1_access.log /opt/npm/data/logs/backend.log
实测回显:
76K /opt/npm/data/logs
-rw-r--r-- 1 root root 21K Oct 18 07:40 /opt/npm/data/logs/backend.log
-rw-r--r-- 1 root root 1.8K Oct 18 07:40 /opt/npm/data/logs/proxy-host-1_access.log
命名规律与用途(完整对应关系见《Nginx Proxy Manager 2.16.0 配置参数详解》):<类型>-<主机ID>_access.log / _error.log 为各主机独立日志(类型含 proxy-host、dead-host、redirection-host、stream),fallback_* 为兜底站点与全局错误,letsencrypt.log 为证书过程日志,backend.log 为管理 API 日志。
访问日志的轮转由 NPM 内置的 logrotate 配置管理(/etc/logrotate.d/nginx-proxy-manager 实测内容节选):
/data/logs/*_access.log /data/logs/*/access.log {
su npm npm
create 0644
weekly
rotate 4
missingok
notifempty
compress
sharedscripts
postrotate
kill -USR1 `cat /run/nginx/nginx.pid 2>/dev/null` 2>/dev/null || true
endscript
即:每周轮转、保留 4 份、压缩归档,轮转后向 Nginx 发 USR1 信号重开日志文件。磁盘巡检时该目录通常稳定在很小体量;v2.16.0 新增的界面内日志查看器读取的正是这些文件,无需登录服务器即可查看。
6.2 故障排查实录
以下五例均为本文实测中真实发生并记录的故障,每例给出「现象 → 根因证据 → 处理动作」。
Q1:数据面配置非法 / 界面提示主机离线 现象:nginx -t 报错,或界面主机卡片出现离线横幅。根因证据链:先看生成配置的错误副本与主机错误日志(配置生成机制见《Nginx Proxy Manager 2.16.0 配置参数详解》):
ls /opt/npm/data/nginx/proxy_host/ /opt/npm/data/nginx/stream/ && tail -5 /opt/npm/data/logs/proxy-host-1_error.log
实测回显(正常实例的基线输出;异常时会出现 .conf.err 文件与 Nginx 错误行):
/data/nginx/proxy_host/:
1.conf
2.conf
/data/nginx/stream/:
2.conf
处理:.conf.err 中的 Nginx 报错即语法错误原文(多数来自 Advanced Config 手写指令),改正后重新在界面保存该主机即可恢复。
Q2:代理返回 502 Bad Gateway 实测现象:停止演示后端后访问 demo.local:
curl -sk -o /dev/null -w 'BACKEND_DOWN=%{http_code}\n' --resolve demo.local:8095:127.0.0.1 https://demo.local:8095/
实测回显:
BACKEND_DOWN=502
根因证据(主机错误日志):
grep -E 'connect|upstream|resolve' /opt/npm/data/logs/proxy-host-1_error.log | tail -2
实测回显:
2026/10/18 07:24:27 [error] 273#273: *11 demo could not be resolved (2: Server failure), client: 10.89.24.1, server: demo.local, request: "GET / HTTP/1.1", host: "demo.local:8095"
处理:could not be resolved → 上游主机名不可解析(后端已停/网络不通),恢复后端即恢复(实测恢复后 502 变回 200);connect() failed → 解析成功但端口不通,查上游服务与防火墙;日志为空但持续 502 → 用 2.2 节 nginx -t 确认配置本身。
Q3:Let's Encrypt 证书申请失败 实测现象(无效域名 + 假邮箱走 HTTP 校验):
{"error":{"code":500,"message":"Internal Error"},"debug":{"stack":["Error: Saving debug log to /data/logs/letsencrypt.log","Unable to register an account with ACME server. The ACME server believes admin@example.com is an invalid email address. ...(节选)]}}
处理:按 letsencrypt.log 中的原始 Certbot 错误分三类处置——邮箱无效(本例)→ 换真实邮箱;域名解析不通 → HTTP 校验需域名公网解析且 80 端口可达,或改用 DNS 校验 + 泛域名;触达频率限额 → LE_STAGING=true 走测试环境调试,正式签发等待限额窗口。
Q4:启动/新建主机时报 port is already allocated 实测现象(8093 已被占用时再绑定同端口,错误关键字行节选):
Bind for 0.0.0.0:8093 failed: port is already allocated
处理:ss -ltnp | grep <端口> 找到占用方——多为同机另一套 NPM 实例或重复执行了部署;停掉多余实例或改端口。Stream 主机新建时端口冲突也会在界面以类似错误提示。
Q5:HTTPS 测试报 tlsv1 unrecognized name 实测现象:
curl -sk https://127.0.0.1:8095/ -H "Host: demo.local"; echo "EXIT=$?"
实测回显:
EXIT=35
加 -v 可见 TLS alert, unrecognized name。根因:TLS 握手按 SNI 匹配证书与 server 块,用 IP 访问时 SNI 不是任何已配置域名。这不是故障,是测试方法问题:用 --resolve(或 openssl s_client -servername)带上正确 SNI 即通过(2.4 节巡检命令即采用该写法)。同类问题也会出现在「客户端未发送 SNI」的老旧设备访问场景。
Q6:单命令形态启动后 Nginx 反复重启报 host not found in upstream 实测现象(元数据里存在指向编排网络服务名的 Stream/代理主机时,脱离编排网络单命令运行):
❯ Starting nginx ...
nginx: [emerg] host not found in upstream "demo" in /data/nginx/stream/1.conf:10
处理:单命令/迁移形态下先保证上游地址可达(改用 IP 或跨网可达的域名),或临时移除引用不可达上游的主机。这也是迁移演练中必须让恢复实例接入与上游连通的网络的原因(3.2 节实测即接入了同一编排网络)。
七、参考链接
- NPM 官方文档:https://nginxproxymanager.com/
- 官方 GitHub 仓库与 Releases(升级依据):https://github.com/NginxProxyManager/nginx-proxy-manager/releases
- 本组件部署流程:《Nginx Proxy Manager Docker Compose 部署指南》
- 本组件配置详解:《Nginx Proxy Manager 2.16.0 配置参数详解》
- 本组件认知与选型:《Nginx Proxy Manager 2.16.0 介绍与选型指南》
- Certbot 官方文档(续期参数与频率限制):https://eff-certbot.readthedocs.io/