2024/02/25

DockerなしでBlueskyのPDSを建てる方法

晴れてBlueskyの連合がスタートした。厳密には、我々はBlueskyの構成要素の一つであるPDS(Personal Data Storage)をセルフホスティングできるようになった。これにより各ユーザは自分のデータを自らの管理下に置くことができる。また、他ユーザの登録を許可しているPDSに移動すれば権威的ではない他の個人にデータを預けられる。

一方、MastodonやMisskeyなどと異なるのは、モデレーションやフィードの生成、固有IDの半永続的な管理を担う上位の構成要素が存在しているところだ。これらは膨大な計算資源を要するため、個人でのホスティングは実質不可能とされている。つまり、PDSは文字通り個人データの保管庫であって、あらゆる制約から逃れられるわけではない。公式のルールに違反する投稿は依然として処罰の対象になりうるし、まだ前例はないが他のPDSとの連合から排除される可能性も考えられる。

とはいえ従来の中央集権型SNSと比べるとデータを自主管理する裁量があり、分散型の競合と比べて透過性の高い体験が得られる点はまずまずの落としどころと言える。大半のユーザには特定の相手が分散しているかどうかさえ判別がつかない。現にMastodonやMisskeyには見向きもしなかった各企業やインフルエンサーがこぞって参入してきている現状を踏まえると、僕のような分散主義者的には中途半端でも市井の需要には適っているのかもしれない。

以下に示すサーバ構築の方法は他の用途でサーバを運用している人向けの指南書であって、初心者に適した内容ではない。PDSの構築のためにまっさらなサーバを契約した人はSSH接続やファイアウォールなどの最低限の設定を済ませた上で、GitHubのリポジトリにあるinstaller.shを実行すれば簡単に建てられる。

今回の方法はなんらかの理由で80番/443番ポートが埋まっている構築にサブドメインを用いるつもりでいる有料のSSL証明書を買いたくないその他、Dockerを使いたくない、などといった条件を満たしてる変人でなければ、ほとんど行う必要のない煩雑な手続きを踏んでいる。このことは予め了承してほしい。

ちなみに、ぶっちゃけると具体的な記述部分はこのページをかなりパクっている。英語に抵抗がない人はこっちを読んだ方が絶対に早い。本稿はあくまで日本語情報の提供を目的にしている。

nginxのリバースプロキシを書く

 1server {
 2  listen 80;
 3  server_name あんたのドメイン.com *.あんたのドメイン.com;
 4  return 302 https://$host$request_uri;
 5}
 6
 7server {
 8  listen 443 ssl http2;
 9  server_name あんたのドメイン.com *.あんたのドメイン.com;
10  ssl_certificate     /etc/ssl/certs/mystech.ink.pem;
11  ssl_certificate_key /etc/ssl/private/mystech.ink.key;
12
13  location / {
14    include proxy_params;
15    proxy_http_version 1.1;
16    proxy_set_header Upgrade $http_upgrade;
17    proxy_set_header Connection $connection_upgrade;
18    proxy_pass http://localhost:4567;
19  }
20}

まずは以上の形式でリバースプロキシを書く。もし利用するドメインがTLDで、かつDNSサーバがCloudflareならSSL証明書の部分は不要だ。だが不幸にもaaa.bbb.comのようなサブドメインをベースに利用するつもりでいる人はここで工夫がいる。なぜならベースドメインがaaa.bbb.comだと各ユーザアカウントごとに作られるドメインがXXX.aaa.bbb.comと三階層になってしまう。

Cloudflareは二階層(aaa.bbb.com)までしか無料でSSL証明書を配給してくれないため、このままサーバを建てるとユーザアカウント部分が不正なURLと見なされて機能しないのである。これを無料で解決するには二つの方法がある。一つ目はXXX.aaa.bbb.comの部分だけ別途無料のSSL証明書を取得することだ。一番手堅く正当な手段と考えられる。

逆に、二つ目は不正上等で建てた上で、カスタムハンドル機能を用いて他の有効なドメインにユーザ名を置き換えるやり方だ。(ccc.bbb.com)建てた本人しか使わないPDSならこのテクニックは少々狡猾ながら合理的だろう。一度置き換えてしまえば名前解決に使われるのはカスタムハンドルの方なので実際のところ問題はなにも起こらない。

もちろん本稿では二つ目の方法を紹介する。リバースプロキシを書き終えたらnginx -tで文法をチェックした後にsystemctl restart nginxで再起動を行う。

データの取得と.envファイルの作成

ここからはユーザ権限で作業を行う。任意のディレクトリ下にてgit clone https://github.com/bluesky-social/pdsを実行してPDSの構築に必要なデータを取得する。/pds/serviceに移動後、下記の要領で.envファイルを作る。

 1PDS_HOSTNAME="あんたのドメイン"
 2PDS_JWT_SECRET="乱数生成"
 3PDS_ADMIN_PASSWORD="乱数生成"
 4PDS_PLC_ROTATION_KEY_K256_PRIVATE_KEY_HEX="乱数生成"
 5PDS_DATA_DIRECTORY=./data
 6PDS_BLOBSTORE_DISK_LOCATION=./data/blocks
 7PDS_DID_PLC_URL=https://plc.directory
 8PDS_BSKY_APP_VIEW_URL=https://api.bsky.app
 9PDS_BSKY_APP_VIEW_DID=did:web:api.bsky.app
10PDS_REPORT_SERVICE_URL=https://mod.bsky.app
11PDS_REPORT_SERVICE_DID=did:plc:ar7c4by46qjdydhdevvrndac
12PDS_CRAWLERS=https://bsky.network
13LOG_ENABLED=true
14NODE_ENV=production
15PDS_PORT=4567

乱数生成と書かれているところは文字通り乱数で生成する。PDS_JWT_SECRETの部分はopenssl rand --hex 16で、他の二つは以下のコマンドをそれぞれ打って作る。

1openssl ecparam --name secp256k1 --genkey --noout --outform DER | tail --bytes=+8 | head --bytes=32 | xxd --plain --cols 32

別に桁数を満たしていればなんでもいいじゃないか、と思っていたが、どうやら生成アルゴリズムにSecp256k1(楕円曲線暗号)を用いていないとダメらしい。このアルゴリズムはBitcoinにも使われているんだとか。怒られが発生した場合はおそらくxxdが入っていないのでapt install xxdで適宜導入する。

PDSの稼働

/pds/serviceにてpnpm install --production --frozen-lockfileを実行する。pnpmを導入していない場合はnpm install -g pnpmで入れる。データ格納用のフォルダもmkdir -p data/blocksで作成しておく。最後に、systemdのユニット定義ファイルを書く。以降はroot権限での作業となる。

 1[Unit]
 2Description=Bluesky PDS Service
 3
 4[Service]
 5WorkingDirectory=/home/あんたのユーザ名/pds/service
 6ExecStart=/usr/bin/node --enable-source-maps index.js
 7Restart=no
 8EnvironmentFile=/home/あんたのユーザ名/pds/service/.env
 9
10[Install]
11WantedBy=default.target

このファイルはpds.serviceなどの名前で/etc/systemd/system/直下に保存する。systemctl daemon-reloadを実行してからsystemctl start pdsでサーバを稼働させる。一連の設定が正しく行われていれば、ブラウザでベースドメインにアクセスした時に下記のメッセージが表示される。

1This is an AT Protocol Personal Data Server (PDS): https://github.com/bluesky-social/atproto  
2Most API routes are under /xrpc/

以上でサーバの構築作業は完了である。

pdsadminの使い方

アカウントの作成などを行えるpdsadminコマンドだが、インストールスクリプトを用いずに構築した我々が使うと環境変数を読んでくれないため正しく動かない。そこで/pds/pdsadmin/に移動してからPDS_ENV_FILE=../service/.env bash account.sh listの形式で.envファイルを直接指定して実行する。ちなみにこれはPDSに登録されているアカウントの一覧を表示してくれる。

1$ PDS_ENV_FILE=../service/.env bash account.sh list
2
3Handle             Email          DID
4riq0h.mystech.ink  [email protected]  did:plc:dqlihaiieq7lpjkwv6x62y4a

アカウントを登録する際は同じ要領でPDS_ENV_FILE=../service/.env bash account.sh createを実行する。当然、この時に作成したアカウントはベースにサブドメインを利用していると不正な状態になっているので、通常と同様にbsky.appでカスタムハンドルをあてがう必要がある。

なお、カスタムハンドルを設定しなくてもユーザのフォローや投稿は可能だが、他のユーザからは常に「invalid handle」と表示されていて明らかに異常者にしか見えない。趣味でなければ正気に戻しておく方が無難だろう。

アップデートの方法

標準で用意されているpdsadmin updateはDocker環境を前提にしているゆえ今回の構築手法では機能しない。代わりにリポジトリをgit pullで更新して実質的にアップデートを行う。更新後は忘れずに依存ファイルを再取得する。

1$ cd pds
2$ git pull
3$ cd service
4$ pnpm install --production --frozen-lockfile
5$ systemctl restart pds

おわりに

とりあえずこれでBlueskyユーザはデータを自主管理する裁量を得た。まだ真の分散には程遠いが偉大な一歩には違いない。次回以降はPDS間のアカウント移行をテストする予定だ。

©2011 Rikuoh Tsujitani | Fediverse | Bluesky | Keyoxide | RSS | 小説