Relayium

把 Relayium 变成常驻接收服务

最近更新: 2026-08-06

relayium serve --once 只处理一次传入的传输就退出——适合偶尔拉取一次的场景。但如果你想让某台机器成为一个常驻的落地点——一台每晚接收备份的家庭服务器、一台 CI 会推送构建产物的构建机、一台随时能接收手机照片的 NAS——你会想让 serve 一直运行,而不是每次传输都手动启动它。

本指南涵盖启动一个长期运行的监听端、批准谁可以向它推送、为没有人守在终端前的场景预先授权对端、在 systemd 下运行它,以及让使用 sync --delete 的发送方镜像删除操作。

开始之前

下面用到的都是 relayium CLI,所以没装的话先装上。在 macOS 或 Linux 上,一条命令就能把预编译二进制放进你的 PATH:

curl -fsSL https://relayium.com/install.sh | sh

启动监听端

开始之前你需要什么

  • 两台机器上都装好 CLI。relayium version 会各自打印版本号;如果 shell 回答 command not found,说明那台还没装。
  • 本机上一个用来接收文件的目录,以及装得下这些文件的磁盘空间。
  • 一个发送方能访问到的地址,和一个放通的入站端口。不指定 --port 时 serve 监听 9031。
  • 如果这台机器将来是没有终端运行的——那正是做成服务的意义——你需要事先拿到推送方的指纹。下面有专门一节讲这个,而它正是常驻接收端把一切都拒掉的最常见原因。

serve 通过证书固定的 TLS 1.3 连接监听 daemon 直连推送(relayium://host:port),并把收到的内容写入某个目录。启动它不需要预先共享任何东西——不用复制指纹,也不用注册服务器:

relayium serve --dir ~/inbox
relayium serve --dir /srv/drop --port 9040   # 非默认端口
relayium serve --dir ~/inbox --allow-delete  # 允许使用 sync --delete 的发送方镜像删除操作
  1. 选好文件落地的位置,把监听器起起来。走到这一步不需要预先交换任何东西。

    relayium serve --dir ~/inbox
  2. 在发送方机器上,按 relayium:// 地址往这台主机推一个文件。

    relayium push ./report.pdf relayium://drop.example.com:9031
  3. 回到接收端,回答那个批准提示。按 y 会把该指纹写入 authorized_fingerprints,之后同一台机器再推就不会再问了。

  4. 确认文件真的落在了 --dir 里,而不是你启动 serve 时所在的那个目录。

    ls -l ~/inbox

一个正常的监听器长什么样

serve 一上来就会说明自己还没有已授权的对端,然后在新机器第一次推送时提示,此后每一次都安安静静。发送方退出码 0,文件出现在 --dir 里。

$ relayium serve --dir ~/inbox
no authorized peers yet — you'll be asked to approve each new peer on its first push.
Incoming push from 203.0.113.7:54021
  fingerprint: 74318e3b…
Accept and remember this peer? [y/N] y

批准谁可以推送

当一个新的对端第一次推送时,如果 serve 运行在终端中,它会显示这次推送来自哪里、它的指纹,并请你批准——就像 SSH 首次连接未知主机时会询问一样:

Incoming push from 203.0.113.7:54021
  fingerprint: 74318e3b…
Accept and remember this peer? [y/N] y

为非交互式场景预先授权对端

当 serve 没有终端可以弹出提示时——作为 systemd 服务、后台进程,或通过管道运行——它无法询问,因此会拒绝任何它尚未识别的指纹。这时应该提前授权对端。在将要推送的那台机器上运行 relayium id 打印它的指纹;在接收方上,在第一次推送到达之前把它加进去:

# 在将要推送的那台机器上:打印它的指纹
relayium id

# 在这台常驻接收机上:预先授权它
relayium authorize 74318e3b...
  1. 在将要推送的机器上打印它的指纹。它是 64 位十六进制,标识的是那台机器而不是它的地址。

    relayium id
  2. 在这台接收端上授权它——要用服务将来运行时相同的 --config-dir。用错用户执行、或者这边用默认路径而 unit 里用的是另一个,指纹就会写进服务永远不会读的那个文件里。

    relayium authorize 74318e3b… --config-dir /etc/relayium

在 systemd 下运行

如果希望服务能在重启和崩溃后依然存活,把 serve 交给 systemd。把 --config-dir 指向一个固定路径,让主机的身份和它的对端允许列表在重启之间保持不变:

# /etc/systemd/system/relayium-serve.service
[Unit]
Description=Relayium always-on receiver
After=network-online.target

[Service]
ExecStart=/usr/local/bin/relayium serve --dir /srv/drop --port 9031 --config-dir /etc/relayium --allow-delete
Restart=always
User=relayium

[Install]
WantedBy=multi-user.target
  1. 在服务存在之前,先授权每一个应该能推送的对端。服务无法弹提示,凡是不在信任列表里的一律拒绝。

  2. 把上面那份 unit 文件写到 /etc/systemd/system/relayium-serve.service,其中 --config-dir 要指向你刚才授权时用的那个固定路径。

  3. 重新加载 systemd 并启动服务,同时设为开机自启,这样重启后还会回来。

    sudo systemctl daemon-reload
    sudo systemctl enable --now relayium-serve
  4. 确认它在运行,并且日志里没有那条「全部拒绝」的警告。两者之中只有后一条是这个场景特有的。

    systemctl is-active relayium-serve
    journalctl -u relayium-serve -n 20 --no-pager

一个正常的服务长什么样

is-active 回答 active,并且启动时那条「没有已授权对端」的警告不出现。这条警告是唯一一行能在任何发送方抱怨之前就告诉你:这个服务会拒掉每一次推送。

$ systemctl is-active relayium-serve
active
$ journalctl -u relayium-serve -n 20 --no-pager | grep -c 'all pushes will be rejected'
0

在 macOS 上开机自启(launchd)

macOS 没有 systemd——它的服务管理器是 launchd。要让 serve 在 Mac 上常驻(比如一台常开、当落地点用的 Mac mini),把它装成 LaunchDaemon,这样开机即启动、无需任何人登录。设置 UserName 让它以你自己的身份(而非 root)运行,并给 --dir 和 --config-dir 绝对路径,这样它的身份和信任文件仍留在你自己的 ~/.config/relayium 里:

<!-- /Library/LaunchDaemons/com.relayium.serve.plist  (replace YOU with your macOS username) -->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>Label</key>              <string>com.relayium.serve</string>
  <key>UserName</key>           <string>YOU</string>
  <key>ProgramArguments</key>
  <array>
    <string>/usr/local/bin/relayium</string>
    <string>serve</string>
    <string>--dir</string>         <string>/Users/YOU/inbox</string>
    <string>--port</string>        <string>9031</string>
    <string>--config-dir</string>  <string>/Users/YOU/.config/relayium</string>
    <string>--allow-delete</string>
  </array>
  <key>RunAtLoad</key>   <true/>
  <key>KeepAlive</key>   <true/>
  <key>StandardOutPath</key>    <string>/Users/YOU/relayium-serve.log</string>
  <key>StandardErrorPath</key>  <string>/Users/YOU/relayium-serve.log</string>
</dict>
</plist>
# 1) authorize each pusher first — launchd gives serve no terminal to prompt on:
relayium authorize <fingerprint>     # get the fingerprint from the pusher's  relayium id

# 2) save the plist above to that path, then load it (root-owned, starts at boot):
sudo chown root:wheel /Library/LaunchDaemons/com.relayium.serve.plist
sudo launchctl bootstrap system /Library/LaunchDaemons/com.relayium.serve.plist

# check it's running / follow logs / stop it:
sudo launchctl print system/com.relayium.serve | grep state
tail -f ~/relayium-serve.log
sudo launchctl bootout system/com.relayium.serve

让 sync --delete 的发送方镜像删除操作

默认情况下,serve 只会新增或更新文件——即使发送方对它运行 sync --delete,新增和修改过的文件依然会被复制,但它请求的删除操作会被跳过,接收方会记录一条警告。用 --allow-delete 启动 serve 即可选择启用真正的镜像同步,让发送方那边删除的文件在这里也被删除:

relayium serve --dir /srv/mirror --allow-delete

出问题时怎么办

这五种里有四种会让服务照常运行、看着一切健康——一个把所有请求都拒掉的监听器,也仍然是个监听器。每一种都有一行可读的输出或一条可跑的命令来判定。

现象、检查、修复

服务起来了也一直在跑,但每一次推送都被拒绝。
journalctl -u relayium-serve -n 20 --no-pager
# warning: no authorized peers and no terminal to approve on; all pushes will be rejected.

服务没有终端,所以它永远跑不了首次推送的批准提示,而它能看到的只有一个陌生指纹。请事先授权每个发送方:在发送方跑 relayium id,在这边跑 relayium authorize <指纹>——并且要用 unit 里那个 --config-dir。这条警告是启动时打印的,所以它从日志第一行起就在那里。

服务压根起不来,报 id.key 权限不安全。
stat -c '%a %U %n' /etc/relayium/id.key
# 400 relayium /etc/relayium/id.key

私钥权限必须恰好是 0600。不能是 0644,而且——这一点最容易踩——也不能是 0400,所以把它「加固得更严」和「放得更松」一样会让服务起不来。给它 chmod 600,并确认属主是 unit 里 User= 指定的那个用户。

发送方报告连接被拒绝。
relayium push ./build relayium://drop.example.com:9031
# hint: if the peer refused the connection, it may not have authorized this host.

接收端不认识这个发送方。在发送方跑 relayium id,把那个指纹在接收端 relayium authorize 一下。如果你已经做过了,那就检查是不是在 unit 的 --config-dir 下做的:信任文件是按目录存的,授权进 ~/.config/relayium 的指纹,对一个读 /etc/relayium 的服务来说根本不存在。

手动跑 serve 时推送正常,走服务就不行,或者换一台机器就不行。
sudo ss -tlnp | grep 9031

两个不同的原因,一条检查就能分开。如果根本没有监听,说明 unit 没有 enable——用 systemctl is-enabled relayium-serve 确认。如果在监听,那就是端口被挡了:在主机防火墙和云安全组里放通 9031。用了非默认 --port 的话,它必须和发送方 relayium://host:N 里的端口一致。

sync --delete 发送方要求的删除在这台机器上从不发生。
journalctl -u relayium-serve | grep -i delete

删除是接收端的显式选项,默认关闭:新增和变更的文件照常复制,每一次被跳过的删除都会在这边记一条警告。在 unit 的 ExecStart 上加 --allow-delete 再重启。光是发送方要求并不够,而这种不对称是刻意的——接收端不会因为别处敲了一个参数就丢文件。

常见问题

serve 默认监听哪个端口?

9031。可以用 --port 同时修改监听端(serve --port N)和推送方的目标地址(relayium://host:N)。

我必须手动批准每一次推送吗?

只需要批准某个指纹的第一次推送,而且仅当 serve 是在带终端的环境下运行时才会提示。此后它会被记住。如果 serve 以非交互方式运行(systemd、管道),就完全不会出现提示,而是直接拒绝未知对端——这时应改为用 relayium authorize 预先授权它们。

发送方可以删除我这台常驻接收机上的文件吗?

只有当你以 --allow-delete 启动了 serve,并且发送方在运行 sync --delete 时才可以。如果没有 --allow-delete,删除操作会被静默跳过,其余内容照常传输。

运行一个常驻接收服务是免费的吗?

是的。relayium serve 是免费、可自托管的 CLI 的一部分——连接的任何一方都不需要账号,也没有付费档位。

serve 把身份和对端列表存在哪里?

默认在 ~/.config/relayium 中(id.key/id.crt 是这台主机的身份,authorized_fingerprints 是允许列表)。对于 systemd 服务,可以把 --config-dir 指向一个固定位置,例如 /etc/relayium。

在 macOS 上怎么让 serve 开机自启?

macOS 没有 systemd——用 launchd。把 serve 装成 /Library/LaunchDaemons 里的 LaunchDaemon(开机启动;设置 UserName 以你的身份运行),或 ~/Library/LaunchAgents 里的 LaunchAgent(登录时启动)。本指南给了一份可直接改的 plist;没有 Homebrew 服务。由于 launchd 不给 serve 终端弹提示,请先用 relayium authorize 预先授权推送方。

把你拥有的任何一台机器变成一个免费的常驻接收方——通过证书固定的 TLS 直接推送,不经过任何中继。

获取 CLI

继续阅读