rsyncの使い方:Linuxでのファイル同期とバックアップの実例
rsyncは、ファイルをローカルやSSH経由で同期し、変更された部分だけを転送するツールです。基本コマンドは rsync -avz 元/ ユーザー@ホスト:/先/ です。-aは権限と時刻を保持し、-vは転送するファイルを表示し、-zは通信を圧縮します。--deleteは転送先を元と完全に一致させ、-nを付けると変更を加えずに結果を事前に確認できます。
rsyncは、Linuxで標準的に使われるファイルのコピーと同期のツールです。ローカルのディスク間でも、SSH経由のサーバー間でも使えます。cp や scp との大きな違いは、変更された部分だけを転送することです。そのため、大きなディレクトリを再同期しても数秒で終わります。以下では、プロジェクトのサーバーへのアップロード、ディレクトリのミラー、除外設定、スナップショット付きのバックアップ、定期実行など、よくある作業の例を紹介します。
構文と重要なフラグ
コマンドの基本形式は次のとおりです。
rsync [オプション] 送信元... 送信先
送信元と送信先には、ローカルのパスか、ユーザー@ホスト:/パス の形式のリモートパスを指定できます。どちらか一方は必ずローカルである必要があります。rsyncは、2台のリモートマシン間で直接コピーすることはできません。
| フラグ | 動作 |
|---|---|
-a | アーカイブモード。再帰的にコピーし、権限、所有者、グループ、更新時刻、シンボリックリンクを保持します(-rlptgoD と同じ) |
-v | 転送されるファイルの一覧を表示 |
-z | ネットワーク転送時にデータを圧縮 |
-h | サイズを読みやすい単位で表示(K、M、G) |
-P | --partial --progress と同じ。進捗表示と、中断されたファイルの再開 |
-n、--dry-run | ドライラン。何が行われるかを表示するだけで、何も変更しない |
--delete | 送信元にないファイルを転送先から削除する |
--exclude | パターンに一致するファイルをコピーしない |
-e | リモートのシェルを指定。例:-e "ssh -p 2222" |
-H、-A、-X | ハードリンク、ACL、拡張属性を保持する(-a には含まれない) |
実際には、ローカルなら rsync -avh、ネットワーク越しなら rsync -avzh で、ほとんどの場合は足ります。
パス末尾のスラッシュ:最大の落とし穴
初心者が最もよく犯すミスは、送信元の末尾のスラッシュに関するものです。スラッシュの有無によって、コピーされるのがディレクトリ自体なのか、その中身だけなのかが決まります。
# ディレクトリ project を /backup の中にコピー → /backup/project/... ができる
rsync -av project /backup/
# project の中身を /backup にコピー → ファイルが直接 /backup/ の中に入る
rsync -av project/ /backup/
覚え方はシンプルです。送信元の末尾にスラッシュを付けると「そのディレクトリの中身」を意味します。送信先のスラッシュは影響しません。迷ったら -n を付けて、rsyncがどのパスを作成するかを確認してください。
ローカルでのコピー
ディレクトリを外付けディスクに進捗表示付きでコピーします。
rsync -avhP ~/photos/ /mnt/usb/photos/
同じコマンドを再実行しても、すべてを再度コピーすることはありません。rsyncはファイルのサイズと更新時刻を比較し、新しいファイルと変更されたファイルだけを転送します。最後に表示される出力で、実際に転送されたデータ量が分かります。
sending incremental file list
2026/10/IMG_2041.jpg
4.12M 100% 38.40MB/s 0:00:00 (xfr#1, to-chk=0/1534)
sent 4.13M bytes received 9.25K bytes 2.76M bytes/sec
total size is 6.82G speedup is 1,648.21
speedup の値は、すべてをコピーした場合と比べて、転送量が何倍少なかったかを示します。
SSH経由のrsync:サーバーへのコピーと取得
リモートのパスでは、rsyncは既定でSSHを使います。特別な設定は不要で、通常の ssh でログインできれば十分です。鍵認証を使えばパスワードの入力が不要になり、コマンドをcronに登録することもできます。
# サイトをサーバーにアップロード
rsync -avz ./site/ deploy@203.0.113.10:/var/www/site/
# サーバーのログを手元にダウンロード
rsync -avz deploy@203.0.113.10:/var/log/nginx/ ./nginx-logs/
# 標準外のポートと特定の鍵を指定してSSH接続
rsync -avz -e "ssh -p 2222 -i ~/.ssh/deploy_key" ./site/ deploy@203.0.113.10:/var/www/site/
rsyncは、両方のマシンにインストールされている必要があります。リモート側ではSSH経由でrsyncが起動されるためです。インストールされていない場合は rsync: command not found と表示されます。その場合はパッケージをインストールしてください(sudo apt install rsync または sudo dnf install rsync)。
ホストが ~/.ssh/config にエイリアスとして登録されていれば、rsyncはそれを認識します。例:rsync -avz ./site/ prod:/var/www/site/。
サーバー側でroot権限が必要な場合
転送先のファイルがrootの所有で、通常のユーザーとしてログインしている場合は、リモート側のrsyncをsudoで実行できます。
rsync -avz --rsync-path="sudo rsync" ./conf/ admin@server:/etc/myapp/
この方法を使うには、サーバーでrsyncに対してsudoがパスワードなしで動作する必要があります(sudoersの設定)。そうでないと、コマンドはパスワードの入力を待って止まってしまいます。
SSHの代わりにrsyncデーモンを使う
信頼できる内部ネットワークでは、SSHを使わずに済ませることもできます。受信側でrsyncデーモンを起動し、/etc/rsyncd.conf に名前付きの共有(モジュール)を定義します。クライアントは rsync:// のアドレスでアクセスするため、サーバー上のシステムアカウントは不要です。転送は高速ですが、データは暗号化されません。そのため、このポート(873)をインターネットに公開してはいけません。
# サーバーの /etc/rsyncd.conf
[share]
path = /backup/
hosts allow = 192.168.3.0/24
read only = false
# クライアント
rsync -avzh /tmp/backup/ rsync://192.168.3.105/share
ディレクトリのミラー:--delete
既定では、rsyncはファイルを追加・更新するだけで、何も削除しません。転送先を送信元と完全に一致させるには --delete を使います。
rsync -avh --delete ~/projects/ /mnt/backup/projects/
これは強力で危険なフラグです。パスの指定ミス(空の送信元や、スラッシュの付け忘れなど)があると、転送先のデータが削除されてしまいます。そのため、--delete を含むコマンドは必ず -n を付けて最初に実行してください。
$ rsync -avhn --delete ~/projects/ /mnt/backup/projects/
sending incremental file list
deleting old-app/README.md
deleting old-app/
app/main.py
sent 1.20K bytes received 64 bytes 2.53K bytes/sec
total size is 18.4M speedup is 14,554.39 (DRY RUN)
deleting で始まる行は、削除される予定のファイルです。内容が正しいことを確認したら、-n を外して実行してください。
ほかにも便利なオプションがあります。--delete-after は転送の後に削除を行うので、転送先が完全な状態のまま長く保たれます。--backup --backup-dir=/mnt/backup/deleted-$(date +%F) は、削除や上書きの対象となるファイルを消す代わりに、指定したディレクトリに退避します。
除外設定:--exclude と --include
一時ファイル、依存関係、秘密情報を除外するのは、デプロイやバックアップでよく行われる作業です。
# 複数のパターンを指定
rsync -avz --exclude='.git/' --exclude='node_modules/' --exclude='*.log' ./app/ server:/srv/app/
# パターンをファイルから読み込む
rsync -avz --exclude-from='.rsyncignore' ./app/ server:/srv/app/
.rsyncignore は、1行に1つずつパターンを書いた単純なリストです。
.git/
node_modules/
*.log
.env
tmp/
パターンの動作は次のとおりです。
- 先頭にスラッシュのないパターン(
*.log)は、どの階層でも一致します。 - 先頭にスラッシュのあるパターン(
/tmp/)は、転送の起点に固定されます。最上位のtmpだけが除外されます。 - 末尾にスラッシュのあるパターン(
cache/)は、ディレクトリにのみ一致します。 - ルールは上から順に評価され、最初に一致したものが適用されます。
最後の点から、「必要なものだけをコピーする」テクニックが生まれます。まず許可し、その後で残りを除外します。
# 設定ファイル(.conf)だけをコピーし、ディレクトリ構造は保持する
rsync -av --include='*/' --include='*.conf' --exclude='*' /etc/ ./etc-confs/
ここで --include='*/' は、rsyncがすべてのサブディレクトリに入るために必要です。空のディレクトリを作りたくない場合は、--prune-empty-dirs(-m)を追加してください。
rsyncによるバックアップ
単純な毎日のコピー
ホームディレクトリを2つ目のディスクにバックアップする最小限の例です。
rsync -aH --delete --exclude='.cache/' /home/alice/ /mnt/backup/alice/
この方法の欠点は、保存されるのが1つのバージョンだけであることです。ファイルを壊してしまい、その壊れた状態がバックアップに同期されてしまうと、古いバージョンは失われます。
--link-dest による増分スナップショット
--link-dest を使えば、この問題をほぼ無料で、同じ場所の中で解決できます。変更されていないファイルはコピーされず、前回のスナップショットのファイルへのハードリンクとして作成されます。各スナップショットは完全なコピーのように見えますが、実際に容量を使うのは変更された部分だけです。
#!/bin/bash
set -euo pipefail
SRC="/home/alice/"
DEST="/mnt/backup/snapshots"
TODAY="$(date +%F)"
mkdir -p "$DEST"
rsync -aH --delete \
--exclude='.cache/' \
--link-dest="$DEST/latest" \
"$SRC" "$DEST/$TODAY"
ln -sfn "$DEST/$TODAY" "$DEST/latest"
初回の実行時には latest がまだ存在しません。その場合rsyncは警告を出し、完全なコピーを作成します。これは正常な動作です。古いスナップショットは通常の rm -rf で削除できます。他のスナップショットから参照されているファイルは消えません。
30日より古いスナップショットを削除するには、次のようにします。
find /mnt/backup/snapshots -maxdepth 1 -type d -name '20*' -mtime +30 -exec rm -rf {} +
サーバーのバックアップを別のマシンへ
方向は「バックアップサーバーから作業用サーバーへ」にすると便利です。バックアップ用のマシンがデータを取りに行き、作業用サーバーはバックアップにアクセスできません。作業用サーバーが侵害されても、バックアップは無事に残ります。
rsync -azH --delete -e "ssh -i /root/.ssh/backup_key" \
backup@web01:/var/www/ /srv/backups/web01/www/
ただし、データベースはこの方法ではコピーできません。稼働中のDBのファイルは、コピーの途中で整合性が失われるためです。先に mysqldump や pg_dump でダンプを作成し、rsyncにはそのダンプファイルを転送させてください。
cronによる定期実行
バックアップスクリプトは crontab -e でcronに登録します。
# 毎日3:15に実行し、出力をログに保存
15 3 * * * /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1
cronからバックアップが確実に動くように、次の点を確認してください。
- cronは PATH が非常に限られており、作業ディレクトリも異なるため、スクリプトでは絶対パスを使います。
- SSH鍵はパスワードなしのものを使い、ホストが
known_hostsに登録されている必要があります。そうしないと、rsyncがホストの真正性を確認する質問で止まってしまいます。 - スクリプトで終了コードを確認します。rsyncは成功すると0を返し、一部のファイルが転送できなかった場合は23、転送中にファイルが消えた場合は24を返します。
- 同時に2つのコピーが動かないように
flockを使います。例:flock -n /tmp/backup.lock /usr/local/bin/backup.sh。
cronの代わりに systemd のタイマーを使うこともできます。出力がジャーナルに記録されるため、journalctl で結果を簡単に確認できます。
大きな転送に役立つオプション
| 目的 | オプション |
|---|---|
| 回線を使い切らないよう速度を制限する | --bwlimit=5M |
| 接続が切れた大きなファイルを再開する | -P(または --partial) |
| ファイルごとの一覧ではなく全体の進捗を表示する | --info=progress2 |
| 時刻ではなく内容で比較する | -c(--checksum)。ただし遅くなる |
| 転送先のほうが新しいファイルは触らない | -u(--update) |
| 既存のファイルを上書きしない | --ignore-existing |
| 転送後に元のファイルを削除する(移動) | --remove-source-files |
| 終了時に詳細な統計を表示する | --stats |
よくあるエラーと解決方法
- 書き込み時の
Permission denied:転送先ディレクトリへの権限がありません。ディレクトリの所有者を確認するか、--rsync-path="sudo rsync"を使います。 - ファイルが毎回コピーし直される:更新時刻が保持されていません。
-aまたは-tが指定されているか確認してください。FAT/exFATでは時刻の精度が2秒なので、--modify-window=2を追加します。 - USBメモリやネットワークフォルダへのコピー時の
chown/chgrpエラー:ファイルシステムが所有者の情報を扱えません。-aを-rltに置き換えてください。 /backup/project/projectのような余分な階層ができる:送信元の末尾のスラッシュを間違えています。connection unexpectedly closed:SSHの問題か、リモート側にrsyncがインストールされていないことが原因です。通常のsshでログインできるか、サーバーにrsyncがあるかを確認してください。
まとめ
日常作業では、いくつかのコマンドを覚えれば十分です。SSH経由のコピーには rsync -avz src/ host:/dst/、ミラーには --delete と事前の -n の組み合わせ、不要なファイルの除外には --exclude、スナップショット付きのバックアップには --link-dest を使います。送信元の末尾のスラッシュにだけは注意してください。そうすれば、rsyncはマシン間でファイルを移動する最も信頼できる方法になります。同期とバックアップは、Linuxコースで実践的に解説しています。
よくある質問
rsync と scp の違いは何ですか?
scp はファイルを毎回まるごとコピーしますが、rsync は変更された部分だけを転送します。さらに、転送の再開、転送先の不要なファイルの削除、パターンによる除外もできます。1つのファイルを一度だけコピーするなら差はほとんどありませんが、定期的な同期では rsync のほうがずっと高速です。
Windowsでrsyncを使えますか?
はい。WSLを使えばLinuxと同じようにrsyncをインストールできます。Cygwinを使う方法もあります。WindowsマシンとLinuxサーバーの間で同期するなら、WSLから実行するのが最も簡単です。
rsync は転送データを暗号化しますか?
rsync自体は暗号化しません。ただし、SSH経由で使う場合は、通信全体がSSHの暗号化された接続を通ります。暗号化されないのは、rsync:// の形式によるrsyncデーモンへの接続だけです。
コピーが元のファイルと一致しているかどうか確認するにはどうすればよいですか?
rsync -avnc 元/ 先/ を実行してください。-c を指定するとチェックサムで比較し、-n によって何も変更されません。表示されるファイル一覧が空であれば、コピーは同一です。
転送の途中でrsyncを中断するとどうなりますか?
転送済みのファイルはそのまま残ります。転送途中のファイルは通常は削除されます。同じコマンドを再実行すると途中から再開されます。-P を指定すると、途中まで転送されたファイルの部分も保持されます。