Misskeyサーバーをちゃんと建ててみた

# はじめに
以前「Misskeyインスタンスを建ててみた」という記事を書いたのですが、その後色々触っているうちにあまりの不備の多さに気付いてしまったので、きちんと書き直すべきと思い新しく記事を作成しています。

https://qiita.com/Soli0222/items/dcbe5113dc7565b87702

# 用意したもの
インスタンスを立ち上げるにあたって、用意したものは以下の通りです。
* サーバー：さくらVPS 石狩第1ゾーン, 仮想2Core, 1GBメモリ, SSD 50GB
* オブジェクトストレージ：Google Cloud Strage
* ドメイン
* Cloudflareアカウント


オブジェクトストレージはアップロードされたファイルの置き場になります。設定していない状態だとホスティングしているサーバーのリソースを無限に食っていくので、最初に設定してしまうことをお勧めします。

現状4人のサーバーですので、この程度のスペックで十分動いています。
自分以外誰も登録しない完全おひとりさまサーバーをGCPの無料枠でも試しましたが、起動に10分近くかかってみたりしたので、あまりおすすめしません。

そういえばサーバーをXserver VPSの仮想3コア、2GBメモリに引っ越しました。
メモリ1GBとは比べ物にならないほど快適なので、余裕がある方はメモリ2GB以上は確保した方が良さそうです。 (2023/06/13 追記)

# 建てていく
早速作業を進めていきます。
今回は、Misskey本体のみDockerコンテナを用いて実行し、Nginxは普通にホスト環境で実行します。

## CDNの設定
DNSレコードを変更する観点から先にCDNの設定を行います。CDNを利用することで負荷の軽減や攻撃の緩和を行うことができます。公式にも推奨されています。

https://misskey-hub.net/docs/admin/cdn.html

Cloudflareが個人利用の範疇で無料で使えるのでこれに登録し、所有しているドメインを追加します。

https://www.cloudflare.com/ja-jp/

また、ページルールで``example.com/api/*``をキャッシュレベルでスキップに設定しておきます。


## スワップ領域の設定
2GB以上のメモリを積んであれば問題ないかと思われますが、1GBですと普通にメモリが足りません。
スワップ領域の設定を行えば、全く解消できるので、やっておいた方が絶対に良いです。下記の記事にわかりやすく全部まとまっているので、参考に。

https://chatnoirlibre.com/ubuntu-22-04-lts-swap/

## Misskeyの構築
Misskey本体を構築していきます。公式のドキュメントは以下の通りです。
基本的にドキュメント通りに進めていけば問題ありませんが、設定の内容なども書きたいので、1から書いていきます。

https://misskey-hub.net/docs/install/docker.html

公式リポジトリを取得します。
```bash:bash
$ git clone -b master https://github.com/misskey-dev/misskey.git
$ cd misskey
$ git checkout master
```
　
各種設定ファイルのサンプルをコピーします。
```bash:bash
$ cp .config/docker_example.yml .config/default.yml
$ cp .config/docker_example.env .config/docker.env
$ cp ./docker-compose.yml.example ./docker-compose.yml
```

この設定ファイルを編集していきます。

``default.yml``で変更した場所は4箇所です。
DB周りは飛ばすと致命的なのでしっかりバックアップをとっておいた方がいいです。
```yml:default.yml
#━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# Misskey configuration
#━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

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

# Final accessible URL seen by a user.
url: https://example.com #ここに使うドメインを記述

...

  # Database name
  db: xxxxx #任意のDBの名前を記述

  # Auth
  user: xxxxx #DBのユーザー名
  pass: xxxxx #DBのパスワード

...
```
　
続いて``docker.env``を編集していきます。
ここにはさっきの``default.yml``に書いたことと同じことを書けば大丈夫です。
```env:docker.env
# db settings
POSTGRES_PASSWORD=xxxxx #さっき設定したDBのパスワード
POSTGRES_USER=xxxxx #さっき設定したDBのユーザー名
POSTGRES_DB=xxxxx #さっき設定したDBの名前
```
　
最後に``docker-compose.yml``を編集していきます。
イメージをビルドするのではなく、Docker Hubからイメージを取得する方に変更しました。手元でビルドできそうなスペックであるなら、変えなくても大丈夫かと思いますが、今回は無理そうと判断したのでイメージを取得するようにしています。

```yml:docker-compose.yml
version: "3"

services:
  web:
    image: misskey/misskey:latest #buildではなくimageを取得する
    restart: always
    links:
      - db
      - redis
...
```
 
これで設定は終わったので初期化と起動を行います。
```bash:bash
$ sudo docker compose run --rm web pnpm run init
$ sudo docker compose up -d
```
 
起動が完了したら
```bash:bash
$ curl localhost:3000
```
で確認しましょう。ちゃんとソースコードが出てきたら完了です。

## 証明書の発行
SSL化を行うので、証明書を発行します。Misskey本体を``example.com``とし、オブジェクトストレージを``media.example.com``といった風にしたかったため、``*.example.com``に対して発行されるワイルドカード証明書を利用します。

こちらの記事を参考に作業を行いました。適切なドメインとメールアドレスに置き換えて実行してください。

https://qiita.com/_whitecat_22/items/f770cbf7b91128c5060e

実行後に、DNSレコードに``_acme-challenge``という項目を追加するように言われるので、それに従って作業してください。CDNの設定において、ネームサーバーを変更していると思うので、DNSレコードの変更はCloudflareのダッシュボードでで行います。

## Nginxの構築
Nginxの構築を行います。まずはインストールします。
```bash
$ sudo apt install nginx
```
 
次にNginxの設定ファイルを``/etc/nginx/conf.d``内に作成します。
今回はMisskey本体と、オブジェクトストレージにリバースプロキシするファイルの2つを作成します。

まずはMisskey本体にまつわるファイルですが、これは公式のドキュメントに設定例があるのでこれに則って記述します。

https://misskey-hub.net/docs/admin/nginx.html

次に、オブジェクトストレージの設定を作成します。筆者はGCSを利用しているため、それに適したものになっています。使用するオブジェクトストレージに合うようにしてください。
```conf:gcs-proxy.conf
upstream gs {
    server                   'storage.googleapis.com:443';
    keepalive                100;
}

server {
  listen 443 ssl;
  server_name media.example.com; #ドメイン名

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

  client_max_body_size 100m;

  location / {
          proxy_set_header    Host storage.googleapis.com;
          proxy_hide_header   x-goog-hash;
          proxy_hide_header   x-goog-generation;
          proxy_hide_header   x-goog-metageneration;
          proxy_hide_header   x-goog-stored-content-encoding;
          proxy_hide_header   x-goog-stored-content-length;
          proxy_hide_header   x-goog-storage-class;
          proxy_hide_header   x-xss-protection;
          proxy_hide_header   accept-ranges;
          proxy_hide_header   alternate-protocol;
          proxy_hide_header      Set-Cookie;
          proxy_ignore_headers   "Set-Cookie";
          proxy_intercept_errors on;

          proxy_http_version     1.1;
          proxy_set_header       Connection ""; 
          proxy_pass	https://gs/[バケット名]$uri;
  }
}

```

編集が終わったら保存し、構文チェックとNginxの再起動を行います。
```bash:bash
$ sudo nginx -t
$ sudo systemctl restart nginx
```

この時点でほぼ完成しているようなものなので、設定したドメインでアクセスし、正しくMisskeyとオブジェクトストレージにアクセスできるか試しましょう。

## Misskeyの設定をする
ここまでの設定がうまくできていればMisskeyで管理者アカウントの作成ができるようになっているはずです。アカウントを作成してしまいましょう。

また、オブジェクトストレージの設定をコントロールパネルから行い、アップロードされるファイルがオブジェクトストレージに送られるか確認しましょう。

ここでコントロールパネルを表示した時にメールサーバーの設定がなされていない旨の警告が出ているかと思います。これは、例えばパスワードを忘れた時の再設定用メールを送るためであったり、お知らせを配信するために用いられます。様々な方法でメールサーバーを設定できますが、ここではGmailを使った手法を紹介します。

以下の記事のGmailの設定に沿ってメールが送信できるか確認します。

https://qiita.com/rokuosan/items/e3415ea30ad5e48d3b0f#gmail-%E3%81%AE%E8%A8%AD%E5%AE%9A

送信できれば、Misskey側の設定に同様なアドレス、SMTPサーバー、ユーザー名、パスワードを設定すれば完了です。


## アップデート
Misskeyは地味な頻度でアップデートが来るので、そのための方法も記述しておきます。以下のコマンドを実行すれば完了ですが。
```bash:bash
$ cd misskey
$ git stash
$ git checkout master
$ git pull
$ git submodule update --init
$ sudo docker pull
$ sudo docker compose stop && sudo docker compose up -d
```


# おわりに
最初にサーバーを建ててから1ヶ月、この構成にしてやっと安定して動かせたなという気持ちと、かなり簡単に構築できる手順にブラッシュアップできたなという感じです。

読んでいただき、ありがとうございました。