Syncthing 中继实战:strelaysrv 私有部署、连通性验证与排错清单
【免费下载链接】syncthingOpen Source Continuous File Synchronization项目地址: https://gitcode.com/GitHub_Trending/sy/syncthing
两台设备都在 NAT 后面,UDP hole-punch 打不通、TCP 直连超时,Syncthing 的同步卡死在"等待连接"。这时就需要一台 strelaysrv(Syncthing 中继服务器):两端各自连到同一台服务器,由它完成字节级双向转发。以下流程按"做选择 → 放行端口 → 启动拿地址 → 客户端接入 → 验证连通 → 长跑监控"展开,全程可照做。
公共池还是私有中继:先做选择再动手
动手前先定一个策略,它决定你后面所有参数。strelaysrv 的默认池地址是公共中继池 relays.syncthing.net/endpoint,不传任何参数启动时,它会向该池 POST 自己的 relay:// 地址完成注册(见 pool.go),并打印醒目横幅:
!! 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 用户开放 | 仅自己填入 URI 的设备可连 |
| 带宽成本 | 持续为公众转发,长期消耗 | 只服务内部流量 |
| 接入方式 | 自动注册到池,客户端可发现 | 手动把 relay:// 填进客户端 |
| 适合场景 | 愿意回馈社区的公网机器 | 团队、家庭、跨内网同步 |
两个私有化补充:其一,-token=...会自动禁用加入任何池(main.go 中直接把poolAddrs置空),并在收到令牌不匹配的JoinRelayRequest时回ResponseWrongToken后断开连接(见 listener.go),等于给中继加了门禁;其二,客户端版本是硬门槛——只有 Syncthing v0.12 及以上才支持中继功能,旧版本填了也不工作。
放行 22067 端口并启动 strelaysrv
端口与防火墙
两个 TCP 端口,一个必需一个可选:
| 端口 | 作用 | 必需性 |
|---|---|---|
| 22067 | 中继主协议,客户端经它加入与收发数据 | 必需,须公网可达 |
| 22070 | /status端点,供池服务器采集指标 | 可选,私有部署可不放行 |
UFW 环境下可直接套用仓库自带的规则模板(strelaysrv):
[strelaysrv] title=Syncthing relay server description=Proxies traffic of syncthing client behind firewalls ports=22067/tcp [strelaysrv-metrics] title=Syncthing relay metrics description=Provides metrics about the syncthing relay server ports=22070/tcp处于 NAT 之后时,在路由器上转发 22067(以及需要暴露的 22070)即可。另一种免手工转发的做法是加-nat,让 strelaysrv 通过 UPnP/NAT-PMP 自动申请映射,-nat-lease(默认 60 分钟)、-nat-renewal(30 分钟)、-nat-timeout(10 秒)分别控制租约时长、续约频率与发现超时——前提是路由器支持 UPnP。
启动命令与 relay:// 地址获取
# 私有部署的最小启动命令 ./strelaysrv -pools="" # 排查问题时可加 -debug 输出连接与消息级日志首次启动若当前目录(-keys指定目录)没有cert.pem/key.pem,会自动生成一对有效期 20 年的自签证书,随后打印URI:一行。由于默认监听:22067,服务器不知道自己的公网 IP,URI 的主机部分是空的:
URI: relay://:22067/?id=EZQOIDM-6DDD4ZI-DJ65NSM-4OQWRAT-EIKSMJO-OZ552BO-WQZEGYY-STS5RQM&pingInterval=1m0s&networkTimeout=2m0s&sessionLimitBps=0&globalLimitBps=0&statusAddr=:22070判断依据:日志出现URI:且无Failed to generate X509 key pair即启动成功。把主机部分补成公网 IP 或域名后得到最终地址,例如relay://192.0.2.1:22067/?id=EZQOIDM-...&statusAddr=:22070。URI 各参数含义:
id:中继证书对应的设备 ID,客户端据此做证书固定(pinning);pingInterval/networkTimeout:心跳间隔与网络超时,对应-ping-interval/-network-timeout;sessionLimitBps/globalLimitBps:会话级与全局限速,为 0 时不写入;statusAddr:/status监听地址。
完整形式建议原样填写——它让客户端能核对证书、获知限速配置;不想要这些参数时,简化成relay://192.0.2.1:22067也合法,代价是放弃证书固定。
特殊场景:监听 443 之外的端口并通过防火墙从 443 转发时,用-ext-address通告对外地址,例如监听 8443 但让客户端以 443 接入。其余参数(超时、限速、监听协议等)执行strelaysrv -help自查即可,部署决策只依赖上表提到的这几个。
客户端侧写入同步协议监听地址
打开 Syncthing 图形界面的 操作 → 设置,在"同步协议监听地址"(Sync Protocol Listen Address)字段末尾追加完整 relay URI,以逗号与其他监听地址并列保存。客户端在直连失败时会自动尝试该中继。
testutil 双终端连通验证
上线后先验证转发通路,再谈接入。testutil(main.go)是仓库自带的连通性工具,提供三种模式:-join加入中继等待邀请、-connect=<设备ID>向指定设备发起连接、-test单进程自检。
双终端验证需要两套 X509 证书(各含key.pem与cert.pem),分别放在certs/client/与certs/server/:
# 终端 A:加入中继并等待对方 ./testutil -relay="relay://192.0.2.1:22067" -keys=certs/client/ -join # 终端 B:用 A 打印的设备 ID 发起连接 ./testutil -relay="relay://192.0.2.1:22067" -keys=certs/server/ \ -connect=BG2C5ZA-W7XPFDO-LH222Z6-65F3HJX-ADFTGRT-3SBFIGM-KV26O2Q-E5RMRQ2✅ 成功标志:两端都打印Joined ...并进入交互提示符,在任一端输入的文字经中继出现在另一端;-test模式则直接输出OK(失败为FAIL: <错误>),适合写进巡检脚本做一键自检。
systemd 托管与 /status 指标速读
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 ProtectSystem=strict ReadWritePaths=/var/lib/syncthing-relaysrv PrivateTmp=true MemoryDenyWriteExecute=true-pools、-status-srv、-token等自定义参数写进/etc/default/syncthing-relaysrv的RELAYSRV_OPTS即可,改参数只需改环境文件后systemctl restart。加固项里ProtectSystem=strict+ 白名单ReadWritePaths保证只有证书目录可写,PrivateTmp与MemoryDenyWriteExecute进一步缩小攻击面。
另外一句话带过过载保护:启动时 strelaysrv 取文件描述符上限的 80% 作为连接数上限,每分钟检查一次,超限后对新连接回RelayFull并清退空闲连接,回落后自动恢复,无需人工干预。
/status 端点关键字段
/status默认挂在:22070,返回 JSON;私有部署不需要它时加-status-srv=""整体关闭(该端口也就不用放行了)。挑运维最相关的几个字段:
{ "bytesProxied": 1048576, "kbps10s1m5m15m30m60m": [0, 12, 30, 28, 25, 20], "numActiveSessions": 2, "numConnections": 3, "numProxies": 2 }bytesProxied:累计代理字节数,长期不增长说明没有流量真正走通;kbps10s1m5m15m30m60m:10 秒 / 1 分 / 5 分 / 15 分 / 30 分 / 60 分六个窗口的吞吐(kbps),每 10 秒采样一次、保留 360 个点,适合接进你的监控采集;numActiveSessions:正在转发的会话数;numConnections/numProxies:已建立的 TLS 控制连接数 / 活跃代理通道数,前者大于后者属正常(加入后等待对端的连接不计入代理);options:启动参数回显,远端核对配置时最省事。
限速参数的令牌桶原理
底层用golang.org/x/time/rate实现,burst 取限速值两倍:-per-session-rate是"每会话一个桶",-global-rate是"整台服务器一个桶",好比给每部电梯限重的同时再给整栋楼限载,两个桶都设时按更严格的那个等待。单位为字节/秒,0 表示不限。
排错速查:现象、原因、动作
| 现象 | 原因 | 动作 |
|---|---|---|
日志反复under load (rate limiting) | 池端 HTTP 429 限流,自动一分钟重试 | 属公共池侧行为,等待即可;私有部署不应出现 |
日志IP address not matching external address | 出口 IP 与通告地址不一致,多为 NAT 映射未生效 | 核对端口转发,或改用-nat/ 手工映射后重启 |
| 客户端始终连不上 | 22067 未公网可达或防火墙拦截 | 外网nc -vz <公网IP> 22067,再对照 UFW 规则与路由器转发 |
| 连接被拒且日志出现 invalid token | 客户端 URI 缺少令牌或令牌不匹配 | 核对-token与客户端配置一致 |
| 不想暴露 /status | 默认开启:22070 | 加-status-srv=""后重启 |
把-pools和-status-srv按定位设好、22067 真正放行、relay URI 完整填入客户端,一台可用的 Syncthing 中继就上线了;异常时先-debug看日志,再对照/status指标定位。延伸阅读:man 手册 strelaysrv.1、中继协议与客户端库 lib/relay、公共发现服务 stdiscosrv 说明。
【免费下载链接】syncthingOpen Source Continuous File Synchronization项目地址: https://gitcode.com/GitHub_Trending/sy/syncthing
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考