Ubuntu16.04に無料でSSL対応のWordPress環境を構築する

## はじめに

業務でMDMの開発をやっていてiOS端末をMDM認証する場合SSL対応したサーバを用意する必要があり、SSL証明書取得の流れを知っておきたかった。

そもそもどういう技術でHTTPS通信が成り立っているかから調べてみた。

## SSL通信とは

SSL通信とはHTTP通信における暗号化のことを指している。

現在ではTLSによる暗号化の方が一般的だが、過去の経緯もありSSL通信と呼ばれることが多い。

このSSL通信は共通鍵暗号と公開鍵暗号の2つが併用されている。

公開鍵暗号は以降で利用される「共通鍵」の受け渡しに初回のみ利用され、共通鍵暗号はその後の暗号化通信において利用される。

[SSLの仕組み](https://cspssl.jp/guide/mechanism.php)

## SSLサーバ証明書とは

SSL通信で利用される共通鍵の受け渡しをする際に使われるのがSSLサーバ証明書である。

サービスを提供するWebサーバが公開鍵とFQDNやドメインの所有者等の情報を認証局に渡すともらえるのがSSLサーバ証明書となる。

これをWebサーバにインストールすることでクライアントがサーバから渡される公開鍵の妥当性を確認することができる。

[SSLサーバ証明書とは？](https://cspssl.jp/guide/certificate.php)

### CSRとは

Certificate Signing Requestの略のことで、自分の組織等の情報が暗号化されたもの。

これを認証局に提出することで上記のSSL証明書が払い出される。

## Let's Encryptとは

無料でSSL証明書を払い出してくれる認証局の役割を果たしてくれるサービス。

2018年1月にワイルドカード証明書を自動更新できるよう対応してくれたらしい。

## Certbotとは

Let's EncryptによるSSL証明書の払い出しまでを簡単にやってくれるツールみたいなもの。

[How To Secure Nginx with Let's Encrypt on Ubuntu 16.04](https://www.digitalocean.com/community/tutorials/how-to-secure-nginx-with-let-s-encrypt-on-ubuntu-16-04)

## WordPressをSSL化する

今回は仮想環境のUbuntuに入れたWordPressをSSL対応させた。

### 環境

Ubuntu16.04
nginx/1.10.3 (Ubuntu)
mysql  Ver 14.14 Distrib 5.7.27

### 前提

以下の2つの準備をする必要がある。

1. ドメイン
2. DNS

ドメインは誤解を恐れず簡単に言えば、人間にわかりやすいURLのこと。

例えば`example.com`とか。

たまに広義の`FQDN`という意味でも使われるかも。

DNSとはIPアドレスとドメインを紐づけてくれるサービスのこと。

そのサービスを提供してくれるサーバをDNSサーバと言う。

どちらも無料で作成・設定が可能な方法でやっていく。

### SSL証明書の取得

ほぼ以下のエントリーを参考にした。圧倒的感謝。

[Ubuntu+nginxの組み合わせで、Let's encryptのワイルドカード証明書取得](https://qiita.com/digitarhythm/items/8e0036dbf5299087a2a2)

DNSは上に倣って`cloudflare`を使った。1ドメインなら無料。こちらにも感謝！

```bash
vagrant@ubuntu-xenial:~$ sudo certbot certonly --manual -d *.example.tk --preferred-challenges dns-01 --server https://acme-v02.api.letsencrypt.org/directory
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator manual, Installer None
Starting new HTTPS connection (1): acme-v02.api.letsencrypt.org
Obtaining a new certificate
Performing the following challenges:
dns-01 challenge for example.tk

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NOTE: The IP of this machine will be publicly logged as having requested this
certificate. If you're running certbot in manual mode on a machine that is not
your server, please ensure you're okay with that.

Are you OK with your IP being logged?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(Y)es/(N)o: Y

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Please deploy a DNS TXT record under the name
_acme-challenge.example.tk with the following value:

bdxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxcww

Before continuing, verify the record is deployed.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Press Enter to Continue
```

ここでcloudflareにログインして（サインインしておく）、DNSレコードの`Type`に`TXT`、`Name`に`_acme-challenge`、`Value`にワンタイムトークンを入力して登録後、ネームサーバー名（`xxx.ns.cloudflare.com`）を指定したらEnter

<img width="1090" alt="cloudflareでのTXTレコード設定.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/87431/26eb1cb5-2d67-3521-57f9-922e67dfd676.png">

<img width="1097" alt="NS名設定.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/87431/fefc9a2d-a386-9b22-f29c-731d17009bd5.png">


```bash
Waiting for verification...
Resetting dropped connection: acme-v02.api.letsencrypt.org
Cleaning up challenges
Resetting dropped connection: acme-v02.api.letsencrypt.org

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at:
   /etc/letsencrypt/live/example.tk/fullchain.pem
   Your key file has been saved at:
   /etc/letsencrypt/live/example.tk/privkey.pem
   Your cert will expire on 2019-09-17. To obtain a new or tweaked
   version of this certificate in the future, simply run certbot
   again. To non-interactively renew *all* of your certificates, run
   "certbot renew"
 - 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
```

以上で設定は完了。

念の為、以下でワンタイムトークンが帰ってくることを確認する。

```bash
vagrant@ubuntu-xenial:~$ dig -t txt _acme-challenge.example.tk @xxx.ns.cloudflare.com

; <<>> DiG 9.10.3-P4-Ubuntu <<>> -t txt _acme-challenge.example.tk @xxx.ns.cloudflare.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 15351
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 512
;; QUESTION SECTION:
;_acme-challenge.example.tk.	IN	TXT

;; ANSWER SECTION:
_acme-challenge.example.tk. 300 IN	TXT	"bdxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxcww"

;; Query time: 33 msec
;; SERVER: 173.245.58.58#53(173.245.58.58)
;; WHEN: Thu Jun 20 00:26:01 JST 2019
;; MSG SIZE  rcvd: 112
```
返ってきてそう。

### DNSの設定

AレコードにwwwありとなしのIPを登録する。

ローカルネットワークのIPを登録する場合プロキシを外しておく。

（この辺よくわかってないのだが、cloudflareを経由するようにすると別のネットワークのIPだと間違えてしまうから？）

外し方はDNS設定画面でオレンジの雲アイコンをクリックする。

<img width="1090" alt="cloudflareでのAレコード設定.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/87431/5ffb82db-ebcc-4609-2556-35e9ce4909ba.png">

### WordPressのインストール

以下を参考にした。

[How To Install WordPress with LEMP on Ubuntu 16.04](https://www.digitalocean.com/community/tutorials/how-to-install-wordpress-with-lemp-on-ubuntu-16-04)

### Webサーバの設定

今回はNginxを使った。

WordPressを入れる場合Apacheとの組み合わせが多いので日本語の記事が少なく苦労した。

以下の設定でSSL化できるようになった。

```
server {
  listen 80 default_server;
  listen [::]:80 default_server;
  server_name example.tk www.example.tk;
  return 302 https://$server_name$request_uri;
}

server {
  listen 443 ssl http2 default_server;
  listen [::]:443 ssl http2 default_server;
  server_name example.tk www.example.tk;
  ssl on;
  # 以下に先ほど取得した証明書と秘密鍵を指定する
  ssl_certificate     /etc/letsencrypt/live/example.tk/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/example.tk/privkey.pem;

  root /var/www/html;

  index index.php index.html index.htm index.nginx-debian.html;

  server_name example.tk www.example.tk;

  location / {
    try_files $uri $uri/ /index.php$is_args$args;
  }

  location ~ \.php$ {
    include snippets/fastcgi-php.conf;
    fastcgi_pass unix:/run/php/php7.0-fpm.sock;
    include fastcgi_params;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
  }

  location ~ /\.ht {
    deny all;
  }

  location = /favicon.ico { log_not_found off; access_log off; }
  location = /robots.txt { log_not_found off; access_log off; allow all; }
  location ~* \.(css|gif|ico|jpeg|jpg|js|png)$ {
    expires max;
    log_not_found off;
  }
}
```

### 結果

<img width="937" alt="スクリーンショット_2019-07-28_18_26_55.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/87431/0d4681ae-b92d-9db4-d86b-f2f891236b0f.png">


やったぜ。

### 今後

ワイルド証明書を作成した場合、サブドメインごとに複数の証明書登録する必要がなくなる。

ブログのみでなく、Redmineでタスク管理したりGrowiでWikiを作ったりしたい。

## Let's Encryptの採用事例

### はてな

[Let's Encrypt 証明書の自動更新システムを作る](https://developer.hatenastaff.com/entry/2018/12/11/133000)

## よくわからんかった

freenomでドメイン取得したけど、DNSもそのままfreenomで設定すればCloudflareに登録しなくてもよかったのではないか？？？

もうやってしまったので忘れることにしよう、、、

あと今回の設定はLAN内でしかアクセスができないと思ってるんだけどあってる？

ネットワークわからないマンつらみある。

## こんどやる

サブドメインも共通の証明書を使えるようにワイルドカード証明書として証明書を作成したらドメインが`*.example.tk`となっていて、`example.tk`でアクセスすると`NET::ERR_CERT_COMMON_NAME_INVALID`と怒られた。

当面はwwwつきで回避して、余裕が出てきたら登録ドメインを`*example.tk`とかに変更するか、Nginxの設定でwwwなしをwwwありにリダイレクトさせるかしたい。

## 参考にした

### サーバ証明書のAレコード、TXTレコード

https://jprs.jp/tech/material/iw2017-lunch-L3-01.pdf

### ワイルドカード証明書の取得手順

https://access-jp.co.jp/blogs/development/197

### Certbotのインストール、ファイアウォール設定、SSL証明書作成

https://www.digitalocean.com/community/tutorials/how-to-secure-nginx-with-let-s-encrypt-on-ubuntu-16-04

### Certbotの使い方

https://certbot.open-code.club/

### エラーログ

https://ptsv.jp/2018/06/14/https-cn-invalid/

https://www.rosehosting.com/blog/how-to-fix-the-missing-mysql-extension-error-in-wordpress/

https://serverfault.com/questions/844161/ssl-ngnix-no-ssl-certificate-is-defined-in-server-listening-on-ssl-port-whi

### WordPressのインストール

https://www.digitalocean.com/community/tutorials/how-to-install-wordpress-with-lemp-on-ubuntu-16-04