https-portalで簡単https対応！

# 前提
[【初心者向け】20分でLaravel開発環境を爆速構築するDockerハンズオン](https://qiita.com/ucan-lab/items/56c9dc3cf2e6762672f4#%E7%92%B0%E5%A2%83%E3%81%AE%E5%86%8D%E6%A7%8B%E7%AF%89)を参考に設定した`docker-compose.yml`を使って、3層アーキテクチャの構築をしました。手元には以下3つのコンテナが作成されています。

- ウェブサーバー(web)コンテナ
- アプリケーションサーバー(app)コンテナ
- データベースサーバー(db)コンテナ

また、VPSサーバーにこれらのファイルをアップロードし、任意のドメインでhttpの動作を確認しています。さて、https対応をするために、`https-portal`を使って`Let's encrypt`の更新を自動化したいと考えています。

作成している`docker-compose.yml`は以下の通りです。

```docker-compose.yml
version: "3"
services:
  app:
    build:
      context: ./docker/php
      args:
        - TZ=${TZ}
    volumes:
      - ./src:/work
      - ./logs:/var/log/php
      - ./docker/php/php.ini:/usr/local/etc/php/php.ini
    working_dir: /work
    environment:
      - DB_CONNECTION=mysql
      - DB_HOST=db
      - DB_DATABASE=${DB_NAME}
      - DB_USERNAME=${DB_USER}
      - DB_PASSWORD=${DB_PASS}
      - TZ=${TZ}
  web:
    image: nginx:1.17-alpine
    depends_on:
      - app
    ports:
      - 10080:80
    volumes:
      - ./src:/work
      - ./logs:/var/log/nginx
      - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf
    environment:
      - TZ=${TZ}
  db:
    image: mysql:8.0
    volumes:
      - db-store:/var/lib/mysql
      - ./logs:/var/log/mysql
      - ./docker/mysql/my.cnf:/etc/mysql/conf.d/my.cnf
    environment:
      - MYSQL_DATABASE=${DB_NAME}
      - MYSQL_USER=${DB_USER}
      - MYSQL_PASSWORD=${DB_PASS}
      - MYSQL_ROOT_PASSWORD=${DB_PASS}
      - TZ=${TZ}

volumes:
  db-store:
```

# 本記事の内容
`https-portal`を使用するために、`docker-compose.yml`と`docker/nginx/default.conf`を修正します。

# docker-compose.ymlの修正
`docker-compose.yml`ファイルを修正していきます。結論を述べると、`https-portal`コンテナを追加し、`ウェブサーバー(web)`コンテナのみ修正しました。

```docker-compose.yml
version: "3"
services:
  app:
    build:
      context: ./docker/php
      args:
        - TZ=${TZ}
    volumes:
      - ./src:/work
      - ./logs:/var/log/php
      - ./docker/php/php.ini:/usr/local/etc/php/php.ini
    working_dir: /work
    environment:
      - DB_CONNECTION=mysql
      - DB_HOST=db
      - DB_DATABASE=${DB_NAME}
      - DB_USERNAME=${DB_USER}
      - DB_PASSWORD=${DB_PASS}
      - TZ=${TZ}
  https-portal:
    image: steveltn/https-portal:1
    ports:
      - '80:80'
      - '443:443'
    restart: always
    environment:
      DOMAINS: 'test.com(yourdomain) -> http://web:8000'
      # STAGE: 'production' # Don't use production until staging works
      # FORCE_RENEW: 'true'
  web:
    image: nginx:1.17-alpine
    ports:
    - 8000:8000
    depends_on:
      - app
    volumes:
      - ./src:/work
      - ./logs:/var/log/nginx
      - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf
    environment:
      - TZ=${TZ}
  db:
    image: mysql:8.0
    volumes:
      - db-store:/var/lib/mysql
      - ./logs:/var/log/mysql
      - ./docker/mysql/my.cnf:/etc/mysql/conf.d/my.cnf
    environment:
      - MYSQL_DATABASE=${DB_NAME}
      - MYSQL_USER=${DB_USER}
      - MYSQL_PASSWORD=${DB_PASS}
      - MYSQL_ROOT_PASSWORD=${DB_PASS}
      - TZ=${TZ}

volumes:
  db-store:
```

https-portalコンテナから見ていきましょう。restartまでは[公式](https://github.com/SteveLTN/https-portal/blob/master/README.md)からそのまま持ってきています。

```docker-compose.yml
  https-portal:
    image: steveltn/https-portal:1
    ports:
      - '80:80'
      - '443:443'
    restart: always
    environment:
      DOMAINS: 'test.com(yourdomain) -> http://web:8000'
      # STAGE: 'production' # Don't use production until staging works
      # FORCE_RENEW: 'true'
```

DOMAINSでは、左側でどのドメインを受けるか、右側でどのコンテナに転送するかを定義できます。左側にはhttpでアクセス可能なドメインを入力しましょう。また、今回はwebサーバーに転送するので、右側はこの例の通りに入力しましょう（ただし、port番号が被らなければ8000番以外でも可能です）。

```docker-compose.yml
DOMAINS: 'test.com(yourdomain) -> http://web:8000'
```

また、本番環境の場合、STAGEのコメントを外しておきましょう。''内には`local or staging or production`を入れることができますが、`local`はLet's encryptが取得できません。

```docker-compose.yml
# STAGE: 'production' # Don't use production until staging works
```

`ウェブサーバー(web)`コンテナでは、`https-portal`コンテナからの転送を受け取るためにポート番号を8000に変更しています。すでに述べたとおり、8000番以外を設定した場合は、その番号を設定します。

```docker-compose.yml
  web:
    image: nginx:1.17-alpine
    ports:
      - 8000:8000
    depends_on:
      - app
    volumes:
      - ./src:/work
      - ./logs:/var/log/nginx
      - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf
    environment:
      - TZ=${TZ}
```

これでdocker-compose.ymlの修正は完了です。

# docker/nginx/default.confの修正

default.confファイルを修正します。それぞれ環境が異なる可能性もありますので、どのファイルを修正するかはwebコンテナのvolumesを確認しましょう。

```docker-compose.yml
   volumes:
      - ./src:/work
      - ./logs:/var/log/nginx
      - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf
```

それでは`docker/nginx/default.conf`を編集します。以下が設定されているので、8000番に変更しましょう（番号はDOMAINSで変更したもの）。

```default.conf
server {
    listern 80
...
```

```default.conf
server {
    listern 8000
...
```

最後にdockerを再起動して数分待ち、httpsでページが表示されることを確認しましょう。

```shell
$ docker-compose down
$ docker-compose up -d
```

お疲れさまでした！

# 参考
- [https-portal/README.md at master · SteveLTN/https-portal](https://github.com/SteveLTN/https-portal/blob/master/README.md)
- [https-portalで既存のdocker環境をhttps化 | RE:ENGINES](https://re-engines.com/2019/03/28/docker-https-portal/)
- [docker で全自動 Let's encrypt](https://qiita.com/kuboon/items/f424b84c718619460c6f)