DockerでBookStackをデプロイ:自宅ラボ(HomeLab)向けセルフホストWikiの構築手順

HomeLab tutorial - IT technology blog
HomeLab tutorial - IT technology blog

クイックスタート(5分)

自宅ラボのドキュメント管理は、あっという間に破綻しがちです。固定IPアドレスの割り当て、Docker Composeファイル、Proxmoxのファイアウォールルール、適当に作ったBashのエイリアスなどが、メモ帳や散らかったテキストファイルにあちこち分散してしまいます。BookStackは、現実の図書館の階層構造(本棚・本・章・ページ)を取り入れることで、この混乱を解消してくれます。

Docker Composeを使えば、LinuxServerが提供する軽量イメージとMariaDBコンテナを活用して、本番運用に耐えうるインスタンスを5分未満で立ち上げることができます。アイドル時のメモリ消費量も250MB未満と非常に軽量です。

まず、専用のプロジェクトディレクトリを作成し、そこに移動します:

mkdir -p ~/homelab/bookstack && cd ~/homelab/bookstack

Composeファイルを作成します:

nano docker-compose.yml

以下のスタック設定を貼り付けます:

version: "3.8"

services:
  bookstack:
    image: lscr.io/linuxserver/bookstack:latest
    container_name: bookstack
    environment:
      - PUID=1000
      - PGID=1000
      - APP_URL=http://192.168.1.50:6875
      - DB_HOST=bookstack_db
      - DB_PORT=3306
      - DB_USER=bookstack
      - DB_PASS=SecretBookStackPassword123
      - DB_DATABASE=bookstackapp
    volumes:
      - ./appdata:/config
    ports:
      - 6875:80
    restart: unless-stopped
    depends_on:
      - bookstack_db

  bookstack_db:
    image: lscr.io/linuxserver/mariadb:latest
    container_name: bookstack_db
    environment:
      - PUID=1000
      - PGID=1000
      - MYSQL_ROOT_PASSWORD=RootSecretPassword456
      - MYSQL_DATABASE=bookstackapp
      - MYSQL_USER=bookstack
      - MYSQL_PASSWORD=SecretBookStackPassword123
    volumes:
      - ./dbdata:/config
    restart: unless-stopped

http://192.168.1.50:6875 を、サーバーの実際のLAN IPアドレスまたはローカルDNSホスト名に置き換えてください。ポート番号は省略しないでください。

コンテナをバックグラウンドで起動します:

docker compose up -d

Webサーバーがリクエストを受け付け始めるまで、マイグレーションログを確認します:

docker compose logs -f bookstack

Nginxの確認ログが表示されたら、ブラウザで http://<your-server-ip>:6875 にアクセスします。以下のデフォルト管理者アカウントを使用してサインインしてください:

このデフォルトパスワードは直ちに変更してください。最初の本棚を作成する前に、右上の「Edit Profile(プロフィールの編集)」から変更を行ってください。

詳細解説

セルフホストのサービスを立ち上げること自体は簡単です。本当に困るのは、8か月後のハードウェア移行時に「どのような設定をしたか」を思い出すときです。専用Wikiを導入すれば、そうしたパニックを防ぐことができます。

BookStackによるナレッジの構造化

フラットなMarkdownツリーや構造化されていないWikiは、すぐにカオスへと陥りがちです。BookStackでは、ドキュメントを整理された状態に保つために厳格な4層の階層構造を採用しています:

  1. 本棚(Shelves): ネットワーク、ストレージプール、Kubernetesといった運用上の大カテゴリです。関連する複数の本を1つの本棚にまとめます。
  2. 本(Books): OPNsense Firewall、TrueNAS Core、メディア自動化など、個々のシステムやサービス単位です。
  3. 章(Chapters): 本の中の任意のセクションです。例えば、VLANトランキングやWireGuardリモートアクセストンネルなどです。
  4. ページ(Pages): コードブロック、ネットワーク構成図、設定のdiff、添付ファイルなどを含む実際の技術記事です。

この構造がガードレールとして機能します。迷子のページが発生するのを防ぎ、自宅ラボのサービスが数十個規模に拡大しても、見通しの良いドキュメント環境を維持できます。

主要な環境変数の解説

本番運用に入る前に、注意すべき3つのCompose環境変数があります:

  • APP_URL: BookStackが内部リンクの生成、アセットパスの解決、リダイレクトヘッダーの構築に厳密に使用する文字列です。プロトコル、IPアドレス、ポート番号がブラウザのアドレスバーの内容と一致しない場合、CSSやJSのアセット読み込みに失敗したり、フォーム送信時にCSRFエラーが発生したりします。
  • PUID および PGID: コンテナ内部のプロセスをホスト側のユーザーID(UbuntuやDebianのプライマリユーザーの場合、通常は 1000:1000)にマッピングするための変数です。これにより、デーモンが永続化ストレージボリューム上にroot所有のファイルを作成してしまうのを防ぎます。
  • DB_HOST: データベースのサービスブロックで定義したサービス名(bookstack_db)と一致させる必要があります。Dockerの組み込みDNSが、デフォルトのブリッジネットワークを介してコンテナ間のルーティングを自動的に処理します。

高度な使い方

リバースプロキシによるHTTPS化

保護されたローカルサブネット内であればプレーンなHTTPでも動作しますが、近年のブラウザは非HTTPS環境においてクリップボードへのコピー&ペーストなどの安全な機能を無効化します。CaddyやNginxなどのリバースプロキシを運用している場合は、まずComposeファイルを調整してください。

セキュアなFQDNに合わせて APP_URL を更新します:

    environment:
      - APP_URL=https://wiki.lab.example.com

SSL証明書の自動生成とプロキシヘッダーの正しい転送を行うCaddyの設定例です:

wiki.lab.example.com {
    reverse_proxy 127.0.0.1:6875 {
        header_up X-Forwarded-Proto https
    }
}

標準的なNginxリバースプロキシの場合は、プロトコルとIPヘッダーが正しく転送されるように設定してください:

location / {
    proxy_pass http://127.0.0.1:6875;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto https;
}

データベースバックアップの自動化

USBメモリの破損やSSDの故障によって、大事な運用手順書まで道連れに失われては困ります。cron経由でシンプルなシェルスクリプトを実行すれば、日次ダンプをわずか数秒で自動作成できます。

~/homelab/bookstack/backup.sh にバックアップスクリプトを作成します:

#!/usr/bin/env bash
set -euo pipefail

BACKUP_DIR="${HOME}/homelab/bookstack/backups"
TIMESTAMP=$(date +"%Y%m%d_%H%M%S")
mkdir -p "${BACKUP_DIR}"

# 実行中のコンテナからMariaDBデータベースをダンプ
docker exec bookstack_db /usr/bin/mariadb-dump \
  -u bookstack \
  -pSecretBookStackPassword123 \
  bookstackapp | gzip > "${BACKUP_DIR}/bookstack_db_${TIMESTAMP}.sql.gz"

# アップロードされたアセット、構成図、添付ファイルをアーカイブ
tar -czf "${BACKUP_DIR}/bookstack_files_${TIMESTAMP}.tar.gz" \
  -C "${HOME}/homelab/bookstack/appdata" www/storages

# 過去14日分より古いバックアップを削除
find "${BACKUP_DIR}" -type f -name "bookstack_*" -mtime +14 -delete

echo "バックアップが完了しました: ${TIMESTAMP}"

スクリプトに実行権限を付与します:

chmod +x ~/homelab/bookstack/backup.sh

タスクをスケジュールするためにcrontabを開きます:

crontab -e

毎朝午前3時(03:00)に実行されるよう、以下のエントリーを追加します:

0 3 * * * /bin/bash /home/ubuntu/homelab/bookstack/backup.sh >> /home/ubuntu/homelab/bookstack/backup.log 2>&1

実践的なTips

デフォルトエディタをMarkdownに設定する

BookStackのデフォルトはWYSIWYGエディタです。一般的な文章を書くには十分ですが、CLIの出力結果やシェルセッションのログ、生の設定ブロックを扱うには不便なことがあります。Markdownエディタに切り替えることで、コードブロックが見やすく整形され、左右分割プレビュー画面で快適に編集できるようになります。

  1. 管理者としてログインします。
  2. 設定(Settings) > カスタマイズ(Customization) に進みます。
  3. ページエディタ(Page Editor) まで下にスクロールし、Markdown を選択します。
  4. 変更を保存します。既存のページは元の形式のまま保持され、新規作成されるすべてのページが2ペインのMarkdownエディタで開くようになります。

ログイン時のCSRFトークンエラーの対処法

ログインフォーム送信時に「Page Expired」や「Token Mismatch」というエラーが発生する場合、環境設定の不一致が疑われます。以下の2点を確認してください:

  1. Composeファイル内の APP_URL が、アドレスバーに表示されているURLと完全に一致していることを確認します。たとえば、http://192.168.1.50:6875 でアクセスしているにもかかわらず、APP_URL=http://localhost:6875 と設定されているとトークン検証で拒絶されます。
  2. HTTPSリバースプロキシの配下で運用している場合、プロキシが X-Forwarded-Proto https ヘッダーを適切に転送しているか確認してください。これがないと、BookStackは接続が暗号化されていないと判断し、セッションCookieを破棄してしまいます。

自宅ラボ用の最初の本棚を設計する

最初から一貫したルールを設けておくことが肝心です。以下は、自宅ラボ環境で実績のある構成例です:

  • 本棚: Infrastructure & Baremetal
    • 本: Proxmox VE Cluster
      • 章: Storage Pools → ページ: ZFS Scrub Schedules & Retention Policies
      • 章: Network Bridges → ページ: VLAN Trunking on vmbr0 (10G SFP+)
    • 本: Docker Hosts
      • ページ: Daemon JSON & Default Log Rotation
      • ページ: Shared Compose Templates & Subnets

今この構成を整えておくことで、アップデートによって内部サービスがトラブルを起こした際にも、わずか2クリックで正確な修正手順にアクセスできるようになります。

Share: