サーバのことを何も知らないフロントエンドエンジニアがさくら VPS でウェブサイトを開設するまで

サーバ？なにそれおいしいの？というフロントエンドエンジニアがさくらの VPS （ CentOS7 ）でウェブサイトを開設するまでにやったことをだいたい全部まとめました。ちなみに現状、 [無事稼働しております](https://mimonelu.net/) 。
サーバエンジニアの方から見たら稚拙極まりない内容でしょうし、書いてある内容も保障できません。過不足あるでしょう。というわけで自己責任でお願いします。
ただ、ドメイン移管の下りは若干参考になるかもしれません。

## アカウントの設定

先に最低限のセキュリティ強化を行います。
作業用の一般ユーザーを作成したり、権限を変更したり。この記事で書いている手段だけでは絶対足りない、はず。

```shell
$ ssh root@160.16.XXX.XXX
# OS インストール時に設定したパスワードを入力
# 一度ログインしている場合はローカル上で `$ ssh-keygen -R 160.16.XXX.XXX` が必要かもしれない
$ useradd janedoe -G wheel
# ジェーン・ドゥの解剖はなかなか良い映画でした。オチがアレだけど
$ passwd janedoe
$ vi /etc/pam.d/su
# `# auth    required    pam_wheel.so use_uid` をコメントイン
$ vi /etc/login.defs
# `SU_WHEEL_ONLY yes` を末尾に入力
$ visudo
# `# %wheel  ALL=(ALL)    ALL` をコメントイン ※既にコメントインされていた
$ yum update
$ exit
$ ssh janedoe@160.16.XXX.XXX
```

## SSH 鍵の設定

まずはリモート（ CentOS ）で、

```shell
$ mkdir ~/.ssh
$ chmod 700 ~/.ssh
$ exit
```

次にローカル（ ここでは Mac ）で、

```shell
$ ssh-keygen -f ~/.ssh/sakura_rsa -t rsa
$ chmod 600 ~/.ssh/sakura_rsa.pub
$ scp ~/.ssh/sakura_rsa.pub janedoe@160.16.XXX.XXX:~/.ssh/authorized_keys
$ exit
# ターミナルを再起動する
$ ssh janedoe@160.16.XXX.XXX
```

ターミナルを再起動した際は下記コマンドが必要かもしれません。

```shell
$ eval "$(ssh-agent -s)" && ssh-add -K ~/.ssh/sakura_rsa
```

ローカルの `~/.bash_profile` などに追記して自動化しておくと良いかも。

```shell
$ sudo vim ~/.bash_profile
# 上記コマンドをコピペして保存
$ source ~/.bash_profile
```

また、 `Permission denied (publickey).` と返されてログインできない場合は、リモートの `/home/janedoe` のモードが `744` など自身以外の書き込みを許可しない設定になっているか確認してください。

## SSH 認証方式の変更

SSH での root ユーザーログインとパスワードによるログインを無効にします。もう後戻りはできない…（コンパネからサーバを初期化すればできますが）。

```shell
$ sudo vim /etc/ssh/sshd_config
# `#PermitRootLogin yes` → `PermitRootLogin no`
# `#PasswordAuthentication yes` → `PasswordAuthentication no`
$ sudo service sshd restart
```

## SSH ポート番号の変更とファイアウォールの設定

動作上は必須ではありませんが、セキュリティ的には必須です。

```shell
$ sudo vim /etc/ssh/sshd_config
# `#Port 22` → `Port XXXXX` ※空いているポートであれば何でも良いが、 `10022` のような類推できる番号は避けたい
$ sudo service sshd restart
$ sudo systemctl enable firewalld
$ sudo systemctl start firewalld
$ sudo systemctl status firewalld
$ sudo cp /usr/lib/firewalld/services/ssh.xml /etc/firewalld/services/ssh.xml
$ sudo vim /etc/firewalld/services/ssh.xml
# `port="22"` → `port="XXXXX"`
$ sudo firewall-cmd --add-service=http --zone=public --permanent
$ sudo firewall-cmd --add-service=https --zone=public --permanent
$ sudo firewall-cmd --reload
$ exit
$ ssh -p XXXXX janedoe@160.16.XXX.XXX
```

## 時刻設定

`$ date` で正しい時刻が表示されたので不要だと思います。

## httpd （ Apache ） のインストール

絶対に失敗したくないので nginx よりも枯れた Apache にしました。

### Mac の場合

```shell
$ sudo apachectl stop
$ sudo launchctl unload -w /System/Library/LaunchDaemons/org.apache.httpd.plist
$ brew install httpd
$ sudo vim /usr/local/etc/httpd/httpd.conf
# `Listen 8080` → `Listen 80`
# `ErrorDocument 404 /404.html` を追記
$ sudo vim /usr/local/etc/httpd/extra/httpd-ssl.conf
# `Listen 8443` → `Listen 443`
$ sudo brew services start httpd
# `sudo` は付けなくても起動するが、接続は拒否されるため
```

すべて正常終了したらブラウザで http://localhost にアクセスして Apache のデフォルトページが表示されることを確認します。
他、些細なメモ。

* 起動コマンド `$ sudo brew services start httpd`
* 再起動コマンド `$ sudo brew services restart httpd`
* 停止コマンド `$ sudo brew services stop httpd`
* 設定ファイル `/usr/local/etc/httpd/httpd.conf`
* 公開フォルダ `/usr/local/var/www`

### CentOS の場合

```shell
$ sudo yum install httpd
$ sudo vim /etc/httpd/conf/httpd.conf
# `ErrorDocument 404 /404.html` を追記
$ sudo systemctl enable httpd
$ sudo systemctl start httpd
```

すべて正常終了したらブラウザで http://160.16.XXX.XXX/ にアクセスして Apache のデフォルトページが表示されることを確認します。
他、些細なメモ。

* 起動コマンド `$ sudo systemctl start httpd`
* 再起動コマンド `$ sudo systemctl restart httpd`
* 停止コマンド `$ sudo systemctl stop httpd`
* 設定ファイル `/etc/httpd/conf/httpd.conf`
* 公開フォルダ `/var/www/html`

## お名前ドットコムからさくらインターネットへのドメイン移管

私は既に `mimonelu.net` というドメインをお名前ドットコム経由で所有していたのですが、 **色々思うところがあったので** ドメインもさくらへ移管することにしました。

1. [お名前.com Navi](https://www.onamae.com/navi/login/) にログイン
2. `ドメイン設定` → `登録情報の設定` → `Whois情報公開代行設定` にて代行設定を解除（ **この時点で自身の情報が公開される点に注意** ）
3. `ドメイン設定` → `登録情報の設定` → `ドメインWhois情報変更` にて自身の情報を再設定（する必要はないかもしれないが念のため）
4. `ドメイン設定` → `ドメイン自動更新設定` にてドメイン自動更新を解除する
5. `ドメイン一覧` → `ドメイン詳細` （ドメイン名のリンクを選択） → `AuthCode` をメモしておく（ついでに `ドメイン情報（Whois情報）` も確認しておく）
6. [WHOIS 検索](https://tech-unlimited.com/whois.html)で情報が更新されているか確認（ `Registrant` などに自身の情報が記載されていれば良い）
7. `登録者名義変更承認手続きのお願い` というようなメールが来るので早急に承認
8. [さくらのドメイン転入申込画面](https://secure.sakura.ad.jp/order/domain/transfer/authentication)から転入を申し込む
9. `[JPRS] レジストラトランスファー承認手続きのご案内` というようなメールが来るので早急に承認
10. [さくらのコンパネ](https://secure.sakura.ad.jp/menu/service/)にて `gTLDドメイン` の `有効期限` が `転入申請中` か `転入手続き中` になっていることを確認
なお、 `【要返信】[さくらインターネット]ドメイン移管手続き未完了のお知らせ` とか `トランスファー申請不承認のご連絡` というメールが来たら失敗
お名前ドットコム側の設定を見直し、再設定依頼の旨をさくらのメールに返信する
11. 成功すると `トランスファー申請承認のご確認` というメールが来るので早急に承認
12. さらにしばらくすると `ドメイン転入作業完了のご連絡` というメールが来る
13. [管理ドメイン一覧](https://secure.sakura.ad.jp/menu/domain/)からドメインの `WHOIS 情報` の `登録者` を編集（任意）。 `名前 (JP)` と `名前 (EN)` には自身の本名が登録されていると思われるため、変更した方が良い

## お名前ドットコムのクレジットカード情報の削除とアカウントの解約

趣旨からは離れますが、私が苦悶する様をお楽しみください。

1. お名前ドットコムで管理しているドメインがなくなったため、[クレジットカード情報を削除](https://navi.onamae.com/payment/detail/domain)しようとしたところ、 **なぜか** できなかった
2. [お問い合わせフォーム](https://help.onamae.com/app/ask/input/)から調査を依頼。先方へ送信した内容は以下の通り

```
クレジットカードを削除できないので、削除していただけますようお願いします。
なお、ドメインは移管済みでひとつもなく、自動更新設定・DNS追加オプション・お名前パーキングといったサービスは使っておりません。
```

3. `【お名前.com】お問い合わせの件につきまして` というメールを受信。ドメインパーキングという機能が **なぜか** ドメインもないのに使用されていることを知る
4. ドメインパーキングの解約日は翌日以降の指定となるため、翌日を解約日として解約を依頼
5. `[お名前.com]ドメインパーキング解約 受付通知` というメールを受信。解約時にあらためてメールを送信する旨を知る
6. 翌日以降になっても **なぜか** 同機能は解約されなかった
7. 翌々日に `[お名前.com]ドメインパーキング解約 完了通知` というメールを受信。クレジットカード情報は削除できた
8. さらに[お名前IDの削除](https://navi.onamae.com/account/delete/check)からアカウントを削除しようとしたところ、 **なぜか** `ご契約中のサービスがあるため、お名前IDを削除することができません。` と拒否された
9. ~~現在に至る~~ 本日2019年5月5日、再試行したところ退会できました。元号を股にかけたぞ

## ドメイン設定

以降は仮に `arien-yosami.com` というドメインを所有しているものとして書いています。

1. さくらではお試し期間中の場合はネームサーバを利用できないため、[契約サービス一覧](https://secure.sakura.ad.jp/menu/service/)から本登録を行う（よくわかりません…しなくてもよいのかも）
2. サーバの `状態` が `申込中` や `準備中` から `利用中` に変更されたら本登録完了
3. [管理ドメイン一覧](https://secure.sakura.ad.jp/menu/domain/)からドメインの `ゾーン編集` を行う
4. `簡単設定` に IP アドレスを指定して設定
5. [管理ドメイン一覧](https://secure.sakura.ad.jp/menu/domain/)からドメインの `WHOIS 情報` を選択
6. 画面最下部の `ネームサーバ1` を `ns1.dns.ne.jp` に、 `ネームサーバ2` を `ns2.dns.ne.jp` に、他は空にして `送信する`

私の場合、小一時間ほどで反映されました。
なお、 `現在、他の方が arien-yosami.com のゾーン情報を編集中です。` と言われた際は、心当たりがない限り `ロック解除` して良いと思います。

## HTTPS 対応

SSL 証明書は [Let’s Encrypt](https://letsencrypt.jp/) を使います。
さくらの VPS には Let’s Encrypt を自動設定するスタートアップスクリプト `CentOS_LetsEncrypt` があるものの、もれなく nginx もインストールされてしまうため（今回は Apache のため）、手動で設定します。
先に Let’s Encrypt の注意点から。

* IP アドレスの SSL には未対応（ドメインのみ対応）
* 証明書の期限は 3 ヶ月。 3 ヶ月が経過する前に更新する必要あり。ただし 30 日未満でなければ更新はされない

次に手順。

```shell
$ sudo httpd -M | grep "ssl"
# mod_ssl （ ssl_module ）がヒットしない場合はインストールが必要
$ sudo yum install mod_ssl
$ sudo systemctl restart httpd
# この状態でも一応 https://arien-yosami.com/ にアクセス可能
$ sudo firewall-cmd --list-all
# `services` に `https` があれば良し
$ sudo yum install certbot python2-certbot-apache
$ sudo certbot --apache -d arien-yosami.com
# 登録するメールアドレスは受信できるものであれば何でも良い
# メールアドレスのシェアは拒否した
```

ここで `Unable to find a virtual host listening on port 80 which is currently needed for Certbot to prove to the CA that you control your domain. Please add a virtual host for port 80.` と表示された場合、

```shell
$ sudo vim /etc/httpd/conf/httpd.conf
```

とし、下記コードを最下部にコピペします。

```
NameVirtualHost *:80

<VirtualHost *:80>
ServerAdmin root@arien-yosami.com
DocumentRoot /var/www/html
ServerName arien-yosami.com
</VirtualHost>
```

続き。

```shell
$ sudo systemctl restart httpd
$ sudo certbot --apache -d arien-yosami.com
```

ここで `No redirect` か `Redirect` かを迫られたので `Redirect` を選択しました（すべての http リクエストを https にリダイレクト）。
すべて正常終了したら再起動します。

```shell
$ sudo systemctl restart httpd
```

しばらくすると https://arien-yosami.com/ にアクセスできるはず。ブラウザで「この接続は保護されています」などと表示されれば OK です。
ついでに、証明書の更新作業を cron で自動化しておきます。更新自体は `sudo certbot renew` で行えるので任意です。 30 日未満でなくとも更新はされないだけで害はない模様。

```shell
$ su
# sudo が必要なので root ユーザーの cron に設定する
$ crontab -e
# `0 0 * * * /usr/bin/certbot renew` を追記（実行タイミングは任意）
$ su janedoe
# `su` したら元のユーザーに戻しておくこと
```

なお、 root ユーザーにおける cron のログは `sudo cat /var/mail/root` で確認できます。

## HTTP/2 対応

**WIP!** Chrome の Audits が減点されるので早く対応したい…。

## 再起動設定

やっぱり一日に一度リブートしたい！という欲求に駆られたので、参考までに書いておきます。

```shell
$ su
$ crontab -e
# `55 5 * * * /sbin/reboot` を追記（実行タイミングは任意）
$ su janedoe
```

## Node.js のインストール

フロントエンドエンジニアなので、バックエンドでも Node を使います。
インストールには、 Node のバージョンマネージャーとしては GitHub のスター数が一番多く、かつ扱いやすい [nvm](https://github.com/creationix/nvm) を使います。

```shell
$ curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.11/install.sh | bash
# 上記のスクリプトは https://github.com/creationix/nvm#install-script を参照して都度変更すること
$ source ~/.bashrc
$ nvm install node
$ nvm use node
$ nvm alias default v10.11.0
# 上記の Node バージョンは https://nodejs.org/ja/ を参照して都度変更すること
$ node -v
$ npm -v
```

## Redis の準備

[これ](https://mimonelu.net/etoris/)と[これ](https://mimonelu.net/textwits/)で Redis を使っています。

### Mac の場合

* インストール

```shell
$ brew install redis
$ redis-server -v
```

* バックグラウンドでサーバを起動 `$ brew services start redis`
* バックグラウンドのサーバを停止 `$ brew services stop redis`

### CentOS の場合

* インストール `$ sudo yum -y install redis`
* サービスの起動 `$ sudo systemctl start redis.service`
* サービスの停止 `$ sudo systemctl stop redis.service`
* サーバ起動時にサービスを自動的に起動するようにする `$ sudo systemctl enable redis.service`

### 良く使うコマンド

* CLI の起動 `$ redis-cli`
* CLI の起動（データベース番号を指定する場合） `$ redis-cli -n DATABASE_INDEX`
* データベースの全データの消去

```shell
$ flushdb
$ quit
```

## MongoDB の準備

お肌に合わないため使いませんでしたが、おまけとして。

### Mac の場合

```shell
$ brew install mongodb
$ sudo mkdir /data/db
$ sudo chown ADMIN_NAME:admin /data/db
# ADMIN_NAME は root ユーザー名
$ mongod --fork --nojournal --noprealloc --logpath /data/db/log.txt --dbpath /data/db
```

### CentOS の場合

```shell
$ yum install mongodb
$ sudo mkdir /home/janedoe/mongodb
$ sudo chown janedoe:janedoe /home/janedoe/mongodb
$ mongod --fork --nojournal --noprealloc --logpath /home/janedoe/mongodb/log.txt --dbpath /home/janedoe/mongodb
```

### 停止したい場合

```shell
$ mongo
$ use admin
$ db.shutdownServer();
$ quit();
```

## その他

* Mac でよく見る `sed -i '' ...` という記法は CentOS 上では `sed -i ...` にしないと動作しない
* cron で npm が認識されない場合は、最初に `PATH` を通すと良い（ `$ echo $PATH` で表示された内容を `0 * * * * PATH=XXX && cd /home/janedoe/hoge && npm run fuga` の `XXX` にコピペする）

## おわりに

いやこれ終わらない気がする💀