Relayium

用 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

启动监听端(在接收方)

你需要准备

  • 两台你自己掌控的机器,并且接收方的地址从发送方可达。主机名或裸 IP 都行。
  • 两端都装好 relayium。daemon 直连只说原生协议,所以这里没有 tar 兜底来救一台没装的机器。
  • 把监听端的端口对发送方开放——默认是 9031/TCP——主机防火墙和云安全组都要开。
  • 接收方在第一次推送时要有一个终端,好回答批准提示。没有终端的话,请改为预先授权发送方(见下文)。

在接收方服务器上,serve 监听推送并把它们写入某个目录。它默认长期运行;加上 --once 可以只接受一次传输就退出。你不需要预先共享任何东西——不用提前复制任何指纹:

  1. 建好推送要落地的目录。

    mkdir -p ~/inbox
  2. 只对发送方开放监听端的端口。把 203.0.113.7 换成发送方自己的地址——公网 IP,或者两台服务器同处一个内网时的内网 IP——并且把云安全组也收敛到同一个来源,而不是对整个互联网开放。

    sudo ufw allow from 203.0.113.7 to any port 9031 proto tcp
  3. 在终端里启动监听端,这样第一次推送时才有人回答批准提示。加 --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…)

向监听端推送(在发送方)

从发送方服务器,推送到接收方的 relayium:// 地址。第一次连接会固定接收方的指纹;此后每次连接都会校验它,指纹一旦变化,监听端就会拒绝连接,而不会默默放行——密钥掉包或中间人攻击会当场暴露,不会被当成可信。在第一次推送时,发送方会稍等片刻,等待接收方批准(下一步)。

  1. 在发送方服务器上执行推送。第一次连接时它会正好停在这里,等接收方批准。

    relayium push ./build.tar.zst relayium://receiver.example.com
  2. 在接收方回答那个提示——就是下一节的内容。之后推送会自己走完,以后的推送也不会再停在这里。

  3. 监听端不在 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…

在首次推送时批准发送方(在接收方)

当一台新机器第一次向你的监听端推送时,serve(在终端中)会显示它的来源和指纹,并请你批准它——就像 SSH 首次连接时的提示,只不过是在接收方这一侧:

# 在接收方,当有新的发送方推送时:
Incoming push from 203.0.113.7:54021
  fingerprint: 74318e3b…
Accept and remember this peer? [y/N] y

实现自动化(或在没有终端的环境下运行)

由于已批准的指纹会一直保留,后续推送不再需要确认——因此 relayium push 可以直接接入 cron、部署脚本或 CI,实现加密、可校验完整性、可续传的服务器到服务器同步。当 serve 在没有终端的环境下运行(作为 systemd 服务、通过管道)时,它无法弹出提示,因此会拒绝未知的推送方;这时应改为预先授权它们。可以从推送方的 relayium id 获取指纹,或者从 serve 日志中「rejected unauthorized peer …」那一行复制它,然后:

# 在接收方:无需提示,预先授权一个发送方
relayium authorize 74318e3b...

在 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

推送不通的时候

先查的是可达性和信任这两件事:在发送方跑 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.key

relayium 拒绝加载一把除属主之外还有人能读的私钥,这和 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

继续阅读