在 Synology 上部署 Trojan(Xray)
Table of Contents
由于还是不时会去 HK/CN 出差,因此还是需要一个科学上网服务。尽管有专业机场,但是敏感服务还是从个人线路走更合适。同时也需要一个 Tailscale 的备份可以连回家中。这篇记录我在 Synology (代号 SO)上部署 Trojan 代理的全过程。目标是稳定、可审阅、可回滚,并配套“一键”脚本完成部署、更新、验证、日志分析与本地客户端测试,大部分代码由 Codex 自动生成。
目的与约束 #
- 使用自有域名
foo.example.im提供 Trojan 服务。 - 走家庭网络:路由器将公网端口转发到 NAS。
- 非 root 运行容器,避免不必要的权限。
- 自动化:配置先渲染、后审阅、再批准部署。证书全流程也都自动化。
- 可验证:本机、NAS 端、通过外部 remote 远端均能自动化检测并输出清晰结果,验证可访问性。
选型 #
首选默认还是 ss,之前家里也一直都跑着,部署方便(即便是混淆),但是 ss 的综合可用性已经都被其他协议超越,因此还是希望尝试新的方式。先是尝试 ss + ShadowTLS 的方式,使用 sing-box 部署,结果每几个小时就因为 goroutines 堆积而 crash,并且瞬发流量一大也会 crash。后来和 ChatGPT 一番对话,加上之前常用的专业机场基本也都使用 Trojan 我相信在规模化运行时所有小概率问题都会放大为确定性问题,既然专业平台都使用 Trojan,那么就选择它吧。
- 核心实现:Xray-core(
ghcr.io/xtls/xray-core)- 原生支持 Trojan inbound,生态活跃、协议扩展灵活(后续可切 VLESS/Reality 等)。
- 证书:acme.sh + Cloudflare DNS-01
- 无需对外开放 80/443,适合家宽环境。
- 客户端测试:sing-box(本机 SOCKS5 验证),兼容多平台。
备选对比:
- trojan-go:轻量,但不如 Xray 的路由/传输栈丰富。
- 纯 Trojan:功能单一,后续扩展不足。
设计 #
- 端口与映射
- 容器监听
12345(注意使用非特权端口,避免 DSM 需要 sudo 运行脚本,导致自动化复杂度) - NAS 暴露
22333,映射到容器12345 - 路由器将公网
54321 → NAS:22333
- 容器监听
- 证书
- DNS-01 申请,安装到
$TROJAN_REMOTE_DIR/cert/{fullchain.pem,privkey.pem} - 容器挂载只读
/etc/xray/cert
- DNS-01 申请,安装到
- 权限
- 以 DSM 用户身份运行容器:
PUID=1026、PGID=100 - 私钥权限
600
- 以 DSM 用户身份运行容器:
- 配置方式
- 单文件
/etc/xray/config.json - 强制 entrypoint:
xray run -c /etc/xray/config.json
- 单文件
flowchart LR
User -- Trojan TLS:54321 --> Internet
Internet --> Router[Router NAT]
Router -- DNAT 54321→22333 --> NAS[Synology:22333]
NAS -- Docker map 22333→12345 --> Xray[Xray Container:12345]
Xray --> Freedom[Freedom Outbound]
实施过程(关键步骤) #
- 环境与目录约定
.env约定:NAS_HOST=192.168.x.yyyTROJAN_DOMAIN=foo.example.comTROJAN_WAN_PORT=54321、TROJAN_HOST_PORT=22333、TROJAN_CONTAINER_PORT=12345TROJAN_UID=1026、TROJAN_GID=100TROJAN_PASSWORD=<强密码>
- 证书目录:
/volumeX/docker/trojan/cert,存储在 NAS 目录中。
- 证书签发(Cloudflare DNS-01)
make trojan.cert- 读取
CF_Token/CF_Account_ID/CF_Zone_ID,使用 acme.sh 申请并安装证书到 NAS 目录。 - 默认不重启容器;如需自动重载,设
TROJAN_CERT_RELOAD=1。
- 读取
- 渲染与部署
- 渲染配置:
make trojan.render(输出build/trojan/config.json) - 一键部署:
make trojan.deploy APPROVE=1- 上传 config 与 compose;如支持 Compose,则
up -d;否则回落到docker run(附--entrypoint xray与端口/卷映射)。
- 上传 config 与 compose;如支持 Compose,则
- 更新镜像:
make trojan.update - 重新应用配置:
make trojan.redeploy APPROVE=1 - 仅重启:
make trojan.restart
- 验证与诊断
- 服务器侧体检:
make trojan.verify- 检查容器状态、端口、NAS 证书、容器挂载(严格校验
/etc/xray/cert <- $TROJAN_REMOTE_DIR/cert)、本机 TLS 探测、日志关键词扫描。
- 检查容器状态、端口、NAS 证书、容器挂载(严格校验
- 远端体检:
make trojan-verify-remote- 从远程机器对
foo.example.com:54321做 DNS/TCP/TLS 验证。
- 从远程机器对
- 详细 TLS 日志:
make trojan-verify-verbose- 临时将
loglevel=info,重启收集 TLS/证书日志后恢复原配置。
- 临时将
- 客户端测试(sing-box):
make trojan.singbox FLAGS="--probe"- 生成 sing-box 配置,在远程机器起 SOCKS5 代理
127.0.0.1:1080,用curl验证经过了代理访问;可指定--dns/--server-ip。
- 生成 sing-box 配置,在远程机器起 SOCKS5 代理
- 日志分析
make trojan.analyze- 输出总览、错误数、Accepted 连接数
- Top 目的站/端口/来源 IP 排名
- 示例“accepted …”行,方便人工核对
关键配置片段 #
Xray inbound(Trojan,容器内端口 12345):
{
"inbounds": [
{
"listen": "0.0.0.0",
"port": 12345,
"protocol": "trojan",
"settings": {
"clients": [{ "password": "YOUR_PASSWORD" }]
},
"streamSettings": {
"security": "tls",
"tlsSettings": {
"alpn": ["http/1.1"],
"certificates": [
{
"certificateFile": "/etc/xray/cert/fullchain.pem",
"keyFile": "/etc/xray/cert/privkey.pem"
}
]
}
}
}
],
"outbounds": [{ "protocol": "freedom" }]
}Compose 运行参数(要点):
services:
xray:
image: ghcr.io/xtls/xray-core:latest
user: "${TROJAN_UID}:${TROJAN_GID}"
entrypoint: ["xray"]
command: ["run", "-c", "/etc/xray/config.json"]
ports:
- "${TROJAN_HOST_PORT}:${TROJAN_CONTAINER_PORT}"
volumes:
- ${TROJAN_REMOTE_DIR}/config.json:/etc/xray/config.json:ro
- ${TROJAN_REMOTE_DIR}/cert:/etc/xray/cert:ro
restart: unless-stopped遇到的问题与解决 #
- 在 DSM 上 Docker 命令不可用/路径不一致(Container Manager)
- 远端自动探测 Docker/Compose 路径(含
/var/packages/...),必要时用 sudo。
- 远端自动探测 Docker/Compose 路径(含
scp失败(SFTP 关闭/策略限制)- 回退到 SSH 流式上传(
cat → ssh → 重定向),目录用 tar 流。
- 回退到 SSH 流式上传(
- Xray 默认读取 confdir
- 显式
xray run -c /etc/xray/config.json,强制读取挂载的单文件配置。
- 显式
- 证书读取权限被拒绝
- 使用容器
user: 1026:100与 NAS 文件属主一致;私钥600。
- 使用容器
- 容器内绑定 443 被拒绝(非 root)
- 采用容器内
12345+ NAS2233+ 路由54321映射链路。
- 采用容器内
- 多次输入 SSH 口令
- 启用 SSH 连接复用(ControlMaster)与可选临时 ssh-agent,“一次输入,多次复用”。
小结 #
最终在远程机器上测试 Youtube 2160p 毫无压力,测速也都达到了带宽满速。完成后的脚本命令列表如下:
(base) ➜ trojan git:(main) make
make nas.check - Check SSH, Docker, directories on NAS
make nas.setup-ssh-key - Configure SSH public key login to NAS
make trojan.render - Render Xray/Trojan config locally for review
make trojan.deploy - Deploy container (APPROVE=1 uploads & runs)
make trojan.status - Show container status and key info
make trojan.logs - Tail/show logs (SINCE=, TAIL=, FOLLOW=1)
make trojan.update - Pull image and update/restart
make trojan.restart - Restart container without pulling image
make trojan.redeploy - Re-render config, upload, restart
make trojan.analyze - Log summary
make trojan.cert - Issue & install cert via acme.sh (DNS-01)
make trojan.verify - Server-side checks: status, certs, ports, TLS probe
make trojan.verify-remote - Client-side DNS/TCP/TLS checks from this machine
make trojan.verify-verbose - Temporarily set loglevel=info, restart, capture TLS logs, restore
make trojan.singbox - Generate sing-box client config (default SOCKS5 127.0.0.1:1080)
Examples:
make nas-check
make trojan-render && less build/trojan/config.json
make trojan-deploy APPROVE=1
make trojan-logs SINCE=2h FOLLOW=1
make trojan-analyze SINCE=24h脚本覆盖了 Synology 路径/权限、Compose 差异、证书获取与部署、入口命令覆盖、端口映射与非 root 运行、远端/本地体检与日志分析,基本囊括运维关键细节。