一直想找个时间说说 Nginx Proxy Manager (以下简称NPM)这个自认为非常适合 self host使用的Reverse Proxy。但是最近也在使用中逐渐发现各种坑爹之处。这下好了,也不用推荐这个项目了,干脆讲讲最近一次修复吧。

官方网站上有这个项目的各种信息。然后Github Issue里面已经积攒了1300多个issue了。怎么说呢,虽然我没有真的用过JS,但是这个数量真的相当打击人。而且再想起来之前经历过的一些坑,想必过不了多久就切换到Caddy了吧。

无法更新证书

前两天,我发现无法用npm更新https证书。查看docker日志,发现 error log 说有另一个 Certbot 实例正在运行。但是我这个Certbot 是由 Ngix Proxy Manager 的 container 管理的,我自己肯定是没有闲的跑两个NPM的。Log中看到的Error如下:

[3/23/2024] [11:46:47 PM] [SSL      ] › ℹ  info      Renewing SSL certs close to expiry...
[3/23/2024] [11:46:47 PM] [SSL      ] › ✖  error     Error: Command failed: certbot renew --non-interactive --quiet --config "/etc/letsencrypt.ini" --work-dir "/tmp/letsencrypt-lib" --logs-dir "/tmp/letsencrypt-log" --preferred-challenges "dns,http" --disable-hook-validation  
Another instance of Certbot is already running.
    at ChildProcess.exithandler (node:child_process:402:12)
    at ChildProcess.emit (node:events:513:28)
    at maybeClose (node:internal/child_process:1100:16)
    at Process.ChildProcess._handle.onexit (node:internal/child_process:304:5)

结果 Google 一下果然有收获:

所以解决方案也很简单

sudo docker exec -it nginx_proxy_manager /bin/bash
 
# in nginx_proxy_manager container
find / -type f -name ".cert.lock"
# Output:
/etc/letsencrypt/.certbot.lock

现在我怀疑,Nginx Proxy Manager在遇到一些 SSL Certificate refresh 的错误的时候,可能会 panic,导致这个 lock 文件就被泄漏了。不删除的话,就会一直报 error log。但是这个container health status 不会有任何反应,在Nginx Proxy Manager的UI上面也不会有什么反应。只有你手动去 renew 你的 Certificate 的时候,才会悻悻给个 Internal Error。然而除此之外就什么都没有了。逼着你去看 log。

这已经不是我第一次遇到这个问题了。现在我甚至怀疑,如果在renew的过程中,stop这个container,这个 lock 文件估计都不会被删除。

SSL 证书和 Proxy Hosts之间可能有Consistency的问题

因为有时候实验的缘故,有些SSL的证书我之后就不会再用了。所以SSL Certificates里面有不少是废弃的证书,而且因为之前的那个Bug,很多都是过期了我才发现。于是在修复了 Renew 的问题之后,我就顺手在 SSL Certificates tab 下面直接删除了几个不再用的证书。 delete-certs

谁知道删除了之后的结果是,在 Proxy Hosts 里面,如果尝试 Edit,或者删除 SSL Certificate 对应的 Proxy 记录,也会触发 Error。这个就也很无厘头。挺难想象这么个基础的 Consistency 问题都解决不好。注意啊,这里我是用 UI 删除 SSL Certificate的,可不是我在DB或者FS里面直接 bypass 所有code删除的。

更过分的事,如果只是这个Proxy Host从此不能用UI修改我也就认了。下次Container启动的时候直接就crash了,Nginx 拒绝启动了,所以一下子所有的 Reverse Proxy 就都挂了。令人崩溃。而且毫不意外的,Nginx Proxy Manager 的 Container Health Status 依旧显示 Healthy。很显然这个根本 container 就没有 health check。

Nginx start failure:

Starting nginx ...
nginx: [emerg] cannot load certificate "/etc/letsencrypt/live/npm-2/fullchain.pem": BIO_new_file() failed (SSL: error:80000002:system library::No such file or directory:calling fopen(/etc/letsencrypt/live/npm-2/fullchain.pem, r) error:10000080:BIO routines::no such file)

Github上面也有不少相应的Issue report,比如这个:

解决方法也很无厘头。把找不到的Nginx pem文件结构补上。然后NPM会发现这个Certificate不对,然后就会再申请一个新的。至于之后再怎样去删除这个 Certificate,暂时就先放一边了。

# As it is complaining npm-2 missing in my case
# so I should re-make the npm-2/ directory
sudo docker exec -it nginx_proxy_manager /bin/bash
 
cd /etc/letsencrypt/live
# I do have npm-1/ dir.
cp -r npm-1 npm-2
 
# Then restart the container.

极慢的启动速度

Nginx本身是很快的。但是我也是万万没想到NPM启动速度可以慢至 5 分钟。从 Log 来看,应该是 ❯ Setting ownership ... 这一步花费了很长的时间。Github上面也是怨声载道:

我查了一下文件数量 find -type f | wc -l

  • /etc/letsencrypt/: 1815
  • /data/: 491

这个数量也不能算特别多吧。也不是很清楚为什么这么慢。不过鉴于我只有20几个hosts,我也看不太明白为什么 /etc/letsencrypt/ 下面有 1815个文件。keys/ 下面有718个,总觉得有点太多了。

这个问题目前我是没有看到有效的解决方案的。只能干等。呃,也许用 NVME 跑的会快?毕竟我这个是 HDD 而且还是远程挂载,所以可以说是我自己的锅…

最后

还是要感谢NPM的作者的。毕竟是用爱发电的开源项目,有的用已经很好了,而且对于一开始接触 Self Host 的朋友来说,NPM 的 UI 还是很友好的 (在不出Bug的情况下)。(不枉我在 [year-of-self-host-2023-summary] 总结里面还强烈推荐它 🤦)

但是如果有更严肃的需求,或者说有点点 Infra-as-code 的想法的,还是及早切换的好。SWAG, Traefik, Caddy,HAProxy 或者直接手撸 Nginx config (不过如果是直接用 Nginx,不如选择 SWAG,配置上面应该是一样的,但是大概可以开箱即用一堆安全插件)都是可以的。接下来如果有时间,本人肯定是要迁移的。