社内wikiとしてBookStackを立てたあと、必ず来るのがバックアップです。データベースだけ取っていても、画像を貼り付けて使っていたなら、それは復元できません。
BookStackには公式の bookstack-system-cli があり、1コマンドでデータベースとアップロードファイルを1つのZIPにまとめられます。ただし実際に環境を破棄して戻してみると、そのままでは困る点が4つありました。

この記事では、バックアップの取り方に加えて復元テストの手順と、その過程で踏んだ4点をまとめます。最後に、CLIを使わず設定ディレクトリごとコピーする方式とも実測で比較します。BookStackの構築手順はBookStackをAlmaLinux 9.4にインストールする手順を参照してください。
検証環境: BookStack v26.05.5(linuxserver/bookstack v26.05.5-ls284)/bookstack-system-cli 0.4.0/MariaDB 11.8.8/Docker Compose。検証はDocker版で行いました。 AlmaLinuxへ手動インストールした場合との差異は、該当箇所で明記します。
1. 結論:公式CLIで取れる。ただしZIPだけでは戻らない
BookStackのインストールディレクトリに bookstack-system-cli が同梱されています。
# バックアップ。ZIP を1つ作るだけ
./bookstack-system-cli backup /path/to/backup.zip
# 復元。ZIP を指定する
./bookstack-system-cli restore /path/to/backup.zip
これだけです。ただし先に知っておくべきことが4つあります。
- ZIPに入る
.envが、設定の復元に使えないことがある - 復元は
.envをマージする。差異があると対話で止まる -n(非対話)を付けると復元されない- 復元後、アップロード先の所有者が
rootになり書き込めなくなる
順に見ていきます。なお実行すると冒頭に WARNING: This CLI is in beta testing. と出ます。APIが変わる可能性がある旨が明示されているので、本番の運用に組み込むならバージョンを固定してください。
2. ZIPに何が入るのか
まず中身を開いて確かめます。
./bookstack-system-cli backup /config/backup.zip
unzip -l /config/backup.zip
実際の出力です。
Length Date Time Name
--------- ---------- ----- ----
2009 09-25-2026 02:10 .env
393659 09-14-2026 22:58 bookstack-system-cli
53256 09-25-2026 02:19 db.sql
14 09-25-2026 02:18 public/uploads/test-a.txt
13 09-25-2026 02:18 storage/uploads/images/gallery/test-b.txt
12 09-25-2026 02:18 storage/uploads/files/test-c.txt
13 09-25-2026 02:18 themes/test-d.txt
アップロード先が3箇所に分かれているのが要点です。
| パス | 中身 |
|---|---|
public/uploads/ | ロゴなど公開用の画像 |
storage/uploads/images/ | ページに貼り付けた画像 |
storage/uploads/files/ | ページに添付したファイル |
themes/ | カスタムテーマ |
手作業でバックアップを組むなら、この3箇所を全部指定しないと画像だけ戻らないことになります。--no-database --no-uploads --no-themes で個別に除外できるので、裏を返せば既定ではこの3種類とデータベースが入ります。
なお、これらが空のときは黙って0件になります。「ZIPが小さいから失敗した」とは限りません。 筆者は最初、まだ画像を1枚も貼っていない状態で取って「uploadsが入らない」と誤解しました。ファイルを置いて取り直したら正しく入っていました。
3. 落とし穴①:ZIP内の .env が設定の復元に使えないことがある
ZIPには .env が入ります。ところが Docker版(linuxserver イメージ)では、この .env がテンプレートのままでした。
unzip -p backup.zip .env | grep -E '^(APP_KEY|APP_URL|DB_HOST|DB_USERNAME)'
APP_KEY=SomeRandomString
APP_URL=https://example.com
DB_HOST=localhost
DB_USERNAME=database_username
全部プレースホルダです。 一方、アプリが実際に使っている値はコンテナの環境変数側にあります。
APP_URL=http://localhost:6875
DB_USERNAME=bookstack
APP_KEY=base64:i99REr……
つまり Docker で運用している場合、ZIPだけ持っていても設定は復元できません。 docker-compose.yml(または .env ファイル)を別途、同じ場所に保管する必要があります。バックアップ対象は「ZIP」ではなく「ZIP+compose定義」と考えてください。
AlmaLinuxへ手動インストールした場合は逆になります。 設定は BookStack ディレクトリ直下の .env に実値で入るため、ZIPから設定ごと戻せます。その代わり、ZIPの中に本物の APP_KEY とデータベースのパスワードが入ります。 保管場所の権限と、バックアップの転送経路に注意してください。
APP_KEY は Laravel がセッションなどの暗号化に使う鍵です。失っても記事本文が消えるわけではありませんが、揃えておくに越したことはありません。
4. 落とし穴②:復元は .env を「マージ」する
復元すると、こう表示されます。
Restoring and merging .env file...
Found different APP_URL values, which would you like to use?
[0] http://localhost:6875
[1] https://example.com
上書きではなくマージで、値が食い違う項目は対話で選ばせます。 別のホストへ移設するときは、ここでURLの選択を誤らないようにしてください。
なお復元後、Docker版では .env にプレースホルダが残ったままになります。それでもアプリが動くのは、環境変数のほうが優先されるためです。「.env が壊れているのに動いている」状態になるので、後から中身を見て混乱しないよう覚えておいてください。
5. 落とし穴③:-n を付けると復元されない
自動化しようとして -n(非対話)を付けると、こうなります。
Contents found in the backup ZIP:
✔ .env Config File
✔ Themes Folder
✔ Public File Uploads
✔ Private File Uploads
✔ Database Dump
The checked elements will be restored into [/app/www].
Existing content will be overwritten.
Stopping restore operation.
確認が取れないので、実行せずに終了します。 エラーにはなりません。終了コードだけ見ていると「成功した」と誤読しかねない出方です。
無人で流すなら確認に応答を渡します。ただし前章のとおり APP_URL が食い違うとさらに選択肢を聞かれるので、定期実行に組み込むのはバックアップ側だけにして、復元は人が実行するのが現実的です。
# 確認に応答して復元する
echo yes | ./bookstack-system-cli restore /config/backup.zip
6. 落とし穴④:復元後、所有者が root になる
復元が終わると、CLI自身がこう言います。
You may need to fix file/folder permissions so that the webserver has
the required read/write access to the necessary directories & files.
実際に確認すると、こうなっていました。
ls -ld /config/www/uploads /config/www/themes /config/www/images
drwxr-xr-x 1 root root 4096 /config/www/uploads
drwxr-xr-x 1 root root 4096 /config/www/themes
drwxr-xr-x 1 abc users 4096 /config/www/images
uploads と themes が root:root に変わっています。 アプリを動かすユーザーで書き込めるか試すと、こうなります。
su abc -s /bin/sh -c 'touch /config/www/uploads/writetest.txt'
# touch: cannot touch '...': Permission denied
復元した直後は、読めるが書けない状態です。 画面を開くと記事は表示されるので正常に見えますが、新しく画像を貼り付けようとした時点で失敗します。復元後は所有者を戻してください。
# Docker(linuxserver)の場合。PUID/PGID に合わせる
chown -R abc:users /config/www/uploads /config/www/themes
# AlmaLinux に手動インストールした場合は Web サーバーのユーザーに合わせる
chown -R nginx:nginx /var/www/bookstack/public/uploads \
/var/www/bookstack/storage/uploads \
/var/www/bookstack/themes
7. 復元テストの手順
バックアップは、戻せることを確認して初めてバックアップです。実際に行った手順を残します。要点は「目印を入れてから壊す」ことです。
① 目印を入れる
データベースとファイルの両方に、復元後すぐ確認できる印を置きます。
# データベース側:設定テーブルに目印を1行入れる
mariadb -u bookstack -p bookstackapp -e \
"INSERT INTO settings (setting_key, value, created_at, updated_at)
VALUES ('restore_marker','MARKER-2026-09-25',NOW(),NOW());"
# ファイル側:3箇所すべてに目印ファイルを置く
echo A > public/uploads/test-a.txt
echo B > storage/uploads/images/test-b.txt
echo C > storage/uploads/files/test-c.txt
② バックアップを取り、退避する
./bookstack-system-cli backup /tmp/backup.zip
ZIPは必ず、これから消す領域の外へ移してください。 設定ディレクトリの中に置いたまま環境を破棄すると、バックアップごと消えます。
③ 環境を完全に壊す
docker compose down
rm -rf ./app_config ./db_config # 設定とデータの実体を消す
④ まっさらな状態で立て直し、空であることを確認する
ここを飛ばすと、元のデータが残っていただけなのか、復元が効いたのかが区別できません。
mariadb -u bookstack -p bookstackapp -e \
"SELECT COUNT(*) FROM settings WHERE setting_key='restore_marker';" # → 0
⑤ 復元し、目印が戻ることを確認する
echo yes | ./bookstack-system-cli restore /tmp/backup.zip
実際の結果です。
setting_key value
restore_marker MARKER-2026-09-25
/config/www/uploads/test-a.txt UPLOAD-TEST-A
/config/www/images/gallery/test-b.txt IMAGE-TEST-B
/config/www/files/test-c.txt FILE-TEST-C
/config/www/themes/test-d.txt THEME-TEST-D
データベースの1行と、3箇所のファイルがすべて戻りました。最後に画面が開くこと(HTTP 200)と、所有者を直したうえで書き込めることまで確認して完了です。
なお復元時、CLIはデータベースのマイグレーションを自動で実行します。ヘルプにも「同じかそれ以降のバージョンへ復元すること」と書かれているので、古いバージョンへ戻すのは想定されていません。バックアップを取ったバージョンは記録しておいてください。
8. フォルダ丸ごとという選択肢
Docker Composeで動かしているなら、CLIを使わず設定ディレクトリごとコピーする手もあります。同じ環境で両方試したので、実測値で比較します。
| 公式CLI(ZIP) | フォルダ丸ごと | |
|---|---|---|
| サイズ | 0.36 MB | 159.3 MB |
| 設定の復元 | 不可(.env がテンプレート) | 可(compose・nginx設定・鍵まで) |
| 復元操作 | 対話プロンプトあり | 戻して up -d だけ |
| 復元後の所有者 | root:root・書き込み不可 | 変化なし・書き込み可 |
| 別バージョンへの移植 | 可(mysqldump なので) | 不可に近い |
| 停止の要否 | 不要 | コールドなら必要(実測 10.6秒) |
どちらも復元に成功し、データベースの1行とアップロードファイルが戻ることを確認しています。
8.1 サイズ差の正体はデータではない
159MBの内訳を見ると、ほぼ全部がInnoDBの固定領域でした。
ib_logfile0 96.0 MB
ibdata1 12.0 MB
ibtmp1 12.0 MB
undo001/2/3 10.0 MB × 3
実データはほとんど入っていません。 記事が増えてもこの150MBは最初から乗っているので、440倍という比率は初期状態特有のものです。運用が進めば差は縮まります。
8.2 フォルダ方式なら落とし穴①と④が起きない
この記事で挙げた4つのうち、2つはフォルダ方式で回避できます。
- 落とし穴①(
.envがテンプレートで設定が戻らない)—docker-compose.ymlが同じ場所にあるので、バックアップ対象を分けて考える必要がありません - 落とし穴④(
uploadsとthemesがrootになる)— 所有者がそのまま保たれ、書き込みも通りました
8.3 代わりに失うもの
移植性がありません。 rawデータファイルはMariaDBのバージョンに紐づくため、別バージョンや別ディストリへ移すなら mysqldump、つまり公式CLIのZIPが必要です。
もうひとつ、稼働したままコピーする方式(ホットコピー)の安全性は確認できていません。 無負荷の状態で試した限りは復元できましたが、1回成功したことは安全の証明になりません。書き込みの最中にコピーすれば、InnoDBのファイルが中途半端な状態で取られる可能性が残ります。無停止が要件なら、フォルダコピーではなく mariadb-dump を使ってください。
8.4 どちらの方式でも、復元後のDBは元と同一にはならない
検証中に気づいた点です。復元して起動したあとのデータベースには、コピー時には存在しなかったテーブルが6つ増えていました。BookStackが起動のたびにマイグレーションを実行するためです。
筆者は最初これを「稼働中コピーがファイルを取りこぼした」と誤解しましたが、停止して取ったコピーにも同じ6つが無かったので、原因はマイグレーションでした。ファイル単位で元と突き合わせても一致しません。 確認するのは中身(目印が戻っているか)にしてください。
8.5 使い分け
- 日常の定期バックアップ — 停止できるならコールドでフォルダ丸ごと。10秒の停止で、設定ごと確実に戻せます
- バージョンアップ前・移設前 — 公式CLIのZIP。移植性があるのはこちらだけです
- 両方取るのが理想 — サイズの桁が違うので、併用のコストはほぼありません
なお所有者が保たれた結果は、Windows上のバインドマウントで検証したものです。Linuxホストで同じことをする場合は、所有者とパーミッションを保つために tar -p か rsync -a を使ってください(こちらは未検証です)。
9. まとめ
BookStackのバックアップと復元について、実測をもとに整理しました。
- 公式CLIで1コマンド。 データベース・アップロード3箇所・テーマが1つのZIPにまとまる
- Dockerで運用しているならZIPだけでは足りない。
.envがテンプレートなので、compose定義も一緒に保管する - 手動インストールならZIPに実値が入る。 保管場所の権限に注意する
-nでは復元されない。 エラーも出ないので終了コードだけ見ない- 復元後は
uploadsとthemesの所有者がrootになる。 読めるが書けない状態になる - 目印を入れてから壊して戻す。 空を確認する手順を飛ばさない
- Docker運用ならフォルダ丸ごとという選択肢がある。 設定ごと戻せて権限も崩れないが、サイズは440倍で移植性が無い。同一ホストへ戻すならフォルダ、移設するならZIP
バックアップを取る設定まではすぐ終わります。戻す側を一度通しておくかどうかで、いざという時の差が出ます。 検証環境を1つ立てて、この手順を一度流しておくことをおすすめします。
サーバーをこれから用意する場合の選び方は、BookStackを社内サーバー無しで始めるにまとめています。
社内ツールを動かすサーバーの選び方
BookStack や Redmine のような社内ツールは、PHP とデータベースを自分で用意して動かします。そのためSSH で操作できる VPS が必要で、共用のレンタルサーバーでは構築できません。メモリはデータベースと同居する分を見て、2GB以上を目安にしてください。
まず試すだけなら、VPS を1台借りて動かしてみるのが手軽です。候補は次の2社です。
お名前.com レンタルサーバー(GMOインターネット)……VPSプランがあります。独自ドメインも同じ事業者でまとめたい場合はこちらです。
ConoHa VPS……Linux のほかに ConoHa for Windows Server も選べます。Windows で検証したい場合はこちらです。
契約前に、使いたい OS のテンプレートが用意されているかと、料金体系・解約条件を確認してください。


コメント