Edited at

全自動Let's Encrypt Dockerコンテナ "https-portal" を使ってウェブサイトをHTTPS化する

More than 1 year has passed since last update.

ウェブサイトをHTTPS化するために必要なDVサーバ証明書を無料で作成してくれるサービス "Let's Enctypt" ですが、公式で用意しているクライアント Certbot を準備したり、取得した証明書を適切に配置したり、失効する証明書の更新を自動化するのに自前でcron書かないといけなかったりとなかなか面倒です。

そこで、Dockerコンテナ "https-portal" を使って証明書周りの手続きを全自動化してみたいと思います。


本投稿の内容


  • dockerおよびdocker-composeが動作するサーバ上のウェブサイトをHTTPS化します

  • ドメインは取得済み/サーバのアドレスに振り向け済みとします

  • 設定を作成するのに必須ではないdocker及びdocker-composeの説明は省略します

  • 下記2パターンについて、https-portalの設定方法を解説します


    • https-portalのNginx上に静的サイトを配置する

    • https-portalをリバースプロキシとして、同サーバ上にウェブアプリケーションを配置する




dockerおよびdocker-composeコマンドの準備


docker

各プラットフォームのインストール方法に従ってインストールしてください。


docker-compose

dockerと一緒に入っていなければ、各プラットフォームのインストール方法に従ってください。

もしくは、pipでインストールするのが楽だと思います。

$ sudo pip install docker-compose


docker-compose.ymlの作成

私の作成した設定ファイルを元に解説します。


docker-compose.yml

version: '3'

services:
# HTTPS Reverse Proxy
https-portal:
image: steveltn/https-portal:1
container_name: org-chimata-https-portal
ports:
- '80:80'
- '443:443'
networks:
- org-chimata
# OS起動時に立ち上げ
restart: always
environment:
# STAGE: 'production'
DOMAINS: >-
anthropomorphous.chimata.org,
remove.chimata.org,
src.chimata.org,
u.chimata.org -> http://dockerhost:8000/,
www.chimata.org
volumes:
# - /var/run/docker.sock:/var/run/docker.sock:ro
- org-chimata-ssl-certs:/var/lib/https-portal
- org-chimata-vhosts:/var/www/vhosts

networks:
org-chimata:

volumes:
# SSL証明書
org-chimata-ssl-certs:
# 静的ウェブサイト
org-chimata-vhosts:



コンテナ名、ポートの指定、サーバ再起動時の自動立ち上げ

services:

# HTTPS Reverse Proxy
https-portal:
image: steveltn/https-portal:1
container_name: org-chimata-https-portal
ports:
- '80:80'
- '443:443'
# OS起動時に立ち上げ
restart: always

services.https-portal.container_nameがdocker上で動作しているコンテナの識別名になります。好きな名前で構いませんが、サイト名-https-portalとかreverse-proxyとかがいいんじゃないでしょうか。

portsには80と443を指定します。Let's Encryptのbotがこのポートにアクセスしてドメイン名の確認を行うため空けておく必要があるので、別のポートを振る意味は無いと思います。

restart: alwaysはつけときましょう。


環境変数

services:

# HTTPS Reverse Proxy
https-portal:
# ...
environment:
# STAGE: 'production'
DOMAINS: >-
anthropomorphous.chimata.org,
remove.chimata.org,
src.chimata.org,
u.chimata.org -> http://dockerhost:8000/,
www.chimata.org


STAGE

環境変数STAGEは次の3通りあります。



  • local: 自己署名証明書を作成します。ローカル環境での確認に。


  • staging: Let's Encryptでテスト用証明書を発行します。試験用。


  • production: Let's Encryptで正式な証明書を発行します。本番環境用。

本番サーバに載せるときに忘れずにSTAGEのコメントアウトを外しましょう


DOMAINS

環境変数DOMAINSがドメイン指定の肝です。基本は下記の形になります。

www.example.com -> http://othercontainer/

ドメイン名 -> Dockerネットワーク内のhttpアドレスで、左辺に指定したドメイン名のサーバ証明書を設定して右辺のアドレスのリバースプロキシとして動作します。複数指定する場合は、カンマで区切ります。


ボリュームについて

version: '3'

services:
# HTTPS Reverse Proxy
https-portal:
# ...
volumes:
# - /var/run/docker.sock:/var/run/docker.sock:ro
- org-chimata-ssl-certs:/var/lib/https-portal
- org-chimata-vhosts:/var/www/vhosts
# ...
volumes:
# SSL証明書
org-chimata-ssl-certs:
# 静的ウェブサイト
org-chimata-vhosts:

コンテナ側の/var/lib/https-portalがSSL証明書の配置場所になります。ボリュームにマウントしておけば永続化するので再起動のたび証明書を取りに行ってrate limitにかかるとかがなくなるはず。

環境変数DOMAINSにドメイン名だけ(右辺なし)の指定をすると、コンテナ側の/var/www/vhosts以下に静的サイトを配置してくれます。具体的には次の節で解説します。

/var/run/docker.sock:/var/run/docker.sock:roは自動でdockerで起動しているコンテナのリバースプロキシとして動作するようになる簡略化設定です。詳細はREADMEを確認。


https-portalのNginx上に静的サイトを配置する

では実際に動かしていきましょう。


docker-compose.yml

version: '3'

services:
# HTTPS Reverse Proxy
https-portal:
image: steveltn/https-portal:1
container_name: sample-https-portal
ports:
- '80:80'
- '443:443'
# OS起動時に立ち上げ
restart: always
environment:
STAGE: 'production'
DOMAINS: >-
www.example.com
volumes:
- sample-vhosts:/var/www/vhosts
volumes:
# 静的ウェブサイト
sample-vhosts:


例のように、環境変数DOMAINSにドメイン名だけ(右辺なし)の指定をすると、コンテナ側の/var/www/vhosts以下に静的サイトを配置してくれます。例の場合だと、/var/www/vhosts/www.example.comフォルダ以下をhttps://www.example.com/で公開します。

volumesセクションに指定した名前付きボリュームは/var/lib/docker/volumes/に作成されますので、そこに出来たドメイン名のフォルダ(例: (compose実行フォルダ_ボリューム名)/_data/www.example.com/)にファイルを配置すれば公開されます。

上記docker-compose.ymlのドメイン名部分を適切に変更したらサーバにアップロードして、配置したフォルダで下記を実行します。

$ sudo docker-compose up -d

ドメイン名のURLでindex.htmlが表示されたかと思います。

$ sudo docker-compose down

でサーバを終了します。


https-portalをリバースプロキシとして、同サーバ上にウェブアプリケーションを配置する

続いてウェブアプリケーションをHTTPS化していきましょう。

ウェブアプリケーションのサンプルとして、公開するマシンでpythonのhttpサーバを動かしておきます。

$ echo '<h1>Hello world!</h1>' > index.html

$ python -m SimpleHTTPServer 8000 &

バックグラウンドでカレントディレクトリを公開するアプリが起動しました。


docker-compose.yml

version: '3'

services:
# HTTPS Reverse Proxy
https-portal:
image: steveltn/https-portal:1
container_name: sample-https-portal
ports:
- '80:80'
- '443:443'
# OS起動時に立ち上げ
restart: always
environment:
STAGE: 'production'
DOMAINS: >-
www.example.com -> http://dockerhost:8000/
volumes:
- sample-vhosts:/var/www/vhosts
volumes:
# 静的ウェブサイト
sample-vhosts:


上記のファイルのドメイン名部分を適切に変更してサーバにアップロードしたら、配置したフォルダで下記を実行しましょう。

$ sudo docker-compose up -d

ドメイン名のURLで見出しだけのページが表示されたはずです。

https-portalはdockerhostでホストマシンにアクセスできるよう調整してあるので、例のようにwww.example.com -> http://dockerhost:8000/とすればDockerホストマシンのポート8000番で公開しているサイトがhttps化します。ですので、例えばApacheをポート8000番で待機させて上記の設定を行えば、Apache上のサイトがhttps化します。


その他こまごまとしたこと


  • https-portalはポート80番の非SSLアクセスを443番へ自動でリダイレクトします


  • 左辺 -> 右辺のかわりに左辺 => 右辺とすると左辺のドメインにアクセスが有ると右辺のURLへHTTP 301リダイレクトします

  • STAGE, DOMAINS以外にもNginxを設定できる環境変数が用意されています。詳細はREADMEとNginxのコンフィグ参照


    • 試していませんが、WebSocketのSSL化も可能のようです




おしまい

YAMLファイル一枚書くだけでサーバ証明書の取得と設置、cronで有効期限切れ間近の証明書の更新まで全部面倒見てくれて、HTTPSのサイトを公開できるようになるなんて最高ですね。

https-portalですが、バージョン2ではワイルドカード証明書の作成にも対応する予定だそうです。その時はまた記事を更新したいと思います。