Nginx Proxy Manager 2.16.0 配置参数详解
Nginx Proxy Manager(NPM)v2.16.0 配置参数详解:编排环境变量、/data 与 /etc/letsencrypt 数据目录结构、界面生成的 Nginx 配置逐段解读与手工修改边界,全部实测于 Ubuntu 22.04
Nginx Proxy Manager 2.16.0 配置参数详解
目标:系统梳理 Nginx Proxy Manager(NPM)v2.16.0 的全部配置入口——编排环境变量、/data 数据目录、/etc/letsencrypt 证书目录与网页界面自动生成的 Nginx 配置,讲清每个参数的含义、默认值、生效方式与手工修改边界,全部结构与文件内容均已在 Ubuntu 22.04 实测通过(真实截取自运行中的 v2.16.0 实例)。
一、环境信息
本章为全文的实测基准,文中出现的目录树、文件内容、回显均截取自同一套 v2.16.0 运行实例。
- 操作系统:Ubuntu 22.04(NPM v2.16.0 运行实例,部署基线见《Nginx Proxy Manager Docker Compose 部署指南》)
- 实例状态:已按《Nginx Proxy Manager Docker Compose 部署指南》完成部署,内含 2 条代理主机(demo.local、acl.local)、1 条 404 主机(notfound.local)、1 条 Stream(8096)、1 张自定义证书与 1 条访问控制列表——正好覆盖全部配置类型,便于逐一解剖
- 挂载关系:宿主机 /opt/npm/data → 服务内 /data;宿主机 /opt/npm/letsencrypt → 服务内 /etc/letsencrypt
二、配置体系总览
NPM 的配置分四层,优先级与职责各不相同。动任何一处配置前,先确定它属于哪一层。
| 层 | 载体 | 典型内容 | 生效方式 |
|---|---|---|---|
| 编排层 | 部署编排文件 | 版本标签、端口映射、环境变量、挂载 | 重建服务实例后生效 |
| 管理层 | /data/database.sqlite(由网页界面/API 写入) | 主机、用户、证书记录、访问控制定义 | 界面保存即生效(自动生成配置并重载 Nginx) |
| 数据面层 | /data/nginx/ 下自动生成的 .conf | 每个 server 块的实际 Nginx 配置 | 由管理层驱动生成,勿手工直改 |
| 引擎层 | /etc/nginx/nginx.conf、conf.d/、conf.d/include/ | 全局指令、默认站点、可复用片段 | 随版本内置,升级后可能被覆盖 |
引擎层的主配置 nginx.conf 开头与注入点(实测节选):
# run nginx in foreground
daemon off;
pid /run/nginx/nginx.pid;
user npm;
# Set number of worker processes automatically based on number of CPU cores.
worker_processes auto;
# Enables the use of JIT for regular expressions to speed-up their processing.
pcre_jit on;
error_log /data/logs/fallback_error.log warn;
# Includes files with directives to load dynamic modules.
include /etc/nginx/modules/*.conf;
# Custom
include /data/nginx/custom/root_top[.]conf;
events {
include /data/nginx/custom/events[.]conf;
}
关键解读:全局配置也预留了 include /data/nginx/custom/root_top[.]conf 与 events[.]conf 等注入点(http 块内还有 server_top 等,同理)。这些文件不存在时等价于空操作,因此「升级不丢自定义」的设计贯穿了整个配置体系——所有手工扩展都应写到 /data 挂载目录内,而不是直接改 /etc/nginx 下的内置文件。
conf.d 目录结构(实测):
/etc/nginx/conf.d/default.conf # 未匹配任何主机时的兜底站点(80/443)
/etc/nginx/conf.d/production.conf # 管理界面(81 端口)的 server 块
/etc/nginx/conf.d/include/ # 可复用片段(代理头、强跳、防注入、TLS 参数等)
三、编排环境变量详解
以下变量写在编排文件 services.app.environment: 下。默认值取自 v2.16.0 运行实例内的配置加载逻辑与初始化脚本实读,逐项在实测实例中核实过。
3.1 运行身份与时区
| 变量 | 默认值 | 说明与建议 |
|---|---|---|
| PUID | 0 | 服务进程用户 ID。挂载目录属主为普通用户时设为该用户 UID,否则以 root 运行会在挂载目录里写入属主为 root 的文件 |
| PGID | 0 | 同上,组 ID |
| TZ | UTC | 时区。影响日志时间戳与证书续期计算的展示,建议显式设为 Asia/Shanghai |
3.2 网络相关
| 变量 | 默认值 | 说明 |
|---|---|---|
| DISABLE_IPV6 | 未设置(生成 IPv6 监听行,但以 # 注释) | 实测效果:生成配置中 listen 80; 生效、#listen [::]:80; 注释,即 IPv6 行默认本就不启用;设 true 是显式声明意图,避免宿主无 IPv6 时产生告警日志 |
| IP_RANGES_FETCH_ENABLED | true | 启动时联网拉取 Cloudflare 等公开 IP 段(供 Access List 的 IP 名单参考)。纯内网环境可设 false,避免每次启动的联网请求 |
3.3 数据库相关
| 变量 | 默认值 | 说明 |
|---|---|---|
| DB_SQLITE_FILE | /data/database.sqlite | SQLite 数据库文件位置(默认数据库) |
| DB_MYSQL_HOST / DB_MYSQL_USER / DB_MYSQL_NAME | 无 | 三者齐备即切换 MySQL |
| DB_MYSQL_PORT | 3306 | MySQL 端口 |
| DB_MYSQL_PASSWORD | 无 | MySQL 密码 |
| DB_MYSQL_SSL | false | MySQL 是否启用 TLS 连接 |
| DB_MYSQL_SSL_REJECT_UNAUTHORIZED / DB_MYSQL_SSL_VERIFY_IDENTITY | true / true | MySQL TLS 校验强度,仅 DB_MYSQL_SSL=true 时有意义 |
| DB_POSTGRES_HOST / DB_POSTGRES_USER / DB_POSTGRES_NAME | 无 | 三者齐备即切换 PostgreSQL |
| DB_POSTGRES_PORT | 5432 | PostgreSQL 端口 |
| DB_POSTGRES_PASSWORD | 无 | PostgreSQL 密码 |
数据库选择优先级(实测自配置加载逻辑):编排/配置文件显式指定 > MySQL 三要素齐备 > PostgreSQL 三要素齐备 > 默认 SQLite。单机部署用默认 SQLite 足够;需要外部备份体系或未来多实例时再迁移外部数据库(迁移前先备份数据目录)。
3.4 证书与调试相关
| 变量 | 默认值 | 说明 |
|---|---|---|
| LE_STAGING | 未设置 | 设 true 后 Certbot 走 Let's Encrypt 测试环境,调试签发流程时不消耗正式环境配额 |
| LE_SERVER | 未设置 | 覆盖 ACME 服务端地址,对接私有 ACME 时使用 |
| DEBUG | 未设置 | 设 true 输出调试级别日志 |
| DISABLE_INTERNAL_AUTH | 未设置 | 设 true 后关闭内置登录鉴权(配合上层网关统一认证的零信任场景;无上层认证时严禁开启) |
3.5 本环境实测取值
部署篇实测编排中只显式设置了一个变量:
environment:
DISABLE_IPV6: "true"
其余全部走默认。DISABLE_IPV6 的实际效果可在生成配置中直接看到:listen 80; 生效,#listen [::]:80; 保持注释(生成配置全文见第五章)。
四、/data 数据目录详解
/data 是 NPM 的全部状态所在:元数据、生成配置、证书、访问控制、日志都在这里。以下目录树与文件说明全部为运行实例实测截取。
4.1 完整目录树
在实例内执行 find /data -maxdepth 3 | sort,实测回显(本实例包含 2 条代理主机、1 条 404 主机、1 条 Stream、1 张自定义证书、1 条访问控制,故文件比全新实例多):
/data
/data/access
/data/access/1
/data/custom_ssl
/data/custom_ssl/npm-1
/data/custom_ssl/npm-1/fullchain.pem
/data/custom_ssl/npm-1/privkey.pem
/data/database.sqlite
/data/keys.json
/data/letsencrypt-acme-challenge
/data/logs
/data/logs/backend.log
/data/logs/dead-host-1_access.log
/data/logs/dead-host-1_error.log
/data/logs/fallback_error.log
/data/logs/fallback_http_access.log
/data/logs/fallback_http_error.log
/data/logs/fallback_stream_access.log
/data/logs/letsencrypt-requests_access.log
/data/logs/letsencrypt-requests_error.log
/data/logs/letsencrypt.log
/data/logs/letsencrypt.log.1
/data/logs/proxy-host-1_access.log
/data/logs/proxy-host-1_error.log
/data/logs/proxy-host-2_access.log
/data/logs/proxy-host-2_error.log
/data/logs/stream-1_access.log
/data/logs/stream-1_error.log
/data/logs/stream-2_access.log
/data/logs/stream-2_error.log
/data/nginx
/data/nginx/dead_host
/data/nginx/dead_host/1.conf
/data/nginx/default_host
/data/nginx/default_www
/data/nginx/proxy_host
/data/nginx/proxy_host/1.conf
/data/nginx/proxy_host/2.conf
/data/nginx/redirection_host
/data/nginx/stream
/data/nginx/stream/2.conf
/data/nginx/temp
4.2 目录用途速查
| 路径 | 用途 | 实测要点 |
|---|---|---|
| /data/database.sqlite | 全部元数据(主机/用户/证书/ACL 定义),实测 102400 字节 | 只能通过界面/API 改;直接改库属于高风险操作 |
| /data/keys.json | API 令牌签名密钥,实测 2186 字节、权限 600 | 备份恢复必须带上,否则旧令牌全部失效 |
| /data/nginx/proxy_host/ | 每条代理主机一个 .conf,编号即主机 ID | 由界面生成,勿直改 |
| /data/nginx/redirection_host/ | 重定向主机的 .conf(本实例未建该类型主机,故为空目录) | 同上 |
| /data/nginx/dead_host/ | 404 主机的 .conf | 同上 |
| /data/nginx/stream/ | Stream 四层转发的 .conf(Nginx stream 块) | 同上 |
| /data/nginx/default_host/ | 兜底站点配置目录(当前版本实测为空,兜底逻辑内置在 conf.d/default.conf) | — |
| /data/nginx/default_www/ | 兜底站点静态页(当前版本实测为空,默认页内置在服务内 /var/www/html) | — |
| /data/nginx/temp/ | 生成过程中的临时目录(实测为空) | — |
| /data/nginx/custom/ | 手工自定义注入片段目录(实测未创建,需要时手工 mkdir) | 详见第六章 |
| /data/custom_ssl/<记录ID>/ | 上传的自定义证书,每张证书一个目录:fullchain.pem + privkey.pem | 证书记录 ID 前缀 npm-,如 npm-1 |
| /data/access/<ACL_ID> | 访问控制列表的 Basic 认证口令文件(htpasswd 格式) | 文件名即 ACL ID |
| /data/letsencrypt-acme-challenge/ | HTTP 校验的 ACME 质询 webroot(letsencrypt.ini 中 webroot-path 指向此处) | 申请证书时由 Certbot 写入 |
| /data/logs/ | 各主机访问/错误日志 + 兜底日志 + Certbot 日志 | 命名规律见 4.6 |
4.3 元数据库与密钥
database.sqlite 集中存放界面里的一切(主机定义、用户、证书记录、ACL 定义、审计日志),keys.json 存放令牌签名密钥。两者关系:备份恢复时必须成对携带;如果只恢复了 database.sqlite 而没有恢复 keys.json,历史 API 令牌全部失效(重新登录即可恢复使用,属于可自愈故障)。生产环境建议把这两个文件的备份纳入每日计划任务(备份流程见《Nginx Proxy Manager 日常运维手册》)。
4.4 证书目录(custom_ssl 与 /etc/letsencrypt)
证书分两个存放点,按来源区分:
- 自定义证书(界面上传):/data/custom_ssl/<记录ID>/,实测本实例只有一张:
/data/custom_ssl/npm-1/fullchain.pem
/data/custom_ssl/npm-1/privkey.pem
- Let's Encrypt 证书(界面申请):/etc/letsencrypt/(即宿主机 letsencrypt/ 挂载目录),实测全新申请前的结构:
/etc/letsencrypt
/etc/letsencrypt/accounts
/etc/letsencrypt/accounts/acme-v02.api.letsencrypt.org
/etc/letsencrypt/accounts/acme-v02.api.letsencrypt.org/directory
/etc/letsencrypt/renewal-hooks
/etc/letsencrypt/renewal-hooks/deploy
/etc/letsencrypt/renewal-hooks/post
/etc/letsencrypt/renewal-hooks/pre
accounts/ 下存放 ACME 账号密钥(首次申请时自动创建),renewal-hooks/ 是续期钩子目录,正式证书申请后会新增 live/ 与 archive/ 两个目录(live/ 内是现行版本证书的软链接)。部署篇 FAQ 里申请失败的真实案例(无公网域名)正是写入 letsencrypt.log 后被 NPM 捕获返回给界面的。
Certbot 的全局参数集中在 /etc/letsencrypt.ini(实测全文):
text = True
non-interactive = True
webroot-path = /data/letsencrypt-acme-challenge
key-type = ecdsa
elliptic-curve = secp384r1
preferred-chain = ISRG Root X1
逐项解读:默认签发 ECDSA(secp384r1)密钥的证书,链偏好 ISRG Root X1,HTTP 校验质询文件落到 /data/letsencrypt-acme-challenge。需要全局调整证书类型/链时改这里(属于引擎层,升级可能重置,建议升级后复核)。
4.5 访问控制文件
每条 ACL 一个目录,Basic 认证的账号密码以 htpasswd 格式存放在 /data/access/<ACL_ID>。实测本实例 ACL 1 的内容:
admin:$apr1$5ImzR62q$8MJXMWw2kXg4gjK7G1NXR/
解读:用户名明文、密码为 apr1(MD5-crypt)散列。生成配置中的 auth_basic_user_file /data/access/1;(见第五章 proxy_host/2.conf)即指向该文件。IP 名单类控制(clients)则直接写入生成配置,无独立文件。
4.6 日志目录
/data/logs 命名规律(结合 4.1 实测树):
| 模式 | 含义 |
|---|---|
| proxy-host-<ID>_access.log / _error.log | 代理主机的访问/错误日志 |
| dead-host-<ID>_* | 404 主机日志 |
| stream-<ID>_*_access.log / _error.log | Stream 日志(access 为格式名,文件名仍是 stream-<ID>*) |
| redirection-host-<ID>_* | 重定向主机日志 |
| fallback_* | 兜底站点与全局错误日志(default.conf 与 nginx.conf 的 error_log 均落在这里) |
| letsencrypt-requests_* | 面向 ACME 质询的请求日志 |
| letsencrypt.log(及轮转 .1) | Certbot 申请/续期全过程日志 |
| backend.log | 管理后端(API)日志 |
排障时按「主机 ID → 对应日志文件」定位,比翻服务日志更快;管理界面 v2.16.0 新增的日志查看器读取的正是这些文件。
五、生成配置详解(以实测实例为样本)
本章把实例中每一类主机生成出来的真实配置逐段讲透。生成位置规则:/data/nginx/<类型>/<主机ID>.conf,ID 即界面/接口里的主机 ID。
5.1 代理主机(含证书与强制 HTTPS):proxy_host/1.conf
demo.local(绑定自定义证书、开启 Block Exploits 与强制 HTTPS)的生成配置全文(实测):
# ------------------------------------------------------------
# demo.local
# ------------------------------------------------------------
map $scheme $hsts_header {
https "max-age=63072000; preload";
}
server {
set $forward_scheme http;
set $server "demo";
set $port 80;
listen 80;
#listen [::]:80;
listen 443 ssl;
#listen [::]:443;
server_name demo.local;
http2 off;
# Custom SSL
ssl_certificate /data/custom_ssl/npm-1/fullchain.pem;
ssl_certificate_key /data/custom_ssl/npm-1/privkey.pem;
# Block Exploits
include conf.d/include/block-exploits.conf;
# Force SSL
set $trust_forwarded_proto "F";
include conf.d/include/force-ssl.conf;
access_log /data/logs/proxy-host-1_access.log proxy;
error_log /data/logs/proxy-host-1_error.log warn;
location / {
# Proxy!
include conf.d/include/proxy.conf;
}
# Custom
include /data/nginx/custom/server_proxy[.]conf;
}
逐段解读:
map $scheme $hsts_header:HSTS 响应头映射表,仅 https 请求携带max-age=63072000; preload(两年 + 预加载标记),http 请求为空;本主机未开 HSTS 故配置中未引用该变量;set $forward_scheme/$server/$port:上游三元组变量化,配合 proxy.conf 里的proxy_pass $forward_scheme://$server:$port$request_uri;实现统一转发模板——对应界面里填写的协议 demo / 80 三个字段;listen 80+listen 443 ssl:证书绑定后同时监听双端口;#listen [::]:80注释行即 DISABLE_IPV6 的效果体现;server_name demo.local:域名匹配依据,界面里多个域名会生成多个值;http2 off:对应界面的 HTTP/2 Support 开关(实测未开启;注意 v2.16.0 使用新写法http2 off而非旧版listen ... http2);ssl_certificate / ssl_certificate_key:指向 /data/custom_ssl/npm-1/——即上传的自定义证书落地路径;Let's Encrypt 证书则指向 /etc/letsencrypt/live/<cert_name>/;include conf.d/include/block-exploits.conf:防注入片段(内容见 5.5);set $trust_forwarded_proto "F"+include force-ssl.conf:强制 HTTPS 的实现(见 5.5),trust_forwarded_proto 对应界面的「信任 X-Forwarded-Proto」开关,供多层代理场景使用;access_log ... proxy / error_log ... warn:本主机独立日志文件(proxy 为自定义日志格式);include conf.d/include/proxy.conf:转发动作与转发头模板(见 5.5);include /data/nginx/custom/server_proxy[.]conf:手工注入点,需要给这台主机追加指令时写该文件(详见第六章)。
5.2 代理主机(访问控制):proxy_host/2.conf
acl.local(挂 ACL、无证书)生成配置与 1.conf 的差异部分(实测节选,其余段落相同):
listen 80;
#listen [::]:80;
server_name acl.local;
location / {
# Authorization
auth_basic "Authorization required";
auth_basic_user_file /data/access/1;
proxy_set_header Authorization "";
# Access checks must...
satisfy all;
# Proxy!
include conf.d/include/proxy.conf;
}
解读:auth_basic_user_file 指向 ACL 的口令文件(4.5 节);proxy_set_header Authorization "" 把认证头在上游转发前清空,避免 Basic 凭据泄露给后端(对应界面 Access List 的 pass_auth 选项:勾选「Satisfy Any + Pass Auth」时该行为变化);satisfy all 表示 IP 名单与 Basic 认证须同时通过,仅配置 IP 名单时同样出现在此。本实例 ACL 未配 IP 名单,故只有 Basic 认证生效。
5.3 404 主机:dead_host/1.conf
notfound.local 生成配置全文(实测):
# ------------------------------------------------------------
# notfound.local
# ------------------------------------------------------------
map $scheme $hsts_header {
https "max-age=63072000; preload";
}
server {
listen 80;
#listen [::]:80;
server_name notfound.local;
http2 off;
access_log /data/logs/dead-host-1_access.log standard;
error_log /data/logs/dead-host-1_error.log warn;
location / {
return 404;
}
# Custom
include /data/nginx/custom/server_dead[.]conf;
}
要点:location / { return 404; }——404 主机的全部实现就这一行;日志格式用 standard(非 proxy 格式);注入点后缀为 server_dead。若给 404 主机也绑证书,会出现与 proxy_host/1.conf 相同的 ssl_certificate 段落。
5.4 Stream 四层转发:stream/2.conf
8096 → demo:80 的 TCP 转发生成配置全文(实测):
# ------------------------------------------------------------
# 8096 TCP: true UDP: false
# ------------------------------------------------------------
server {
listen 8096 reuseport;
#listen [::]:8096 reuseport;
proxy_pass demo:80;
access_log /data/logs/stream-2_access.log stream;
error_log /data/logs/stream-2_error.log warn;
# Custom
include /data/nginx/custom/server_stream[.]conf;
include /data/nginx/custom/server_stream_tcp[.]conf;
}
要点:这是 Nginx stream 模块的 server 块(非 http),proxy_pass demo:80; 无 scheme/URI;reuseport 是 v2.16.0 新增特性(发布说明提到启用 reuseport 降低高并发丢包);头部注释记录了 TCP/UDP 开关状态;TCP 与 UDP 各生成一个 server(注释后缀 _tcp/_udp 对应不同注入文件)。
5.5 引擎层可复用片段:conf.d/include/
这些片段被各主机配置反复 include,理解它们等于理解 NPM 的转发行为。实测三份关键片段:
proxy.conf(转发模板):
add_header X-Served-By $host;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Scheme $x_forwarded_scheme;
proxy_set_header X-Forwarded-Proto $x_forwarded_proto;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_pass $forward_scheme://$server:$port$request_uri;
解读:后端拿到的 Host 是用户访问的域名(而非上游地址),并注入完整的 X-Forwarded-* 链路头——这是大多数 Web 框架正确生成绝对 URL 与获取真实客户端 IP 的前提。后端日志里看到的全是 NPM 所在宿主机 IP 时,需要检查应用是否读取 X-Forwarded-For。
force-ssl.conf(强制 HTTPS 跳转):
set $test "";
if ($scheme = "http") {
set $test "H";
}
if ($request_uri = /.well-known/acme-challenge/test-challenge) {
set $test "${test}T";
}
...(中段:trust_forwarded_proto 与 X-Forwarded-Proto/Scheme 的组合判定,实测全文见实例)...
if ($test = H) {
return 301 https://$host$request_uri;
}
解读:HTTP 请求置标记 H,最终命中则 301 到 https;.well-known/acme-challenge 路径置 T 标记豁免——保证证书续期质询不被强跳拦截;多层代理时由 trust_forwarded_proto 决定是否信任上游传入的协议头(部署篇 4.7 节实测的 301 跳转即由本片段实现)。
block-exploits.conf(防注入片段):对 query_string 做四类正则拦截并返回 403——SQL 注入(union.*select 等 3 条)、文件注入(=http://、路径穿越、绝对路径 3 条)、常见漏洞特征(script 标签、GLOBALS、_REQUEST、proc/self/environ、mosConfig、base64 编解码 6 条)、垃圾关键词与恶意 UA(libwww-perl 等工具类 UA 共 12 条)。全部为特征规则,属于轻量防护;需要语义级 WAF 能力时应叠加专业 WAF(选型对比见《Nginx Proxy Manager 2.16.0 介绍与选型指南》第七章)。
ssl-ciphers.conf(TLS 参数):
# intermediate configuration. tweak to your needs.
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384';
ssl_prefer_server_ciphers off;
即 Mozilla 推荐的 intermediate 配置:仅 TLS 1.2/1.3、ECDHE 优先套件、服务端不强制选套件。
include 目录完整清单(实测):assets.conf、block-exploits.conf、force-ssl.conf、ip_ranges.conf、letsencrypt-acme-challenge.conf、log-proxy.conf、log-stream.conf、proxy.conf、resolvers.conf、ssl-cache-stream.conf、ssl-cache.conf、ssl-ciphers.conf。其中 resolvers.conf 定义内部 DNS 解析器(代理主机的上游域名动态解析依赖它),ssl-cache.conf 与 ssl-cache-stream.conf 定义会话复用缓存,ip_ranges.conf 生成 Access List 的 IP 段白名单。
5.6 兜底站点:conf.d/default.conf
未匹配任何主机时由内置兜底站点响应(实测节选):
# "You are not configured" page, which is the default if another default doesn't exist
server {
listen 80;
#listen [::]:80;
set $forward_scheme "http";
set $server "127.0.0.1";
set $port "80";
server_name localhost-nginx-proxy-manager;
access_log /data/logs/fallback_http_access.log standard;
error_log /data/logs/fallback_http_error.log warn;
include conf.d/include/assets.conf;
include conf.d/include/block-exploits.conf;
include conf.d/include/letsencrypt-acme-challenge.conf;
location / {
index index.html;
root /var/www/html;
}
}
解读:80 端口的兜底直接服务内置静态页(/var/www/html,即部署篇实测不带 Host 头访问时看到的欢迎页);443 段落在无任何 443 主机时同样存在(首个 443 主机成为默认)。部署篇实测的「不带 Host 头返回欢迎页」现象由此而来。
六、界面生成配置与手工修改的边界
NPM 的配置哲学:数据库是唯一事实来源,.conf 文件是生成产物。因此:
- 不要直改 /data/nginx/ 下的 .conf——下一次在界面点「保存」(任何一条主机)都会全量重生成,直改内容静默丢失;
- 追加自定义指令的两个正道:
- 单主机:界面的 Advanced Config(API 字段 advanced_config),内容注入该主机 server 块;
- 全局/局部注入点:创建 /data/nginx/custom/ 下对应文件(root_top、events、http_top、server_proxy、server_dead、server_stream、server_stream_tcp、server_stream_udp 等,均来自生成配置里的 include 行),重建服务也不受影响;
- 保存时的校验机制:界面保存会先做 Nginx 配置测试,失败则不生效;签发失败的配置以 .conf.err 后缀保留在 /data/nginx/ 对应目录下供排障(v2.16.0 发布说明明确的行为),错误详情同时记录在 /data/logs/letsencrypt.log 与对应主机 error 日志;
- 生效即重载:配置变更通过 Nginx reload 应用(日志可见
Reloading Nginx),不断连接;若某条配置导致数据面启动失败,NPM 会标记该主机 nginx_online=false 并在界面给出错误横幅,此时元数据与生成配置的偏差即为修复线索。
七、常见问题
Q1:生成配置文件里大量空行是 bug 吗? 不是。生成模板按「开关是否启用」拼接段落,未启用的段落留下空位,属于模板原貌。理解每段含义后即可按空行定位到对应功能块(本文第五章的全文截取即含原始空行,便于对照)。
Q2:界面提示主机离线(nginx_online=false)怎么办? 先看三个地方:/data/nginx/<类型>/<ID>.conf.err(语法错误原文)、/data/logs/<类型>-<ID>_error.log(运行错误)、服务运行日志里的 Nginx reload 报错。常见诱因是 Advanced Config 里写了非法指令或证书文件被手工移动。修复后重存该主机即可恢复。
Q3:改了环境变量为什么不生效?
环境变量属于编排层,必须重建服务实例才能应用(仅重启进程不会重新注入环境变量)。判断依据:在服务实例的运行环境里执行 env | grep DISABLE,确认新值已生效。
Q4:手工改了 /data/nginx/ 下的 .conf,为什么过一会儿就还原了? 界面任一保存动作都会触发相关主机配置全量重生成(见第六章第 1 条)。自定义需求写进 /data/nginx/custom/ 注入文件或 Advanced Config。
Q5:上游用域名时偶发 502,日志报 could not be resolved? 代理主机的上游域名由 resolvers.conf 定义的解析器动态解析。内网环境需保证该解析器能解析你的内网域名;上游主机名在编排网络内(如部署篇的 demo 服务名)只在同一编排网络内有效——跨网络或单命令形态部署时改用可达的 IP/域名(部署篇 Q7 有实测案例)。
八、参考链接
- NPM 官方文档(Advanced Ideas 一节含 custom 注入说明):https://nginxproxymanager.com/advanced-config/
- 官方 GitHub 仓库(v2.16.0 源码中的生成模板):https://github.com/NginxProxyManager/nginx-proxy-manager
- 本组件部署与实测流程:《Nginx Proxy Manager Docker Compose 部署指南》
- 本组件认知与选型:《Nginx Proxy Manager 2.16.0 介绍与选型指南》
- Nginx 官方文档(指令语义权威来源):https://nginx.org/en/docs/