LoginSignup
2
1

More than 1 year has passed since last update.

Mastodon を Rocky Linux 9.1 で構築する

Last updated at Posted at 2023-02-13

はじめに

某青い鳥の SNS がにわかに先行き不安なので、Mastodon を構築してみました。その備忘録です。

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

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

環境

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

項目 備考
OS Rocky Linux 9.12 RHEL 9.1 のバイナリ互換
Mastodon 4.0.2 2023/02/08 時点での最新版
マシン環境 WebARENA Indigo 1GB 月額 349 円の VPS
RAM 1GB・SSD 20GB・vCPU 1コア
ドメイン名管理 Value Domain
メール配送 XREA Value Domain と同じ会社のサービス

作業手順

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

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

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

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

ローカル環境で生成する

SSH 接続用の鍵を用意します。
PuTTY3 付属の puttygen.exe を用いる場合、こんな感じ。
puttygen.png

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

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

Indigo コントロールパネルの「インスタンス管理」-「SSH鍵」を開き、右側の「SSH鍵のインポート」を選ぶ。
key_import.png
先ほど保存した「OpenSSHのauthorized_keysファイルにペーストするための公開鍵」欄の文字列を貼り付ける。
鍵名は適当で OK(鍵のコメントと揃えておくといいかもしれません)。
最後に「作成」を押してインポート完了。
key_import_2.png
「インスタンス管理」-「SSH鍵」に戻り、先ほど追加した鍵が一覧表示されていれば OK。

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

インスタンスを起動する

「インスタンス管理」-「インスタンス」メニューの、右側の「インスタンスの作成」をクリック。
instance_1.png
以下のような選択画面が表示されるので、インスタンスの構成を選択する。
instance_2.png

  1. イメージは Rocky Linux 9.0。
  2. インスタンスのサイズは 1 vCPU / 1 GB RAM / 20 GB SSD / 100 Mbps。月 349 円のプランになる。
  3. SSH 鍵は先ほどアップロードしたものを選ぶ。
  4. インスタンス名は他と区別が付く名前を適当に。
  5. 選択し終わったら、「インスタンスの作成」をクリック。

作成が始まると「OS のインストール中」のような表示が出るので、数分待ちます (なぜか手元ではOS インストールが終わっても表示が更新されないので、いったん別のタブを開いてから戻ってくる必要がありました…)。
instance_3.png
先ほど作成したインスタンスが「Stopped」と表示されているので、

  1. IP アドレスを記録しておきます。
  2. 右端の「選択」を展開します。
  3. 「インスタンスの起動」を選びます。

SSH 接続してみる

Indigo の Rocky Linux イメージの場合、デフォルトで rocky というユーザが作成されています。
https://help.arena.ne.jp/hc/ja/articles/360049807634/
先ほど設定した SSH の鍵を使って接続してみます。
first_login.png
ここまでで、素の状態のインスタンスが起動しました。

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

デフォルトの port 22 はブルートフォース攻撃の定番なので、負荷軽減と心理的安心も兼ねて変更しておきます。
(ポート番号が分かれば攻撃可能なので、悪意を持った攻撃者に対しては意味ないですが)

/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 の設定も変更してね」とのコメントに従い、スーパーユーザで以下を実行します。

# semanage port -a -t ssh_port_t -p tcp 60022
# systemctl restart sshd

※まだ port 22 で接続しているセッションは閉じないで!

この状態で、port 60022 で SSH 接続してみて繋がれば OK。
putty_setting.png

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

# semanage port -l | grep ssh_port_t
ssh_port_t                     tcp      60022, 22

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

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

まず、Indigo コントロールパネルの「ネットワーク管理」-「ファイアーウォール」より、「ファイアーウォールの作成」をクリックします。
firewall_1.png
ファイアーウォール作成画面に移ったら、以下を行います。
firewall_2.png

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

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

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

SSH で接続するためのユーザ (ここでは yamazaki) を作成します。

# groupadd -g 1001 yamazaki
# useradd -g 1001 -u 1001 yamazaki
# passwd yamazaki

passwd yamazaki は任意。
やっておけば万が一 SSH で繋がらなくなった場合(ex. ファイアウォールの設定を間違えた時)に VPS のコンソールからローカルログインできます。

デフォルトユーザの所属グループをコピーします。

# 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 に追加します。

/etc/sudoers.d/99-nopasswd
yamazaki ALL=(ALL) NOPASSWD: ALL

上記の設定だと $ sudo 実行時にパスワードを聞かれなくなります。
パスワードを聞かれたい場合は yamazaki ALL=(ALL) ALL で。

# chmod 0640 /etc/sudoers.d/99-nopasswd

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

# 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 を削除します。

# userdel -r rocky

-r : ホームディレクトリとメールスプールも削除。

sudoers から、末尾の rocky で始まる行を削除します。

# vi /etc/sudoers

なぜかこっちにも居るので削除します。

# rm /etc/sudoers.d/90-cloud-init-users

事前準備

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

# dnf check-update
# dnf update
# reboot

2023/02/12 時点では、Rocky Linux 9.1 になりました。

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

タイムゾーン

# timedatectl set-timezone Asia/Tokyo

ロケール

# dnf install glibc-locale-source
# localedef -f UTF-8 -i ja_JP ja_JP

ホスト名

ホスト名は mstdn.yamachan.org とします。

# hostnamectl set-hostname mstdn.yamachan.org

その他

デフォルトだと vi エディタがショボくて扱いづらいので

# dnf install vim

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

kdump を無効化する

1GB プランなのに、free の結果表示される total 欄は 0.75GB 弱しかありません。

$ free
               total        used        free      shared  buff/cache   available
Mem:          783012      218668      521272        5708      161148      564344
Swap:              0           0           0

RHEL 9 系の仕様で kdump のためにメモリを予約しているのが原因なので、kdump を無効化します。
詳細は以下を参照してください。

スワップを有効化する

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

# dd if=/dev/zero of=/swapfile bs=1M count=1024
# chmod 0600 /swapfile
# mkswap /swapfile
# swapon /swapfile

ここまででスワップファイルが有効になりました。

free 実行時に以下のようになっていれば OK。

$ 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 に追記します。

/etc/fstab
/swapfile  none  swap  sw  0  0

Mastodon の導入

拡張リポジトリの導入

EPEL

# dnf install epel-release

RPM Fusion

# 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

# dnf config-manager --set-enabled crb

必要なツール類を入れる

wget

# dnf install wget

ImageMagick

# dnf install ImageMagick

FFmpeg

# dnf install ffmpeg ffmpeg-devel

Redis

# dnf install redis
# systemctl enable redis
# systemctl start redis

PostgreSQL

# 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

# dnf install nginx

有効化はまた後で。

Node.js

# dnf install nodejs

yarn5

# 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 系でのパッケージ名6
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
# 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 グループに追加します。

# groupadd -g 9001 mastodon
# useradd -g 9001 -u 9001 mastodon
# usermod -aG redis mastodon

PostgreSQL ユーザの作成とパスワード設定

PostgreSQL ユーザ mastodon を作成し、特権ユーザ (postgres) と mastodon にパスワードを設定します。

# 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 側の準備を。

/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
# systemctl restart redis

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

Perl モジュールを導入する

これをやっておかないと、次の Ruby 導入時にコケる

# dnf install perl-FindBin perl-lib perl-File-Compare

Ruby を導入する

# 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 を導入する

mastodon$ gem install bundler --no-document

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

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

各種サービスによって異なりますが、Value Domain の場合は概ね以下となります。
dns.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

Mastodon を導入する

環境変数を設定する

最初に、環境変数 NODE_OPTIONS を設定します。

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 ソースコードを取得する

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)

依存性解決

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

設定ファイルの生成

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 ドメインソケット化します。

.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

パスワード文字列が入っているので、パーミッションを固めておきます。

mastodon$ chmod 0600 .env.production

SELinux の設定を行う

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

root に戻ります。

mastodon$ exit

以下を実行します。

# setsebool -P httpd_can_network_connect 1
# setsebool -P httpd_enable_homedirs 1
# setsebool -P httpd_read_user_content 1

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

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 };

上記ファイルを用いて、以下のコマンドを実行します。

# 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 に変更します。

/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 を有効にします。

/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;

ディレクトリを作成します。

# cd /etc/nginx
# mkdir sites-available
# mkdir sites-enabled

ログディレクトリを起動ユーザの所有に変更します。
(これをしないとログロテートが正常に働きませんでした)

# cd /var/log/nginx
# chown mastodon .
# chmod 0750 .

起動します。

# 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 の設定を行う

まずは証明書を発行します。

# 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 にスクリプトを置きます。

/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

実行権限を付与します。

# chmod 0700 /etc/cron.weekly/lets_encrypt

Mastodon のサービス設定を行う

# 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.commstdn.yamachan.org で置き換え、ssl_certificate で始まる行を有効化します。

# sed 's/example.com/mstdn.yamachan.org/' /home/mastodon/live/dist/nginx.conf | sed 's/# ssl_certificate/ssl_certificate/' > /etc/nginx/sites-available/mastodon

シンボリックリンクを貼ります。

# ln -s /etc/nginx/sites-available/mastodon /etc/nginx/sites-enabled/mastodon

/var/lib/nginx の所有者を mastodon に変更します。

# chown -R mastodon /var/lib/nginx

起動時有効化した上で、デーモンを再起動します。

# systemctl enable nginx
# systemctl restart nginx

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

# 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 行を追記します (@weekly0 0 * * 0 になるそうなので、敢えて時間をずらしました)。

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

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

  1. 連合の仕組みも v1 時代の OStatus から ActivityPub に変わっていたりとガラ変しているようなので、データの引継ぎも行いませんでした

  2. インスタンス構築時に OS イメージとして Rocky Linux 9.0 を選択した後、dnf update で更新したもの

  3. https://ice.hotmint.com/putty/ の putty-gdi-20210719.zip

  4. ホントは Ed25519 鍵にしたいが、Indigo が受け付けてくれない

  5. https://github.com/nodejs/corepack

  6. 動けばいいやの精神で似た名前のを当てはめただけなので、正しくないかもしれませんがご容赦を

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1