PostgreSQLのWALアーカイブとPITRで任意時点に復元する手順|archive_modeの設定からリカバリターゲット指定まで

宮崎智広 この記事の監修:宮崎智広(Linux実務・教育歴20年以上・受講者3,100名超)
HOMELinux技術 リナックスマスター.JP(Linuxマスター.JP)Linuxtipsデーターベース管理 > PostgreSQLのWALアーカイブとPITRで任意時点に復元する手順|archive_modeの設定からリカバリターゲット指定まで
「誤ってテーブルをDROPしてしまった」「バッチが暴走して数十万行を書き換えた」——そんなとき、論理バックアップ(pg_dump)では「バックアップ取得時点まで」しか戻せません。作業ミスが発生した直前の状態に正確に戻すには、WALアーカイブを活用したPITR(Point-In-Time Recovery)が必要です。

この記事では、Rocky Linux 9.4 / Ubuntu 24.04 LTS上でPostgreSQL 16を対象に、WALアーカイブの有効化からpg_basebackupによるベースバックアップの取得、recovery.signalを使ったPITR実行までを実機コマンドつきで解説します。pg_dumpとPITRをどう使い分けるかも整理しているので、バックアップ設計を見直したい方にも参考になります。

この記事のポイント

・WALアーカイブを有効にして変更ログを継続保存する
・pg_basebackupで定期的なベースバックアップを取得する
・recovery.signalを置き、recovery_target_timeで任意時点に復元
・pg_stat_archiverでアーカイブの失敗を常時監視する


「このままじゃマズい」と感じていませんか?
参考書を開く気力もない、同年代に取り残される不安——
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら

pg_dumpとWALアーカイブは何が違うのか

PostgreSQLのバックアップには大きく2種類あります。

論理バックアップ(pg_dump / pg_dumpall):SQLの形でスキーマとデータをエクスポート。バックアップ取得時点のスナップショットしか残らない
物理バックアップ+WALアーカイブ:データファイルをそのままコピーし、その後の変更をWALセグメントで継続保存。任意の時刻・LSNまでの巻き戻しが可能

論理バックアップは「昨夜3:00のダンプしかない」状態になりがちで、翌朝10:00に発生したミスには無力です。WALアーカイブを組み合わせた物理バックアップなら「10:00の5分前まで戻す」ことができます。

PITRを実現するには以下の3点が揃う必要があります。

wal_level = replica 以上(PostgreSQL 16のデフォルト値)
archive_mode = onarchive_command の設定(WALをアーカイブ先へコピー)
・定期的なベースバックアップ(pg_basebackupで取得)

WALアーカイブを有効にする(archive_mode・archive_commandの設定)

1. アーカイブ保存先ディレクトリを作成する

まずpostgresユーザーが書き込めるディレクトリを用意します。

# mkdir -p /var/lib/pgsql/wal_archive # chown postgres:postgres /var/lib/pgsql/wal_archive # chmod 700 /var/lib/pgsql/wal_archive

2. postgresql.confにアーカイブ設定を追加する

postgresql.confを編集します(Rocky Linux 9ではデフォルト /var/lib/pgsql/16/data/postgresql.conf)。

# vi /var/lib/pgsql/16/data/postgresql.conf wal_level = replica # デフォルト値。replicaまたはlogical archive_mode = on # アーカイブを有効化 archive_command = 'test ! -f /var/lib/pgsql/wal_archive/%f && cp %p /var/lib/pgsql/wal_archive/%f' # %p : WALファイルのフルパス %f : WALファイル名のみ

archive_commandの解説:
test ! -f .../wal_archive/%f:同名ファイルが既存の場合は上書きしない(二重コピーを防ぐ)
&& cp %p .../wal_archive/%f:存在しない場合のみコピー
・コマンドが終了コード0を返したとき「アーカイブ成功」とPostgreSQLが判断する

3. PostgreSQLを再起動して設定を反映する

archive_mode の変更はリロード(pg_reload_conf())では反映されないため、再起動が必要です。

# systemctl restart postgresql-16 # systemctl status postgresql-16 * postgresql-16.service - PostgreSQL 16 Database Server Loaded: loaded (/usr/lib/systemd/system/postgresql-16.service; enabled; preset: disabled) Active: active (running) since Mon 2026-09-22 09:45:02 JST; 5s ago

設定が反映されたか確認します。

# su - postgres -c "psql -c "SHOW archive_mode;"" archive_mode -------------- on (1 row)

pg_basebackupでベースバックアップを取得する

アーカイブを有効にしただけでは復旧の起点(ベースバックアップ)がありません。定期的にpg_basebackupを実行し、直近のベースバックアップからWALを当てる設計にします。

1. ベースバックアップ保存先を用意する

# mkdir -p /var/lib/pgsql/backup # chown postgres:postgres /var/lib/pgsql/backup # chmod 700 /var/lib/pgsql/backup

2. pg_basebackupを実行する

# su - postgres $ pg_basebackup -D /var/lib/pgsql/backup/base_20260922 --checkpoint=fast -Xs -P 24390/24390 kB (100%), 1/1 tablespace

主なオプションの意味:
-D /path:バックアップ出力先ディレクトリ
--checkpoint=fast:チェックポイントを即時実行してバックアップ開始を速くする
-Xs:ストリーミングでWALをバックアップに同梱(-x は非推奨)
-P:進捗表示

3. バックアップ後のファイルを確認する

$ ls -la /var/lib/pgsql/backup/base_20260922/ | head -8 total 84 drwx------. 21 postgres postgres 4096 Sep 22 10:31 . drwx------. 3 postgres postgres 47 Sep 22 10:31 .. -rw-------. 1 postgres postgres 224 Sep 22 10:31 backup_label -rw-------. 1 postgres postgres 88 Sep 22 10:31 backup_manifest drwx------. 9 postgres postgres 91 Sep 22 10:31 base drwx------. 2 postgres postgres 4096 Sep 22 10:31 global -rw-------. 1 postgres postgres 5065 Sep 22 10:31 postgresql.conf $ ls -la /var/lib/pgsql/wal_archive/ | head -8 total 49156 drwxr-x---. 2 postgres postgres 4096 Sep 22 10:58 . drwx------. 5 postgres postgres 111 Sep 22 10:31 .. -rw-------. 1 postgres postgres 16777216 Sep 22 10:31 000000010000000000000001 -rw-------. 1 postgres postgres 16777216 Sep 22 10:31 000000010000000000000002 -rw-------. 1 postgres postgres 16777216 Sep 22 10:58 000000010000000000000003

WALファイルが順次アーカイブされていることが確認できます。デフォルトのWALセグメントサイズは16MiBです。

recovery.signalとリカバリターゲットを設定する(PostgreSQL 12以降)

PostgreSQL 12からrecovery.confが廃止され、リカバリパラメータはpostgresql.confに書くように変わりました。データディレクトリにrecovery.signalという空ファイルを置くことがリカバリモード開始のスイッチになります。

ここでは「2026年9月22日11:00に誤って大規模DELETEが実行された」ケースを想定し、10:55時点に戻す手順を示します。

1. 現在のデータディレクトリを退避する

# systemctl stop postgresql-16 # mv /var/lib/pgsql/16/data /var/lib/pgsql/16/data.broken

2. ベースバックアップをデータディレクトリにコピーする

# cp -a /var/lib/pgsql/backup/base_20260922 /var/lib/pgsql/16/data # chown -R postgres:postgres /var/lib/pgsql/16/data # chmod 700 /var/lib/pgsql/16/data

3. postgresql.confにリカバリパラメータを追加する

# vi /var/lib/pgsql/16/data/postgresql.conf # --- PITRパラメータ追加 --- restore_command = 'cp /var/lib/pgsql/wal_archive/%f %p' recovery_target_time = '2026-09-22 10:55:00' recovery_target_timezone = 'Asia/Tokyo' recovery_target_action = 'promote'

パラメータの意味:
restore_command:WALファイルをアーカイブから取り込むコマンド(%f=ファイル名・%p=コピー先パス)
recovery_target_time:この時刻の直前のコミットまでWALを再生して停止
recovery_target_action = 'promote':目標到達後に自動昇格して通常運用へ移行(pauseにすれば手動で確認もできる)

4. recovery.signalファイルを作成する

# su - postgres -c "touch /var/lib/pgsql/16/data/recovery.signal" # ls -la /var/lib/pgsql/16/data/recovery.signal -rw-------. 1 postgres postgres 0 Sep 22 11:15 /var/lib/pgsql/16/data/recovery.signal

PITRの実行ログと完了確認

1. PostgreSQLを起動してリカバリを開始する

# systemctl start postgresql-16

2. ログでリカバリの進捗を追う

# tail -f /var/lib/pgsql/16/data/log/postgresql-Mon.log 2026-09-22 11:20:03.412 JST [1234] LOG: starting point-in-time recovery to 2026-09-22 10:55:00+09 2026-09-22 11:20:03.501 JST [1234] LOG: restored log file "000000010000000000000001" from archive 2026-09-22 11:20:04.100 JST [1234] LOG: restored log file "000000010000000000000002" from archive 2026-09-22 11:20:04.318 JST [1234] LOG: recovery stopping before commit of transaction 742, time 2026-09-22 10:55:47.441512+09 2026-09-22 11:20:04.320 JST [1234] LOG: pausing at the end of recovery 2026-09-22 11:20:04.322 JST [1234] LOG: database system is ready to accept read only connections 2026-09-22 11:20:04.330 JST [1234] LOG: selected new timeline ID: 2 2026-09-22 11:20:04.350 JST [1234] LOG: archive recovery complete

archive recovery complete が確認できれば完了です。recovery.signal は自動的に削除され、通常の読み書き可能な状態に移行します。

3. データが正しく戻ったか確認する

$ psql -U postgres -c "SELECT count(*) FROM orders WHERE order_date < '2026-09-22 11:00:00';" count ------- 24387 (1 row)

誤削除前の件数が復元されていることを確認します。recovery_target_actionをpromoteにしていたため、pg_wal_replay_resume()を手動で実行しなくても自動で通常運用へ移行しています。

トラブルシュート

アーカイブが進まない(WALファイルが積み上がる)

archive_commandが失敗するとWALはpg_walディレクトリに溜まり続け、ディスクを圧迫します。まずpg_stat_archiverで失敗件数を確認します。

$ psql -U postgres -c "SELECT archived_count, last_archived_wal, failed_count, last_failed_wal FROM pg_stat_archiver;" archived_count | last_archived_wal | failed_count | last_failed_wal ----------------+-------------------------------------+--------------+---------------------------------------- 12 | 000000010000000000000003 | 2 | 000000010000000000000004

failed_countが増加している場合、archive_commandを手動で実行して原因を特定します。

# su - postgres -c "test ! -f /var/lib/pgsql/wal_archive/000000010000000000000004 && cp /var/lib/pgsql/16/data/pg_wal/000000010000000000000004 /var/lib/pgsql/wal_archive/000000010000000000000004" # echo 0 0

よくある原因:
・アーカイブディレクトリがディスク不足でフル
・postgresユーザーの書き込み権限がない
・archive_commandのパスが誤っている(再起動後は反映されるがreloadでは反映されない)

restore_commandが「No such file or directory」で失敗する

PITRリカバリ時にアーカイブから取り込めない場合、ログに以下のようなエラーが出ます。

2026-09-22 11:21:00.100 JST [1234] LOG: could not restore file "000000010000000000000005" from archive: return code 1

restore_commandにエラーログ出力を追加して調査します。

restore_command = 'cp /var/lib/pgsql/wal_archive/%f %p 2>/tmp/restore_err.log'

WALファイルが連続していない(途中のファイルが欠損)場合、そのLSN以降への復元はできません。ベースバックアップ直後からのWALが全て揃っているか定期的に検証することが重要です。

recovery_target_timeの時刻に止まらない

recovery_target_timeのタイムゾーンがズレていると正しい時刻に止まりません。必ずrecovery_target_timezone = 'Asia/Tokyo'を明示するか、UTC表記(例: '2026-09-22 01:55:00+00')で指定します。

本記事のまとめ

やりたいこと コマンド・設定
WALアーカイブを有効化する archive_mode = onarchive_command = '...' をpostgresql.confに追加後に再起動
ベースバックアップを取得する pg_basebackup -D /path/to/backup --checkpoint=fast -Xs -P
アーカイブ状況を確認する SELECT archived_count, failed_count FROM pg_stat_archiver;
リカバリ目標時刻を指定する postgresql.confに recovery_target_time = '2026-09-22 10:55:00' を追加
リカバリモードを開始する touch /var/lib/pgsql/16/data/recovery.signal 後にPostgreSQLを起動
リカバリ完了後に通常運用へ移行する recovery_target_action = 'promote' で自動昇格 / または手動で SELECT pg_wal_replay_resume();
タイムゾーンを明示してリカバリする postgresql.confに recovery_target_timezone = 'Asia/Tokyo' を追加

PostgreSQLの実運用は「Linux基盤の設計」が土台になります

WALアーカイブやPITRを安心して運用するには、Linuxサーバーのファイルシステム・ストレージ設計・サービス管理を体系的に理解することが重要です。独学で断片的に覚えるより、現場で実際に使われる設計パターンを一度体系的に身につける方が、障害時にも慌てず対応できます。
現場で通用する安全なLinuxサーバー構築の「型」を体系的に身につけたい方へ、『Linuxサーバー構築入門マニュアル(図解60P)』を完全無料でプレゼントしています。

「独学の時間がもったいない」「プロから直接、現場の技術を最短で学びたい」という本気の方には、2日で実務レベルのスキルが身につく【初心者向けハンズオンセミナー】も開催しています。

無料メルマガで学習を続ける

Linuxの実践スキルをメールで毎週お届け。
登録は30秒、解除もいつでも可。

登録無料・いつでも解除できます

暗記不要・1時間後にはサーバーが動く

3,100名以上が実践した「型」を無料で公開中

プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。

姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら

Linux無料マニュアル(図解60P) 名前とメールで30秒登録
宮崎 智広

この記事を書いた人

宮崎 智広(みやざき ともひろ)

株式会社イーネットマーキュリー代表。現役のLinuxサーバー管理者として20年以上の実務経験を持ち、これまでに累計3,100名以上のエンジニアを指導してきたLinux教育のプロフェッショナル。「現場で本当に使える技術」を体系的に伝えることをモットーに、実践型のLinuxセミナーの開催や無料マニュアルの配布を通じてLinux人材の育成に取り組んでいる。

趣味は、キャンプにカメラ、トラウト釣り。好きな食べ物は、ラーメンにお酒。休肝日が作れない、酒量を減らせないのが悩み。最近、ドラマ「フライトエンジェル」を観て涙腺が崩壊しました。