Monthly Archives: May 2023

威联通 NAS 中使用 Nginx Proxy Manager 反向代理多个 docker 应用

  前一阵在威联通 QNAP 的 NAS 中通过 docker 安装了 ChatGPT-Next-Web 这个项目,给朋友分享ChatGPT使用,但这个 web 项目本身不涉及SSL证书的配置,于是应用一直跑在未加密的 HTTP 协议下;加上之前的另一个 docker 媒体播放应用 Jellyfin,目前已经在路由器上设置了多个端口转发,需要通过记忆特定端口来打开对应的应用。有没有什么办法能同时解决这两个问题呢?显然 Nginx 来做反向代理再合适不过了。但这次跳过手写配置文件,我们使用 Nginx Proxy Manager 来达到目的。

目的

  现状:

  要实现的目的:

  • docker中运行的应用都可以通过 HTTPS 方式访问。
  • 通过不同的(子)域名访问对应的应用,方便记忆。比如: https://chat.mydomain.com:7443 打开 ChatGPT 应用, https://jellyfin.mydomain.com:7443 打开 Jellyfin 应用。
    • 注:因为运营商屏蔽 80 和 443 端口,所以你需要选择一个非默认端口来打开你的应用。

具体步骤

1. docker 安装 Nginx Proxy Manager 。我这里使用 docker compose 方式如下:

version: '3.3'
services:
  nginx-proxy-manager:
    container_name: nginx-proxy-manager
    image: 'jc21/nginx-proxy-manager:latest'
    restart: unless-stopped
    ports:
      - '9080:80' # 监听的 HTTP 端口
      - '9081:81' # 管理页面的端口
      - '9443:443' # 监听的 HTTPS 端口
    volumes:
      - /share/Container/nginxProxyManager/data:/data
      - /share/Container/nginxProxyManager/letsencrypt:/etc/letsencrypt 

2. 通过 http://<nasIP>:9081 登陆 Nginx Proxy Mananger,SSL Certificates 页面给想要分配给应用的域名申请 SSL 证书。

  • 默认用户名密码是 admin@example.com/changeme,首次登陆需要修改。
  • mydomain 是你提前注册好的域名。我的域名托管在 CloudFlare,所以 DNS Provider 处选择 Cloudflare;另外需要在 CloudFlare 提前设置好 API token 填入下图对应位置。

3. 将你的域名 DNS 记录解析至家里 NAS 的 DDNS 地址。比如我在 CloudFlare 对应域名的 DNS 设置中,添加了两个子域名 chat.mydomain.com 和 jellyfin.mydomain.com,都通过 CNAME 记录指向我的 DDNS 地址 https://mydns.myqnapcloud.com 。之后通过这些域名和特定端口的请求会被运行的 Nginx Proxy Manager 接管。

4. Nginx Proxy Manager 的 Hosts 页面,添加 New Proxy Host。Forward Hostname / IP 和 Forward Port 是你内网应用运行的地址和端口,Nginx Proxy Manager 会将此域名的请求转发到这个应用。其中 SSL tab 页的 SSL Certificate 选择步骤 2 中申请号的泛域名证书。

5. 最后到路由器中设置端口转发,允许特定外网端口转到 Nginx Proxy Manager 监听的端口。比如我所有应用都强制 HTTPS 访问,则只需转发上面 docker compose 文件中的 9443 端口到外网 7443 (可随意修改)即可。

  至此设置完毕。

遇到的问题和解决办法

  此时发现通过 https://chat.mydomain.com:7443 并不能打开内网的 ChatGPT 应用,等待之后显示 504 Gateway Time-out openresty 错误。但如果通过路由器端口转发,直接访问 ChatGPT 应用或 Nginx Proxy Manager 管理页面都是没有问题的,证明这两个应用本身可以独立运行。
进入 Nginx Proxy Manager docker 的控制台,查看 /data/logs 下的 _error.log 和 _access.log 文件,发现提示上游请求无法通过;另外通过 curl 命令打到内网 ChatGPT 应用地址发现无响应。判断是 Nginx Proxy Manager 的 docker 和其它 docker 应用无法通信。
  查看威联通的”网络与虚拟交换机“,发现自己通过 docker compose 方式创建的应用,都分别使用了独立的虚拟交换机并且网段不同;而如果通过 Container Station UI 创建的 docker 应用,则都会默认连接到名为 lxcbr0 的同一个虚拟交换机中,可以互相通信。因此只需将 docker compose 创建的应用,接入同一个网络中即可。
  为此,首先 SSH 到 NAS 主机中,通过 docker network create my-custom-network 命令在 docker 中创建一个新的网络。之后在需要连接到此网络的应用的 docker compose 文件中加入对应的 networks 配置。修改后的 Nginx Proxy Manager docker compose 文件如下:

version: '3.3'
services:
  nginx-proxy-manager:
    container_name: nginx-proxy-manager
    image: 'jc21/nginx-proxy-manager:latest'
    restart: unless-stopped
    ports:
      - '9080:80'
      - '9081:81'
      - '9443:443'
    volumes:
      - /share/Container/nginxProxyManager/data:/data
      - /share/Container/nginxProxyManager/letsencrypt:/etc/letsencrypt
    networks:
      - my-dockers-network

networks:
  my-dockers-network:
    external: true

  同样修改 ChatGPT 和 Jellyfin 应用的 docker compose 文件,添加上面最后几行 networks 的设置并重启后,”网络与虚拟交换机“里可以观察到几个 docker 应用接入了同一个虚拟交换机。此时通过不同域名加固定端口号的方式,便可以分别访问对应的应用了。