Mastodon を Rocky Linux 9.1 で構築する

# はじめに

某青い鳥の SNS がにわかに先行き不安なので、[Mastodon](https://joinmastodon.org/ja) を構築してみました。その備忘録です。

実は以前にも一度構築していましたが放置状態[^oldmastodon]だったので、改めてやり直してみます。

https://qiita.com/ymchn/items/1df8453fd2c8ceb8ad71

この手順に従って実際に構築したサイトは以下となります。

https://mstdn.yamachan.org/

## 環境

とりあえずはお遊びなのでケチケチの方針で。

|項目||備考|
|:--|:--|:--|
|OS|[Rocky Linux](https://rockylinux.org/ja/) 9.1[^rocky]|[RHEL](https://www.redhat.com/ja/technologies/linux-platforms/enterprise-linux) 9.1 のバイナリ互換|
|Mastodon|4.0.2|2023/02/08 時点での最新版|
|マシン環境|[WebARENA Indigo](https://web.arena.ne.jp/indigo/) 1GB|月額 349 円の VPS<br />RAM 1GB・SSD 20GB・vCPU 1コア|
|ドメイン名管理|[Value Domain](https://www.value-domain.com)||
|メール配送|[XREA](https://www.xrea.com)|Value Domain と同じ会社のサービス|

# 作業手順

基本的には公式手順に従います。

https://docs.joinmastodon.org/admin/install/

ただし、公式手順は Ubuntu を想定して書かれているので、RHEL 系では読み替えが必要になります。

## Indigo でインスタンスを立ち上げる

### 公開鍵認証用の鍵を作成する

#### ローカル環境で生成する

SSH 接続用の鍵を用意します。
PuTTY[^putty_patch] 付属の puttygen.exe を用いる場合、こんな感じ。
![puttygen.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/177073/eea0e004-e759-6a00-0d89-3cfe5c3817bb.png)

1. 生成する鍵の種類として「RSA」を選択する[^key_rsa] (いわゆる SSH-2 RSA となる)。
1. 「生成」をクリックする。マウスを適当にグリグリ動かしていると完了する。
1. 「OpenSSHのauthorized_keysファイルにペーストするための公開鍵」欄の文字列をコピーして、テキストエディタなどで保存しておく。
1. 「公開鍵の保存」ボタンで、公開鍵を保存しておく。
1. 「秘密鍵の保存」ボタンで、秘密鍵を保存しておく (拡張子は .ppk)。

#### 公開鍵を VPS サービス側に登録する

Indigo コントロールパネルの「インスタンス管理」-「SSH鍵」を開き、右側の「SSH鍵のインポート」を選ぶ。
![key_import.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/177073/817a2bcf-8a5d-8728-ba1a-d98b5a616e74.png)
先ほど保存した「OpenSSHのauthorized_keysファイルにペーストするための公開鍵」欄の文字列を貼り付ける。
鍵名は適当で OK（鍵のコメントと揃えておくといいかもしれません）。
最後に「作成」を押してインポート完了。
![key_import_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/177073/a5fbced5-cc66-2238-54cf-7e11c10af8e2.png)
「インスタンス管理」-「SSH鍵」に戻り、先ほど追加した鍵が一覧表示されていれば OK。

:::note warn
うまく行かない場合、RSA 以外の鍵を使用していないか確認すること
:::

### インスタンスを起動する

「インスタンス管理」-「インスタンス」メニューの、右側の「インスタンスの作成」をクリック。
![instance_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/177073/d18024ca-7f55-edb6-e05f-50232072c0e3.png)
以下のような選択画面が表示されるので、インスタンスの構成を選択する。
![instance_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/177073/76a91349-5b4b-d60c-ceeb-2377a4eccd33.png)
1. イメージは Rocky Linux 9.0。
1. インスタンスのサイズは 1 vCPU / 1 GB RAM / 20 GB SSD / 100 Mbps。月 349 円のプランになる。
1. SSH 鍵は先ほどアップロードしたものを選ぶ。
1. インスタンス名は他と区別が付く名前を適当に。
1. 選択し終わったら、「インスタンスの作成」をクリック。

作成が始まると「OS のインストール中」のような表示が出るので、数分待ちます (なぜか手元ではOS インストールが終わっても表示が更新されないので、いったん別のタブを開いてから戻ってくる必要がありました…）。
![instance_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/177073/d57d6ebc-7ac9-dae9-3daf-d51c686089ad.png)
先ほど作成したインスタンスが「Stopped」と表示されているので、
1. IP アドレスを記録しておきます。
1. 右端の「選択」を展開します。
1. 「インスタンスの起動」を選びます。

### SSH 接続してみる

Indigo の Rocky Linux イメージの場合、デフォルトで rocky というユーザが作成されています。
https://help.arena.ne.jp/hc/ja/articles/360049807634/
先ほど設定した SSH の鍵を使って接続してみます。
![first_login.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/177073/c8f9ce1b-6617-bc70-0c6e-8626b4b5fcde.png)
ここまでで、素の状態のインスタンスが起動しました。

### SSH 接続用のポートを変更する

デフォルトの port 22 はブルートフォース攻撃の定番なので、負荷軽減と心理的安心も兼ねて変更しておきます。
(ポート番号が分かれば攻撃可能なので、悪意を持った攻撃者に対しては意味ないですが)
```diff_conf: /etc/ssh/sshd_config
 # SELinux about this change.
 # semanage port -a -t ssh_port_t -p tcp #PORTNUMBER
 #
-#Port 22
+Port 60022
 #AddressFamily any
 #ListenAddress 0.0.0.0
 #ListenAddress ::
```
「ポート番号を変更するときは SELinux の設定も変更してね」とのコメントに従い、スーパーユーザで以下を実行します。
```shell-session
# semanage port -a -t ssh_port_t -p tcp 60022
# systemctl restart sshd
```
※まだ port 22 で接続しているセッションは閉じないで！

この状態で、port 60022 で SSH 接続してみて繋がれば OK。
![putty_setting.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/177073/86078f97-acd9-85eb-e72a-7c8b96d0c2b1.png)

:::note warn
もし繋がらなければ `/etc/ssh/sshd_config` の記述と、`semanage` で設定した内容、さらに Indigo コントロールパネルのファイアウォールの設定が合ってるか確認を。
`semanage` の設定内容は以下で確認できます。

```shell-session
# semanage port -l | grep ssh_port_t
ssh_port_t                     tcp      60022, 22
```
:::

### ファイアウォールの設定をする

標準だと (Indigo 側、インスタンスの OS 自体のいずれも) 何も制限されていないようなので、まずはファイアウォールを設定します。

まず、Indigo コントロールパネルの「ネットワーク管理」-「ファイアーウォール」より、「ファイアーウォールの作成」をクリックします。
![firewall_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/177073/5520a59b-6e93-3b45-47fd-a4c326e77f63.png)
ファイアーウォール作成画面に移ったら、以下を行います。
![firewall_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/177073/26f855aa-83d1-271b-d70b-fab9215c7a2f.png)

1. 任意の名前を付ける。
1. 「新規ルール」ボタンをクリックして、「HTTP」「HTTPS」「Custom」を一回ずつ選ぶ。
1. 「Custom」のポート番号欄に「60022」（SSH のポート番号）を入力する。
1. 「IPアドレス」欄に「0.0.0.0」を入力する。
1. 「インスタンスへの適用」欄は、先ほど立ち上げたインスタンスの名前を選ぶ。
1. 「作成」をクリックする。

上記の作業が正しく行われていれば、新たに SSH 接続を開始しても正常につながるはずです。

### 作業用のユーザを作成する

SSH で接続するためのユーザ (ここでは `yamazaki`) を作成します。
```shell-session
# groupadd -g 1001 yamazaki
# useradd -g 1001 -u 1001 yamazaki
# passwd yamazaki
```
`passwd yamazaki` は任意。
やっておけば万が一 SSH で繋がらなくなった場合（ex. ファイアウォールの設定を間違えた時）に VPS のコンソールからローカルログインできます。

デフォルトユーザの所属グループをコピーします。
```shell-session
# id rocky
uid=1000(rocky) gid=1000(rocky) groups=1000(rocky),4(adm),190(systemd-journal)
# usermod -aG adm,systemd-journal yamazaki
# id yamazaki
uid=1001(yamazaki) gid=1001(yamazaki) groups=1001(yamazaki),4(adm),190(systemd-journal)
```

`sudoers` に追加します。
```conf:/etc/sudoers.d/99-nopasswd
yamazaki ALL=(ALL) NOPASSWD: ALL
```
上記の設定だと `$ sudo` 実行時にパスワードを聞かれなくなります。
パスワードを聞かれたい場合は `yamazaki ALL=(ALL) ALL` で。
```shell-session
# chmod 0640 /etc/sudoers.d/99-nopasswd
```

公開鍵認証できるように、公開鍵をコピーします。

```shell-session
# su - yamazaki
$ mkdir -m 0700 ~/.ssh
$ echo "ssh-rsa AAA...xyz ssh2-rsa-2023-02-12" >> ~/.ssh/authorized_keys
$ chmod 0600 ~/.ssh/authorized_keys
```

この状態で、公開鍵で SSH ログインでき、`sudo su -` でスーパーユーザに昇格できることを確認します。

### 標準ユーザを削除する

最初から作成されていたユーザ `rocky` を削除します。
```shell-session
# userdel -r rocky
```
`-r` : ホームディレクトリとメールスプールも削除。

`sudoers` から、末尾の `rocky` で始まる行を削除します。
```shell-session
# vi /etc/sudoers
```
なぜかこっちにも居るので削除します。
```shell-session
# rm /etc/sudoers.d/90-cloud-init-users
```

## 事前準備

### OS・アプリケーションを最新にする

```shell-session
# dnf check-update
# dnf update
# reboot
```
2023/02/12 時点では、Rocky Linux 9.1 になりました。

### 基本的なサーバ全体の設定

#### タイムゾーン
```shell-session
# timedatectl set-timezone Asia/Tokyo
```

#### ロケール
```shell-session
# dnf install glibc-locale-source
# localedef -f UTF-8 -i ja_JP ja_JP
```

#### ホスト名
ホスト名は `mstdn.yamachan.org` とします。
```shell-session
# hostnamectl set-hostname mstdn.yamachan.org
```

#### その他
デフォルトだと vi エディタがショボくて扱いづらいので
```shell-session
# dnf install vim
```

### メモリ周りに余裕を持たせる

#### kdump を無効化する

1GB プランなのに、`free` の結果表示される `total` 欄は 0.75GB 弱しかありません。
```shell-session
$ free
               total        used        free      shared  buff/cache   available
Mem:          783012      218668      521272        5708      161148      564344
Swap:              0           0           0
```
RHEL 9 系の仕様で kdump のためにメモリを予約しているのが原因なので、kdump を無効化します。
詳細は以下を参照してください。

https://qiita.com/ymchn/items/75a3dfec4023cf299c42

#### スワップを有効化する

スワップファイルを使用することで、メモリが足りなくなるのを回避します。

```shell-session
# dd if=/dev/zero of=/swapfile bs=1M count=1024
# chmod 0600 /swapfile
# mkswap /swapfile
# swapon /swapfile
```
ここまででスワップファイルが有効になりました。

`free` 実行時に以下のようになっていれば OK。
```shell-session
$ free
               total        used        free      shared  buff/cache   available
Mem:          979620      242144       67544        4488      815312      737476
Swap:        1048572           0     1048572
```
`Mem:` の `total` が 1GB 弱、`Swap:` が 1GB になっています。

再起動後も適用されるように、以下の行を `fstab` に追記します。
```conf:/etc/fstab
/swapfile  none  swap  sw  0  0
```

## Mastodon の導入

### 拡張リポジトリの導入

#### EPEL
```shell-session
# dnf install epel-release
```
#### RPM Fusion
```shell-session
# dnf install https://mirrors.rpmfusion.org/free/el/rpmfusion-free-release-9.noarch.rpm
# dnf install https://mirrors.rpmfusion.org/nonfree/el/rpmfusion-nonfree-release-9.noarch.rpm
```
#### CRB
```shell-session
# dnf config-manager --set-enabled crb
```

### 必要なツール類を入れる

#### wget
```shell-session
# dnf install wget
```
#### ImageMagick
```shell-session
# dnf install ImageMagick
```
#### FFmpeg
```shell-session
# dnf install ffmpeg ffmpeg-devel
```
#### Redis
```shell-session
# dnf install redis
# systemctl enable redis
# systemctl start redis
```
#### PostgreSQL
```shell-session
# dnf install postgresql postgresql-server libpq-devel
# su - postgres
postgres$ initdb --encoding=UTF-8 --no-locale -D /var/lib/pgsql/data
postgres$ exit
# systemctl enable postgresql
# systemctl start postgresql
```
#### nginx
```shell-session
# dnf install nginx
```
有効化はまた後で。

#### Node.js
```shell-session
# dnf install nodejs
```
#### yarn[^yarn]
```shell-session
# npm uninstall -g yarn pnpm
# npm install -g corepack
# corepack enable
# yarn set version classic
```

#### その他もろもろ
https://docs.joinmastodon.org/admin/install/#system-packages で足りないものを
|Ubuntu でのパッケージ名|RHEL 系でのパッケージ名[^rhel_equiv_pkg]|
|:--|:--|
|libprotobuf-dev|protobuf-devel|
|protobuf-compiler|protobuf-compiler|
|certbot|certbot|
|python3-certbot-nginx|python3-certbot-nginx|
|libicu-dev|icu, libicu-devel|
|libidn11-dev|libidn-devel|
|postgresql-contrib|postgresql-contrib|
|gcc, g++|gcc-c++|
|git-core|git-core|
|libssl-dev|openssl-devel|
|zlib1g-dev|zlib-devel|
|libreadline6-dev|readline-devel|
|libjemalloc-dev|jemalloc-devel|
```shell-session
# dnf install protobuf-devel protobuf-compiler certbot python3-certbot-nginx \
    icu libicu-devel libidn-devel postgresql-contrib gcc-c++ git-core \
    openssl-devel zlib-devel readline-devel jemalloc-devel
```

### 事前設定変更

#### ユーザ mastodon を作成する
OS ユーザ `mastodon` を作成します。
Redis と Unix ドメインソケット経由で通信させるため、`redis` グループに追加します。
```shell-session
# groupadd -g 9001 mastodon
# useradd -g 9001 -u 9001 mastodon
# usermod -aG redis mastodon
```

#### PostgreSQL ユーザの作成とパスワード設定
PostgreSQL ユーザ `mastodon` を作成し、特権ユーザ (`postgres`) と `mastodon` にパスワードを設定します。
```shell-session
# su - postgres
postgres$ psql
postgres=# CREATE USER mastodon CREATEDB;
CREATE ROLE
postgres=# alter user postgres with password 'password-for-psql-posgtres';
ALTER ROLE
postgres=# alter user mastodon with password 'password-for-psql-mastodon';
ALTER ROLE
postgres=# \q
```
`password-for-psql-***` の箇所はパスワード文字列なので取扱注意です。
(OS のユーザとは別物なので要注意)

#### Redis を Unix ドメインソケット通信に対応させる
まずは Redis 側の準備を。
```diff_conf:/etc/redis/redis.conf
 # incoming connections. There is no default, so Redis will not listen
 # on a unix socket when not specified.
 #
-# unixsocket /run/redis.sock
-# unixsocketperm 700
+unixsocket /run/redis/redis.sock
+unixsocketperm 770

 # Close the connection after a client is idle for N seconds (0 to disable)
 timeout 0
```
```shell-session
# systemctl restart redis

# ls -lF /run/redis/
合計 0
srwxrwx---. 1 redis redis 0  2月 13 02:40 redis.sock=
```

#### Perl モジュールを導入する
これをやっておかないと、次の Ruby 導入時にコケる
```shell-session
# dnf install perl-FindBin perl-lib perl-File-Compare
```

### Ruby を導入する

```shell-session
# su - mastodon
mastodon$ git clone https://github.com/rbenv/rbenv.git ~/.rbenv
mastodon$ cd ~/.rbenv && src/configure && make -C src
mastodon$ echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc
mastodon$ echo 'eval "$(rbenv init -)"' >> ~/.bashrc
mastodon$ exit
# su - mastodon
mastodon$ git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build
mastodon$ RUBY_CONFIGURE_OPTS=--with-jemalloc rbenv install 3.0.4
mastodon$ rbenv global 3.0.4
```
`exit` して即入り直しているのは `.bashrc` の適用のためです。
(`source ~/.bashrc` や `. ~/.bashrc` だと `$PATH` がどんどん長くなるのが気に入らず…まぁ好みの問題ですが)

### Bundler を導入する

```shell-session
mastodon$ gem install bundler --no-document
```

### ドメイン関連の設定を行う

#### IP アドレスとドメイン名の関連付けを行う

各種サービスによって異なりますが、Value Domain の場合は概ね以下となります。
![dns.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/177073/39688093-e926-7a67-7d07-b82ae8e0ae5c.png)
図のように、`a subdomain 203.0.113.55` という A レコードの行を追加すると、IP アドレス `203.0.113.55` に対して `subdomain.example.com` でアクセスできるようになります。
（`example.com` でアクセスしたい場合は `a @ 203.0.113.55` になります）

#### メールサーバの設定を行う

各種サービスによって異なりますが、今回は XREA でメールボックスを専用に割り当てました。
![mail.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/177073/6d51f1f4-9b45-850f-6f3a-921b1bb39729.png)

### Mastodon を導入する

#### 環境変数を設定する

最初に、環境変数 `NODE_OPTIONS` を設定します。
```shell-session
mastodon$ echo "export NODE_OPTIONS='--openssl-legacy-provider --max-old-space-size=1536'" >> .bashrc
mastodon$ exit
# su - mastodon
```

- `--openssl-legacy-provider` を設定しておかないと、Mastodon ビルド時に OpenSSL 絡みで `ERR_OSSL_EVP_UNSUPPORTED` なるエラーを生じます。
- `--max-old-space-size=1536'"` を設定しておかないと、Mastodon ビルド時に Node.js のヒープ領域不足でエラーを生じます。

#### Mastodon ソースコードを取得する

```shell-session
mastodon$ git clone https://github.com/mastodon/mastodon.git live && cd live
mastodon$ git checkout $(git tag -l | grep -v 'rc[0-9]*$' | sort -V | tail -n 1)
```

#### 依存性解決

```shell-session
mastodon$ bundle config deployment 'true'
mastodon$ bundle config without 'development test'
mastodon$ bundle install -j$(getconf _NPROCESSORS_ONLN)
mastodon$ yarn install --pure-lockfile
```

#### 設定ファイルの生成

```shell-session
mastodon$ RAILS_ENV=production bundle exec rake mastodon:setup
Domain name: mstdn.yamachan.org
Do you want to enable single user mode? (y/N) n
Are you using Docker to run Mastodon? (Y/n) n
PostgreSQL host: (/var/run/postgresql) [そのまま Enter]
PostgreSQL port: (5432) [そのまま Enter]
Name of PostgreSQL database: (mastodon_production) [そのまま Enter]
Name of PostgreSQL user: (mastodon) [そのまま Enter]
Password of PostgreSQL user: password-for-psql-mastodon    ★PostgreSQL ユーザ mastodon のパスワード。入力しても表示されない

Redis host: (localhost) [そのまま Enter]
Redis port: (6379) [そのまま Enter]
Redis password: [そのまま Enter]

Do you want to store uploaded files on the cloud? (y/N) n

Do you want to send e-mails from localhost? (y/N) n
SMTP server: (smtp.mailgun.org) s???.xrea.com    ★XREA の契約サーバ名
SMTP port: (587) [そのまま Enter]
SMTP username: ?????@yamachan.org    ★専用に割り当てたメールボックスのアカウント名
SMTP password: ***    ★メールボックスのパスワード。入力しても表示されない
SMTP authentication: (plain) [そのまま Enter]
SMTP OpenSSL verify mode: none [そのまま Enter]
Enable STARTTLS: auto [そのまま Enter]
E-mail address to send e-mails "from": (...) *****@yamachan.org    ★メールボックスと同じドメイン名にすること！デフォルトの "notifications@mstdn.yamachan.org" だとエラーになる。"@" より左側は違ってても大丈夫。
Send a test e-mail with this configuration right now? (Y/n) y
Send test e-mail to: (お好きなメールアドレスを入力)

Save configuration? (Y/n) y

Prepare the database now? (Y/n) y

Compile the assets now? (Y/n) y

Do you want to create an admin user straight away? (Y/n) y
Username: (admin) [そのまま Enter]
E-mail: *****@yamachan.org
```
最後に、`You can login with the password: 115e44f01e7a...96bc` のような表示が出ます。
Mastodon の管理ユーザの初期パスワードなので、メモっておきます。

#### 設定ファイルに追加設定

Redis への接続を Unix ドメインソケット化します。
```diff_conf:.env.production
 DB_NAME=mastodon_production
 DB_USER=mastodon
 DB_PASS=password-for-psql-mastodon
-REDIS_HOST=localhost
-REDIS_PORT=6379
+#REDIS_HOST=localhost
+#REDIS_PORT=6379
+REDIS_URL=unix:///var/run/redis/redis.sock
 REDIS_PASSWORD=
 SMTP_SERVER=s???.xrea.com
 SMTP_PORT=587
```
パスワード文字列が入っているので、パーミッションを固めておきます。
```shell-session
mastodon$ chmod 0600 .env.production
```

### SELinux の設定を行う

※これをしないと、後ほど Mastodon を動かす際に bundle がエラーになります。

root に戻ります。
```shell-session
mastodon$ exit
```

以下を実行します。
```shell-session
# setsebool -P httpd_can_network_connect 1
# setsebool -P httpd_enable_homedirs 1
# setsebool -P httpd_read_user_content 1
```

以下のようなテキストファイル `my-mastodon-policy.te` を作成します。

```conf:my-mastodon-policy.te
module my-mastodon-policy 1.0;

require {
        type user_home_t;
        type init_t;
        class file { execute execute_no_trans open read };
}

allow init_t user_home_t:file { execute execute_no_trans open read };
```
上記ファイルを用いて、以下のコマンドを実行します。
```shell-session
# checkmodule -M -m -o my-mastodon-policy.mod my-mastodon-policy.te
# semodule_package -o my-mastodon-policy.pp -m my-mastodon-policy.mod
# semodule -i my-mastodon-policy.pp
```

### nginx の設定を行う (1/2)

起動ユーザを `nginx` から `mastodon` に変更します。
```diff_conf:/etc/nginx/nginx.conf
 #   * Official English Documentation: http://nginx.org/en/docs/
 #   * Official Russian Documentation: http://nginx.org/ru/docs/

-user nginx;
+user mastodon;
 worker_processes auto;
 error_log /var/log/nginx/error.log;
 pid /run/nginx.pid;
```
`sites-enabled` を有効にします。
```diff_conf:/etc/nginx/nginx.conf
     # for more information.
     include /etc/nginx/conf.d/*.conf;

+    # to enable virtual host
+    include /etc/nginx/sites-enabled/*;
+
     server {
         listen       80;
         listen       [::]:80;
```
ディレクトリを作成します。
```shell-session
# cd /etc/nginx
# mkdir sites-available
# mkdir sites-enabled
```

ログディレクトリを起動ユーザの所有に変更します。
（これをしないとログロテートが正常に働きませんでした）
```shell-session
# cd /var/log/nginx
# chown mastodon .
# chmod 0750 .
```

起動します。
```shell-session
# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
# systemctl start nginx
```

### Let's Encrypt の設定を行う

まずは証明書を発行します。
```shell-session
# certbot certonly --nginx -d mstdn.yamachan.org

Enter email address: *****@yamachan.org

Please read the Terms of Service at ... Do you agree?
(Y)es/(N)o: y

... share your email address with the Electronic Frontier Foundation ... ?
(Y)es/(N)o: n
```

次に、一週間に一度自動更新するように cron.weekly にスクリプトを置きます。
```shell:/etc/cron.weekly/lets_encrypt
#!/usr/bin/sh
/usr/bin/certbot renew --deploy-hook '/usr/bin/systemctl reload nginx' >> /root/lets_encrypt.log 2>&1
```
実行権限を付与します。
```shell-session
# chmod 0700 /etc/cron.weekly/lets_encrypt
```

### Mastodon のサービス設定を行う

```shell-session
# cp /home/mastodon/live/dist/mastodon-*.service /etc/systemd/system/
# systemctl daemon-reload
# systemctl enable --now mastodon-web mastodon-sidekiq mastodon-streaming
```

### nginx の設定を行う (2/2)

Mastodon のサイト設定をコピーします。
この時 `example.com` を `mstdn.yamachan.org` で置き換え、`ssl_certificate` で始まる行を有効化します。
```shell-session
# sed 's/example.com/mstdn.yamachan.org/' /home/mastodon/live/dist/nginx.conf | sed 's/# ssl_certificate/ssl_certificate/' > /etc/nginx/sites-available/mastodon
```
シンボリックリンクを貼ります。
```shell-session
# ln -s /etc/nginx/sites-available/mastodon /etc/nginx/sites-enabled/mastodon
```
`/var/lib/nginx` の所有者を `mastodon` に変更します。
```shell-session
# chown -R mastodon /var/lib/nginx
```
起動時有効化した上で、デーモンを再起動します。
```shell-session
# systemctl enable nginx
# systemctl restart nginx
```

### クリーンアップタスクを設定する

https://docs.joinmastodon.org/admin/setup/

```shell-session
# su - mastodon
mastodon$ echo $PATH
/home/mastodon/.rbenv/shims:/home/mastodon/.rbenv/bin:/home/mastodon/.local/bin:/home/mastodon/bin:/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin
# crontab -e
```
下記のように、`echo $PATH` で調べた内容を先頭に `PATH=` として書きます。
更に公式に記載のあるコマンド 2 行を追記します (`@weekly` は `0 0 * * 0` になるそうなので、敢えて時間をずらしました)。
```conf:crontab
PATH=/home/mastodon/.rbenv/shims:/home/mastodon/.rbenv/bin:/home/mastodon/.local/bin:/home/mastodon/bin:/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin

4   4   *   *   0   RAILS_ENV=production /home/mastodon/live/bin/tootctl media remove
24  4   *   *   0   RAILS_ENV=production /home/mastodon/live/bin/tootctl preview_cards remove
```

以上で、Mastodon が構築されました。
![mastodon_top.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/177073/ac60ee8e-7fa7-e67d-00f8-61d7749f0df9.png)



# 参考にさせていただいたページ

https://kyohju.com/article/post-1393.html

https://zenn.dev/kwh/articles/08be260b56b833

[^oldmastodon]: 連合の仕組みも v1 時代の OStatus から ActivityPub に変わっていたりとガラ変しているようなので、データの引継ぎも行いませんでした
[^rocky]: インスタンス構築時に OS イメージとして Rocky Linux 9.0 を選択した後、`dnf update` で更新したもの
[^putty_patch]: https://ice.hotmint.com/putty/ の putty-gdi-20210719.zip
[^key_rsa]: ホントは Ed25519 鍵にしたいが、Indigo が受け付けてくれない
[^yarn]: https://github.com/nodejs/corepack
[^rhel_equiv_pkg]: 動けばいいやの精神で似た名前のを当てはめただけなので、正しくないかもしれませんがご容赦を