Files
trojanZ/部署架构建议.md
T
2026-07-26 00:09:57 +08:00

9.2 KiB
Raw Blame History

Trojan、Nginx 与 Caddy 共用 80/443 的部署方案

适用对象:已按项目 README 的 Docker 方式运行 Trojan 管理程序,希望同一台服务器继续部署多个 HTTPS 网站或 Web 服务。

本文只给出架构和操作建议,不直接修改已经运行的服务器。

已确认的现状

  • Trojan 对外域名:www.hk.chermack.top
  • 容器 trojan:镜像 jrohy/trojan,已运行约两年,当前已连续运行七周;docker ps 没有显示端口映射。这与项目 README 的 --net=host 启动方式一致,意味着它很可能直接使用宿主机网络,并占用 Trojan 的 443 与管理 Web 的 80
  • 容器 trojan-mariadb:镜像 mariadb:10.2,当前映射 0.0.0.0:3306->3306[::]:3306->3306;即 MySQL/MariaDB 已对全网开放。

本文后续均直接使用该真实 Trojan 域名:www.hk.chermack.top

1. 结论

不能让 Trojan、Nginx 或 Caddy 同时直接监听宿主机的 80443:同一 IP:端口只能被一个进程绑定。

由于 Trojan 使用的并非 HTTP/HTTPS Web 请求,而是基于 TLS 的代理协议,普通的 reverse_proxy 规则无法把 //api 一类路径转发给它。要同时使用 Trojan 和多个网站,应按 TLS 握手中的 SNI(访问域名) 在四层分流:

flowchart TB
  Internet["Internet"] --> N80["Nginx :80\nHTTP 转发"]
  Internet --> N443["Nginx stream :443\n按 TLS SNI 分流"]
  N80 --> Caddy["Caddy :8080 / :9443\n自动申请、续期证书\n托管网站"]
  N443 -->|"www.hk.chermack.top"| Trojan["Trojan 容器 :8443\nTLS 直通"]
  N443 -->|"app.example.com\nwww.example.com"| Caddy
  Caddy --> App1["网站 / 应用 1"]
  Caddy --> App2["网站 / 应用 2"]

推荐职责划分:

  • Nginx:唯一占用公网 80443443 使用 stream + ssl_preread 按域名转发 TLS 流量,自己不终止 TLS。
  • Caddy:监听本机 8080/9443,为普通网站自动申请和续期 Let's Encrypt/ZeroSSL 证书,并反向代理到各个 Web 应用。
  • Trojan:改为仅监听宿主机本地端口(示例使用 8443),由 Nginx 按 www.hk.chermack.top 的 SNI 转发。它仍使用自己的 Trojan TLS 证书。

2. 域名规划

应使用不同的子域名,不要让 Trojan 和网站共用同一个域名:

用途 示例域名 TLS 终止位置
Trojan 服务 www.hk.chermack.top Trojan
Trojan 管理后台 建议新增 panel.hk.chermack.top Caddy
普通网站 例如 site.hk.chermack.top Caddy
其他应用 例如 app.hk.chermack.top Caddy

所有域名的 A/AAAA 记录都指向这台服务器。Trojan 客户端应继续使用 www.hk.chermack.top 作为 SNI 和服务器地址。

3. 前置条件与注意事项

  1. 所有服务应只向 Docker 内网或 127.0.0.1 发布端口;不要把 Trojan 的新端口、Caddy 的 8080/9443 直接暴露到公网。
  2. Nginx 需要带有 streamssl_preread 模块。Ubuntu/Debian 通常需要安装 libnginx-mod-stream;确认方式:nginx -V 2>&1 | grep stream
  3. 防火墙、安全组只开放公网 TCP 80443(以及 SSH 管理端口);关闭原先直接暴露的 Trojan 端口。
  4. 当前 trojan-mariadb3306 正暴露于 IPv4/IPv6 公网。除非确有远程数据库访问需求,切换时应改为仅容器网络或 127.0.0.1:3306,并从安全组和防火墙移除公网 3306。
  5. Trojan 的 TLS 证书仍应有效且包含 www.hk.chermack.top。Caddy 的自动 HTTPS 只负责它所托管的网站,不会自动替 Trojan 申请或安装证书
  6. Caddy 使用 HTTP-01 验证时,Nginx 的 80 必须完整转发到 Caddy。Caddy 成功续期不需要人工定时执行证书申请命令。

4. 修改现有 Trojan Docker 端口

README 示例使用 --net=host,因此 Trojan 和管理 Web 服务会直接占用宿主机端口。建议改为显式端口映射,或在仍使用 host 网络时把 Trojan 和 Web 的监听端口改为非公网端口。

建议的目标端口

服务 容器/程序内端口 宿主机绑定 公网暴露
Trojan 改为 8443 127.0.0.1:8443 否,由 Nginx 443 转发
Trojan Web 管理后台 改为 8081 127.0.0.1:8081 否,由 Caddy 代理
Caddy HTTP 8080 127.0.0.1:8080 否,由 Nginx 80 转发
Caddy HTTPS 8443 127.0.0.1:9443(避免与 Trojan 冲突) 否,由 Nginx 443 转发

上表特意将 Caddy 的宿主机 HTTPS 端口设为 9443,避免和 Trojan 的 8443 冲突。实际端口可以调整,但必须保证唯一。

Trojan 配置原则

在 Trojan 的 /usr/local/etc/trojan/config.json 中,把 local_port443 改为 8443;管理程序的 Web 服务以类似方式改为 8081(例如 systemd 服务执行 trojan web -p 8081)。

如果容器仍采用 --net=host,以上端口是宿主机端口。若改为 Docker bridge 网络,推荐使用仅回环地址的映射,例如:

-p 127.0.0.1:8443:8443
-p 127.0.0.1:8081:8081

重建容器前,应先备份:

docker inspect trojan > trojan.inspect.backup.json
docker cp trojan:/usr/local/etc/trojan/config.json ./trojan-config.backup.json

不要在未确认持久化目录和数据库位置前删除旧容器。README 所用方案还会单独运行 MariaDB,必须保留其数据卷。

5. Nginx 四层 SNI 分流示例

以下配置应放在 Nginx 主配置可加载的位置;stream 块通常不能放入普通的 server {} HTTP 配置文件。域名和端口必须替换为实际值。

# /etc/nginx/nginx.conf(顶层 stream 块)
stream {
    map $ssl_preread_server_name $tls_upstream {
        www.hk.chermack.top trojan_backend;
        default            caddy_https_backend;
    }

    upstream trojan_backend {
        server 127.0.0.1:8443;
    }

    upstream caddy_https_backend {
        server 127.0.0.1:9443;
    }

    server {
        listen 443 reuseport;
        proxy_pass $tls_upstream;
        ssl_preread on;
        proxy_timeout 1h;
        proxy_connect_timeout 5s;
    }
}

http {
    server {
        listen 80;
        server_name _;

        location / {
            proxy_pass http://127.0.0.1:8080;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto http;
        }
    }
}

此配置的关键是:Nginx 在 443 上只读取 ClientHello 的 SNI,不解密 TLS;因此 Trojan 和 Caddy 都能拿到自己完整的 TLS 握手和证书。

若客户端未发送 SNI,会被送到默认的 Caddy 后端;Trojan 客户端必须明确配置 SNI 为 www.hk.chermack.top

6. Caddy 自动 HTTPS 示例

在 Caddyfile 设置内部监听端口。Caddy 仍会使用域名来签发和管理证书,只是外部 80/443 由 Nginx 转发到它。

{
    http_port 8080
    https_port 9443
    email ops@example.com
}

panel.hk.chermack.top {
    reverse_proxy 127.0.0.1:8081
}

site.hk.chermack.top {
    reverse_proxy 127.0.0.1:3000
}

app.hk.chermack.top {
    reverse_proxy 127.0.0.1:9000
}

其中 panel.hk.chermack.top 反向代理 Trojan 管理后台;其他站点各自指向对应容器或本机应用。Caddy 会保存证书与续期状态,容器部署时必须挂载其数据目录,例如 /data/config,否则重建容器会丢失 ACME 账户和证书缓存。

7. 建议实施顺序

  1. 记录现有容器、端口、配置、数据库卷和证书路径,并完成备份。尤其保存 docker inspect trojandocker inspect trojan-mariadb 和 MariaDB 数据卷信息;trojan 没有端口映射,变更前必须确认其是否为 --network host
  2. trojanpanel、网站分别创建 DNS 记录。
  3. 安装并验证 Nginx 的 stream 模块,但暂不切走 80/443。
  4. 启动 Caddy 于 127.0.0.1:8080127.0.0.1:9443,先验证内部反向代理可用。
  5. 将 Trojan 改至 127.0.0.1:8443,将管理后台改至 127.0.0.1:8081,确认直连本机端口均正常。
  6. 配置 Nginx 80 转 Caddy、443 SNI 分流,执行 nginx -t
  7. 在维护窗口切换 Nginx 到公网 80/443,验证网站 HTTPS、Caddy 证书签发、Trojan 客户端连接、管理后台登录和订阅链接。
  8. 最后收紧 Docker 端口映射与防火墙,只留 80/443 公开;将当前 MariaDB 的公网 3306 映射关闭或至少限制为 127.0.0.1

8. 不建议的方案

  • 让 Caddy 或 Nginx 直接以 HTTP reverse_proxy 转发 Trojan:协议不匹配,不能工作。
  • Trojan 与网站共用同一个域名且共用 443:SNI 无法区分目标,除非引入更复杂的协议伪装/回落设计;不适合当前项目的常规部署。
  • 将 Trojan 改端口后直接对公网开放该端口:虽能运行,但无法达到只使用 80/443 的目标,也增加暴露面。
  • 认为 Caddy 能替 Trojan 自动处理证书:Caddy 只能为它实际终止 TLS 的连接管理证书;本方案中 Trojan 的 TLS 是端到端直通。

9. 后续执行前需要确认的信息

实施时需要根据真实状态补全:当前 Trojan 容器的 docker inspect 输出、实际 config.json、MariaDB 容器/卷、当前占用 80/443 的进程、服务器系统发行版、可用域名及 DNS 提供商。