Relayium

2台のサーバー間で大きなフォルダーを同期する(再開可能・バックグラウンド)

最終更新: 2026-08-05

一方のサーバーに大きなフォルダー(数十 GB)があり、それをもう一方に完全な複製として欲しいとします。何時間もターミナルを見張ることはできませんし、途中で落ちた転送が最初からやり直しになるのも困ります。relayium sync はまさにこのために作られています。一方向の増分ミラーで、すでにあるものはスキップし、途中まで送ったファイルは止まったところから再開し、送信した各ファイルを端から端まで検証します。

本ガイドでは、無人で自己修復する転送を構築します。送信側を一度だけ承認し、リスナーをバックグラウンドで動かし、tmux 内のリトライループで relayium sync を回して、接続が切れても続行させ、フォルダー全体が届くまで走らせます。

なぜ relayium sync がこの用途に向くのか

sync はネイティブプロトコル上の一方向増分ミラーです(両端に relayium をインストールします)。無人で繰り返し実行しても安全な理由が3つあります:

前提条件

必要なもの

  • 本ガイドはデーモン直結(relayium://)を使うため、2台のサーバー間に SSH アクセスは不要です。
  • 受信側のファイアウォールまたはセキュリティグループで、リスナーのポート(既定 9031)を送信側に開放してください。
  • 受信側にフォルダー全体が入る空き容量。数時間かかる転送を始める前に、送信側の du -sh /root/workspace と受信側の df -h /root を突き合わせてください。

両方のサーバーに relayium をインストールします(sync はネイティブプロトコルを話すため、各端に必要です):

# 両方のサーバーで
curl -fsSL https://relayium.com/install.sh | sh

送信側を一度だけ承認する(受信側)

受信側は送信側のマシンを一度だけ承認します。承認はディスクに書き込まれ、再起動をまたいでも有効なので繰り返す必要はありません。まずターミナルでリスナーをフォアグラウンド起動し、--dir を親ディレクトリに向けます。relayium sync /root/workspace は受信側で workspace/... を再現するので、--dir /root ならファイルは /root/workspace/ に着地します。

送信側の初回接続時(次節)、serve はそのアドレスとフィンガープリントを表示して承認を求めます。y と答えれば永続的に記憶されます:

# 受信側で(フォアグラウンド、対話的に承認するため)
relayium serve --dir /root --port 9031
# 受信側で、初回接続時:
Incoming push from 203.0.113.9:52140
  fingerprint: 9f2c41ab…
Accept and remember this peer? [y/N] y

リスナーをバックグラウンドで動かす(受信側)

フィンガープリントを承認したら、フォアグラウンドの serve を止め(Ctrl-C)、ログアウト後も生き残るようデタッチして再起動します。保存済みのフィンガープリントを読み込み、送信側を確認なしで受け入れます。今回はプロンプトは出ません。同じ行が新しいプロセスの PID を ~/relayium-serve.pid に記録し、本ガイドの最後の手順はそれを使って、自分が起動したリスナーを止めます。relayium という文字列を含むコマンドを片端から止めるわけではありません:

# 受信側で
nohup relayium serve --dir /root --port 9031 > ~/relayium-serve.log 2>&1 & echo $! > ~/relayium-serve.pid

tmux 内のリトライループで sync を回す(送信側)

長い転送は中断されます。セッション切断、不安定なネットワーク、再起動。解決策は高級なツールではなく、sync を成功するまで再実行するループと、ログアウト後も生き残らせる端末マルチプレクサです。ここでは tmux のほうが nohup より扱いやすいです:間違えやすい出力リダイレクトがなく、再接続して進捗を見られます。

tmux セッションを開始し、until ループでミラーを実行します。10秒ごとに再試行し、sync が成功を返したら自分で終了します:

  1. ループを起動元の ssh セッションより長生きさせるため、送信側で tmux セッションを開きます。

    # 送信側で
    tmux new -s xfer      # tmux が無ければ apt install -y tmux
  2. until ループの中でミラーを回します。10秒ごとに再試行し、sync が成功を返したところで自分から終了します。

    until relayium sync /root/workspace relayium://203.0.113.43:9031; do echo "$(date) retrying"; sleep 10; done
  3. Ctrl-b の次に d でデタッチします。ループはそのまま動き続けるので、見たくなったらいつでも再接続してください。

    tmux attach -t xfer

成功した一巡の表示

一巡ごとに、実際に送ったファイルの数だけ行が表示され、続いて今回送った数と受信側にすでにあった数の要約が出ます。ループは sync が最初に成功を返した時点で終わり、その要約がミラーの状態です。

relayium sync /root/workspace relayium://203.0.113.43:9031
  workspace/data/part-004.bin (1073741824 bytes)
synced: 1 sent, 812 unchanged

検証と仕上げ

until ループが終わり、通常のシェルプロンプトに戻ったら転送は完了です。両側が一致することを確認してから、リスナーを停止します:

  1. until ループが自分から終わるのを待ちます。通常のシェルプロンプトに戻っているのは、転送が終わったということであって、途中で中断されたということではありません。

  2. 両方のサーバーで合計を比較します。

    # 両方のサーバーで合計を比較
    du -sh /root/workspace
  3. 合計が一致したら受信側のリスナーを止めます。マシン上の relayium コマンドを文字列で総なめにするのではなく、起動時に記録した PID にシグナルを送り、PID ファイルはシグナルが成功したときにだけ削除されます。前回の実行が残した PID ファイルは、システムが再利用した別の PID を指していることがあります。そのファイルがまだ自分のものか確信が持てないときは、まずその PID のコマンドラインを表示し、serve が返ってきた場合にだけ kill してください。

    # 受信側で、確認できたら
    ps -p "$(cat ~/relayium-serve.pid)" -o command=
    kill "$(cat ~/relayium-serve.pid)" && rm ~/relayium-serve.pid

ミラーが完了したときの表示

両方のサーバーで du -sh が同じ合計を報告し、until ループは再試行に戻らず、通常のシェルプロンプトへ戻っています。合計の一致は大まかな完了確認であって、内容が同一であることの証明ではありません。sync はサイズと mtime でどのファイルを送らないかを決めているため、スキップしたファイルの中身について合計は何も語りません。

# the same total, on BOTH servers
46G	/root/workspace

トラブルシューティング

数時間かかるミラーでは6つのことが起こります。うち3つは失敗に見えて失敗ではなく、残り3つは本当の問題です。どれについても、いま自分が見ているのがどれかを教えてくれるコマンドがあります。

症状・確認・対処

長いあいだ何も表示されず、転送が止まったように見える。
# 送信側で、数秒あけて2回
ss -tinp dst :9031
# ESTAB    リスナーに届いたことを示すだけで、バイトが動いている証拠ではない
# SYN-SENT リスナーに届いていない

進捗はファイルが1つ完了したときにしか表示されないので、大きなファイル1つはまったくの無音で転送されます。ESTAB が示すのは到達できたことだけで、確立済みのソケットが無通信のまま止まっていることもあり、それだけでは前進の証拠になりません。このチェックを数秒あけて2回実行し、-i がそのソケットについて表示する bytes_acked カウンターを比べてください。増えていれば転送は動いており、変わらなければ本当に止まっています。

ソケットが SYN-SENT のままで、転送がまったく始まらない。
# 受信側で
sudo ufw allow from 203.0.113.9 to any port 9031 proto tcp
ss -tlnp | grep 9031

ポートが遮断されています。9031/TCP は送信側にだけ開けてください。203.0.113.9 は送信側自身のアドレス、グローバル IP か、2台が同じネットワークにいるならプライベート IP に置き換えます。クラウドのセキュリティグループも同じ送信元に絞ったうえで、serve が本当に待ち受けているかを確かめてください。転送が始まらない原因として最も多いものです。

バックグラウンド用のコマンドを貼ると、シェルが > の継続プロンプトで止まる。
tmux new -s xfer
until relayium sync /root/workspace relayium://203.0.113.43:9031; do echo "$(date) retrying"; sleep 10; done

引用符と > リダイレクトを含む複数行の nohup コマンドは、貼り付け時にリダイレクトのところで壊れがちです。代わりに tmux とこの1行ループを使ってください。書き間違えるリダイレクトが無く、再接続して様子も見られます。

後片付けのつもりが、殺すつもりのないものまで殺してしまった。
pgrep -af relayium
ps -p "$(cat ~/relayium-serve.pid)" -o command=
tmux kill-session -t xfer
kill "$(cat ~/relayium-serve.pid)" && rm ~/relayium-serve.pid

コマンドラインのパターンで殺すやり方は、その文字列を含むプロセスすべてにシグナルを送るので、転送が複数動いているマシンでは狙った相手とは限りません。しかもミラーは止まりません。sync を所有しているのは until ループなので、子プロセスを殺しても10秒後にまた起動されます。まず pgrep -af で確認し、このガイドが実際に所有しているものを終わらせてください。tmux kill-session -t xfer でループを終了し、~/relayium-serve.pid にある PID を kill して、自分で起動したリスナーを止めます。その PID ファイルが前回の実行から残っているなら、シグナルを送る前にコマンドラインを表示してください。システムが再利用した PID は、まったく別のプロセスのものです。

あるサブディレクトリだけ除きたいのに、exclude のフラグが無い。
relayium sync /root/workspace/src /root/workspace/data relayium://203.0.113.43:9031

sync が取るのは -i と -p、--delete、--watch、--config-dir だけで、木の途中でパスを除外する仕組みはありません。代わりに欲しいサブディレクトリを列挙してください。各ソースは受信側の --dir の下に自分の名前で届くので、serve --dir /root/workspace に対してこのコマンドを実行すると /root/workspace/src と /root/workspace/data が再現され、作り直せる venv は一度も走査されません。

ミラーされるはずのソースが、中身のない状態で届く。
relayium sync ./links relayium://203.0.113.43:9031
# warning: no regular files to send (symlinks and special files are skipped)

sync が転送するのは通常ファイルだけで、この警告はまさに「シンボリックリンクしか無い木」の姿です。リンクが指している実体のディレクトリを sync に渡し、受信側で必要なシンボリックリンクは別途用意してください。

よくある質問

転送が途中で中断されたらどうなりますか?

何も失われません。relayium sync を再実行してください。受信側にすでにあるファイルはスキップし、半分送ったファイルはディスク上のバイトオフセットから再開します。本ガイドの until ループが、フォルダー全体がミラーされるまでこれを自動で行います。

これは rsync と何が違いますか?

どちらも増分の一方向ミラーですが、relayium sync は証明書ピンニング付き TLS 接続で動作し、SSH アカウントを必要とせず(デーモン直結)、証明書のフィンガープリントで2台を認証し、転送する各ファイルを SHA-256 で検証します。rsync の既定と同じく、受信側でサイズと mtime がすでに一致するファイルはハッシュを取り直さずスキップされます。relayium の他モードと同じ転送エンジンです。

ソースから削除したファイルを、sync は受信側でも削除しますか?

求めたときだけです。既定では sync は追加と更新だけを行います。削除をミラーするには --delete を渡し、それが有効になるには受信側が --allow-delete で serve を実行している必要があります。さもなければ削除は無視され、報告されます。

2つのフォルダーを継続的に同期し続けられますか?

はい。--watch を付けると sync は動き続け、ソース配下の変更のたびに再ミラーします。大きなフォルダーの一度きりの移動には不要です。リトライループと素の sync で十分です。

ポートを開ける必要がありますか?

デーモン直結ならはい。リスナーのポート(既定 9031)が送信側から到達可能である必要があります。ポートを開けたくなく、サーバー間にすでに SSH があるなら、sync は SSH 経由でも動きます:relayium sync /path user@host:/path(リモートに relayium が必要)。

自分の2台のサーバー間でフォルダーをミラーしましょう。増分、再開可能、張り付き不要。

CLI を入手する

続けて読む