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

342 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 已对全网开放。
### 2026-07-26 服务器只读核查结果
- `trojan` 容器实际使用 Docker `host` 网络,没有持久化挂载卷。配置和证书只在这个已运行两年的容器内;迁移前必须导出备份,不能直接删除或重建。
- `443` 由 Trojan 监听,`80` 由容器内的 `/usr/local/bin/trojan web` 监听。
- Trojan 配置已确认:`local_port=443``remote_addr=127.0.0.1``remote_port=80`SNI 为 `www.hk.chermack.top`。这表示非 Trojan 的 HTTPS 请求会由 Trojan 回落到管理后台。
- `trojan-mariadb` 的 3306 当前对 IPv4/IPv6 公网开放,后续应收紧到内部网络或回环地址。
本文后续均直接使用该真实 Trojan 域名:**`www.hk.chermack.top`**。
## 1. 结论
不能让 Trojan、Nginx 或 Caddy 同时直接监听宿主机的 `80``443`:同一 IP:端口只能被一个进程绑定。
由于 Trojan 使用的并非 HTTP/HTTPS Web 请求,而是基于 TLS 的代理协议,普通的 `reverse_proxy` 规则无法把 `/``/api` 一类路径转发给它。要同时使用 Trojan 和多个网站,应按 TLS 握手中的 **SNI(访问域名)** 在四层分流:
```mermaid
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**:唯一占用公网 `80``443``443` 使用 `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 和服务器地址。
### 是否必须新增 `panel.hk.chermack.top`
**不一定。**项目源码中附带的 systemd 服务执行的是 `trojan web`,而该命令默认监听 `0.0.0.0:80`、不启用 TLS;Trojan 服务则通常监听 `443`。这只是源码默认行为,典型原始部署会按端口区分:
```text
http://www.hk.chermack.top:80 -> Trojan 管理后台(HTTP
www.hk.chermack.top:443 -> Trojan TLS 服务
```
服务器已核实 `http://www.hk.chermack.top``https://www.hk.chermack.top` 都能访问后台的原因:Trojan 已配置将非 Trojan 的 HTTPS 请求回落到 `127.0.0.1:80`。因此当前同域名 HTTPS 后台是已验证的 Trojan 回落链路,不需要新增 `panel.hk.chermack.top`
迁移后应保持这一关系:Nginx 仅按 SNI 将 `www.hk.chermack.top` 的所有 443 TLS 流量转给 TrojanTrojan 负责识别协议,并将普通 HTTPS 后台请求回落到迁移后的后台端口 `127.0.0.1:8081`。Nginx 不应尝试把相同的 `www.hk.chermack.top` SNI 拆分到 Caddy 与 Trojan。
`panel.hk.chermack.top` 仍可作为将来独立管理后台的可选项,但不是本服务器部署 Gitea 的必要条件。
## 3. 前置条件与注意事项
1. 所有服务应只向 Docker 内网或 `127.0.0.1` 发布端口;不要把 Trojan 的新端口、Caddy 的 `8080/9443` 直接暴露到公网。
2. Nginx 需要带有 `stream``ssl_preread` 模块。Ubuntu/Debian 通常需要安装 `libnginx-mod-stream`;确认方式:`nginx -V 2>&1 | grep stream`
3. 防火墙、安全组只开放公网 TCP `80``443`(以及 SSH 管理端口);关闭原先直接暴露的 Trojan 端口。
4. 当前 `trojan-mariadb``3306` 正暴露于 IPv4/IPv6 公网。除非确有远程数据库访问需求,切换时应改为仅容器网络或 `127.0.0.1:3306`,并从安全组和防火墙移除公网 3306。
5. Trojan 的 TLS 证书仍应有效且包含 `www.hk.chermack.top`。Caddy 的自动 HTTPS 只负责它所托管的网站,**不会自动替 Trojan 申请或安装证书**。
5. 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_port``443` 改为 `8443`;管理程序的 Web 服务以类似方式改为 `8081`(例如 systemd 服务执行 `trojan web -p 8081`)。
如果容器仍采用 `--net=host`,以上端口是宿主机端口。若改为 Docker bridge 网络,推荐使用仅回环地址的映射,例如:
```bash
-p 127.0.0.1:8443:8443
-p 127.0.0.1:8081:8081
```
重建容器前,应先备份:
```bash
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 配置文件。域名和端口必须替换为实际值。
```nginx
# /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 转发到它。
```caddyfile
{
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 trojan``docker inspect trojan-mariadb` 和 MariaDB 数据卷信息;`trojan` 没有端口映射,变更前必须确认其是否为 `--network host`
2.`trojan``panel`、网站分别创建 DNS 记录。
3. 安装并验证 Nginx 的 `stream` 模块,但暂不切走 80/443。
4. 启动 Caddy 于 `127.0.0.1:8080``127.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 提供商。
## 10. 与 Gitea 共存:`git.hk.chermack.top`
### 能否完全不改变当前 Trojan Docker 服务?
**不能同时满足“完全不变”与“通过 `https://git.hk.chermack.top` 对外访问”这两个条件。**
目前 `trojan` 容器没有端口映射,结合原项目的启动方式可推断其使用宿主机网络,并直接占用宿主机 `80/443`。Gitea 可以新增容器并运行在 `127.0.0.1:3000`SSH Git 可以运行在 `2222`,但在 Trojan 持续独占公网 `80/443` 时:
- 不能启动 Nginx/Caddy 绑定公网 `80/443`
- 不能让 Caddy 为 `git.hk.chermack.top` 完成 HTTP-01 校验并提供 HTTPS
- Trojan 的 `plain_http_response` 不是 HTTP 反向代理,不能把 Gitea 的 Web 请求转发出去。
因此分为两个阶段:
1. **不改变现状的准备阶段**:仅部署 Gitea 与 PostgreSQL,不发布 Web 域名;本机可通过 `curl http://127.0.0.1:3000` 验证,公网可暂时使用 SSH Git 端口 `2222`
2. **正式上线阶段(必要变更)**:按本文第 4~7 节让 Trojan 改至本机 `8443`、管理后台改至本机 `8081`,让 Nginx 接管公网 `80/443`,再由 Caddy 为 `git.hk.chermack.top` 托管 HTTPS。
现有容器中的 Trojan 和 MariaDB 数据不会被删除;但 Trojan 容器需要在完成备份后重建或调整启动配置,才能释放宿主机 `80/443`。这是端口绑定的硬性限制,不是 Gitea 配置能够规避的问题。
### 目标流量关系
```mermaid
flowchart LR
U["用户 / Git 客户端"] -->|"HTTPS :443\ngit.hk.chermack.top"| N["Nginx stream"]
U -->|"Trojan 或后台 HTTPS :443\nwww.hk.chermack.top"| N
N -->|"SNI = git.hk.chermack.top"| C["共享 Caddy"]
N -->|"SNI = www.hk.chermack.top"| T["Trojan :8443"]
T -->|"非 Trojan TLS 回落"| Pnl["管理后台 :8081"]
C -->|"HTTP"| G["Gitea :3000"]
U -->|"SSH Git :2222"| G
G --> P["PostgreSQL\n仅 Docker 网络"]
```
### DNS 与端口
新增 DNS 记录:
```text
类型:A(若已启用 IPv6,则另加 AAAA)
主机记录:git
记录值:本服务器公网 IP
结果:git.hk.chermack.top
```
开放公网 TCP `2222` 供 SSH Git 克隆/推送;公网 `80/443` 仍只由统一 Nginx 入口占用。不要开放 PostgreSQL 的 `5432`,也不需要公开 Gitea 的 `3000`
### Gitea Compose(不再单独启动 Caddy
原 Gitea 部署方案中的独立 `gitea-caddy` 不应再映射宿主机 `80:80` / `443:443`,因为这些端口已由统一入口占用。Gitea 目录建议为 `/opt/gitea`,其 `docker-compose.yml` 可只保留数据库与 Gitea
```yaml
services:
db:
image: postgres:16
container_name: gitea-db
restart: unless-stopped
environment:
POSTGRES_USER: gitea
POSTGRES_PASSWORD: CHANGE_TO_A_LONG_RANDOM_PASSWORD
POSTGRES_DB: gitea
volumes:
- ./postgres:/var/lib/postgresql/data
networks: [gitea]
gitea:
image: docker.gitea.com/gitea:CHANGE_TO_A_VALIDATED_VERSION
container_name: gitea
restart: unless-stopped
depends_on: [db]
environment:
USER_UID: "1000"
USER_GID: "1000"
GITEA__database__DB_TYPE: postgres
GITEA__database__HOST: db:5432
GITEA__database__NAME: gitea
GITEA__database__USER: gitea
GITEA__database__PASSWD: CHANGE_TO_A_LONG_RANDOM_PASSWORD
GITEA__server__DOMAIN: git.hk.chermack.top
GITEA__server__ROOT_URL: https://git.hk.chermack.top/
GITEA__server__PROTOCOL: http
GITEA__server__SSH_DOMAIN: git.hk.chermack.top
GITEA__server__SSH_PORT: "2222"
ports:
- "127.0.0.1:3000:3000"
- "2222:22"
volumes:
- ./gitea:/data
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
networks: [gitea]
networks:
gitea:
```
示例固定 Gitea 镜像版本,避免 `latest` 在重建时产生不可预期的大版本升级。实际部署前应选定并验证当时支持的稳定版本;升级前先备份 `./gitea` 与 PostgreSQL。
### 共享 Caddy 新增站点
在第 6 节的**共享** Caddyfile 中新增:
```caddyfile
git.hk.chermack.top {
reverse_proxy 127.0.0.1:3000
}
```
当 Nginx 的 `443` stream 根据 SNI 将 `git.hk.chermack.top` 转到 Caddy 后,Caddy 会自动申请和续期该域名证书,再将 HTTP 请求反向代理给 Gitea。Gitea 生成的网页链接与 clone 地址则由 `ROOT_URL``SSH_*` 配置保持为正确的公网地址。
对本服务器,最终的 443 分流应是:`www.hk.chermack.top` 全部转给 Trojan`git.hk.chermack.top` 转给 Caddy。迁移后的 Trojan 监听 `127.0.0.1:8443`,其 `remote_port` 改为 `8081`Caddy 对外通过 Nginx 使用 `127.0.0.1:8080`HTTP)和 `127.0.0.1:9443`HTTPS)。
Nginx 的 80 端口按域名转发:`www.hk.chermack.top``127.0.0.1:8081``git.hk.chermack.top` 到 Caddy 的 `127.0.0.1:8080`。Trojan 证书续期不能再依赖独占 80 的 acme standalone 方式;正式迁移时应改用 Nginx 可服务的 ACME webroot 验证,或 DNS-01 验证。
### 验证清单
```bash
# Gitea 准备阶段:仅确认服务已运行(在服务器执行)
cd /opt/gitea
docker compose up -d
curl -I http://127.0.0.1:3000
# 正式切换统一入口之后
curl -I https://git.hk.chermack.top
ssh -T -p 2222 git@git.hk.chermack.top
git clone ssh://git@git.hk.chermack.top:2222/<组织>/<仓库>.git
```
`ssh -T` 的首次连接会要求确认主机指纹;应通过服务器控制台或管理员提供的指纹核验,不应盲目接受来源不明的密钥变更。