鯖缶の務め is 何?

はじめに

おつかれさまです、村雲です。

ここしばらくは本当に色々あり、Misskeyはよき現実逃避として機能していたかと思われます。 関わってくださった皆様、いつもありがとうございます。いや本当に。

辛うじて動ける隙間時間みたいなものをかき集めて自分の個人鯖を構築してからは、 こちらのブログもどきそっちのけでマイクロブログのほうをやっちゃっておりますね。 こちらのほうが私に合っているのでしょうか?

ともかく、今回は私のできたてほやほやな個人鯖 「つじごや」 の運用について書いていこうかと。 と言ってもおひとりさま前提の手抜き仕様なんですけど。

背景: うちの構成

本編の前に、うちの現環境について軽くさらっていこうかと。

つじごや鯖構成図

リバースプロキシだけさくらのVPSに置き、残りをオンプレミス (越したばかりの自室) で構築、 両者をWireGuard VPNのトンネルで繋ぐようにしました。

一応はVのものを自称している以上、 グローバルIPアドレスは隠しておきたいなっていう意図です。

VPS側

さくらのVPSの最安である 512M プランですが、Nginxだけ、かつ今の規模なら余裕そうです。 おかげさまでIPv4 / IPv6両方のグローバルアドレスを持った子が月643JPYです。 お得 (注1)。

それと初めてRocky Linux 9を使いました。 そこそこ新しいパッケージが降ってくるCentOS、みたいな使用感?

オンプレ側

DeskminiっていうミニPCなのですが、以前VMを試していたらちょっと重く感じたので、 より軽量なLinux Container (LXC) とLXDで仮想化しています。 DeskminiというかCPUがちょっと古くて4コア8スレッドなので多分それなんですけれども (注2)。

それとホストOS側・コンテナ側共にディストロはOpenSUSE Tumbleweedにしました。 Btrfsが使えれば何でもいい説はある。

ほんへ

nexryaiさまのこちらの記事 がたいへん充実しておりますので、ぜひご一読を。

以下に私のガバガバ運用をまとめます。

  1. ファイアウォール
  2. バックアップ
  3. パッケージ更新

みたいに分けてみました。

1. 公開サーバを安全にする

セキュリティなんもわからん……

うちの場合、主に直接外に公開しているVPS側の対策になります。

SSHポートを外部から隠す

22/TCP以外に変更しても /var/log/secureが埋まりがちだったので、 グローバルIPへ直接SSHしに行くのではなく、トンネルを経由させるようにしました。

うちだと少々回りくどいですが、 上図のメインPCから一度LXCインスタンスを踏み台にして、 それからトンネルの向こうの鯖に、といった具合に。

↓ Main PC: ~/.ssh/config

Host さくらのVPS               # お好きな名前で
    ProxyJump LXCインスタンス   # 別途configに記述
    Port SSHのポート番号        # 22番に戻していない
    Hostname A.B.C.D          # VPSのLAN用アドレス、今回はDummy I/Fを使用
    User ログインユーザ名
    IdentityFile /path/to/鍵_ed25519
    IdentitiesOnly yes

そしたらファイアウォールでSSHのポートを塞いじゃいましょう。 Rockyの標準であるFirewalldを使っています。

## さくらのVPSにて
# firewall-cmd --remove-service=ssh --zone=public

## 一時的に塞いでもSSHが途切れないことを確認してから
# firewall-cmd --remove-service=ssh --zone=public --permanent

それとトンネルはトンネルで 公開ポート番号をデフォルトから変更するとか、 時々更新をチェックするとか、必要な対策を施せるとよいかなと。

WireGuardのログを確認する

デフォルトだと記録されないようですが、 ダイナミックデバッグなるものを有効化することでカーネルリングバッファに出力させて dmesgで読めるようになります。

## さくらのVPSにて、設定をする
# echo module wireguard +p > /sys/kernel/debug/dynamic_debug/control

## ログを読む
$ dmesg | grep wireguard  # インターフェース名で絞ってもいいかも

例えば自分以外の誰かが侵入を試みていたら

$ dmesg | grep wg0 | grep -v Keypair | grep -v 自分の端末のIPアドレス

みたいな感じで絞れば気づけるかも? (まだ観測していない)

Firewalldでブラックリストを作る

さっきのWireGuardや /var/log/nginx/access.logなどで怪しい履歴を見つけたら、 IPアドレス単位でアクセスを拒否できるようにしましょう。

## さくらのVPSにて、IPv4用のipsetを作成し対象をdropさせる
# firewall-cmd --permanent --new-ipset=blacklist4 --type=hash:ip
# firewall-cmd --permanent --zone=public --add-rich-rule='rule source ipset=blacklist4 drop'

## IPv6用はこんな感じ
# firewall-cmd --permanent --new-ipset=blacklist6 --type=hash:net --option=family=inet6
# firewall-cmd --permanent --zone=public --add-rich-rule='rule source ipset=blacklist6 drop'

## ブラックリストへの登録 (IPv6のほうもipsetを合わせるだけ)
# firewall-cmd --permanent --ipset=blacklist4 --add-entry=A.B.C.D

SELinuxを有効にする

これどっちかと言うと構築時の話ですね。 さくらのVPSのスタートアップスクリプトのほうで有効化しちゃったので。

その場合、sshdやnginxがブロックされてしまわないように コンテクストやブールをいじってあげる必要があるんですね。

以下を読みながらなんとかしました。 CentOS用の記事がまんま使えてよきですね。


2. バックアップを取ってインシデントに備える

ことActivityPubサーバに関しては、 DBが吹っ飛ぶと同じドメインネームが使えなくなる仕様があり。 先ほどの図のオンプレ側をいじります。

コンテナを丸ごとバックアップする

LXCのストレージバックエンドでもBtrfsを使わせることで、 スナップショット機能がこれを利用したものになるはずです。多分。

コンテナの一時停止・スナップショット取得共に時間は掛からず、十数秒のダウンタイムで済みそうです。 ただ、これだけではストレージ破損で逝ってしまうので (注3)、

  1. スナップショット取得
  2. スナップショットからイメージを生成
  3. それを別のSSDにエクスポート

までSystemd Timerで毎日実行しています。

↓ Deskmini: ~/work/backup_lxc.sh

#!/bin/bash

instance=$1  # コマンドラインから渡してね
now=$(date +%y%m%d_%H)
dir=/mnt/別のSSD/exported/$instance/

lxc snapshot $instance $now
lxc publish $instance/$now --alias $instance_$now
lxc image export $contain_$now $dir

lxc image delete $contain_$now

先日レストア試験で復旧できそうってこともざっくりですが確認が取れました (N=1)。

添付ファイルを別途rsyncする

これまたLXDの機能お試しを兼ね、ストレージボリュームなる仮想ディスクをさっきの別SSDの上で作り、 コンテナにattachしています……つまりさっきのコンテナのデータとは別に管理しているんですね。

コンテナの中からはいつも通りmountしているように見えるので、画像など添付ファイルを置いている misskey/files/をシンボリックリンクにしてあげるとその保存先を変えられる訳ですね。

こちらは将来的に肥大化することも考え、ただのrsyncで別のPCと同期させることにしました。 メインPCのHDDに (比較的) 余裕があったので「たまにうっかり電源切ってて失敗してもええか」 くらいの気分で (注4)。 毎晩22時なら起きているでしょう。多分。

↓ LXC instance: /etc/systemd/system/mi-data-bak.service

[Unit]
Description = Backup https://mi.tsujigoya.net/ media files

[Service]
Type = oneshot
User = misskey
Group = misskey
ExecStart = /usr/bin/rsync -auv /mnt/ストレージボリューム/ メインPC:/mnt/d/バックアップ/

↓ LXC instance: /etc/systemd/system/mi-data-bak.timer

[Unit]
Description = Backup https://mi.tsujigoya.net/ media files

[Timer]
OnCalendar=*-*-* 22:00:00
Persistent=true

[Install]
WantedBy=timers.target

rsyncのリモートホスト名には、~/.ssh/config で設定したものが使えます。 パスワード入力を不要にしておけば簡単に自動化できるという寸法ですね。

先述のコンテナバックアップも ExecStartと時間が違うくらい。長いので省略。


3. パッケージを新しくする

手動。再起動が必要になったりしますからね。

まれにニュースサイトやTLで脆弱性や障害について情報が流れてくることもあるので、 それとな~く普段から意識しておくのも良いかもしれません。

OSのパッケージマネージャで更新をかける

RockyはともかくTumbleweedに関しては、 同じローリングリリースのArch Linuxを1年ほど放置した結果キーイングに失敗して 「あれ鍵の再生成どうやんだっけな~?」 とかいって調べ始める、みたいなあるあるネタがあるのでちょっと用心した方がいいかも。

なお、OpenSUSEの場合はzypper upのタイミングで勝手にスナップショットしてくれます。 心臓に優しいですね。

Misskey側の更新をかける

手動インストールなので https://misskey-hub.net/docs/install/manual.html の通りですね。

「Node.jsとかどうやって入れたっけ?」 なんてのも忘れないようメモっておくと後々困らないでしょう。


今後やりたいこと

先述のとおりだいぶやっつけなもんで……

例えば今後オンプレ側でMisskey以外のサービスを増やして、 それを同じリバースプロキシで公開するなら、 WireGuardは別のコンテナに分けたほうがよいでしょうね。

あとストレージが今までそれほど使っていなかった分、 あまり手元に残っていないのでNASが欲しくなってきました。

サーバの負荷 (ロードアベレージ) やRAMの使用率はかなり余裕があるので、 もし私の体調が良くなったりしたら、 招待制のまま利用者を募って実際にユーザを収容してみるのもいいかもしれません。

おわりに

思ったより長くなっちゃいましたね。3,000字とか久々に書きました。

また140字くらいに収まるつぶやきがメインになりそうですが、 たまにはこうしてマイクロじゃないほうのブログをやってみるのも楽しいものですね。 ともかく、これからも気ままにやっていく所存でございますので、どうぞよしなに。

あっ、よろしければチャンネル登録の代わりに SNSのフォローをお願いいたします。村雲ルネでした。


2023.09.09 投稿、直後に誤字修正、注釈追加

注釈

  1. ぶっちゃけ好み。探せばもっと安いVPSサービスは幾らでもあるはず、 でも「最安プランだとIPv6非対応」なんてのもちょいちょい見かけるような?

  2. 当時Deskmini A300に載せられるもので一番良さそうだった Ryzen 5 3400Gという石です。

  3. Btrfsについてはこちらの資料が詳しいです。ソフト的な変更をすぐに巻き戻せるイメージ。 https://event.ospn.jp/osc2020-online-spring/session/61353

  4. 今回WSL2めがけてSSHしているのですけれども、 Windows側でファイアウォールを開けつつnetshでポートフォワーディング……でよかったのかなこれ?