手把手部署 Syncthing 中继服务器 strelaysrv:从端口放行到私有上线的完整流程
【免费下载链接】syncthingOpen Source Continuous File Synchronization项目地址: https://gitcode.com/GitHub_Trending/sy/syncthing
当两台 Syncthing 设备都躲在 NAT 之后时,P2P 直连经常握手失败,同步任务就此卡住。strelaysrv(Syncthing 中继服务器)就是为这种场景准备的绕行通道:它只在两端之间转发字节、不看数据内容。下面按真实操作的顺序,带你把私有中继部署完整跑一遍:先定公共还是私有、放行端口、拿到连接地址、接入客户端、验证连通性,最后做到长期稳定运行。
一、先做决定:你的中继是公共的还是私有的
🚦 敲任何命令之前,先回答一个问题:这台中继为谁服务?
默认行为是公开的。不带任何参数启动 strelaysrv 时,它会自动加入默认的公共中继池并对外通告,任何互联网上的 Syncthing 客户端都可能借用你的机器转发流量,消耗的是你的公网带宽。默认池地址在代码里是写死的:
defaultPoolAddrs = "https://relays.syncthing.net/endpoint"启动时检测到这一默认值,日志会打印一整屏横幅,不可能错过:
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !! Joining default relay pools, this relay will be available for public use. !! !! Use the -pools="" command line option to make the relay private. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!所以两条路线很清晰:
- 回馈社区:无参数直接跑,注册进公共池;
- 只服务自己的设备:启动时务必显式加上
-pools="",池列表为空就不会执行任何注册动作。
另外记住一个前提:中继功能要求客户端为Syncthing v0.12 及以上版本,更老的客户端用不上。
| 对比维度 | 公共池模式 | 私有模式 |
|---|---|---|
| 启动参数 | 无需传-pools | 必须传-pools="" |
| 可用对象 | 任何能发现它的客户端 | 只认识 URI 的客户端 |
| 带宽去向 | 被公网流量共享 | 仅自己的设备 |
| /status 端口 | 建议开放(池要采集指标) | 可开可关 |
二、开机前准备:放行 22067 端口并配置防火墙
中继对外只需要两个 TCP 端口:
- 22067:中继主协议端口,客户端从这里接入,必须放行;
- 22070:
/status指标端口,只供中继池读取运行数据,私有部署可以完全不开放。
仓库里自带了 UFW 防火墙规则模板 cmd/strelaysrv/etc/firewall-ufw/strelaysrv,两条规则分别放行 22067/tcp 与 22070/tcp,可以直接照抄。
如果机器在路由器后面,需要在路由器上做端口转发(22067 是刚需,22070 按需),再在防火墙放行。公共池模式下端口真实可达是硬门槛——池服务器会反向连接你的中继做验证,连不通就不会接收你。
三、启动私有中继并拿到 relay:// URI
先准备可执行文件。strelaysrv 在 syncthing 仓库的 cmd/strelaysrv/ 目录里,克隆源码后用 Go 编译即可:
git clone https://gitcode.com/GitHub_Trending/sy/syncthing cd syncthing/cmd/strelaysrv && go build然后一条命令完成最小化启动:
./strelaysrv -pools=""首次启动时它会在-keys指定的目录(默认当前目录)发现没有密钥对,于是自动生成一份cert.pem和key.pem,有效期 20 年。之后每次启动都复用这对证书,中继的设备 ID 也就固定了。
启动成功后日志会打印一行URI::
URI: relay://:22067/?id=EZQOIDM-6DDD4ZI-DJ65NSM-4OQWRAT-EIKSMJO-OZ552BO-WQZEGYY-STS5RQM&pingInterval=1m0s&networkTimeout=2m0s&sessionLimitBps=0&globalLimitBps=0&statusAddr=:22070注意relay://后面主机部分是空的——没指定-listen时程序不知道你面向公网的地址,需要把主机部分替换成你的公网 IP:
relay://192.0.2.1:22067/?id=EZQOIDM-6DDD4ZI-DJ65NSM-4OQWRAT-EIKSMJO-OZ552BO-WQZEGYY-STS5RQM&pingInterval=1m0s&networkTimeout=2m0s&sessionLimitBps=0&globalLimitBps=0&statusAddr=:22070查询参数逐个拆解:
| 参数 | 含义 | 来自哪个开关 |
|---|---|---|
id | 中继的设备 ID,客户端拿它做证书固定,防冒用 | 由证书自动生成 |
pingInterval | 心跳间隔 | -ping-interval,默认 1 分钟 |
networkTimeout | 网络操作超时,超时即断开 | -network-timeout,默认 2 分钟 |
sessionLimitBps | 单会话限速(字节/秒),非零才出现 | -per-session-rate |
globalLimitBps | 全局总限速(字节/秒),非零才出现 | -global-rate |
statusAddr | /status 监听地址,未禁用才出现 | -status-srv |
如果你不打算做证书固定、也不想给客户端一串参数,只保留主机部分就是合法地址:relay://192.0.2.1:22067。不过推荐用完整形式,既更安全,客户端也能据此感知限速与超时设置。
日常最常用的几个参数先列在这里:
| 参数 | 默认值 | 什么时候要动它 |
|---|---|---|
-listen | :22067 | 不想用默认中继端口时 |
-pools | 公共池地址 | 私有中继必须传"" |
-token | 空 | 限定特定客户端才能用,设置后自动禁止入池 |
-status-srv | :22070 | 传""彻底关掉 /status |
-keys | . | 指定证书存放目录 |
-debug | false | 排查问题、看更多日志 |
四、把 URI 填入 Syncthing 客户端完成接入
打开 Syncthing 的网页界面,进入操作 → 设置,把最终的中继 URI 粘贴到Sync Protocol Listen Address字段。这个字段支持逗号分隔的多个地址,你的私有中继就作为其中的一个备选通道生效了。
私有中继强烈建议加一道访问控制:
./strelaysrv -pools="" -token=你的访问令牌这里有两个连带效果要知道:一是设置令牌后,程序会自动清掉池配置(等价于强制私有化);二是客户端提交的令牌与服务器不一致时,中继会直接回应令牌错误并断开连接——只有"知道口令"的设备才进得来。
五、验证中继连通性:testutil 自检 + /status 观察
别等真实的同步任务出问题了才来排查。仓库自带一个专用工具 cmd/strelaysrv/testutil/,三种模式覆盖所有验证需求:
-test:一键自检,结果只有 OK 或 FAIL,最省事;-join:以"等待方"身份加入中继,等别人来连;-connect=<设备ID>:以"发起方"身份主动经中继连接指定设备。
用两个终端做双向验证。先准备两套密钥对(各含key.pem与cert.pem),分开放:
certs/client/ certs/server/终端 A 先加入,它会打印自己的设备 ID:
./testutil -relay="relay://192.0.2.1:22067" -keys=certs/client/ -joinID: BG2C5ZA-W7XPFDO-LH222Z6-65F3HJX-ADFTGRT-3SBFIGM-KV26O2Q-E5RMRQ2终端 B 拿着这个 ID 发起连接:
./testutil -relay="relay://192.0.2.1:22067" -keys=certs/server/ -connect=BG2C5ZA-W7XPFDO-LH222Z6-65F3HJX-ADFTGRT-3SBFIGM-KV26O2Q-E5RMRQ2✅ 连上后两边都会出现交互式提示符:在任意一端敲字,内容都会经中继转发到另一端显示。能看到回显,就说明转发链路通了。
用 /status 看运行指标。默认:22070上挂着这个端点,浏览器或 curl 直接看:
curl http://127.0.0.1:22070/status返回 JSON,几个字段值得盯住:
bytesProxied:累计中转字节数,中继在干活时它应该持续上涨;numActiveSessions/numProxies:活动会话数与正在转发的代理通道数;numPendingSessionKeys:待加入的会话密钥数。每个会话随机生成两把密钥、两端各一把,所以这个值最高可以是待加入会话数的两倍;numConnections:已建立的 TLS 控制连接数;kbps10s1m5m15m30m60m:最近 10 秒 / 1 / 5 / 15 / 30 / 60 分钟的吞吐率,每 10 秒采一个点,最长覆盖 60 分钟;options:启动参数的回显,远程核对"服务器到底跑在什么配置下"很方便。
完全用不到这个端点就传-status-srv=""关掉;反过来加-pprof,同一个 HTTP 服务上还会多出/debug/pprof/路径做内置性能剖析。
六、生产化:限流、连接上限与 systemd 长期运行
要长期跑起来,需要敲定三件事:给多少带宽、能扛多少连接、崩了怎么自愈。
用两个速率参数限定带宽
./strelaysrv -pools="" -per-session-rate=1048576 -global-rate=10485760两个参数单位都是字节/秒,0表示不限:-per-session-rate管单个会话(避免一对设备霸占全部带宽),-global-rate管机器总量(保护你的公网出口)。底层是令牌桶实现,突发容量设为限速值的两倍;两者同时设置时,会话限流与全局限流并行生效,以等待更久的一方为准。
理解连接上限的自我保护机制
启动时程序会先把文件描述符上限提到最高,再扣掉约 20% 的"未知泄漏"余量,用剩下的 80% 作为连接上限(启动日志里的Connection limit就是这个数)。之后每分钟检查一次:超限就对新连接回应"中继已满"、清退空闲连接,回落之后自动恢复接纳。高并发时它会优雅降级而不是崩溃。
用 systemd 单元长期运行
仓库提供了现成的单元模板 cmd/strelaysrv/etc/linux-systemd/strelaysrv.service,核心片段:
[Service] WorkingDirectory=/var/lib/syncthing-relaysrv EnvironmentFile=/etc/default/syncthing-relaysrv ExecStart=/usr/bin/strelaysrv -nat=${NAT} $RELAYSRV_OPTS User=syncthing-relaysrv Group=syncthing ProtectSystem=strict ReadWritePaths=/var/lib/syncthing-relaysrv NoNewPrivileges=true PrivateTmp=true MemoryDenyWriteExecute=true所有运行时开关(-pools=""、限速等)都通过环境文件/etc/default/syncthing-relaysrv里的$RELAYSRV_OPTS注入,证书放在/var/lib/syncthing-relaysrv,配合独立用户与一系列加固项,直接套用即可。
进阶参数一览,按需取用:
| 参数 | 默认值 | 作用 |
|---|---|---|
-network-timeout | 2m | 该周期内无数据则断开连接或会话 |
-ping-interval | 1m | 心跳发送间隔 |
-message-timeout | 1m | 等待关键消息到达的最长时间 |
-network-buffer | 65536 | 每条被代理连接占用两个该大小的缓冲区 |
-ext-address | 同-listen | 对外通告地址,可监听普通端口再从 443 转发接入 |
-protocol | tcp | tcp双栈,tcp4/tcp6单栈 |
-nat | false | 用 UPnP/NAT-PMP 自动申请外部端口映射 |
-nat-lease/-nat-renewal/-nat-timeout | 60/30/10 | 租约时长(分)/ 续约频率(分)/ 发现超时(秒) |
-pprof | false | 在状态服务器上开启内置剖析 |
-provided-by | 空 | 提供方说明,超过 30 字符会直接报错退出 |
七、故障排查:按日志现象对号入座
🔎 上线后出问题,先看日志里是哪种"腔调":
| 日志或现象 | 原因与对策 |
|---|---|
| 启动即打印公共池横幅 | 漏了-pools="",私有部署补上 |
Failed to join ...: under load (rate limiting) | 池端限流(HTTP 429),一分钟后自动重试,持续出现多半是池侧负载高 |
IP address not matching external address | 池服务器发现你的出口 IP 与通告地址对不上,常见于 NAT/转发配置错误;此分支会直接放弃加入,先修网络 |
| 客户端连不上中继 | 确认 22067 公网可达、防火墙已放行、URI 主机是真实公网地址 |
反复出现Joined pool ..., rejoining in 48m0s | 正常现象:池给出驱逐倒计时,中继在 80% 时间点主动续注册,不是故障 |
最后一行其实是好消息——看到它说明公共池注册链路已经跑通。
写在最后
整个部署其实就四件事:定好公共还是私有(-pools)、放行 22067、拿到 URI 填进客户端、用 testutil 与 /status 验证。后续再遇到异常,用-debug启动看日志,对照 /status 的指标字段和上面的现象表,绝大多数问题都能在几分钟内定位。
【免费下载链接】syncthingOpen Source Continuous File Synchronization项目地址: https://gitcode.com/GitHub_Trending/sy/syncthing
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考