Docker上にNginxコンテナをプロキシサーバーとして構築し、Let's EncryptでHTTPS対応しました。構築にあたって かなり苦戦した ので、そのノウハウを記事としてまとめました。
「Nginx」とは
Apacheなどの従来のWebサーバーは、クライアントの数が多くなるとサーバーがパンクする 「C10K問題(クライアント1万台問題)」 を抱えていました。「Nginx」はこの問題を解決するために誕生した、静的コンテンツを高速配信するWebサーバーです。2017年10月現在、そのシェアは Apacheとほぼ同等 となっています。
Webサーバー | シェア |
---|---|
Micosoft IIS | 49.44% |
Apache | 18.78% |
Nginx | 18.40% |
- これから始める人のためのNginx(1):高速・軽量・高機能……Nginxの基礎知識 - @IT
- Web2.0の先にあるC10K問題 - @IT
- October 2017 Web Server Survey | Netcraft
「Let's Encrypt」とは
「Let's Encrypt」は すべてのWebサーバへの接続を暗号化する ことを目指し、SSL/TLSサーバ証明書を 無料 で発行する認証局(CA)です。シスコ、Akamai、電子フロンティア財団、モジラ財団などの大手企業・団体がスポンサーとして支援しています。
本稿が目指すシステム構成
本稿ではAmazon EC2、Dockerコンテナを使用して以下のようなシステムを構築することを目標とします。
前提条件
- 独自ドメインを取得していること(本稿で使用するドメインは
example.com
とします) - IPv4パブリックIP(Elastic IP)がEC2インスタンスに設定されていること
- EC2インスタンスにDocker、docker-composeがインストールされていること
事前に準備すること
DockerでHTTPS対応のプロキシサーバーを構築するにあたり、事前に以下の設定をしておく必要があります。
- EC2のインバウンドルールで443ポートを開放する
- DNSのAレコードを設定する
- プロキシ用のネットワークを構築する
EC2のインバウンドルールで443ポートを開放する
インバウンドルールを以下のように設定し、443ポートを外部へ公開します。
タイプ | プロトコル | ポート範囲 | ソース |
---|---|---|---|
HTTPS | TCP | 443 | 0.0.0.0/0 |
HTTPS | TCP | 443 | ::/0 |
DNSのAレコードを設定する
DNSの設定方法は利用しているドメイン取得サービスによって異なります。例えばバリュードメインの場合、DNSの設定方法は「DNS情報・URL転送の設定 | VALUE-DOMAIN ユーザーガイド」に記載されています。
DNSのAレコードを以下のように設定します。xx.xx.xx.xx
にはEC2インスタンスに割り当てられているIPv4パブリックIPを設定します。
a @ xx.xx.xx.xx
a www xx.xx.xx.xx
上記設定は以下を意味します。
- example.com(サブドメイン無し)をIPアドレス
xx.xx.xx.xx
にポイントする -
www.example.com をIPアドレス
xx.xx.xx.xx
にポイントする
プロキシ用のネットワークを構築する
プロキシサーバーとWebサーバー間のネットワークは外部との通信を行う必要がありません。そこで
プロキシサーバーとWebサーバー間の 内部ネットワーク を構築するため、EC2のインスタンスにログインし、以下のコマンドを入力します。
$ docker network create --internal sample_proxy_nw
上記コマンドは以下を意味します。
-
--internal
: ネットワーク外との通信が行えないネットワークを作成します。 -
sample_proxy_nw
: 任意のネットワーク名です。
以下のコマンドを入力し、ネットワークの設定情報がコンソールに出力されていることを確認しましょう。
$ docker network inspect sample_proxy_nw
Dockerコンテナの定義ファイルを作成する
事前準備が完了したら、Dockerコンテナの定義ファイルを作成しましょう。本稿におけるディレクトリ構成は以下のとおりです。
/path/to/dir/
.
├── docker-compose.yml // プロキシサーバーとWebサーバーのコンテナを定義するファイル
└── proxy
├── default.conf // プロキシサーバー上にあるNginxのデフォルト定義ファイル
├── Dockerfile // プロキシサーバーのイメージを構築するためのファイル
└── entrypoint.sh // プロキシサーバーにSSL証明書を取得するためのファイル
以下では、各ファイルの内容を解説します。
./docker-compose.yml
docker-compose.ymlでは、以下のコンテナを定義しています。
- proxy: プロキシサーバー(Nginxベース)
- web1: Webサーバー(httpdベース)
- web2: Webサーバー(httpdベース)
version: '3'
services:
proxy:
build: ./proxy
tty: true
image: sample_proxy
container_name: sample_proxy
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
ports:
- "443:443"
volumes:
- '/srv/letsencrypt:/etc/letsencrypt'
networks:
- default
- sample_proxy_nw
depends_on:
- "web1"
- "web2"
command: ["wait-for-it.sh", "sample_web1:80", "--", "./wait-for-it.sh", "sample_web2:80"]
web1:
image: httpd
container_name: sample_web1
tty: true
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
networks:
- sample_proxy_nw
web2:
image: httpd
container_name: sample_web2
tty: true
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
networks:
- sample_proxy_nw
networks:
proxy_nw:
external: true
上記コマンドは以下を意味します。
- サービス
proxy
のports
: 外部からのHTTPSアクセスとproxyサーバーの内部ポートを疎通させるため、443:443
を定義します。 - サービス
proxy
のvolumes
:/srv/letsencrypt:/etc/letsencrypt
を定義します。/etc/letsencrypt
は Let's Encryptで取得した証明書が生成されるディレクトリ です。 -
networks
: 上述の説明で生成したsample_proxy_nw
を各サービス(proxy, web1, web2)に定義します。 -
depends_on
: コンテナの起動順序を制御するオプションです。 Nginxのproxy_passに設定されているWebサーバーが起動していない状態でプロキシサーバーが起動した場合にエラーとなる ため、web1, web2を設定します。
- wait-for-it/README.md at master · vishnubob/wait-for-it · GitHub
- Control startup order in Compose | Docker Documentation
./proxy/default.conf
./proxy/default.conf
はNginxのデフォルト定義ファイル(/etc/nginx/conf.d/default.conf
)を書き換えるためのファイルです。
server{
server_name example.com www.example.com;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
location / {
proxy_pass http://sample_web1/;
}
location /example/ {
proxy_pass http://sample_web2/;
}
}
上記設定は以下を意味します。
-
server_name
: ユーザーから要求されるHTTPリクエストのヘッダに含まれるHostフィールドとserver_name
が一致した場合、該当するサーバ設定を採用します。Nginxではキャッチオールサーバーとして_
を定義することもできますが、 certbot-autoがサーバー情報を正しく取得することができない ため、上記のようにドメイン名を入力します。 -
location
: ルートディレクトリ(example.com/)とサブディレクトリ(example.com/example/)にアクセスした際の振り分け先URIを設定します。proxy_pass
には、http://[コンテナ名]/
を設定します。コンテナ名はdocker-compose.ymlのcontainer_name
で設定した名前となります。
また、http://sample_web1/
のように 末尾に/
を入れる ことに注意しましょう。例えばlocation /example/
において、プロキシパスの末尾に/
が含まれていない(http://sample_web2
)場合、振り分け先はhttp://sample_web2/example/
となってしまいます。
./proxy/Dockerfile
FROM nginx
COPY default.conf /etc/nginx/conf.d/default.conf
RUN apt-get update && apt-get install -y \
wget && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
ADD https://raw.githubusercontent.com/vishnubob/wait-for-it/master/wait-for-it.sh /usr/local/bin/wait-for-it.sh
RUN chmod +x /usr/local/bin/wait-for-it.sh
ADD https://dl.eff.org/certbot-auto /usr/local/bin/certbot-auto
RUN chmod a+x /usr/local/bin/certbot-auto
RUN certbot-auto --os-packages-only -n
COPY ./entrypoint.sh /usr/local/bin/entrypoint.sh
RUN chmod +x /usr/local/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]
上記設定は以下を意味します。
-
ADD https://dl.eff.org/certbot-auto /usr/local/bin/certbot-auto
: Let's Encryptが発行するSSL/TLSサーバ証明書を自動で取得・更新するツール「 certbot-auto 」をダウンロードします。
./proxy/entrypoint.sh
#!/bin/bash
certbot-auto --nginx -d example.com -d www.example.com -m your-account@gmail.com --agree-tos -n
certbot-auto renew
/bin/bash
上記設定は以下を意味します。
-
--nginx
: プロキシサーバーにNginxを使用する場合のオプションです。default.conf
の設定を自動的に書き換えます。(2017年12月現在、アルファ版のプラグイン) -
-d example.com -d www.example.com
: SSL/TLSサーバ証明書の取得を申請するドメイン名を指定します。 -
-m your-account@gmail.com
: アカウントの登録や回復などに使用する電子メールアドレスを指定します。 -
--agree-tos
: Let's Encryptの利用規約に同意します。 -
-n
: インタラクティブ設定をオフにします。 -
./certbot-auto renew
: 3ヶ月で失効する SSL/TLSサーバ証明書を自動で更新します。
以下のコマンドを入力してentrypoint.shに 実行権限を付与する ことを忘れないようにしましょう。
$ chmod +x entrypoint.sh
Dockerコンテナを起動する
それでは以下のコマンドを入力してDockerコンテナを起動しましょう。
docker-compose up -d
しばらく時間をおいてから、以下のコマンドを入力します。
docker-compose logs
以下のように出力されていれば成功です。
-------------------------------------------------------------------------------
Congratulations! You have successfully enabled https://example,com and
https://www.example.com
You should test your configuration at:
https://www.ssllabs.com/ssltest/analyze.html?d=example.com
https://www.ssllabs.com/ssltest/analyze.html?d=www.example.com
-------------------------------------------------------------------------------
HTTPSでアクセスする
ブラウザを起動し、実際に以下のURLにアクセスしてみましょう。
- https://example.com
- https://example.com/example/
- https://www.example.com
- https://www.example.com/example/
Chromeブラウザの場合はデベロッパーツール > Security > View certificate
からSSL/TLSサーバ証明書を確認することができます。
「発行元: Let's Encrypt Authority X3」となっているはずです。