マストドンのインスタンスをGCPで立ち上げてみた

# 概要
- マストドン始めてみたけど、ハマるタンスがない
- サッカー（ガンバ大阪）が好き
- そうだ、ガンバ大阪のタンスを立ち上げてみよう！

## 環境構成
- GCP VM f1-micro (CentOS7, Storage 30G)
- nginx
- dockerは使わない
- 独自ドメイン(お名前.com)

## 手順
### GCPでVMインスタンスを生成する。
- f1-micro, 30G
- us-west1(オレゴン)

お名前.comのネームサーバ変更に反映させる

###swapを作成する
```
dd if=/dev/zero of=/swapfile bs=1M count=2048
chmod 600 /swapfile
mkswap /swapfile
swapon /swapfile
```

### Timezoneを東京に設定
```
timedatectl set-timezone Asia/Tokyo
```

### SELINUXを無効化
```
vim /etc/selinux/config 
> SELINUX=disabled
```

### firewallにhttp,httpsポートを解放
```
firewall-cmd --permanent --add-service={http,https} && firewall-cmd --reload
```

### 一旦再起動
```
shutdown -r now
```

### 環境構築
```
yum -y update && yum -y groupinstall "Development tools"
```

### PostgreSQL
```
yum -y install https://download.postgresql.org/pub/repos/yum/reporpms/EL-7-x86_64/pgdg-redhat-repo-latest.noarch.rpm
yum -y install yum-utils
yum-config-manager --enablerepo=pgdg96
yum -y install postgresql96-{contrib,devel,server}
```

インストール出来たら、DBの初期化＆confファイルを編集して起動

```
/usr/pgsql-9.6/bin/postgresql96-setup initdb
echo "listen_addresses = '*'" >> /var/lib/pgsql/9.6/data/postgresql.conf 
cd /var/lib/pgsql/9.6/data/
cp pg_hba.conf p_hba.conf.org
echo "# PostgreSQL Client Authentivation Configuration File" > ./pg_hba.conf 
echo "# ==============================================" >> ./pg_hba.conf 
echo "local all all             trust" >> ./pg_hba.conf 
echo "host all all 127.0.0.1/32 trust" >> ./pg_hba.conf 
echo "host all all ::1/128      trust" >> ./pg_hba.conf 
systemctl start postgresql-9.6 && systemctl enable $_
 
```

mastodon用DB作成

```
cd ~/
su - postgres -c 'psql -c "CREATE USER mastodon CREATEDB;"'
sed -i '/shared_preload_libraries/ s/^#//' /var/lib/pgsql/9.6/data/postgresql.conf
set -i "/shared_preload_libraries/ s/''/'pg_stat_statements'/" /var/lib/pgsql/9.6/data/postgresql.conf
sed -i "/shared_preload_libraries/a pg_stat_statements.track = all" /var/lib/pgsql/9.6/data/postgresql.conf
systemctl restart postgresql-9.6 
```

### LetsEncrypt(certbot)
```
yum -y install certbot
certbot certonly --standalone -d example.com
```
example.comの部分を自分のサイトドメインに変更する

### nginx
```
cat << "_EOF_" > /etc/yum.repos.d/nginx.repo
[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/centos/$releasever/$basearch/
gpgcheck=0
enabled=1
_EOF_
yum install nginx
```
インストール出来たら、confファイルを作成

```
mv /etc/nginx/conf.d/default.conf /etc/nginx/conf.d/default.conf.old
cat << "_EOF_" > /etc/nginx/conf.d/mastodon.conf
map $http_upgrade $connection_upgrade {
  default upgrade;
  ''      close;
}
server {
  listen 80;
  listen [::]:80;
  server_name example.com;
  return 301 https://$host$request_uri;
}
server {
  listen 443 ssl;
  listen [::]:443 ssl;
  server_name example.com;
  ssl_protocols TLSv1.2;
  ssl_ciphers EECDH+AESGCM:EECDH+AES;
  ssl_ecdh_curve prime256v1;
  ssl_prefer_server_ciphers on;
  ssl_session_cache shared:ssl:10m;
  ssl_certificate          /etc/letsencrypt/live/example.com/fullchain.pem;
  ssl_certificate_key      /etc/letsencrypt/live/example.com/privkey.pem;
  ssl_trusted_certificate  /etc/letsencrypt/live/example.com/chain.pem;
  ssl_stapling             on;
  ssl_stapling_verify      on;
  keepalive_timeout    70;
  sendfile             on;
  client_max_body_size 0;
  root /home/mastodon/live/public;
  gzip on;
  gzip_disable "msie6";
  gzip_vary on;
  gzip_proxied any;
  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; includeSubDomains; preload";
  location / {
    try_files $uri @proxy;
  }
  location @proxy {
    proxy_set_header Host $host;
    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;
    proxy_set_header Proxy "";
    proxy_pass_header Server;
    proxy_pass http://localhost:3000;
    proxy_buffering off;
    proxy_redirect off;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $connection_upgrade;
    tcp_nodelay on;
  }
  location /api/v1/streaming {
    proxy_set_header Host $host;
    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;
    proxy_set_header Proxy "";
    proxy_pass http://localhost:4000;
    proxy_buffering off;
    proxy_redirect off;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $connection_upgrade;
    tcp_nodelay on;
  }
  error_page 500 501 502 503 504 /500.html;
}
_EOF_
systemctl start nginx && systemctl enable $_
```
ここも、example.comを置換する。


### ImageMagick
```
yum -y install ImageMagick
```

### FFmpeg
画像処理系プラグイン

```
yum -y install https://download1.rpmfusion.org/free/el/rpmfusion-free-release-7.noarch.rpm
yum -y install ffmpeg
```

### Redis
sidekiqで利用するNoSQLデータベース。

```
yum -y install epel-release && yum -y install redis
systemctl start redis && systemctl enable $_
```

### Node.js
バージョンにこだわりはないが、10.x系を入れる

```
curl -sL https://rpm.nodesource.com/setup_10.x | bash
yum install -y nodejs
```

### Yarn
```
curl -sL https://dl.yarnpkg.com/rpm/yarn.repo -o /etc/yum/repos.d/yarn.repo
curl -o- -L https://yarnpkg.com/install.sh | bash
```
これで入るはずだが、失敗したら

```
npm install -g yarn
yarn init
```

### Ruby
Rubyは2.6.1を入れる
依存性パッケージを先に入れる

```
yum -y install bzip2 gcc-c++ git {openssl,readline,zlib}-devel
```

以下はmastodonインストールで個別インストールすることになったので、先に入れておく

```
yum -y install {libicu,protobuf,libidn}-devel
```

```
useradd mastodon
su - mastodon
git clone https://github.com/rbenv/rbenv.git ~/.rbenv
cd ~/.rbenv && src/configure && make -C src && cd ~
echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile
echo 'eval "$(rbenv init -)"' >> ~/.bash_profile && source ~/.bash_profile
git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build
rbenv install 2.6.1 && rbenv global $_ && rbenv rehash
```
f1-microだと非力な為にそこそこ時間掛かるので、気長に待つ
尚、gemインストール途中で`killed'が出たらメモリ不足なので、swap設定ミスってるか容量不足なので適宜修正して再実行すること

### Bundler
```
gem install bundler
```

### mastodon本体
```
cd ~ && git clone https://github.com/tootsuite/mastodon.git live && cd live
git checkout $(git tag | tail -n 1)
// 途中でエラーになるので先に個別インストール
gem install charlock_holmes -v '0.7.6' --source 'https://rubygems.org/'
export PKG_CONFIG_PATH=/usr/lib64/pkgconfig:/usr/share/pkgconfig
gem install cld3 -v '3.2.4' --source 'https://rubygems.org'
gem install idn-ruby -v '0.1.0' --source 'https://rubygems.org/'
// 一括インストール
bundle install --deployment --without development test
yarn install
```

### 設定ウィザード
```
cd ~/
RAILS_ENV=production bundle exec rake mastodon:setup
```
```
Your instance is identified by its domain name. Changing it afterward will break things.
Domain name: (Mastodon稼働サーバドメイン)

Single user mode disables registrations and redirects the landing page to your public profile.
Do you want to enable single user mode? (お一人様モードならyes)

Are you using Docker to run Mastodon? (Docker使用しているならyes)

PostgreSQL host: (defaultならlocalhost)
PostgreSQL port: (5432)
Name of PostgreSQL database: (mastodon)
Name of PostgreSQL user: (mastodon)
Password of PostgreSQL user: (未設定なら未入力でok)

Redis host: (localhost)
Redis port: (6379)
Redis password: (未設定なら未入力でok)

Do you want to store uploaded files on the cloud? (後で設定するのでNo)

Do you want to send e-mails from localhost? (一旦yes)
E-mail address to send e-mails "from": (送信元アドレスを設定)
Send a test e-mail with this configuration right now? (yes)
Send test e-mail to: (テスト送信先アドレス)

This configuration will be written to .env.production
Save configuration? (Yes)

// 初期化を実行
Now that configuration is saved, the database schema must be loaded.
If the database already exists, this will erase its contents.
Prepare the database now? (Yes)
(略)

// これが出たら完了！
All done! You can now power on the Mastodon server 🐘

// 管理者ユーザー作成
Do you want to create an admin user straight away? (yes)
Username: (管理者ユーザーID。任意)
E-mail: (登録アドレス)
You can login with the password: (ここにパスワードが表示されるので、メモる)
You can change your password once you login.
```

### サービス起動
mastodon-web.serviceの設定

```
cat << "_EOF_" > /etc/systemd/system/mastodon-web.service
[Unit]
Description=mastodon-web
After=network.target

[Service]
Type=simple
User=mastodon
WorkingDirectory=/home/mastodon/live
Environment="RAILS_ENV=production"
Environment="PORT=3000"
ExecStart=/home/mastodon/.rbenv/shims/bundle exec puma -C config/puma.rb
TimeoutSec=15
Restart=always

[Install]
WantedBy=multi-user.target
_EOF_
```

mastodon-sidekiq.serviceの設定

```
cat << "_EOF_" > /etc/systemd/system/mastodon-sidekiq.service 
[Unit]
Description=mastodon-sidekiq
After=network.target

[Service]
Type=simple
User=mastodon
WorkingDirectory=/home/mastodon/live
Environment="RAILS_ENV=production"
Environment="DB_POOL=5"
ExecStart=/home/mastodon/.rbenv/shims/bundle exec sidekiq -c 5 -q default -q mailers -q pull
TimeoutSec=15
Restart=always

[Install]
WantedBy=multi-user.target
_EOF_
```

mastodon-streaming.serviceの設定

```
cat << "_EOF_" > /etc/systemd/system/mastodon-streaming.service
[Unit]
Description=mastodon-streaming
After=network.target

[Service]
Type=simple
User=mastodon
WorkingDirectory=/home/mastodon/live
Environment="NODE_ENV=production"
Environment="PORT=4000"
ExecStart=/usr/bin/npm run start
TimeoutSec=15
Restart=always

[Install]
WantedBy=multi-user.target
_EOF_
```

サービス起動

```
systemctl daemon-reload && \
systemctl start mastodon-{web,sidekiq,streaming} && \
systemctl enable $_
```

これで、mastodonを立ち上げたアドレスにアクセスして、ログイン画面が表示されればOK

そんな訳で、[ガンバ大阪丼](https://gamba.osaka.jp)をよろしくお願いします。


## 参考リンク
- [Mastodon を CentOS にインストールする (Docker未使用)](https://qiita.com/bezeklik/items/1a8530d530613acd665c)
- [Mastodon構築手順・非Docker版](https://qiita.com/kumasun/items/543c62eedeb0f00e5afd)
- [Mastodonの弱小インスタンスを運用するのに設定したこと（随時更新）](https://qiita.com/yakumo/items/6af1d26c601cd0672e68)
- [Mastodon 保守メモ](https://qiita.com/kumasun/items/bf4997f181f893130041)
- [Google Compute Engine から SendGrid 経由でメール送信](https://blog.apar.jp/web/5411/)