僕は一寸
2024/11/04

Bluesky の PDS サーバーを建てる

特定の Big-world に依存することを前提とした AT Protocol の実装が果たして本当に分権的かというと,実際にはそれは分散的であるに過ぎないようにも思われる。どうやら Bluesky は発表当初 1 や AT Protocol が ADX と呼ばれていた頃のものからは離れ,より「bsky.app のための実装」という色を強める方向に進んだらしい。しかし,Bluesky のアプローチが (特に MastodonPleroma といった ActivityPub の実装たちに対して) スケーラビリティに優れていることは事実であり,その Twitter alternative としての取っつきやすさは「脱出先」を探す人々や,企業の公式アカウントには魅力的に映ったらしい。そこにはネットワーク外部性が物をいう microblogging service におけるトレードオフの関係が横たわっている。

とにかく,Bluesky にアカウントを持つ知り合いが増えた。人質を取られてしまうと,おちおち「一家に一台 ActivityPub 実装」などと能天気なことを宣うばかりにもいかない。いつの間にかセルフホストした PDS の連合が許可されるようになっていた 2 し,Small-world の所有という妥協点でひとつ Bluesky に飛び込んでみようと決めた。

といった具合で公式ドキュメントが想定する条件とは多少ズレがあるため,installer.sh の中身を読みながら手動でセットアップを行った。以下はその記録である。端折っている点もあるので,参考にする場合は公式ドキュメントを併せて参照されたい。

フォルダ構成

.
└── bsky/
    ├── pds/
    │   ├── pds.env
    │   └── ...
    ├── pdsadmin/
    │   ├── account.sh
    │   └── ...
    └── compose.yaml

上述のような構成にした。好きな構成にすればいいだろう。

nginx の設定

server {
  listen 80;
  listen [::]:80; // IPv6 に関する記述は特に見当たらないが,どうせ Cloudflare を経由するのであってもなくても特に問題は起きないだろう
  server_name pds.example.com *.pds.example.com; // PDS を建てるドメイン
  return 302 https://$host$request_uri;
}

server {
  listen 443 ssl http2;
  listen [::]:443 ssl http2;
  server_name pds.example.com *.pds.example.com; // PDS を建てるドメイン
  ssl_certificate     /etc/certs/example.com/cert.pem; // 証明書
  ssl_certificate_key /etc/certs/example.com/key.pem;

  location / {
    include proxy_params;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $connection_upgrade;
    proxy_pass http://localhost:4567;
  }
}

nginx でリバースプロキシを設定する。私は Cloudflare を使っているので Cloudflare のオリジン証明書を指定している。

DNS 設定も,上記の設定に対応するように pds.example.com および *.pds.example.com に A レコードや AAAA レコードを張ってやればいい。

ところで,Cloudflare の無料プランでは,*.pds.example.com のような 3 階層以上のサブドメインのエッジ証明書を発行してくれない 3 。Bluesky は各ユーザーごとに misoni.pds.example.com といった具合にサブドメインを割り当てるので,そのままアカウントを作成すると当然ながら不正なものとみなされ,プロフィールが表示されなくなる (正確には,Invalid handle とだけ表示される)。

この問題を無料で解決する一つの方法は,ZeroSSL や Let's Encrypt などのワイルドカード証明書を別途用意することである。

しかし,管理しなくてはならない証明書の数は少なければ少ないほうが良いに決まっている (?) ので,ここではお一人様 PDS にのみ許される小賢しい技を用いる。Invalid handle 表示になることを承知の上でアカウントを作り,bsky.app 側からカスタムハンドルとして他の有効なドメインをあてがうのである。変更さえしてしまえば,その後のハンドル解決に用いられるのもカスタムハンドルになり,プロフィールも正常に表示される。

ちなみにここで PDS と同じドメインをハンドルに使ってしまうと,同じ PDS にログインしている場合に内部でのハンドル解決が優先されてしまい,自分のプロフィールが表示されなくなってしまうらしいので注意されたい。

Docker Compose の設定

version: '3.9'
services:
  pds:
    container_name: pds
    image: ghcr.io/bluesky-social/pds:0.4
    network_mode: host
    restart: unless-stopped
    volumes:
      - type: bind
        source: ./pds
        target: /pds
    env_file:
      - ./pds/pds.env

既に nginx がホストで動いているので Caddy を消し,更新は手動で行うので watchtower を消し,バインドマウントのホスト側の位置をルートディレクトリからカレントディレクトリに変えている。

pds.env ファイルの設定

PDS_HOSTNAME=pds.example.com # PDS を建てるドメイン
PDS_JWT_SECRET=*** #openssl rand --hex 16
PDS_ADMIN_PASSWORD=*** #openssl rand --hex 16
PDS_PLC_ROTATION_KEY_K256_PRIVATE_KEY_HEX=*** #openssl ecparam --name secp256k1 --genkey --noout --outform DER | tail --bytes=+8 | head --bytes=32 | xxd --plain --cols 32
PDS_DATA_DIRECTORY=/pds #念の為: Docker コンテナ内のディレクトリなのでこのままでいい

# PDS_BLOBSTORE_DISK_LOCATION=/pds/blocks
PDS_BLOBSTORE_S3_BUCKET=bsky # R2 のバケット名
PDS_BLOBSTORE_S3_REGION=auto
PDS_BLOBSTORE_S3_ENDPOINT=*** # R2 のエンドポイント
PDS_BLOBSTORE_S3_ACCESS_KEY_ID=*** # R2 の Access Key
PDS_BLOBSTORE_S3_SECRET_ACCESS_KEY=*** # R2 の Secret Access Key

PDS_BLOB_UPLOAD_LIMIT=52428800
PDS_DID_PLC_URL=https://plc.directory
PDS_BSKY_APP_VIEW_URL=https://api.bsky.app
PDS_BSKY_APP_VIEW_DID=did:web:api.bsky.app
PDS_REPORT_SERVICE_URL=https://mod.bsky.app
PDS_REPORT_SERVICE_DID=did:plc:ar7c4by46qjdydhdevvrndac
PDS_CRAWLERS=https://bsky.network
LOG_ENABLED=true

PDS_PORT=4567

コメントにあるコマンドを実行して埋めていけば設定は完了する。R2 のリージョンは auto しか無い。R2 API の権限は Object Read & Write で,バケットも PDS サーバー用に作ったものだけ指定すればいい。権限は小さければ小さいほど良い。

PDS サーバーの起動に必要な設定は以上。docker compose up -d で起動する。ブラウザからアクセスして This is an AT Protocol Personal Data Server... と表示されれば成功。

pdsadmin について

pdsadmin のサブコマンドの中身は GitHub に置いてあるシェルスクリプトなので,これらを wget なり git clone なりして,PDS_ENV_FILE を適切に書き換えるなり実行時に変数を渡すなりすればいい。

アカウントの作成時は account create で対話していけばいい。ログイン後にカスタムハンドルの設定を忘れずに。_atproto. に指示された TXT レコードを設定すればカスタムハンドルの設定は完了する。

$ PDS_ENV_FILE=../pds/pds.env ./account.sh list
Handle     Email              DID
misoni.me  [email protected]  did:plc:sb2whxh6nvmdmxvlobyekii4

上手く行けばこのような結果が帰ってくる。

私のアカウント: https://bsky.app/profile/misoni.me

参考サイト

ほぼ丸パクリ。感謝感謝,感謝ですよー!

2

「許可」されるまで連合できなかったという事実は,すでに私の Bluesky への失望を誘うに十分な要素ではあるが,さておき。

3

オリジン証明書については *.pds.example.com といった 3 階層のものも無料で発行できる。

← 野外フェスに行ったら刺傷事件が起きてフェスが中止になった これ以上新しい投稿はありません