Dockerで構築したWebアプリケーションの常時SSL化

# はじめに
趣味で、RaspberrypiにDocker環境を構築して、redmineやWodpressを運用しています。それらのWebアプリケーションをSSL化したいと思います。
環境は下記の通り。

* HW：Raspberry pi 4 model B
* OS：Ubuntu 19.10

# Letsencryptの導入
SSL証明書は、Letsencryptを利用して発行します。RaspberrypiのCPUはARMアーキテクチャなので、使えるDockerイメージが限られます。今回は、ARMで利用できる「linuxserver/swag」を利用します。

docker-composeは下記の通り。詳しい説明は、作者のgithubのREADMEを読んでください。
https://github.com/linuxserver/docker-swag/blob/master/README.md

```
services:
  letsencrypt:
    image: linuxserver/swag
    container_name: letsencrypt
    cap_add:
      - NET_ADMIN
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=Asia/Tokyo
      - URL=asubee.local
      - SUBDOMAINS=wordpress,redmine
      - VALIDATION=http
    ports:
      - "80:80"
      - "443:443"
    restart: unless-stopped
    volumes:
      - letsencrypt-config:/config

volumes:
  letsencrypt-config:
    external: true
```
このdocker-composeでは、「asubee.local」ドメインに、追加でサブドメインとして「wordpress」「redmine」を追加しています。事前に、「asubee.local」のDNS登録とワイルドカードの有効化をしておきます。Dynamic DNSのサービスがインターネット上でたくさんあるので、好きなドメインを取得してください。

証明書の取得の際には、`http://<YOUR_DOMAIN>/.well-known/acme-challenge/<TOKEN>`が外部からアクセスできる状態にする必要があります。事前にLinuxのFW設定や、ルータのポート変換の設定をしておきましょう。

##### LinuxのFW設定
Ubuntuは、「ufw」というFWの機能があります。事前に80番と443番の穴あけをしておきます。

````
$sudo ufw allow 80
Rule added
Rule added (v6)

$sudo ufw allow 443
Rule added
Rule added (v6)

$sudo ufw status
To                         Action      From
--                         ------      ----
80                         ALLOW       Anywhere
443                        ALLOW       Anywhere
22                         ALLOW       192.168.11.0/24
80 (v6)                    ALLOW       Anywhere (v6)
443 (v6)                   ALLOW       Anywhere (v6)
````

##### ルータの設定
ルータには、ポート変換の設定をしておきます。今回、raspberrypiのIPアドレスは「192.168.11.10」を設定してるので、80番、443番に来たリクエストをすべてraspberrypiに転送する設定をしました。
Buffaloのルータを使っている場合は、セキュリティ＞ポート変換で設定できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/468729/2d57d0d3-82c7-ec08-0db9-61ed1ebb6fe2.png)


##### letsencryptの起動
下記コマンドでletsencryptのコンテナを起動します。「Server ready」と表示されていれば起動完了です。

````
$ docker-compose up -d
letsencrypt    | Variables set:
letsencrypt    | PUID=1000
letsencrypt    | PGID=1000
letsencrypt    | TZ=Asia/Tokyo
letsencrypt    | URL=llasuka.local
letsencrypt    | SUBDOMAINS=wordpress,redmine
letsencrypt    | EXTRA_DOMAINS=
letsencrypt    | ONLY_SUBDOMAINS=false
letsencrypt    | DHLEVEL=2048
letsencrypt    | VALIDATION=http
letsencrypt    | DNSPLUGIN=
letsencrypt    | EMAIL=
letsencrypt    | STAGING=
(省略）
letsencrypt    | [cont-init.d] 50-config: exited 0.
letsencrypt    | [cont-init.d] 99-custom-files: executing...
letsencrypt    | [custom-init] no custom files found exiting...
letsencrypt    | [cont-init.d] 99-custom-files: exited 0.
letsencrypt    | [cont-init.d] done.
letsencrypt    | [services.d] starting services
letsencrypt    | [services.d] done.
letsencrypt    | Server ready

````

# リバースプロキシの設定
letsencryptは、nginxで動いているので、設定を追加してリバースプロキシとして機能するように設定します。
リバースプロキシについては、下記URLを参照してください。
https://github.com/linuxserver/reverse-proxy-confs/blob/master/README.md

重要なディレクトリは下記の通り。

* `/config/nginx` nginxの設定ファイルが入っているディレクトリ
* `/config/nginx/site-confs` 追加のnginxの設定を格納するディレクトリ
* `/config/nginx/proxy-confs` proxy設定例がたくさん格納されているディレクトリ。この配下にあるファイル名の「.sample」を削除するだけで設定が有効になります
* `/config/log/nginx` nginxのアクセスログの格納場所

リバースプロキシの設定を記述したredmine.confとwordpress.confを作成し、`/config/nginx/site-confs/`　配下に格納します。記述方法は、`/config/nginx/proxy-confs`配下のサンプルを参考にしています。

##### redmine.conf

redmineは、raspberryiのポート3000番でアクセスできるように設定しています。基本的な設定は、すでにconfigが存在しているので、includeすることで最小限の記述だけでリバースプロキシが設定できます。
redmineをコンテナで起動する方法は、こちらを参照してください。
https://qiita.com/asubee/items/db6985549d83334d0a46


````
server {
    listen 443 ssl;
    listen [::]:443 ssl;

    server_name redmine.*;

    include /config/nginx/ssl.conf;

    client_max_body_size 0;

    location / {
        include /config/nginx/proxy.conf;
        proxy_pass http://192.168.11.10:3000;
        proxy_redirect off;

    }
}
````

##### wordpress.conf
wordpressも同様に設定をします。Wordpressは8080番でアクセスできるように設定しています。


````
server {
    listen 443 ssl;
    listen [::]:443 ssl;

    server_name wordpress.*;

    include /config/nginx/ssl.conf;

    client_max_body_size 0;

    location / {
        include /config/nginx/proxy.conf;
        proxy_pass http://192.168.11.10:8080;
        proxy_redirect off;

    }
}
````

##### Firewallの設定
redmine、Wordpressのコンテナを起動したら、Firewallの設定も忘れずに実施しましょう。
Dockerのデフォルト設定では、コンテナ間の通信は172.16.0.0/12のクラスBが使われます。

````
$sudo ufw allow from 172.16.0.0/12 to any port 8080
$sudo ufw allow from 172.16.0.0/12 to any port 3000
#sudo ufw status
Status: active

To                         Action      From
--                         ------      ----
80                         ALLOW       Anywhere
22                         ALLOW       192.168.11.0/24
443                        ALLOW       Anywhere
8080                       ALLOW       172.16.0.0/12
3000                       ALLOW       172.16.0.0/12
80 (v6)                    ALLOW       Anywhere (v6)
443 (v6)                   ALLOW       Anywhere (v6)
````

##### （参考）コンテナの起動状態
raspberrypiには、5つのコンテナが起動しています。

````
CONTAINER ID        IMAGE                              COMMAND                  CREATED             STATUS              PORTS                                      NAMES
196aeda36993        linuxserver/swag            "/init"                  19 minutes ago      Up 19 minutes       0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp   letsencrypt
fd2cd08a15d9        wordpress:latest                   "docker-entrypoint.s…"   2 days ago          Up 38 hours         0.0.0.0:8080->80/tcp                       withdb_wordpress_1
cd2fb1865f32        mariadb                            "docker-entrypoint.s…"   2 days ago          Up 38 hours         3306/tcp                                   withdb_wordpress-mariadb_1
ca2df570bed6        withdb_redmine                     "/docker-entrypoint.…"   5 days ago          Up 38 hours         0.0.0.0:3000->3000/tcp                     withdb_redmine_1
f8c4f8c289b0        mariadb                            "docker-entrypoint.s…"   5 days ago          Up 38 hours         3306/tcp                                   withdb_mariadb_1

````
# 参考サイト

* https://github.com/linuxserver/docker-letsencrypt/blob/master/README.md
* https://github.com/linuxserver/reverse-proxy-confs/blob/master/README.md
* https://qiita.com/schwarz471/items/9b44adfbec006eab60b0