Raspberry Pi で運用していたサービスを VPS に移行した話
SD カードが壊れた。3 度目だ。Raspberry Pi 5 の microSD が突然 read-only に落ち、復旧に半日溶かした金曜の夜、観念して VPS への移行を決めた。
2 年間ラズパイで動かしてきたサービスは 6 つ。Caddy のリバースプロキシ、Vaultwarden、PhotoPrism、Tandoor、自前の家計簿 API、それと小さな Web ツール群。トラフィックは月 2 万 PV ほど。電気代込みで月 500 円くらいの計算でずっと回していた。
移行を済ませて 2 週間。今のところ後悔はない。むしろ「もっと早くやればよかった」と思っている。判断材料と手順を残しておく。同じ温度感で迷っている人の役に立つかもしれない。
ラズパイ運用で詰んだ瞬間
故障の主因は、ほぼ間違いなく書き込みの偏り。PhotoPrism がサムネイルを再生成するたびに SD カードに大量書き込みが走るのは把握していたし、SSD への boot 移行も計画にはあった。けど先延ばしにしていた。ツケが回ってきた、というだけの話。
痛かったのは、復旧コストよりも「いつ次が来るか分からない」という不安だった。家族のパスワードボルトもラズパイ上に乗っていた。Vaultwarden が朝起きて死んでいたら、シャワー前にパスワードを取り出せない。これはまずい。
もう一つ、夏場の挙動も無視できなかった。室温 32 度を超えると Raspberry Pi 5 はサーマルスロットリングで体感半分の速度に落ちる。以前まとめたラズパイ運用Tipsに書いた通り、ヒートシンクを盛って多少は改善したが、根本対策ではなかった。
VPS に移すか、自宅でハードウェアを強化するか
正直、最初は中古の小型 NAS に乗せ替えるか、N100 のミニ PC を買う案も真剣に検討した。電気代と初期費用の差し引きを ChatGPT に計算させてみたら、3 年スパンでは自宅機の方が安い。
でも結局 VPS にした。理由は 3 つ。
- 停電や回線断のときに死ぬのが嫌だった(去年の台風で 4 時間落ちた)
- 固定 IP 取得とポート開放まわりの作業に飽きた
- 引っ越しの予定があり、自宅機を運ぶオペレーションを未来の自分に課したくなかった
金額勝負ではなく、運用負荷の勝負だった、というのが今振り返っての感想。月 1,000 円くらいまでなら払う、と腹を決めたら選択肢が一気に絞れた。VPS は お名前.com の VPS を契約した。2GB プランで月 968 円、SSD 100GB、東京リージョン。決め手は最低利用期間の縛りが緩いことと、コンパネからスナップショットがワンクリックで取れること。![]()
移行の流れ
大筋は「Docker Compose のままごっそり持っていく」。ラズパイ時代から全サービスを compose ファイル管理にしていたのが、ここで効いた。
1. データのバックアップと圧縮
# volumes ディレクトリをまるごと固める
sudo systemctl stop docker
sudo tar -czf /tmp/services.tar.gz -C /srv volumes/
ls -lh /tmp/services.tar.gz # 4.2GB
PhotoPrism の写真本体は別系統で S3 互換ストレージに置いていたので、ここでは Vaultwarden の SQLite と Tandoor の Postgres ダンプ、Caddy の autosave 証明書だけが対象になった。
2. VPS 側の下準備
Ubuntu 24.04 LTS を選んで初期化。最低限やったのは以下。
- 非 root ユーザー作成と SSH 鍵認証化、パスワード認証 OFF
- ufw で 22, 80, 443 のみ許可
- Docker と Docker Compose プラグインの導入
- fail2ban の jail 設定(sshd と nginx-botsearch)
- サーバー時刻を JST に変更(cron 系の整合のため)
このへんは雑にやると後で泣くので、Ansible Playbook 化しておいた。次回の移行時はこれを流すだけで終わる。
3. データを転送して compose up
# ラズパイ側から VPS へ rsync
rsync -avz --progress /tmp/services.tar.gz \
user@vps.example.com:/srv/
# VPS 側で展開して docker compose
ssh user@vps.example.com
sudo tar -xzf /srv/services.tar.gz -C /srv/
cd /srv/services
docker compose up -d
ここで一発で全部上がる、と期待していたら、案の定 Caddy の自動 SSL でつまずいた。新サーバーの IP に DNS が向いていないため、Let's Encrypt のチャレンジが通らない。当たり前といえば当たり前。
4. DNS の切り替えと TLS の再取得
段階的にやった。まず DNS の TTL を 60 秒に下げて、ラズパイ側を生かしたまま VPS の IP に向けて切り替え。Caddy が /data/caddy/certificates/ 配下に新しい証明書を取りにいくのを journalctl -u caddy -f で見守った。Caddy のリバースプロキシ設定を整理しておいたおかげで、設定ファイルはそのままコピーで動いた。
移行後の体感
PhotoPrism のインデックス再構築が、ラズパイ時代に 47 分かかっていたのが VPS で 8 分に短縮された。サムネイル生成中も他のサービスがもたつかなくなった。これだけで月 1,000 円の価値はある、と一瞬で納得した。
家計簿 API のレスポンスは中央値で 180ms → 65ms。CPU が 4 コアの x86 になったというより、SD カードのランダム I/O が消えた効果が大きい気がしている。ベンチマークを正しく取ったわけではないので、ここは感覚値。
意外な副作用として、宅内ネットワークがやや軽くなった。Tailscale 経由で外から自宅にアクセスする頻度が減ったので、上り帯域の取り合いがなくなった。Tailscale を使った自宅 VPN 構成はそのまま残してあるが、用途が「メディアサーバーアクセス」だけに絞られた。
ハマりどころメモ
移行で詰まった点を、未来の自分のために書き残しておく。
- UID/GID のズレ: ラズパイの pi ユーザーは UID 1000、VPS の新規ユーザーも UID 1000 だったので volumes はそのまま読めた。けど Tandoor のように内部で固定 UID を使うアプリはここでパーミッションエラー祭りになる。
chown -Rで逃げた。 - aarch64 → x86_64 の Docker イメージ: ほぼ全部マルチアーキで配布されていて影響なかったが、自前ビルドした 1 個だけ作り直しが必要だった。Dockerfile を読み返すきっかけになった、と前向きに捉えている。
- cron の方言: ラズパイで動かしていた一部のシェルスクリプトを移すついでに、systemd timer に切り替えた。前にまとめた cron→systemd timer の移行手順がそのまま使えた。
- ログ送信先のハードコード: ntfy のトピック URL や Discord Webhook を
~/.bashrcに書いていたものがあって、そのまま動かなくて 30 分ハマった。設定の場所はちゃんと一箇所に集約しておくべき、という当たり前の教訓。
ラズパイをどう使うか、再考した
ラズパイは捨てなかった。今は宅内 LAN 専用で、Pi-hole と Home Assistant、それと SwitchBot ハブだけを動かしている。WAN に晒さない用途に絞ったので、SD カード書き込みもログ最小化で 1/10 程度に落ちた。役割を絞れば、ラズパイは今でも頼れる。
結論じみたものを書くなら、こうなる。外から触られる用途は VPS、家の中で完結する用途はラズパイ。境界をはっきり決めたら、運用の頭の中もスッキリした。次の引っ越しのときに自宅機を箱詰めしなくてよくなったのも、地味に効いている。
同じ判断で迷っている人がいたら、SD カードが壊れる前に動いた方がいい、とだけ伝えておきたい。3 度目で気付いた身としては、それくらいしか言えることがない。