用 Relayium CLI 实现服务器到服务器直传(daemon 直连)
最近更新: 2026-08-05
当两台机器都是你自己的,并且彼此知道对方地址时,用 SSH 是白绕一道,走会合服务器更是纯粹的额外开销。daemon 直连正是为此而生:一台服务器监听,另一台通过证书固定的 TLS 1.3 连接直接推送过去。无需中继、无需 SSH、无需配对码——信任基于公钥,只需设置一次。
本指南涵盖启动监听端、向其推送、在首次联系时批准新的推送方、实现自动化,以及把监听端作为 systemd 服务运行。
开始之前
下面用到的都是 relayium CLI,所以没装的话先装上。在 macOS 或 Linux 上,一条命令就能把预编译二进制放进你的 PATH:
curl -fsSL https://relayium.com/install.sh | sh
- 想自己挑文件,或在 Windows 上?从发布页下载二进制——relayium.com/cli 列出了所有安装方式(装了 Go 也可 go build -o relayium ./cmd/relayium)。
- relayium --version 可确认是否装好。不装这一步,下面的命令只会报 “command not found”。
启动监听端(在接收方)
你需要准备
- 两台你自己掌控的机器,并且接收方的地址从发送方可达。主机名或裸 IP 都行。
- 两端都装好 relayium。daemon 直连只说原生协议,所以这里没有 tar 兜底来救一台没装的机器。
- 把监听端的端口对发送方开放——默认是 9031/TCP——主机防火墙和云安全组都要开。
- 接收方在第一次推送时要有一个终端,好回答批准提示。没有终端的话,请改为预先授权发送方(见下文)。
在接收方服务器上,serve 监听推送并把它们写入某个目录。它默认长期运行;加上 --once 可以只接受一次传输就退出。你不需要预先共享任何东西——不用提前复制任何指纹:
建好推送要落地的目录。
mkdir -p ~/inbox只对发送方开放监听端的端口。把 203.0.113.7 换成发送方自己的地址——公网 IP,或者两台服务器同处一个内网时的内网 IP——并且把云安全组也收敛到同一个来源,而不是对整个互联网开放。
sudo ufw allow from 203.0.113.7 to any port 9031 proto tcp在终端里启动监听端,这样第一次推送时才有人回答批准提示。加 --once 只接一次传输就退出,加 --port 可以离开 9031。
relayium serve --dir ~/inbox
监听端跑起来是什么样
serve 会写明它绑定的地址、写入的目录,以及本机自己的指纹。在还没有已批准的对端时,它还会说明每遇到一个新对端都会来问你。
relayium serve --dir ~/inbox
no authorized peers yet — you'll be asked to approve each new peer on its first push.
relayium serve: listening on [::]:9031, receiving into /home/you/inbox (fingerprint 5c1d9f04…)- 监听端依次处理连接,并把文件落到 --dir 指定的目录下。
- 默认端口是 9031;可用 --port 修改,并在防火墙上开放该端口。
向监听端推送(在发送方)
从发送方服务器,推送到接收方的 relayium:// 地址。第一次连接会固定接收方的指纹;此后每次连接都会校验它,指纹一旦变化,监听端就会拒绝连接,而不会默默放行——密钥掉包或中间人攻击会当场暴露,不会被当成可信。在第一次推送时,发送方会稍等片刻,等待接收方批准(下一步)。
在发送方服务器上执行推送。第一次连接时它会正好停在这里,等接收方批准。
relayium push ./build.tar.zst relayium://receiver.example.com在接收方回答那个提示——就是下一节的内容。之后推送会自己走完,以后的推送也不会再停在这里。
监听端不在 9031 时,在地址后面加上端口。
relayium push ./build.tar.zst relayium://receiver.example.com:9040
推送成功是什么样
第一次接触时,发送方会学到并固定监听端的指纹,然后开始传输。接收方会记下推送方的指纹,并报告文件数和字节数。
# on the SENDER, first contact
learned receiver.example.com:9031 5c1d9f04… (added to known_hosts)
build.tar.zst (48213004 bytes)
# on the RECEIVER
authorized 74318e3b… (added to /home/you/.config/relayium/authorized_fingerprints)
received 1 file(s), 48213004 bytes from 74318e3b…- 没有中继,也没有回退:如果监听端无法到达,推送就会失败——文件字节永远不会经过其他任何人转发。
- 使用与其他模式相同的传输引擎:可续传,并对每个文件做 SHA-256 校验。
在首次推送时批准发送方(在接收方)
当一台新机器第一次向你的监听端推送时,serve(在终端中)会显示它的来源和指纹,并请你批准它——就像 SSH 首次连接时的提示,只不过是在接收方这一侧:
# 在接收方,当有新的发送方推送时:
Incoming push from 203.0.113.7:54021
fingerprint: 74318e3b…
Accept and remember this peer? [y/N] y
- 回答 y,该指纹就会记入 authorized_fingerprints;此后同一台机器的每次推送都会静默通过。
- 指纹是一台机器的稳定身份(重启和 IP 变化都不受影响),因此批准对每个推送方来说只是一次性的步骤。
- 推送方则在首次连接时获知监听端的密钥(首次使用即信任),并将其固定在 known_hosts 中。
实现自动化(或在没有终端的环境下运行)
由于已批准的指纹会一直保留,后续推送不再需要确认——因此 relayium push 可以直接接入 cron、部署脚本或 CI,实现加密、可校验完整性、可续传的服务器到服务器同步。当 serve 在没有终端的环境下运行(作为 systemd 服务、通过管道)时,它无法弹出提示,因此会拒绝未知的推送方;这时应改为预先授权它们。可以从推送方的 relayium id 获取指纹,或者从 serve 日志中「rejected unauthorized peer …」那一行复制它,然后:
# 在接收方:无需提示,预先授权一个发送方
relayium authorize 74318e3b...
- 身份和信任文件存放在 ~/.config/relayium/ 中(可用 --config-dir 覆盖,例如作为服务时用 /etc/relayium)。
- authorize 是幂等的——对同一个指纹再次运行它不会有任何效果。
在 systemd 下运行监听端
要做一个常驻收件箱,把 serve 作为 systemd 服务运行。把 --config-dir 指向一个固定位置,例如 /etc/relayium,让身份在重启之间保持稳定,并交给 systemd 来保活:
# /etc/systemd/system/relayium-serve.service
[Unit]
Description=Relayium daemon-direct listener
After=network-online.target
[Service]
ExecStart=/usr/local/bin/relayium serve --dir /srv/inbox --config-dir /etc/relayium
Restart=always
User=relayium
[Install]
WantedBy=multi-user.target
- 用 systemctl enable --now relayium-serve 启动它,并让它开机自启。
- 让 /etc/relayium/id.key 只对服务用户可读——权限过于宽松时 relayium 会拒绝加载该密钥。
推送不通的时候
先查的是可达性和信任这两件事:在发送方跑 ss -tinp,能看出监听端到底通没通;在接收方跑 relayium authorize,则是把被拒绝的发送方缺的那份信任补上。但推送出错的方式不止这两类——接收方磁盘满了、收件目录对运行它的用户不可写、某个文件传完后过不了完整性校验,这些都会自己报错——所以请先看眼前的报错,而不是假定它一定是下面四种之一。
现象、检查、修复
- 推送一直挂着,最后报连接错误。
# 在发送方,推送还在跑的时候——隔几秒跑两次 ss -tinp dst :9031 # ESTAB 说明够得着监听端,但不说明有没有进展 # SYN-SENT 那个端口上没人应答SYN-SENT 意味着数据包根本没到达一个正在监听的套接字。先在接收方用 ss -tlnp | grep 9031 确认 serve 起着,再在主机防火墙和云安全组里把 9031/TCP 对发送方开放。ESTAB 只能证明够得着——一条已建立的连接照样可以闲着或者卡住——所以要区分「在传」和「卡住」,得隔几秒把这条检查跑两次,比较 -i 为该套接字打印的 bytes_acked 计数。这里没有中继通路,所以监听端不可达是硬失败,而不是变慢。
- serve 日志里写着 “rejected unauthorized peer …”,推送失败。
# 在发送方 relayium id # 74318e3b… # 在接收方 relayium authorize 74318e3b…serve 当时没有终端可问——比如跑在 systemd 下或接了管道——所以对未知指纹选择拒绝而不是信任。预先授权即可:拒绝那行里的指纹,正是发送方 relayium id 打印出来的那个,而 authorize 是幂等的。
- “fingerprint mismatch for receiver.example.com:9031”。
grep receiver.example.com ~/.config/relayium/known_hosts监听端出示的密钥,和首次接触时固定下来的那把不一样。如果是你自己有意轮换了密钥,就删掉对应的 known_hosts 那一行再推。如果不是,先别动那一行,弄清楚密钥为什么变了,再发任何东西。
- systemd 单元一启动就因为权限不安全而退出。
systemctl status relayium-serve # secure: /etc/relayium/id.key has insecure permissions 0644; run: chmod 600 /etc/relayium/id.key ls -l /etc/relayium/id.keyrelayium 拒绝加载一把除属主之外还有人能读的私钥,这和 ssh 的规矩一样。对报错里给出的路径执行 chmod 600,确认它属于那个服务用户,然后重启单元。
常见问题
daemon 直连和通过 SSH 推送有什么不同?
通过 SSH 推送会把传输隧道进你的 SSH 连接,并且需要在远端有一个 SSH 账号。daemon 直连不需要 SSH,也不需要账号——两台服务器通过证书固定的 TLS,用证书指纹互相验证身份,当两台机器都是你自己的时候,这样更轻量。
我需要手动到处复制指纹吗?
不需要。在终端中,serve 会在每个新推送方首次推送时提示你批准它——显示其地址和指纹——并记住它,因此后续推送是静默的。只有在没有终端的非交互式场景(比如作为 systemd 服务运行,没有人来回应提示)时,你才需要用到 relayium id 或 relayium authorize。
身份和信任文件在哪里?
默认在 ~/.config/relayium/ 中(可用 --config-dir 覆盖)。id.key / id.crt 是这台主机的持久身份,known_hosts 保存着你推送过的监听端的指纹,authorized_fingerprints 则是监听端的推送方允许列表。
指纹变化了会怎样?
监听端会拒绝这次推送并发出警告。监听端的密钥在首次使用时就固定在 known_hosts 中,因此之后的变化——无论是主机重新生成了密钥,还是中间人攻击——都会遭到拒绝,而不会默默放行。只有在你确实主动轮换了密钥时,才应删除 known_hosts 中对应的那一行。
有没有中继回退?
没有。daemon 直连假定监听端地址是可达的;如果无法建立连接,就会失败。任何数据都绝不会经由 Relayium 代理——这正是这个模式的意义所在。
把你自己的两台服务器接起来做直接传输——无需中继、无需 SSH、无需配对码。
获取 CLI