Ubuntuシステム全体はTimeshiftで保護出来るようになったので、次はLXDを導入していきます。
なお、LXDコンテナはTimeshiftの対象外としておいたほうが運用しやすいでしょう。システムに不具合があり環境を巻き戻しても、LXDコンテナは影響を受けなくなります。
そのため、LXDコンテナ部分は監視対象から除外されるように、@lxdというサブボリュームを作成し、デフォルトプールをサブボリュームにマウントするよう設定します。
サブボリュームを作成してLXDを導入
サブボリューム作成
# デバイス名とUUID確認
findmnt -t btrfs
# Btrfsルートをマウント
sudo mount -o subvolid=5 /dev/デバイス名 /mnt
# サブボリューム作成
sudo btrfs subvolume create /mnt/@lxd
sudo umount /mnt
サブボリュームにマウント
# UUIDを確認
sudo blkid /dev/デバイス名
# マウントポイント作成
sudo mkdir -p /var/snap/lxd/common/lxd
# fstabに追記(UUIDは実際の値に置き換え)
echo "UUID=xxxx /var/snap/lxd/common/lxd btrfs defaults,subvol=@lxd,noatime 0 0" | sudo tee -a /etc/fstab
# マウント確認
sudo mount -a
findmnt /var/snap/lxd/common/lxd
systemdへ反映
sudo systemctl daemon-reload
LXDインストール
# LXD インストール
sudo snap install lxd --channel=latest/stable
# lxd グループにユーザー追加
sudo usermod -aG lxd $USER
# 初期化
cat <<EOF | sudo lxd init --preseed
config: {}
networks:
- name: lxdbr0
type: bridge
config:
ipv4.address: auto
ipv6.address: none
storage_pools:
- name: default
driver: btrfs
config:
source: /var/snap/lxd/common/lxd/storage-pools/default
profiles:
- name: default
devices:
root:
path: /
pool: default
type: disk
eth0:
name: eth0
network: lxdbr0
type: nic
EOF
# HTTPS API 有効化
sudo lxc config set core.https_address :8443
# UI 有効化
sudo snap set lxd ui.enable=true
sudo systemctl reload snap.lxd.daemon
ここで一度再ログインします。確実に、再起動しておきましょう。
再起動したら、確認してみます。
sudo btrfs subvolume list /mnt
一時的にマウントが必要なので。
sudo mount -o subvolid=5 /dev/デバイス名 /mnt
sudo btrfs subvolume list /mnt
sudo umount /mnt
@lxd配下にサブボリュームが作られているはずで、Timeshiftは@と@homeのみをスナップショット対象にするため、@lxd以下は自動的に除外されます。
TimeshiftのGUIで「スナップショット」タブを見ると対象サブボリュームが確認できるので、念のためチェックしておくと安心です。
top level 5 (Btrfsルート)
├── @ ← Timeshift対象 ✅
├── @home ← Timeshift対象 (✅ 設定で対象外)
├── timeshift-btrfs/... ← スナップショット保存先
└── @lxd ← Timeshift対象外
└── storage-pools/default ← LXDデフォルトプール(対象外)
ちなみに@homeは除外設定していればスナップショットされません。Timeshiftは@のみが実質の対象になっています。
Timeshiftでホストを戻した場合:@(ルートファイルシステム)のみが巻き戻るので、@lxd以下のコンテナデータは一切影響を受けません。
ただし一点注意があり、ホストを巻き戻すとLXDの設定ファイル(/var/snap/lxd/以下のunix socketや設定など)も古い状態に戻ります。コンテナのデータ自体は無事でも、巻き戻し後にlxd initのやり直しや設定の再投入が必要になるケースがあります。
なので重要な設定変更をしたタイミングでTimeshiftのスナップショットを手動で取っておくと、ホスト側の設定とコンテナの状態が乖離するリスクを減らせます。
LXDインストールまでを1クリックで実行
ここまでの内容を1クリックで実行するなら、下記スクリプトを貼り付けて実行します。
#!/bin/bash
# =============================================================================
# LXD セットアップスクリプト
# - Btrfsデバイスを自動検出
# - @lxd サブボリューム作成
# - LXDインストール・初期設定・UI有効化
# 実行後は再起動してください(lxdグループの反映のため)
# =============================================================================
set -euo pipefail
# -----------------------------------------------------------------------------
# 色付きログ
# -----------------------------------------------------------------------------
info() { echo -e "\e[32m[INFO]\e[0m $*"; }
warn() { echo -e "\e[33m[WARN]\e[0m $*"; }
error() { echo -e "\e[31m[ERROR]\e[0m $*" >&2; exit 1; }
# -----------------------------------------------------------------------------
# root確認
# -----------------------------------------------------------------------------
if [ "$EUID" -eq 0 ]; then
error "このスクリプトは一般ユーザーで実行してください(sudo不要)"
fi
# -----------------------------------------------------------------------------
# Step 1: Btrfsデバイスを自動検出
# -----------------------------------------------------------------------------
info "Btrfsデバイスを検出中..."
# / にマウントされているBtrfsデバイスを取得
DEVICE=$(findmnt -n -o SOURCE -t btrfs / | sed 's/\[.*\]//')
if [ -z "$DEVICE" ]; then
error "Btrfsデバイスが見つかりません"
fi
info "デバイス: $DEVICE"
# UUIDを取得
UUID=$(sudo blkid -s UUID -o value "$DEVICE")
if [ -z "$UUID" ]; then
error "UUIDの取得に失敗しました"
fi
info "UUID: $UUID"
# -----------------------------------------------------------------------------
# Step 2: @lxd サブボリューム作成
# -----------------------------------------------------------------------------
info "@lxd サブボリュームを作成中..."
# すでに存在するか確認
if sudo btrfs subvolume list / | grep -q " path @lxd$"; then
warn "@lxd サブボリュームはすでに存在します。スキップします。"
else
sudo mount -o subvolid=5 "$DEVICE" /mnt
sudo btrfs subvolume create /mnt/@lxd
sudo umount /mnt
info "@lxd サブボリュームを作成しました"
fi
# -----------------------------------------------------------------------------
# Step 3: マウントポイント作成 & fstab追記
# -----------------------------------------------------------------------------
MOUNT_POINT="/var/snap/lxd/common/lxd"
FSTAB_ENTRY="UUID=$UUID $MOUNT_POINT btrfs defaults,subvol=@lxd,noatime 0 0"
info "マウントポイントを作成中: $MOUNT_POINT"
sudo mkdir -p "$MOUNT_POINT"
# fstabに重複追記しないよう確認
if grep -q "@lxd" /etc/fstab; then
warn "fstabに@lxdのエントリがすでに存在します。スキップします。"
else
echo "$FSTAB_ENTRY" | sudo tee -a /etc/fstab > /dev/null
info "fstabに追記しました"
fi
# マウント & systemd反映
sudo mount -a
sudo systemctl daemon-reload
# マウント確認
if findmnt "$MOUNT_POINT" > /dev/null 2>&1; then
info "$MOUNT_POINT のマウント確認OK"
else
error "$MOUNT_POINT のマウントに失敗しました"
fi
# -----------------------------------------------------------------------------
# Step 4: LXD インストール
# -----------------------------------------------------------------------------
if snap list lxd > /dev/null 2>&1; then
warn "LXDはすでにインストールされています。スキップします。"
else
info "LXDをインストール中..."
sudo snap install lxd --channel=latest/stable
fi
# -----------------------------------------------------------------------------
# Step 5: lxdグループにユーザー追加
# -----------------------------------------------------------------------------
if groups "$USER" | grep -q "\blxd\b"; then
warn "$USER はすでにlxdグループに所属しています。"
else
sudo usermod -aG lxd "$USER"
info "$USER をlxdグループに追加しました"
fi
# -----------------------------------------------------------------------------
# Step 6: LXD 初期化
# -----------------------------------------------------------------------------
# すでに初期化済みか確認(storage poolが存在するか)
if sudo lxc storage list 2>/dev/null | grep -q "default"; then
warn "LXDはすでに初期化されています。スキップします。"
else
info "LXDを初期化中..."
cat <<EOF | sudo lxd init --preseed
config: {}
networks:
- name: lxdbr0
type: bridge
config:
ipv4.address: auto
ipv6.address: none
storage_pools:
- name: default
driver: btrfs
config:
source: /var/snap/lxd/common/lxd/storage-pools/default
profiles:
- name: default
devices:
root:
path: /
pool: default
type: disk
eth0:
name: eth0
network: lxdbr0
type: nic
EOF
info "LXD初期化完了"
fi
# -----------------------------------------------------------------------------
# Step 7: HTTPS API & UI 有効化
# -----------------------------------------------------------------------------
info "HTTPS APIを有効化中..."
sudo lxc config set core.https_address :8443
info "LXD UIを有効化中..."
sudo snap set lxd ui.enable=true
sudo systemctl reload snap.lxd.daemon
# -----------------------------------------------------------------------------
# 完了メッセージ
# -----------------------------------------------------------------------------
echo ""
echo "====================================================="
info "セットアップ完了!"
echo "====================================================="
echo ""
echo " デバイス : $DEVICE"
echo " UUID : $UUID"
echo " マウント : $MOUNT_POINT"
echo ""
warn "lxdグループを反映するために再起動してください:"
echo ""
echo " sudo reboot"
echo ""
echo " 再起動後、ブラウザで以下にアクセスしてUIを確認:"
echo " https://localhost:8443"
echo ""

サービスごとにサブボリュームを作成
Btrfsバックエンドにしたなら、コンテナをコピーしても使用量は増えないので、1サービス1コンテナで運用するほうが良いでしょう。小さなサービスであれば、1コンテナなすべて閉じ込めておけば、バックアップや移行もしやすくなります。
immichやNextcloudのようなデータが大きくなりがちなサービスは、データ保存用にサブボリュームを作成したほうが管理しやすくなります。
Btrfsルート (subvolid=5)
├── @
├── @home
├── @lxd
│ └── storage-pools/default
├── @data-immich ← サービスごとに個別サブボリューム
└── @data-nextcloud
つまり、次のようなイメージでコンテナにデータ部分のディレクトリをマウントして運用する形です。
LXDコンテナ: immich
├── / (rootfs) ← @lxd/storage-pools/default 内のサブボリューム
│ (OS、アプリ、設定)
└── /var/lib/immich ← @data-immich をマウント
(写真・動画データ)
LXDコンテナ: nextcloud
├── / (rootfs) ← @lxd/storage-pools/default 内のサブボリューム
│ (OS、アプリ、設定)
└── /var/lib/nextcloud ← @data-nextcloud をマウント
(ユーザーファイル)
コンテナ作成例。
lxc config device add immich data disk \
source=/mnt/data/immich \
path=/var/lib/immich
lxc config device add nextcloud data disk \
source=/mnt/data/nextcloud \
path=/var/lib/nextcloud
これでコンテナを丸ごとlxc exportしてもデータは含まれず、アプリ設定だけの軽いバックアップになります。データは別途btrbkなどで管理、という役割分担がきれいにできます。
なお、TimeshiftのGUIはあくまで@と@home専用なので、@data-immichのような独自サブボリュームはコマンドで管理することになります。手動スナップショットの例は次の通り。
手動スナップショット
# スナップショット作成
sudo btrfs subvolume snapshot /mnt/data/immich /mnt/data/immich-snap-20260330
# 確認
sudo btrfs subvolume list / | grep data
特定時点に戻す場合
# LXDコンテナを止めてから
lxc stop immich
# 現行を退避(念のため)
sudo mv /mnt/data/immich /mnt/data/immich-broken
# スナップショットから戻す
sudo btrfs subvolume snapshot /mnt/data/immich-snap-20260330 /mnt/data/immich
lxc start immich
スナップショット置き場の整理
スナップショットが増えると散らかるので、置き場を決めておくと良いです。
sudo mkdir -p /mnt/data/.snapshots/immich
sudo btrfs subvolume snapshot /mnt/data/immich /mnt/data/.snapshots/immich/20260330
自動化したい場合
cronやsystemd timerで定期実行するスクリプトを作るのが現実的です。世代管理ツールとしてbtrbkが使いやすくておすすめです。
sudo apt install btrbk
設定ファイルでサブボリュームごとに保持世代数を指定できるので、Timeshiftに近い感覚で使えます。


