MastodonサーバーをXserver VPSからKagoya Cloud VPSへ移行しました
公開日:
[tech] #Mastodon #Ubuntu #VPS #docker
きっかけ
https://blog.asterism.xyz/posts/20251103-0000016c/
前回のMastodonアプデ記事の時に書いた通り、Ubuntu 26.04への移行と合わせてインスタンス作り直したかったというのがまずあります。
元々redisとpsqlだけdocker上じゃなくネイティブに動いていました。(これは歴史的経緯が強い。変えるタイミングはたくさんあったけどやってなかった)
この状態で sudo do-release-upgrade をすると、ポスグレのアプグレがめっちゃ大変です。
昔Ubuntu 18.04からUbuntu 20.04辺りに上げた時、pg_upgradeみたいなコマンドであれこれやったのを覚えています。めちゃくちゃ時間かかったしドキュメントも微妙だしで超大変でした。今みたいに困ったらAIに聞いちゃおwってのもできないし。
そういうのもあってインプレースアップグレードはやりたくなくて、それに加えてDBもdocker内に押し込みたくて、あとは /home/aries/mastodon/docker-compose.yml みたいにホームディレクトリの中にコンテナのあれこれを置いてるのも正直センスないなぁって感じなので /opt/mastodon/docker-compose.yml みたいに色々整理したいなー、というのがあり。
Xserver VPSで新インスタンスを作るか、別サービスでインスタンス建てるかの二択。
VPS比較(3年ぶり)
円安どころか半導体高騰でどこのサービスも何ともって感じの時代になってしまいました。
LinodeからXserver VPSに移った時の記事
https://blog.asterism.xyz/posts/20230306-000000d3/
ConoHaとさくらとIndigoは以前の記事で書いた時とほぼ変わってないので無し、となると国内サービスだとKagoyaくらいしか移行先が無い訳ですが、当時Kagoyaを避けた理由は今思えば大した話じゃなかった(記事には書かないですしもううろ覚えですけど)のと、あとプランの再編でストレージが値段の割に容量多いというのが魅力的。
4.4.xへのアップデート作業のとき、VPSの容量不足でちょっと危なかったのが頭にありました。KagoyaはRAM3GBでも4GBでも、Xserver VPSの2200円プランの二倍三倍くらいストレージが多いので、まぁこれなら困る事ないだろうなと。
インスタンス移行するとなるとダンプファイルを一時的に置かなきゃとかもありますし、ストレージに余裕があって、かつ今使っているXserver VPSよりも安いKagoya VPSが良さそうです。
RAM3GBプランで月1430円、4GBでも1760円。国内だと最安クラス。一応CPUとメモリだけで見たらシンVPSがもっと安いですが、あっちはその分ストレージケチってるのでどちらを取るかですね。
Mastodonで言うと、例えば外部投稿含めて1週間しかデータ持ちませんよ、みたいな運用するならシンVPSでも悪く無いんじゃないかなーと思います。
そうじゃない場合、私のサーバーでもDB50GBくらい(ダンプすると9GBくらい)掛かるので分散SNS用途でシンVPSはちょっと合わないかなと思います。
あとは色々こだわりたい気持ちが強かった昔と違って今は「とりあえずちゃんと動いてセキュリティ問題なければインフラ構成なんてできる限りシンプルな方がええ」って考えに変わってきてるので、プラットフォーム側FW機能なんかもあんまり気にしなくなりました。
ZeroTierはトラブったから一応辞めて、またdocker使うからufwも微妙だしFWもしょぼいプラットフォーム側ので十分かな。SSHきつめにしばらないとログ汚れるけど…。
そんな感じで色々な方針も合わせてKagoya VPSのRAM3GBプランで一旦決定。うまくいかなかったらまた考えましょうって感じ。
新旧の構成比較
新旧どちらでもメディアファイルについては、S3へアップしてCloudFrontの無料枠(月1TB転送まで無料になったのも結構前ですね)でプロキシしてます。
リバースプロキシはどっちもCaddyのdockerコンテナ使ってます。非常に楽。
旧サーバー
- Xserver VPS 月2200円
- RAM 4GB(無料オプションで+2GBくらい追加出来て、それ入れて実測値5.8GBくらい)
- vCPU 4コア
- NVMe SSD 150GB
- Ubuntu 22.04.5
- プラットフォーム側FWは使ったり使わなかったり。切り替えに1時間かかります
- Mastodonアプリケーション自体はdockerで実行
- PostgreSQLとRedisはaptでインストールしdocker外、ネイティブに実行
- 管理アクセスはZeroTier経由のSSHとプラットフォーム側のVNC
- DBのバックアップはsystemd-timerで簡単なスクリプトを実行
- AWS CloudWatch Logsにログ全部流してた(一か月で消えるようにしてたけどごくまれに$0.3くらい取られてた)
新サーバー
- Kagoya Cloud VPS 月1430円
- RAM 3GB(キャッシュ含む。実際に物理メモリとして見えるのは2.52G)
- vCPU 3コア( Intel(R) Xeon(R) Silver 4416+でした。結構新しい)
- NVMe SSD 400GB
- Ubuntu 26.04
- プラットフォーム側FWはXserver VPSより結構使いやすい(ICMPだけ無理なのが不便だけどちゃんと送信元指定したりできるし反映も早い)
- Mastodonアプリケーション本体もポスグレもredisも全部docker-compose.ymlに押し込む
/opt/mastodon/にdocker-compose.yml置いて、DBのdocker volumeは/var/lib/mastodon/に置いてみた
- 管理アクセスは直SSHとプラットフォーム側VNC
- DBのバックアップはサイドカーコンテナとして作成
- ログは全部journaldで。IAM持ってきてcontainerd設定するのだるかったから
移行手順
ざっくりの手順としては
- Kagoya VPS側でアカウント作ってインスタンス作って初期設定する
- 新サーバー側でdocker-compose.ymlとか設定ファイル色々配置
- 旧サーバー側でMastodon停止、自動バックアップも停止
- 旧サーバーでDBダンプ実行
- 新サーバーにrsyncで転送
- pg_restore
- 旧サーバーと件数やテーブルなどを突き合わせ
- 新しく作ったバックアップ用のサイドカーコンテナがちゃんと動くか確認
- DNS向き先変更
- docker compose up -d
こんな感じ。いたって普通ですね。
VMの準備だけ週末にやって、その後
2026/08/11 11:40頃から作業開始、14時頃にサーバー復旧しました。
DB周りの作業時間としては
- 旧サーバーでのダンプに10分
- 新サーバーへのrsyncに15分
- pg_restoreで20~25分くらい(気づいたら終わってたので細かくは不明)
- VACUUM ANALYZE;に3分
他にサーバー移行後に少し試した感じだと
- バックアップ(ダンプ→S3への転送含むで20分くらい)
- S3からダンプファイルを持ってくるのに10分
- リストアテスト用DBにリストアかけてみて25分
バックアップのやり方変えたのもあったので念のためテストした結果こんな感じ。中身も確認できたので一安心。
Kagoya固有の注意点
今回の記事の本題です。やっぱり初めて使うサービスなのもあって色々ありました。
Kagoyaアカウント
Kagoya ID(Kagoyaのサービスをまとめるアカウントらしい?)を作ったうえで、そのKagoya IDに紐づく形でKagoya VPSアカウントを作ります。
なので実質管理が必要なアカウントは二つです。Kagoya IDとKagoya VPSのアカウント。
両方二要素認証使えるので、ちゃんと設定しましょう。
住所確認メール
アカウント作って初期設定した次の日の夕方に住所確認のメールが届きました。
正しい住所かどうか確認して、メールの返事をしてくださいとのこと。(期日は次の日だったので期限まで六時間。あのさぁ…)
案内に従ってメールの返事を書きました。
SSH設定
インスタンス作成時あるいは作成前に、VPS管理画面から鍵を発行します。
そこで作った鍵を、インスタンス作成時デフォルトユーザー(Ubuntuだったら ubuntu )に設定してくれるという感じでした。
ただこの状態だと、デフォルトのsshd_configではパスワードログインが有効のままです。
とはいえubuntuユーザーはパスワードが未設定なので、パスワードでのSSHは不可能という状態になっています。
またインスタンス作成時に「コンソールパスワード」という項目があります。
こちらはプラットフォーム側のVNCでrootログインするときに使う、rootユーザーのパスワードです。
ちなみにsshd_configでrootログインは無効化されてました。
なので、新しいユーザーを作って管理しようと考えている場合は注意してください。デフォルトではパスワードでのSSHログインが無効化されていないのでユーザー作ったタイミングからログインできてしまいます。
私の場合、新しく作ったユーザー名もパスワードも安全なものだったので特にログイン試行などもされませんでしたが注意が必要なポイントかと。
/etc/ssh/sshd_config.d/10-hardening.conf なんてのを作って
PermitRootLogin no
PasswordAuthentication no
DenyUsers ubuntu
こんなのを設定しました。
新しく作ったユーザーは別途鍵ファイルを設置してSSHログインを確認してから反映しています。
後細かいですが、SSHDの設定変更をするときは接続済みのSSHセッションは残しておくようにしましょう。
設定ミスで一切なにもつながらない、なんて状態になったら最悪インスタンス作成から作業し直しになってしまいます。
ついでに整理した項目
移行ついでにディレクトリ構成とかログの構成、バックアップの取り方なんかを変更しています。
ディレクトリ構成
前述の通り、元々は /home/aries/ の中にmastodonやcaddy、今動いてないマルコフ連鎖botなどのファイルを置いていました。
流石にちょっと…って感じではありますが、ちゃんと動いているものをわざわざ変える理由もあまりなく、2018年からずっとこんな状態でした。
今回は考え直そうとなったため、以下のようにディレクトリ構成を変更しています。
- アプリケーション用
/opt/mastodon//opt/caddy/
- DBなどデータ用
/var/lib/mastodon/
ログ設定
元々はdocker-compose.ymlで、logging driverをawslogsにしてました。
この状態からjournaldであれこれ管理できるようにするために、少しだけ設定を入れてあります。
/etc/systemd/journald.conf.d/mastodon.conf
[Journal]
Storage=persistent
SystemMaxUse=4G
MaxRetentionSec=3month
RateLimitBurst=0
journald側を設定してから、mastodonなどを動かしているdocker-compose.yml側で
x-logging: &logging
driver: journald
options:
tag: "mastodon/{{.Name}}"
こんなのを冒頭に書いて、serviceの中に logging: *logging と書いてます。
Ubuntu Pro
Linuxカーネルへのライブパッチを使って運用少し楽しちゃお、という事で個人用途なら無料で5インスタンスまで使えるUbuntu Proを設定しています。
リソース監視
mackerelの無料アカウントを使っています。
また今回はdocker pluginも使っています。
mackerelのインスタンス追加からワンライナーをコピーしてきてインストールした後で、
sudo apt install mackerel-agent-plugins
とかやって、 /etc/mackerel-agent/mackerel-agent.conf に
[plugin.metrics.docker]
command = "/usr/bin/mackerel-plugin-docker"
を記入した上で sudo systemctl restart mackerel-agent.service
バックアップ用サイドカーコンテナ
今までsystemd-timerとホームディレクトリ以下にポン置きしたスクリプトで動かしてたバックアップをコンテナ化しました。 これでこのサーバーで見ればいいのはdockerだけになったので、今後するかもしれない移行なんかも楽になるかなと。
Dockerfile
FROM alpine:3.24
# postgresql18-client / curl / tzdata は main、rclone は community。
# 公式 alpine イメージは main と community の両方が有効なので追加設定は不要。
RUN apk add --no-cache postgresql18-client rclone curl tzdata \
&& pg_dump --version && rclone version && curl --version
ENV SCHEDULE="0 4 * * 6"
COPY backup.sh /usr/local/bin/backup.sh
CMD echo "$SCHEDULE /usr/local/bin/backup.sh > /proc/1/fd/1 2>&1" > /etc/crontabs/root && exec crond -f -l 8
backup.sh
#!/bin/sh
set -eu
FILE="$PGDATABASE-$(date -u +%Y%m%dT%H%M%SZ).dump"
trap 'rm -f "/scratch/$FILE"' EXIT
pg_dump -Fc -f "/scratch/$FILE"
rclone copyto "/scratch/$FILE" "$RCLONE_DEST/$FILE"
if [ -n "${PING_URL:-}" ]; then
curl -fsS -m 10 "$PING_URL"
fi
rclone.confや環境変数$RCLONE_DEST, $PING_URLはdocker-compose.ymlで渡してます。
healthchecks.ioを使ってみています。
外形監視について
元々freshstatusのカスタムページを使ってましたが今はもう独自ドメイン使いたきゃ有料アカウントが必要になってしまったので一旦無しで。
discord通知くらいはn8nとか使って良い感じにやろうかな?と考えてますが、そもそも自分が使おうとしたとき死んでたら気づくから別によくない?とも思わんでもない。
移行結果
8/11の昼下がりに作業完了してから翌日夕方の今まで、今のところは元気に動いています。(プラットフォーム側に止められたりも無し)
ただメモリが結構ぎりぎりなので、サーバー動いてる状態でバックアップコンテナ動かしてどうなるかなーとか色々見ておきたいポイントはまだまだたくさん残ってるって感じです。
グラフ上は800MB~1GBくらいメモリ余裕あるので大丈夫だとは思うんですけどね。変に負荷掛かった時どうかなーって感じ。

ちなみにswapはデフォで4.7G用意されてました。
今後
今はMastodon4.4.x系を使ってるので流石にそろそろ4.6.x系への更新と、自分用のMastodonクライアントに引用機能とか追加したりとかもしたい。
結構やりたい事多いな…。

