nginx と Let's Encrypt で1台のサーバーで複数サイトを SSL 化

ここではLet's Encryptとnginxを使ってサイトをSSL化する方法と、さらにそのままnginxの機能を使って1台のサーバーで複数のサイトを運営し、それらのすべてSSL化した時にやったことをご紹介します。
nginxの設定ファイルを公開しましたので、詳細はこちらを参照してください。
https://github.com/TakuKobayashi/ActivatingNginxConf

# SSLとは
SSLとはデータを暗号化して通信を行う仕組みです。
SSLを使うことができるようにすると、URLに以下のように`https://`であったり(HTTPの場合)、`wss://`(Websocketの場合)といったURLを使うことができるようになります。
![https.png](https://qiita-image-store.s3.amazonaws.com/0/72596/d7f2d720-7a8f-64db-cd02-5696d1812617.png)

詳しくは[こちら](https://ja.wikipedia.org/wiki/Transport_Layer_Security)など

# SSL証明書
サーバーをSSLに対応させて通信を行えるようにするためには<font color="#FF0000">**SSL証明書**</font>というものが必要です。
SSL証明書は一般的に[認証局](https://ja.wikipedia.org/wiki/%E8%AA%8D%E8%A8%BC%E5%B1%80)と呼ばれる、信頼された第三者からお金を払って証明書を発行してもらう必要があります。
<font color="#FF0000">費用は年間数万円〜数十万円</font>です。
高いです...

# Let's Encryptとは
[Let's Encrypt](https://letsencrypt.jp/)とは<font color="#FF0000">SSL証明書を無料で発行</font>してくれる認証局(団体・プロジェクト)です。

# Let's Encryptを用いてSSL証明書を取得する
Let's Encryptを用いてSSL証明書を取得するにはPython2.7以上が入っている必要があるので、Python2.7以上をインストールする。
Pythonのバージョンを切り替えられるように、私は[Pyenv](https://github.com/pyenv/pyenv)を入れた後Pythonをインストールしました。
## Pythonをインストール
### Pyenvを使うために必要なライブラリなどをインストール(CentOSの場合)

```
yum install gcc gcc-c++ make git openssl-devel bzip2-devel zlib-devel readline-devel sqlite-devel bzip2 sqlite
zlib-devel bzip2 bzip2-devel readline-devel sqlite sqlite-devel openssl-devel
```
### Pyenvをインストール

```
git clone git://github.com/yyuu/pyenv.git
```

### Pyenvにパスを通す

```
cd pyenv/
vi ~/.bashrc
```

`.bashrc` にpyenvのある場所を調べて(ここでは `/app/library/pyenv` にある)、以下のように記述してパスを通す。

```sh
export PYENV_ROOT="/app/library/pyenv"
if [ -d "${PYENV_ROOT}" ]; then
    export PATH=${PYENV_ROOT}/bin:$PATH
    eval "$(pyenv init -)"
fi
```
設定したパスを有効にする。

```
source ~/.bashrc
```
そして

```
pyenv
```
を実行し、エラーが出なければパスが通りました。

### インストール可能なPythonのバージョンを調べる

```
pyenv install --list
```
### Pyenvを使ってPythonをインストール
ここではPython2.7.13をインストールします

```
pyenv install 2.7.13
```
### インストールしたPythonを使えるようにする

```
pyenv global 2.7.13
```
これで

```
python
```
を実行し、エラーが出なければインストール完了です。

## Let's EncryptからSSL証明書を取得する
### 証明書の確認のための専用のパスを作成する
この後行うcertbotを使って証明書を取得する際、サーバーが存在するか、チェックが行われます。このチェックに対応するために専用のパスを作成する必要があります。
今回はドキュメントルート以下にディレクトリを作成することで対応します。
[Nginx](https://ja.wikipedia.org/wiki/Nginx)を使います
Nginxの場合、ドキュメントルートは `[nginxのルートディレクトリ]/conf.d/default.conf` で確認できます。今回の場合は以下に記載されている内容です。

```nginx
 location / {
   root   /usr/share/nginx/html;
   index  index.html index.htm;
 }
```
よって以下のようにドキュメントルートからパスを設定するために空のディレクトリを作成します。

```
mkdir [nginxのルートディレクトリ]/html/.well-known
```
次に、作成したパスをnginx側で使えるようにするために、`[nginxのルートディレクトリ]/nginx.conf`を編集します。

```nginx
http{
  ...
  server {
    ...
    location ^~ /.well-known/acme-challenge/ {
      root /usr/share/nginx/html/.well-known;
    }
    ...
  }
}
```
その後、nginxを再起動して、変更内容を適用させます。

```
service nginx restart
```

### [certbot](https://github.com/certbot/certbot)を(Gitを使って)インストールする
certbotとはLet’s Encrypt が提供しているツールであり、Let’s Encrypt と通信するエージェント（クライアント）です。
Gitを使わない方法もありますが今回はGitを使った方法でインストールします。

```
git clone https://github.com/certbot/certbot
```
### certbotを使って証明書を取得する

```
cd certbot/
./certbot-auto certonly
```
とすると以下のようなアナウンスがあるので各種設定していく。

```
How would you like to authenticate with the ACME CA?

1: Spin up a temporary webserver (standalone)

2: Place files in webroot directory (webroot)

Select the appropriate number [1-2] then enter: 2
Enter email address (used for urgent renewal and security notices) (Enter 'c' to

cancel):[メールアドレス]

Please read the Terms of Service at
https://letsencrypt.org/documents/LE-SA-v1.1.1-August-1-2016.pdf. You must agree
in order to register with the ACME server at

https://acme-v01.api.letsencrypt.org/directory

(A)gree/(C)ancel: A



Would you be willing to share your email address with the Electronic Frontier
Foundation, a founding partner of the Let's Encrypt project and the non-profit
organization that develops Certbot? We'd like to send you email about EFF and

our work to encrypt the web, protect its users and defend digital rights.

(Y)es/(N)o: Y
Please enter in your domain name(s) (comma and/or space separated)  (Enter 'c'
to cancel):[ドメイン名](複数ドメイン設定したい場合は、カンマ区切りで列挙していきます。ここでは ue4yochi.net と設定します)
Obtaining a new certificate
Performing the following challenges:
http-01 challenge for ue4yochi.net

Select the webroot for ue4yochi.net:

1: Enter a new webroot

Press 1 [enter] to confirm the selection (press 'c' to cancel): 1
Input the webroot for ue4yochi.net: (Enter 'c' to cancel):[上記で作成したディレクトリのパス]

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at
   /etc/letsencrypt/live/ue4yochi.net/fullchain.pem. Your cert will
   expire on 2017-10-03. To obtain a new or tweaked version of this
   certificate in the future, simply run certbot-auto again. To
   non-interactively renew all of your certificates, run
   "certbot-auto renew"
 - Your account credentials have been saved in your Certbot
   configuration directory at /etc/letsencrypt. You should make a
   secure backup of this folder now. This configuration directory will
   also contain certificates and private keys obtained by Certbot so
   making regular backups of this folder is ideal.
 - If you like Certbot, please consider supporting our work by:

Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
   Donating to EFF:                    https://eff.org/donate-le
```
以上で、
<font color="#FFAA00">/etc/letsencrypt/live/[ドメイン名]/</font> に
<font color="#FFAA00">fullchain.pem</font> と <font color="#FFAA00">privkey.pem</font> のファイルがあれば証明書を取得完了です。

# 取得した証明書を適用し、SSLを有効にする。
`nginx.conf`ファイルを以下のように編集します。


```nginx
http{
  ...
  server {
    listen 443 ssl;
　　　　　　　　server_name ドメインA;
    ...
    ssl_certificate     /etc/letsencrypt/live/[ドメイン名]/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/[ドメイン名]/privkey.pem;
    ...
    location ^~ /.well-known/acme-challenge/ {
      root /usr/share/nginx/html/.well-known;
    }
    ...
    location / {
      ...
    }
  }
}
```
その後、nginxを再起動して、変更内容を適用させます。

```
service nginx restart
```
これでサーバーが稼働していれば、
`https://ドメインA` にブラウザでアクセスすることができれば、SSL化完了です。

# nginxを使って一台のサーバーで複数のサイトを運用し、かつ全てをSSL化
上記のnginxでのSSL化対応は1台のサーバーで複数のサイトを運用しようとする場合にも適用させることができます。
あまり、お金かけたくないので1台のサーバーで複数サイト運営できたらいいですよね♪
しかも、全てSSLに対応できたらうれしいですね♪
ただし、<font color="red"><b>1台のサーバーで複数のサイトを運営するためには、ドメインを1個以上必要</b></font>です。

## nginxで1台のサーバーで複数のサイト(異なるドメイン)を運用する設定
ここまでで、すでにひとつのサイトの設定は完了しています。
まずは、2個目のサイトをcertbotで証明書を取得できるように、1個目同様にチェック可能なパスを作成します。
1個目の場合と同じものを使うこともできますが、それぞれ設定する必要があります。
以下のようにnginxの設定ファイルを記述します。

```nginx
http{
  ...
  server {
    listen 443 ssl;
　　　　　　　　server_name ドメインA;
    ...
    ssl_certificate     /etc/letsencrypt/live/[ドメイン名]/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/[ドメイン名]/privkey.pem;
    ...
    location ^~ /.well-known/acme-challenge/ {
      root /usr/share/nginx/html/.well-known;
    }
    ...
    location / {
      ...
    }
  }

  server {
    listen 443 ssl;
　　　　　　　　server_name ドメインB;
    ...
    location ^~ /.well-known/acme-challenge/ {
      root /usr/share/nginx/html/.well-known;
    }
    ...
    location / {
      ...
    }
}
```
その後、nginxを再起動して、変更内容を適用させます。

```
service nginx restart
```

### 複数サイトで使えるSSL証明書の発行
上記の証明書取得手順と同様に以下のように入力する。

```
./certbot-auto certonly
```
この場合、すでに証明書を取得しており、新たにドメインを取得して証明書を追加する場合も同様に実行すれば適用できます。
出てきたアナウンスを読み進めていき、

```
...
Please enter in your domain name(s) (comma and/or space separated)  (Enter 'c'
to cancel):ドメインA,ドメインB,...
...
```
以上の質問がされたところで、複数種類のドメインを,で区切って並ることで複数のドメインに対応した証明書を発行することができます。
設定の際にそれぞれ、チェックする場所を尋ねられますが、同じものを指定するのでOKです。

### nginxで取得した証明書をそれぞれに適用させる。
複数ドメインに対応した証明書は上記1個目の場合と同じ場所に同じファイルに設定されているので、複数のドメインに適用させる場合も同様になるように`nginx.conf`を以下のように修正します。

```nginx
http{
  ...
  server {
    listen 443 ssl;
　　　　　　　　server_name ドメインA;
    ...
    ssl_certificate     /etc/letsencrypt/live/[ドメイン名]/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/[ドメイン名]/privkey.pem;
    ...
    location ^~ /.well-known/acme-challenge/ {
      root /usr/share/nginx/html/.well-known;
    }
    ...
    location / {
      ...
    }
  }

  server {
    listen 443 ssl;
　　　　　　　　server_name ドメインB;
    ssl_certificate     /etc/letsencrypt/live/[ドメイン名]/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/[ドメイン名]/privkey.pem;
    ...
    location ^~ /.well-known/acme-challenge/ {
      root /usr/share/nginx/html/.well-known;
    }
    ...
    location / {
      ...
    }
  }
}
```
その後、nginxを再起動して、変更内容を適用させます。

```
service nginx restart
```

これでサーバーが稼働していれば、
`https://ドメインA`
および
`https://ドメインB`
にブラウザでアクセスすることができれば、両方共SSL化完了です。

### 補足
上記の1台のサーバーで複数の異なるドメインを見ることができる設定をした場合、`nginx.conf`に記述した上の方の設定が優先されます。例えば、以下のURLを入力した場合
`https://[IPアドレス]`
や
`https://[DNS名]`
を入力した場合、ドメインAのサイトが表示されます。

# SSL証明書の自動更新
Let's Encryptで取得した証明書の<font color="#FF0000">有効期限は3ヶ月</font>です。
よって、有効期限が切れる前に証明書の更新が必要です。
証明書の更新を自動で行う場合、cronを設定しておくことで自動的に更新させることができます。

```
crontab -e
```
でcronの設定を開き、以下のように設定します。

```
0 4 1 * * [certbot-autoがあるpass]/certbot-auto renew && service nginx reload
```
これでSSL証明書の更新及びnginxに設定を反映させる処理を自動的に行うことができます。
(上記の処理は1ヶ月に1回、証明書の更新がないか確認する)

# 参考
* [Nginx+リバースプロキシ環境でWebサーバを停止させずに Let's Encrypt (Certbot) のSSL証明書を自動更新する - Qiita](http://qiita.com/noraworld/items/a2b4a5fabd7bf6ca25e0)
* [Nginxをリバースプロキシとして使ってるところにLet'sEncryptしようとしたらはまった話 - Qiita](http://qiita.com/kamemory/items/958fdbc220359c341a23)
* [Nginxで起動中のサーバーにLet's Encryptを導入してSSL証明書を発行する - UTALI](http://www.utali.io/entry/2016/11/21/224814)
* [Let's Encrypt+NginxでSSL証明書発行、自動更新の設定方法 - Qiita](http://qiita.com/yudsuzuk/items/83115236e9ca184326d2)
* [光の速さのWEBサーバー(nginx)をlet's encryptでSSL化及びHTTP/2化。ついでにセキュリティ評価をA＋にする。 - Qiita](http://qiita.com/sak_2/items/ff835b669c0a7e110b09)
* [Let’s EncryptのSSL証明書で、安全なウェブサイトを公開 - さくらのナレッジ](http://knowledge.sakura.ad.jp/knowledge/5573/)