Lambdaカクテル

京都在住Webエンジニアの日記です

Invite link for Scalaわいわいランド

軽量MastodonことPleromaインスタンスを立てたメモ

立てました

PleromaというActivityPubを使ったマイクロブログの実装がある。Elixirで書かれていて、バックエンドとフロントエンドが分離されていて、Mastodonよりやや軽量な感じらしい。

pleroma.social

分散SNSにおける標準的なプロトコルであるActivityPubを採用しているため、MastodonやMisskeyと相互にフォローしたり投稿を見たりできる。こういうことができるのがFediverseの面白いところだ。

MastodonはRubyでMisskeyはNodeだが、PleromaはElixirで書かれている。ElixirだからそのバックにはErlang/OTPがいる。この手のたくさんの通信を捌くようなアプリケーションにはうってつけだろう。また、RDBMSとしてPostgreSQLを採用している(9系以上に対応)。このあたりは他のActivityPub系のマイクロブログサーバと同じ感じだろう(MastodonやMisskeyと同様)。ただし、Mastodonと違ってRedisのインストールが不要なので、より手軽に自分のお一人様インスタンスを立てることができる。

公式にFreeBSDへのインストール方法が用意されているので、それに従ってPleromaインスタンスを立てたメモを残す。FreeBSDではなくLinuxを使っていても共通して使える知見も残しておいた。また、公式にDebianへのインストール手順(日本語)も提供されているので、これも参考にしてほしい。

ちなみにどうしてFreeBSDなのかというと、ZFSによる強力なストレージ管理機能(めちゃくちゃ良いLVMみたいな感じに受け取ってもらえたらと思う)が充実しており、ボリュームごとの暗号化や圧縮などをきめ細やかに設定でき、スナップショットしやすいため。加えて、Dockerほどではないが便利なコンテナ環境もあるためである。なにより、軽量ながらしっかりした安定性が好みだ。

www.freebsd.org

僕のアカウントはここ。

plrm.capslock.dev

構成

以下の構成で自宅サーバにPleromaを立ち上げる。

  • ドメイン: plrm.capslock.dev(ネームサーバはCloudflare管理下)
  • 母艦: 自宅サーバ FreeBSD 13.1
  • 外界との通信とSSL終端: Cloudflare Tunnelにやってもらう
  • 仮想化システム: BastilleBSD(Jailベース)
  • コンテナ: Pleroma本体とPostgresを分離して構成する
  • ストレージ: ZFS(Postgres用にデータセットを構成する)
  • Postgres: 15

主な手順は、

  1. PostgresのためのZFS設定
  2. Postgres構成
  3. Pleroma構成
  4. Cloudflare Tunnelで外部開放

の流れである。

環境

uname -a
FreeBSD *** 13.1-RELEASE-p2 FreeBSD 13.1-RELEASE-p2 GENERIC amd64

BastilleBSD

BastilleBSD とは、FreeBSDの軽量コンテナ環境であるJailにいくつかの追加機能をほどこしたソフトウェア。Jail自体は単なるファイルシステム隔離機構だが、Bastilleを使うことでLinuxのDocker同様に様々なリソースの隔離や管理が行えるようになる。個人的にJailはちょっと管理機構が貧弱だと感じていたり、類似のソフトウェアであるiocageが開発停止(開発者が飽きた)されたりと困っていたので、試してみることにした。

LinuxでPleromaを構築しようとしている人はDockerを使えば良さそう。

また、BastilleBSDはZFSに対応していたり、スナップショットが可能だったりと、Misskeyインスタンスの運用にはそこそこ使えそう。

また、podman同様にデーモンレスなシステムなのもうれしい。

BastilleBSDのインストール

BastilleBSDはpkgでインストール可能だった。

sudo pkg install bastille

起動時に自動的にBastilleが起動するように設定する。

sudo sysrc bastille_enable=YES

ZFSサポート

ZFSサポートはデフォルトでは無効なので有効化する。今回は事前に準備したtankという名前のzpoolを使う。

https://bastille.readthedocs.io/en/latest/chapters/zfs-support.html#zfs-support

sudo sysrc -f /usr/local/etc/bastille/bastille.conf bastille_zfs_enable=YES
sudo sysrc -f /usr/local/etc/bastille/bastille.conf bastille_zfs_zpool=tank

ベースイメージのダウンロード

BastilleBSDの中身はJailなので、ベースとなるFreeBSDのデータを用意しておく。bastille bootstrapサブコマンドで、ベースイメージが用意される。これは最初の一回でよい。

sudo bastille bootstrap 13.1-RELEASE update

PostgreSQL

ZFSデータセットの構成

管理しやすくするためにPostgres用のZFSデータセットを構成する。これにより、のちのちスナップショットやバックアップをやりやすくする。

https://lackofimagination.org/2022/04/our-experience-with-postgresql-on-zfs/ を参考にインストールする。

lackofimagination.org

sudo zfs create -p tank/pleroma/postgres
sudo zfs set compression=zstd tank/pleroma/postgres
sudo zfs set atime=off tank/pleroma/postgres
sudo zfs set recordsize=32k tank/pleroma/postgres

Zstdによる圧縮を有効化し、パフォーマンスのためにatimeを切った。ブロックサイズを32KiBに設定した。

Zstd圧縮アルゴリズムについては、以前に書いた拙記事にて解説している。

blog.3qe.us

コンテナ作成

postgresql用にコンテナを作成する。igb0はネットワークインターフェイスで、環境によって書き換えてほしい。

sudo bastille create pleroma-postgres 13.1-RELEASE 192.168.32.157 igb0
sudo bastille console pleroma-postgres
(at container)
pkg install postgresql15-server postgresql15-contrib

また、RUMインデックスのための拡張がcontribでは入らないので https://github.com/postgrespro/rum から入れる。

github.com

(at container)
pkg install git gmake
git clone https://github.com/postgrespro/rum
cd rum
gmake USE_PGXS=1
gmake USE_PGXS=1 install

いったん母艦に戻って、コンテナにさきほど作成したZFSのデータセットをマウントする。

sudo bastille mount pleroma-postgres /tank/pleroma/postgres /var/db/postgres nullfs rw 0 0
sudo bastille restart pleroma-postgres

さらに、Postgresはいくつかのシステムコールを使うので、Jailからいくつかのシステムコールを許可する。

sudo bastille config pleroma-postgres set sysvmsg=new
sudo bastille config pleroma-postgres set sysvsem=new
sudo bastille config pleroma-postgres set sysvshm=new
sudo bastille sysrc pleroma-postgres postgresql_enable="YES"
sudo bastille restart pleroma-postgres
sudo bastille console pleroma-postgres

ふたたびコンテナに接続し、postgresを初期化する。

(at container)
chown -R postgres /var/db/postgres
service postgresql initdb

DB設定

これからDBを組み上げるので、いったんLANからの接続を受け付けるようにする。 必要に応じて書き換えてほしい。 https://www.postgresql.org/docs/15/auth-pg-hba-conf.html

sudo bastille console pleroma-postgres
(at container)
vi /var/db/postgres/data15/pg_hba.conf
host    pleroma             pleroma             192.168.32.0/24            trust
host    all                 postgres            192.168.32.0/24            trust

次にストレージまわりの設定。

By design it is impossible to write partial pages on ZFS

とのことなので、full page writesを無効化する。

(at container)
service postgresql start
psql -d postgres -U postgres
ALTER SYSTEM set full_page_writes=off; CHECKPOINT;

これでPostgresコンテナの準備は完了。

Pleroma (backend)

ここからは実際にPleromaをインストールしていく。Pleromaはフロントエンドとバックエンドが分離した構成になっていて、好みのフロントエンドを選べるようになっているけれど、特に何もしなくてもデフォルトのフロントエンドがインストールされる。

ここからは基本的に https://docs-develop.pleroma.social/backend/installation/freebsd_en/ の指示に従うが、SSL終端としてNginxを使わずCloudflare Tunnelを使うのでNginxや証明書まわりの手順はスキップする。

まずはPleroma用のBastille jailを生成する。

sudo bastille create pleroma 13.1-RELEASE 192.168.32.158 igb0
sudo bastille console pleroma

必要なソフトウェアをインストールする。

(at container)
pkg install elixir postgresql15-client postgresql15-contrib git-lite sudo gmake cmake ImageMagick7-nox11 ffmpeg p5-Image-ExifTool

ユーザ作成

pleroma用のユーザを作成する。

(at container)
pw add user pleroma -m
echo 'export LC_ALL="en_US.UTF-8"' >> /home/pleroma/.profile
su -l pleroma

clone

リポジトリをcloneしてくる。

(as pleroma)
cd $HOME
git clone -b stable https://git.pleroma.social/pleroma/pleroma.git

インスタンス生成コマンドを実行するとインタラクティブに色々質問されるので、ドメイン名などを指定し、初回の最小限の設定を行う。RUMインデックスというPostgres拡張を使い、レンジクエリの効率性を上げる選択もした。

(as pleroma)
cd /home/pleroma/pleroma
mix deps.get
MIX_ENV=prod mix pleroma.instance gen
cp config/generated_config.exs config/prod.secret.exs

自動的に色々設定されたconfig/setup_db.psqlが生成されるので、これを使ってDBを初期化する。

(as root)
cd /home/pleroma/pleroma
psql -h 192.168.32.157 -U postgres -f config/setup_db.psql

/var/db/postgres/data15/pg_hba.confの設定を再確認し、セキュリティを強化したなら、初回マイグレーションを開始する。

su -l pleroma
(as pleroma)
cd /home/pleroma/pleroma
MIX_ENV=prod mix ecto.migrate

Startup Script

起動用スクリプトを作成する。PleromaはFreeBSD用の起動スクリプトを用意してくれているので、コピペでよい。

その前に、いったんサーバを起動して全てのコンパイルを終わらせる(Elixir(Erlang)なので実行時にコンパイルする?)。

su -l pleroma
cd $HOME/pleroma
MIX_ENV=prod mix phx.server

(なんかRUMうまく動いてないよと言われたので指示に従って有効化する)

MIX_ENV=prod mix ecto.migrate --migrations-path priv/repo/optional_migrations/rum_indexing/

すると無事起動したので、しばらく落ち着かせてからサーバを停止させ、起動スクリプトをコピーしてくる。

(as root)
cp /home/pleroma/pleroma/installation/freebsd/rc.d/pleroma /usr/local/etc/rc.d/pleroma
chmod +x /usr/local/etc/rc.d/pleroma
sysrc pleroma_enable=YES
service pleroma start

最後に自分のユーザを作成する。

(as root)
sudo -Hu pleroma MIX_ENV=prod mix pleroma.user new windymelt windymelt@3qe.us --admin

すると画面にパスワードリセットリンクが表示されるので、これをメモしておく。 まだトンネルの設定をしていないので、アクセスはできない。

user windymelt created
Admin status of windymelt: true
Generated password reset token for windymelt
URL: https://plrm.capslock.dev/api/v1/pleroma/password_reset/TOKENTOKENTOKEN...

cloudflared

さて、サーバを立てるにあたって誰もが嫌がるのがSSL終端まわりのゴタゴタだが、文明の利器を使うことにする。

CloudflareはCloudflare Tunnelというトンネリングツールを用意しており、ngrokのような感じでLAN内のサーバの特定のポートをインターネットに公開することができる。今回はplrm.capslock.devへのアクセスをPleromaサーバに転送してもらう。

ちなみにこれを行う際は、ドメインのネームサーバをCloudflareの管理下に置いており、Cloudflare上にウェブサイトの設定を済ませている必要がある。こうすることで自分の好きなホスト名にPleromaを繋ぐことができる。

今回は簡単のためにPleromaコンテナの中でcloudflaredを動かして、127.0.0.1:4000plrm.capslock.devに飛ばしてもらう。

(in container)
pkg install cloudflared
cloudflared update
cloudflared tunnel login

あとはだいたい公式ドキュメントの通りにする。

developers.cloudflare.com

トンネル設定

pleroma-backendという名前でトンネリングプロファイルを作成する。

cloudflared tunnel create pleroma-backend
vi ~/.cloudflared/config.yaml
tunnel: GUIDがここに入る

credentials-file: /root/.cloudflared/GUIDがここに入る.json

ingress:
  - hostname: plrm.capslock.dev
    service: http://127.0.0.1:4000
  - service: http_status:404

上掲のようにconfig.yamlを設定することで、plrm.capslock.dev127.0.0.1:4000にフォワードされる。

加えて、plrmというホストをDNSに登録するべく、DNS設定用コマンドを呼ぶ。

cloudflared tunnel route dns pleroma-backend plrm.capslock.dev

これで動作確認をする。

cloudflared tunnel run pleroma-backend

トンネルが開通することを確認したら、リセットリンクからパスワードを設定する。

加えて、このインスタンスはお一人様であって新規登録はさせないので、いったん、 https://ホスト/pleroma/admin/#/settings/instance に遷移し、Registrations openをオフにし、submitする。

Startup Script

コンテナが起動するときに自動的にトンネルが起動してほしいので、rc.confに設定を追記してトンネルをバックグラウンドで起動する。

sysrc cloudflared_enable=YES
sysrc cloudflared_conf=/root/.cloudflared/config.yaml
sysrc cloudflared_mode="tunnel run"
service cloudflared start

トンネルが開通していることを確認する。

cloudflared tunnel info pleroma-backend

これでplrm.capslock.devの立ち上げが完了した。

感想

Elixir特有の箇所はあまり慣れていなくて独特のコマンドだな〜などと思ったりもしたものの、基本的にポチポチするだけでインスタンスを作ることができた。

そしてCloudflare Tunnelはかなり便利。このまま1ヶ月運用してみて、費用がどうなるか確認してみたい。便利なngrokとして普通に運用できそうな雰囲気を感じた。

いずれにせよ、引っかかったり困ったりする箇所はあまりなかった。

Pleromaはデフォルトで新規登録を開放する設定になっているので、そこはちょっと注意が必要だなと思った。

また、実際のメモリ使用量は、Elixirのランタイム(Erlang BEAM)が512MiBを切る程度、加えてPostgresが数百MiB、さらにCloudflaredが64MiB程度を消費しているくらいで、ほどほどに軽量な印象がある。

plrm.capslock.dev

SNSとして使ってみた感想としては、やはりサクサク動いて面白いし、欲しい機能はだいたいあるな、という感じ。最近絵文字を付ける機能も追加されたので、ややMisskeyに近い感じになっている。TwitterやMastodonみたいにintent用の画面を出す方法が分からないので、発見したらシェアボタンも作れるな〜、と思った。

★記事をRTしてもらえると喜びます
Webアプリケーション開発関連の記事を投稿しています.読者になってみませんか?