目次

Misskey

概要

Misskeyは日本発のActivePub対応のSNSシステムです。 mastodonなどと連携してメッセージのやり取りができます。 どちらかというと趣味的要素が強い実装となっているように思います。

導入には、mongoDBの比較的新しいバージョンが必要で、これがあるいはネックになるかもしれません。

また、頻繁なバージョンアップにより、構築の手引きや、巷に多くある導入ガイド的記事ではおいつかず、少なからずソース(JavaScript)を読んで、探ったりする必要があります。

このあたりに抵抗を感じる方は、既存のインスタンス上でユーザ登録して遊んでみるにとどめたほうがいいでしょう。

導入

ユーザの作成

Misskeyを実行する権限を持ったユーザを作成する。 これは一般ユーザとし、root権限を持たせない。

# groupadd misskey
# useradd -g misskey misskey

などとする。 別に misskeyでなくても構わない。

Misskeyの取得

$ git clone -b master git://github.com/syuilo/misskey.git
$ cd misskey
$ git checkout $(git tag -l | grep -v 'rc[0-9]*$' | sort -V | tail -n 1)
$ npm install

設定

Misskey そのものの設定の一部は、.config/default.yml で行います。 バージョンアップに伴って、いくつかの項目が、DB上に移動され、管理メニューから設定するようになっているため、設定について記述された記事よりも少ない項目になっています。

ひな形として、.config/example.ymlがあるので、まずは、これを .config/default.ymlにコピーして必要な項目を編集すればいいでしょう。 コメントの形で説明もついているので、それを参照すればいいが、一部、不明瞭なものもあるので、適宜、推測したり、ソースを読むなどして補完する必要があります。

接続するためのポートですが、直接 Misskeyを露出するよりは、リバースプロキシーなどを挟む方が一般的でしょう。 特にLet's Encryptを利用した証明書を利用する場合には、特権ユーザでないとアクセス出来ないため、HTTPSを利用したいのであれば、リバースプロキシーを使うべきでしょう。

リバースプロキシーを利用する場合には、portだけを設定し、httpsに関するパラメータはコメントアウトしたままにしておきましょう。

3000番で待ち受ける場合の例を下に示します。 なお、1000番以下のポートを利用する場合には、特権ユーザである必要がある場合がありますので、避けておいたほうがよいでしょう。

port: 3000

mongoDBの設定は不可欠です。 特に難しいことはなく、mongoDBが動作しているホスト、ポート、作成したDB、アクセスするためのユーザとパスワードを記述します。 設定ファイルはymlなので、インデントは意味があります。 mongodb: 以下の項目は、同じだけ段下げをして記述します。

mongodb:
  host: mongodb.example.jp
  port: 27017
  db: misskey_db
  user: misskey
  pass: xxxxxxxx

minioを利用したメディアファイルの管理は少々厄介でした。 ここで storage: 'db' とサンプルのママの設定で利用される方は特に気にする必要はありません。

ポイントとなるのは、ファイルの操作を行う際には、endPoint+port+bucket+prefixの組み合わせでアクセスされるのに対して、そのファイルにアクセスするURIを生成するのは、baseUrl+prefixで行われるという所です。

サンプルとして、複数のminioの場合の例がコメントの形で入っていますが、portは項目としてなかったし、baseUrlにはbucketを含める必要があることなどは、ソースや、実際に生成されたURIをみてみないと分かりませんでした。

以下には、drive.example.jp:9000 で動作しているminioに minio.example.jpという名前でリバースプロキシーを介してアクセスするケースの例を書いておきます。 なお、drive.exmaple.jp:9000はHTTPSではアクセスしない想定です。

drive:
  storage: 'minio'
  bucket: misskey
  prefix: files
  baseUrl: https://minio.example.jp/misskey
  config:
    endPoint: drive.example.jp
    port: 9000
    region: ap-northeast-1
    useSSL: false
    accessKey: XXXXXXXXXXXXXXXXXXXX
    secretKey: yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy

特に難しいことはありません。 Redisが未導入なら導入してサービスが起動されるようにしておきましょう。 パスワードを使ったアクセスはうまくいかないらしいので、パスワードは設定しないようにしておきます。 まあ、内部ネットワークでのアクセスなら特段問題は無いでしょう。

redis:
  host: redis.example.jp
  port: 6379
#  pass: example-pass

現時点ではわたしは設定していないので割愛します。

サイトによっては、このあとに、Service Workerのための VAPID KEYを設定しろとか、ReCAPTCHAのためのキーを設定しろとか書いてありますが、これらの項目は、少なくともバージョン10.98.3の時点で、DBに移動されており、Misskeyの管理者権限で設定画面上から設定することになりますので、最低限の設定はこれでおしまいです。

mongoDB

mongoDBは、非SQL型のデータベースです。 パッケージが用意されているディストリビューションもありますが、古いバージョンが多いようです。

Misskeyは3.6以降を要求していますので、最新版を取得することをおすすめします。

ソースからの構築は、かなり新しめのgccが必要だったりと敷居が高いので、もうはじめからバイナリを持ってきた方がいいでしょう。

/etc/mongod.conf に設定ファイルを配置します。 こちらもymlなのでインデントに注意しながら、

storage:
  dbPath: /var/lib/mongo
  journal:
    enabled: true

net:
  port: 27017
#  bindIp: 127.0.0.1  # Listen to local interface only, comment to listen on all 

interfaces.

  bindIpAll: true

security:
  authorization: enabled

といったあたりを設定します。dbPathはお好きなところに、portはdefault.ymlで指定したものと同じにします。 bindIpは、Misskeyと同じホストならコメントを外しましょう。 securityでauthorizationをenableしておきます。

サービスを起動したら、mongoコマンドでDBに接続し、まず、全体を管理するユーザを作成します。

$ mongo
MongoDB shell version v4.0.7
connecting to: mongodb://127.0.0.1:27017/?gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("8a56f89b-ed3d-41b8-9d35-0b9ebbe1c400") }
MongoDB server version: 4.0.7
> use admin
> db.createUser({user:"admin",  pwd:"xxxx",  roles:[{ role:"userAdminAnyDatabase", db:"admin" }]})
> db.auth("admin","xxxx")

“xxxx”はパスワードです。管理者は別に 'admin'じゃなくてもいいので、適当にすきな名前でつくります。 ポイントは、db.authをしておくこと。 これをしないと、Misskey用のユーザがつくれません。

次に、Misskey用のDBとユーザの設定をします。

> use misskey
> db.createUser( { user: "misskey", pwd: "xxxxxxxx", roles: [ { role: "readWrite", db: "misskey" } ] } )
> exit

ここで、use misskey はdefault.ymlで設定したデータベース名です。 user, pwd も、同じく指定したものと同じにします。

これで、mongoDB回りの設定は完了です。 あとは、余程のことがない限り、mongoコマンドで直接DBに触ることはないかと思います。

redis

特にバージョンの指定はないけれど、mastodonが指定している2.8で問題はないようです。

別のホストで動作させているのであれば、redis.confを以下のように編集しておきます。

# bind 127.0.0.1 ←コメントアウトする
protect-mode no # 追加する

編集後は、redisを再起動しておきます。

Node.js

Node.jsはさまざまなバージョンがありますが、Misskey 10.98.3ではとりあえず10.0.0以降のものであればよいようなので、n コマンドなどで導入します。

# n 10.15.3

などとすればいいだろう。 n stable とする方法もあるが、バージョン11と互換性があるかどうか不明。 すくなくともmastodonは11ではエラーが出てしまった。

nginx(リバースプロキシー)

様々なサンプルが存在しているけれど、当サイトは以下のような感じで設定してあります。 ポイントは、WebSocket対応で、これがないと、延々と接続中になるらしいです。 その他の細かなところは枝葉のようなものであるので、動いているという人の所を真似るので十分だと思います。

upstream misskey_handler {
    server 127.0.0.1:3000;
}

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

server {
    listen 80;
    server_name misskey.example.jp;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name misskey.example.jp;
    #ssl on;
    ssl_session_cache shared:ssl_session_cache:10m;

    ssl_certificate /etc/letsencrypt/live/example.jp/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.jp/privkey.pem;

    ssl_protocols TLSv1 TLSv1.2;
    ssl_ciphers ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:AES128-SHA;
    ssl_prefer_server_ciphers on;

    keepalive_timeout   70;
    sendfile            on;
    client_max_body_size 80m;

    gzip on;
    gzip_disable "msie6";
    gzip_vary on;
    gzip_comp_level 6;
    gzip_buffers 16 8k;
    gzip_http_version 1.1;
    gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;

    add_header Strict-Transport-Security "max-age=31536000";

    location / {
        try_files $uri @proxy;
    }

    root /var/www/misskey;

    location @proxy {
        proxy_set_header Host                   $host;
        proxy_set_header X-Real-IP              $remote_addr;
        proxy_set_header X-Forwarded-Host       $host;
        proxy_set_header X-Forwarded-Server     $host;
        proxy_set_header X-Forwarded-For        $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto      https;
        proxy_set_header Proxy                  "";
        # for WebSocket
        proxy_pass_header Server;
        proxy_pass http://misskey_handler;
        proxy_http_version 1.1;
        proxy_set_header Upgrade                $http_upgrade;
        proxy_set_header Connection             $connection_upgrade;
        proxy_redirect off;
        proxy_buffering off;
        tcp_nodelay on;
        # cache
        proxy_cache_lock on;
        proxy_cache_use_stale updating;
        add_header X-Cache $upstream_cache_status;
    }
    access_log /var/log/nginx/misskey_access.log;
    error_log /var/log/nginx/misskey_error.log warn;
}

minio(S3)

minioの設定の詳細はmastodonのminioのセクションを参照してください。 default.ymlで指定した bucketをminio上に作成し、権限を付与すれば、あとは、minioの管理画面から操作できるので、特にminioの管理画面に来ることはないと思います。

build-essential

Debian GNU/Linuxまたはその派生ディストリビューションで運用する場合には、build-essentialパッケージが必要だそうです。 未導入の場合は、

# apt install build-essential

としてインストールしておきます。

構築

全ての要素が揃ったら、ビルドします。

$ NODE_ENV=production npm run build

一般的には、問題ないと思いますが、Raspberry Piなど、非x86環境で運用する場合には、node-gypが必要になるかと思います。

# npm install -g node-gyp

として、あらかじめ用意しておきましょう。 バイナリパッケージの場合、x86版以外は用意されていなかったりしますので、その場合はnode-gypを使ってバイナリの構築が行われます。

もしかすると、最後に、セキュリティ修正が必要だというようなことを言われるかも知れませんが、とりあえず、無視しておいても大丈夫そうです。

運用

サービス化

systemcltを利用している場合には、/etc/systemd/system/misskey.serviceとして、以下のような内容のファイルを作成します。 systemctlを利用しない場合には、適当に起動スクリプトを組んでください。

User, WorkingDirectoryは作成したユーザ、Misskeyを導入した場所を指定するようにしてください。 ExecStartに関しては、/usr/local/bin など別のパスにnpmが導入されている場合にはそちらを指定するようにします。

[Unit]
Description=Misskey daemon

[Service]
Type=simple
User=misskey
ExecStart=/usr/bin/npm start
WorkingDirectory=/var/www/misskey
Environment="NODE_ENV=production"
TimeoutSec=60
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=misskey
Restart=always

[Install]
WantedBy=multi-user.target

ファイルを保存したら、

# systemctl misskey enable

として、サービスを有効化します。 あとは、

# systemclt start misskey 

あるいは

# service misskey start

として、Misskeyを開始します。 起動には少々時間がかかるので、慌てないで少し待ってから、Misskeyへブラウザからアクセスします。

Misskeyが起動中にアクセスすると、nginxを経由している場合には、502 (Bad Gateway)エラーが返りますので、少し待ってからアクセスしてみてください。

更新

更新は、gitで行うことが出来る。 Misskeyを展開したディレクトリで以下のコマンドを実行する。

$ git checkout $(git tag -l | grep -v 'rc[0-9]*$' | sort -V | tail -n 1)

更新があれば、

$ NODE_ENV=production npm run build
# service misskey restart

のようにして、新しいモジュールをビルドし、サービスを再起動する。

トラブルシュート

ブラウザーが延々とリロードし続ける

Cookieを消去することで回避できる場合があります。 わたしの場合、以前、一度導入を試みたときに、中途半端にログインした状態が残っていて、今回まっさらから導入しなおしたところ、そのときの認証情報を使って接続を試みては拒絶されるを繰り返していたようです。

mastodon

mastodonは、productionモードでは、プライベートアドレスからのリモートフォロー、またプライベートアドレスへのリモートフォローともに拒絶する仕様になっています。

このため、プライベートアドレスを利用している場合には、相互にフォローができません。

どうしてもしたい場合には、mastodon側で、手をいれて、フォローできるようにする以外に方法はありません。 将来の版において変わるかもしれませんが、現状は、最低限度のRubyの知識が必要です。

画像が登録できない

driveのstorageをdbではなくminioにしていると発生するかも知れません。 minioの設定に関しては、一応サンプルはついていますが、色々と不足しています。

endPointがポート番号を含む場合

mastodonでは、minio.example.com:9000 のようにポートも含んだ形でエンドポイントを指定していましたが、これをそのままやると、Bad endPointのエラーになって画像の登録ができません。

ポート番号は、パラメータportで指定します。 node_modules/@type/minio/index.ts に書いてありました。

登録した画像が表示できない

同じくminioを利用している場合に発生すると思われます。 minioを使う場合には、minio上のファイルの操作は、useSSLとendPointとportとbucketとprefixを使って、minioへのアクセスURIを生成して行います。

ところが読み出しは、baseUrlとprefixだけで行うため、bucketがするっと抜けて、無効なURIを生成してしまいます。

baseUrlには bucketまで含んだ形で指定すると、この問題は回避できます。

start