📖

ローカル上に構築した仮想マシン上のMisskey同士を連合させてみる

2024/12/10に公開

Misskey Advent Calendar 2024 10日目の記事です。

前提

この記事は、手元のローカルPCに複数の仮想マシンを構築し、その上にMisskeyをのせてそれらを連合させてみよう!…という内容になります。

ターゲットとする方々

本記事の内容は 手元のPCでActivityPub(連合)周辺の動作を試してみたい方 向けの参考情報としてまとめています。

ターゲットとしない方々

本記事の内容は 本番運用を想定したMisskeyの構築手順を探している方 向けの参考情報としては想定しておりません。

なぜかというと、手順の途中で発行する自己署名証明書が本番運用で耐えられる代物ではないからです。具体的には、中間者攻撃などのリスクがあること、特殊な手順を踏まないとブラウザやNodeが通信を拒否するなどの制約があることが挙げられます。

詳細については本筋から逸れるため割愛とさせていただきますが、以下のサイトや記事が参考になるので興味がある方は覗いてみるとよいかもしれません。

詳しく書かないこと

下記に記載することについてはそもそも記載しないか、大幅に端折った内容となることをあらかじめご承知いただけると幸いです。なぜなら、それぞれのトピックだけで1つから複数の記事が書けてしまうほどの内容になることが予想されるからです…。

  • Misskeyそのものや詳細な構築手順・設定内容について
  • PostgreSQL、Redis、nginxなどのミドルウェアそのものや詳細な構築手順・設定内容について
  • SSL/TLSとはなんぞや
  • 自己署名証明書とはなんぞや
  • ActivityPubとはなんぞや

準備

仮想マシンそのものの準備

仮想化ソフト

VMWareやVirtualBox、Hyper-Vなど様々なものがありますが、お好みのものでOKです。

参考までに…自分の環境ではHyper-Vを採用しています。加えて、物理ネットワークとブリッジ接続するネットワークアダプタを作成し、ホストマシンと仮想マシンが同じネットワークに所属できるようにしています。ホストマシンが192.168.0.2/24であれば、仮想マシンは192.168.0.3/24192.168.0.4/24となるイメージです。

ホストマシン <-> 仮想マシンで疎通が出来れば問題は無いのですが、自分にとってはこの方が楽なので…

インストールするOS

Node.jsが動作すれば何でもOKです。
なお、この記事ではUbuntu22 LTSを採用しています。コマンドなどもそれに準じたものになりますので、ほかのOSを利用して構築される際はご注意ください。

仮想マシンの台数

「仮想マシンの同士での連合」が趣旨なので、最低でも2台は用意する必要があります。

仮想マシン内の環境準備

あらかじめインストールしておきたいソフト

nginx

Misskeyはhttpsでのホスティングをサポートしていないため、間に入ってhttp->https化をしてくれるものが必要になります。nginxはその役割としてうってつけの存在です。この記事でもhttp->https化をするためのツールとしてnginxを採用しています。

Docker

Misskeyを動作させるにあたり必須の物ではありませんが、上手く活用すればMisskeyに必要なミドルウェアを手軽に構築出来ます。この記事ではRedisとPostgreSQLを構築するためにDocker(rootlessモード)を採用しています。

ホスト名を考える

Misskeyを稼働させる仮想マシンのホスト名を考えます。今回は以下の2つを仮想マシンのホスト名として使うこととします。

  • test-a.osamu-storage.info
  • test-b.osamu-storage.info

続いて、ホストマシンと各仮想マシンのhostsを編集し、ホスト名で各仮想マシンにアクセスできるようにしておきます。

sudo vi /etc/hosts
# これを追記。仮想マシンのIPが変動しないように固定しておくと後々楽になります
192.168.0.203 test-a.osamu-storage.info
192.168.0.204 test-b.osamu-storage.info

手順

1. 自己署名証明書の作成

※ホストマシンでの作業です。Windowsの場合はWSLのUbuntuで作業するとスムーズです

MisskeyがActivityPub経由で相互にやり取りする際は、互いのサーバがhttpsをサポートしている必要があります。httpsをサポートするためには証明書を用意しなければなりませんが、信頼できる機関の証明書はお金や手間が掛かるなどの難点があります。これはローカルでちょっと試す程度の用途には不向きですよね。

そこで、今回は自己署名証明書を手軽に作成できるmkcertを利用させてもらうことにします。早速READMEを参考に環境を整えましょう。

# 前提ツールをインストール
sudo apt install libnss3-tools golang-go

# ソースを取得してビルド&インストール
git clone https://github.com/FiloSottile/mkcert && cd mkcert
go build -ldflags "-X main.Version=$(git describe --tags)"

# 実行ファイルがカレントディレクトリに生成されるので、
# PATHの通ったところに配置します(今回は/usr/local/bin)
sudo mv mkcert /usr/local/bin

# これで"/usr/local/bin/mkcert"と出ればOK
which mkcert

続いて、ビルドしたmkcertを用いて証明書の生成に移ります。

# ルート証明書の出力先をカレントディレクトリ内に指定します。
# デフォルトでは違う場所に生成・配置されますが、
# 生成されたものを取り出しやすい場所に確保しておきたい意図があります。
export CAROOT=./

# サーバ証明書の生成を行います。
# あらかじめ考えておいたホスト名を書けば十分ですが、念のためいくつか他のも足してあります。
mkcert osamu-storage.info "*.osamu-storage.info" localhost "127.0.0.1"

# ディレクトリの中身を確認してみて、コメントと同じような感じで出力されていればOK。
# rootCA.pemがルート証明書、ドメイン名つきのpemがサーバ証明書です。
ls -l
# drwxr-xr-x 2 osamu osamu 4096 Dec  7 13:17 ./
# drwxr-xr-x 3 osamu osamu 4096 Dec  6 21:28 ../
# -rw------- 1 osamu osamu 1704 Dec  7 13:17 osamu-storage.info+3-key.pem
# -rw-r--r-- 1 osamu osamu 1549 Dec  7 13:17 osamu-storage.info+3.pem
# -r-------- 1 osamu osamu 2484 Dec  7 13:17 rootCA-key.pem
# -rw-r--r-- 1 osamu osamu 1659 Dec  7 13:17 rootCA.pem

2. nginxの設定

※仮想マシンでの作業です

続いて、作成したサーバ証明書を仮想マシン上のnginxで使えるようにしていきます。nginxの設定ファイル構成は環境によって異なると思いますので、適宜読み替えていただければと思います。

まずはサーバ証明書をホストマシンから移送し、仮想マシンへ配置します。

# しばらくnginxの設定を行うのでディレクトリを移動しておきます
cd /etc/nginx

# サーバ証明書置き場としてディレクトリを作っておきます
sudo mkdir cert

# 何らかの方法でホストマシンにあるサーバ証明書ファイルを輸送します。
# (今回は中身をターミナル越しにコピペするパワープレイでやりました)
sudo vi cert/osamu-storage.info+3-key.pem
sudo vi cert/osamu-storage.info+3.pem

続いて、nginxのサイト設定を作成します。

# まずはファイルとシンボリックリンクだけ先に作成しておきます
sudo touch sites-available/misskey
sudo ln -s /etc/nginx/sites-available/misskey sites-enabled

次に、作成したsites-available/misskeyを編集します。

sudo vi sites-available/misskey

ファイルの中身はMisskey-Hubに記載されている設定例をベースとして、以下のようにしてみました。

# For WebSocket
map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}

proxy_cache_path /tmp/nginx_cache levels=1:2 keys_zone=cache1:16m max_size=1g inactive=720m use_temp_path=off;

server {
    listen 80;
    listen [::]:80;
    # ↓↓↓ ここを仮想マシンのホスト名にします ↓↓↓
    server_name test-a.osamu-storage.info;
    # ↑↑↑ ここを仮想マシンのホスト名にします ↑↑↑

    # For SSL domain validation
    root /var/www/html;
    location /.well-known/acme-challenge/ { allow all; }
    location /.well-known/pki-validation/ { allow all; }
    location / { return 301 https://$server_name$request_uri; }
}

server {
    # nginxのバージョンに依りますが、http2ディレクティブに対応しておらずエラーとなるので
    # 書き方を少し変えています
    # listen 443 ssl;
    # listen [::]:443 ssl;
    # http2 on;
    listen 443 ssl http2;
    listen [::]:443 ssl http2;

    # ↓↓↓ ここを仮想マシンのホスト名にします ↓↓↓
    server_name test-a.osamu-storage.info;
    # ↑↑↑ ここを仮想マシンのホスト名にします ↑↑↑

    ssl_session_timeout 1d;
    ssl_session_cache shared:ssl_session_cache:10m;
    ssl_session_tickets off;

    # ↓↓↓ ここを前の手順で移送してきたファイルに書き換えました ↓↓↓
    ssl_certificate     /etc/nginx/cert/osamu-storage.info+3.pem;
    ssl_certificate_key /etc/nginx/cert/osamu-storage.info+3-key.pem;
    # ↑↑↑ ここを前の手順で移送してきたファイルに書き換えました ↑↑↑

    # SSL protocol settings
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
    ssl_prefer_server_ciphers off;
    ssl_stapling on;
    ssl_stapling_verify on;

    # Change to your upload limit
    client_max_body_size 80m;

    # Proxy to Node
    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_set_header Host $host;
        proxy_http_version 1.1;
        proxy_redirect off;

        # If it's behind another reverse proxy or CDN, remove the following.
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto https;

        # For WebSocket
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;

        # Cache settings
        proxy_cache cache1;
        proxy_cache_lock on;
        proxy_cache_use_stale updating;
        proxy_force_ranges on;
        add_header X-Cache $upstream_cache_status;
    }
}

ファイルを保存後、下記コマンドで設定を反映します。

sudo systemctl reload nginx

# 設定ファイルを正常に読み込めた場合はコマンドの実行後に何も出力されませんが…
# エラーがある場合、下記のようなメッセージが出ます
# Job for nginx.service failed.
# See "systemctl status nginx.service" and "journalctl -xeu nginx.service" for details.

3. ルート証明書の配置とインストール

ホストマシンへのインストール

信頼のない自己署名証明書を使用しているサイトに対してhttps接続を行うと、ブラウザが警告を発してページの表示をブロックします。通常であれば大変ありがたい機能なのですが、今回のケースにおいては抑制したいところです。警告を抑止するには、今回生成したルート証明書をインポートすればOKです。

インポート手順についてはホストOSによりけりのため、詳しく解説されているサイトの紹介に留めさせていただきます。

仮想マシンへの配置

ホストマシン側でのブラウザ表示と同じ理屈で、Misskey同士の通信も同様に失敗します。これを回避するには、環境変数NODE_EXTRA_CA_CERTSに対し、ルート証明書のパスを設定した状態でMisskeyを起動する必要があります。

# パスはどこでもよいのですが、今回は下記に配置します。
# (例によってターミナル経由でのコピペ)
sudo vi /usr/share/ca-certificates/rootCA.pem

4. Misskeyのセットアップ

※仮想マシンでの作業です

冒頭に記載した通り、最低限の構成でとりあえず起動する所までの手順に留めます。


# ホームディレクトリに任意のディレクトリがあると作業しやすいです
cd
mkdir develop
cd develop

# リポジトリを取得してディレクトリ移動
git clone https://github.com/misskey-dev/misskey.git --recursive
cd misskey

# 依存関係のインストールとMisskeyのビルド
pnpm install
pnpm build

# 設定ファイルの作成
cp .config/docker_example.env .config/docker.env
cp .config/example.yml .config/default.yml

次に.config/default.ymlを編集し、urlの値を仮想マシンのホスト名へと書き換えます。

#   ┌─────┐
#───┘ URL └─────────────────────────────────────────────────────

# Final accessible URL seen by a user.
# url: https://example.tld/
url: https://test-a.osamu-storage.info/

続いてRedisとDBの作成及び初期化を行います。

# PostgreSQLとRedisだけを起動する構成のファイルでコンテナ群を起動
docker compose -f compose.local-db.yml up -d

# テーブルの作成
pnpm migrate

最後にNODE_EXTRA_CA_CERTS=/usr/share/ca-certificates/rootCA.pem pnpm startを実行し、以下のログが出るかを確認します。

DONE *  [core boot]     All workers started
DONE *  [core boot]     Now listening on port 3000 on https://test-a.osamu-storage.info

ログに表示されたURLにアクセスし、Welcome to Misskey!と表示されたら構築成功です。

仮想マシン上のMisskeyにアカウントを作成し、root@test-a.osamu-storage.infoからroot@test-b.osamu-storage.info目掛けてメンションを送ってみました。

無事届いてますね。

続いて、root@test-a.osamu-storage.infoからroot@test-b.osamu-storage.infoをフォローしてみます。

root@test-b.osamu-storage.info側でノートを投稿してみると…

root@test-a.osamu-storage.info側のTLに流れてきました!

総括

ちょっとニッチな内容ですが、刺さるところには刺さるのかな…?(主にMisskeyのソースを触る人など)
あらゆるツールが発達しているおかげでかなり手順が簡略化されているので、一家に一台用意しておくと吉かもしれません(?)

GitHubで編集を提案

Discussion