最近因为个人的需求,需要搭建一个独立并且能够与 OneDrive 互通的一个网盘,用来代替同步全平台设备之间的文件。经过短暂的探索之后,我使用 Syncthing 完成了个人的最佳实践。
此搭建方案中的流程并没有严格从 0 开始阐述,所以部分内容可能需要一定的 docker 和命令行基础。
整体结构
Syncthing 本身做的是多端的设备文件同步,设备间掉线或者断开连接就会失去同步,这和传统意义上的云盘有些不同。由于我们需要实现的是云盘场景,所以自然需要在结构配置上满足一些基本特性。
基本特性
- 一直在线:所以我们需要存在一台长期在线的机器作为中间设备,让其他设备实时同步文件;
- 跨系统:这一点 Syncthing 已经提供了几乎全平台的客户端,所以基本不需要我们做什么,按照平台下载软件即可;
- 暴露公网:此处方案就比较多样了,公网服务器的话可以直接搭建,本地可以通过 Nginx 反向代理 + FRP 实现公网暴露。
- 安全性 & 私密性:Syncthing 提供的发现服务和中继服务默认会暴露公网,变成公共服务吃池的一部分;所以如果完全个人使用需要的话,需要额外进行配置。
此时整体流程就清晰了起来:我们需要搭建一套 Syncthing 服务 + 中继 + 发现 一体的服务端当成实时在线的中心节点,并且部署在公网上;然后其他需要同步文件的设备(比如手机、笔记本、平板)只需安装 syncthing 的本体,然后将中继和远程设备配置到服务端,正常与服务端进行同步即可。
这样虽然比其他的 Syncthing 同步方案稍显复杂,但是可以通过中心节点来避免设备下线就断开同步的问题,做到设备下线也不影响文件的同步。
具体搭建操作
搭建操作主要围绕着上文提到的服务端,我们需要搭建。Syncthing 的主程序 syncthing
、发现服务 stdiscov
和中继服务 strelay
都提供了容器化的解决方案,所以可以通过容器很方便地进行部署。
拉取容器
首先通过一下命令拉取所需的三个容器:
docker pull syncthing/syncthing
docker pull syncthing/relaysrv
docker pull syncthing/discosrv
命令行启动参数
因为个人单独写了一套类 Kubernetes 的单机配置方案,最终所有配置都会转化为命令行;如果有
docker-compose
相关的需要,可以直接通过命令行的参数进行等价转换。
Syncthing
docker run --rm -dit --name=syncthing \
-u $(id -u):$(id -g) \ # 设置容器内用户权限
--link relayserver --link discoverserver \ # 网桥搭桥,保证容器内能与 relay 和 disov 正常通信
-p <port>:8384 -p <port>:22000 \ # 8384 是前端页面端口,22000 是服务发现端口
-v <path_to_syncthing_config>:/var/syncthing/config \ # syncthing 配置文件路径映射
-v <path_to_syncthing_Sync>:/var/syncthing/Sync \ # syncthing 默认同步文件夹路径映射
syncthing/syncthing
如果基于本方案,那么流量会全部走 relay 中继,22000 可不用暴露公网使用。
需要注意的是,如果配置了 --link relayserver --link discoverserver
,需要保证 syncthing 在中继服务和发现服务拉起之后再启动,不然会报错找不到 link
的容器。
Relay
docker run --rm -dit --name=relayserver \
-u $(id -u):$(id -g) \ # 设置容器内用户权限
-p <port>:22067 \ # 中继服务端口
-v <path_to_relay_config>:/var/strelaysrv \ # 配置路径
syncthing/relaysrv \
-pools="" -listen=":22067" # relay 的参数配置,"" 表示不暴露公网,listen 为监听端口
部署容器并启动成功后,可以通过 docker logs
命令查看该容器日志,看到对应的 relay
地址(格式为relay://<ip_or_domain>:<port>?id=XXXX
)。在所有的 syncthing 服务(前台页面)右上角的 “操作” → “连接” → “协议监听地址” 加上 realy 地址。
Discover
docker run --rm -dit --name=discoverserver \
-u $(id -u):$(id -g) \ # 设置容器内用户权限
-p 22066:22066 \ # 发现服务端口
-v {SERVICE_DATA_DIR}/syncthing/discosrv:/var/stdiscosrv \ # 配置路径
syncthing/discosrv \
-listen=":22066" # discov 的参数配置,listen 为监听端口
discov 主要是为了进行服务发现;如果纯靠配置让所有流量走中继的话,可以不用部署发现服务器。
同中继服务,发现服务也可以使用 docker logs
查看对应的发现服务地址(格式为tcp://<ip_or_domain>:<port>?id=XXXX
),然后在所有的 syncthing 服务(前台页面)右上角的 “操作” → “连接” → “全局发现服务器” 加上该地址。
可能涉及的问题
设备路由线路选择顺序
Syncthing 内部配置了很多公共发现服务、本地发现服务之类的地址,有时候就会出现一个很难受的问题:明明局域网内连接着,但是偏偏走了全球发现服务器,然后挂了一条公共的 relay 小水管,同步速度只有几 KB/s。
Syncthing 内部设备路由默认顺序:{TCP,QUIC} LAN → {TCP,QUIC} WAN → Relay LAN → Relay WAN → Disconnected
(Github)
“远程设备” → “选项” → “高级” → “地址列表” 里面配置的路由会依照这个顺序进行选择。
因为本方案自己搭建了网络环境更好的 relay,所以就把 dynamic 给删了,只保留了局域网地址(tcp://<ip>:<port>
)和 relay 服务地址(relay://<ip_or_domain>:<port>
),这样不会选到其他中继服务,也更安全。
开源软件最好的就是,不会的问题永远可以通过翻源码找到答案。
中继与发现服务 Nginx 反向代理
中继服务和发现服务在反向代理的时候出现了一些小问题,一致没有办法通过反向代理来把流量路由给 syncthing。这块我最后是通过 DNS + CNAME 解析的方式路由到了 Nginx。