下記の図のように、ウェブブラウザからのアクセスを一つのNginxコンテナで待ち受け、各種アプリにリバースプロキシする構成を組み立てる例を紹介します。
利点
- 外部公開する設定を一つのコンテナにまとめられ、アプリコンテナはデフォルトのまま使える
- すべてのサービスを強制的にHTTPSにすることが容易
- Let’s EncryptのSSL証明書取得・更新が楽(ホストnginxの80番を常に固定パスに流せばいい)
やりかた
OSはCentOS7、Let’s Encryptのcertbot
はインストールしてある前提です。
例としてRedmineのコンテナを作ることにします。
appsネットワーク作成
ホストコンテナからアプリコンテナへ橋渡しをするためのネットワークを作成します。
# docker network create --driver=bridge apps
ホストコンテナ作成
Nginx公式のイメージから作るためのdocker-compose.yml
を書きます。
networks
には先ほど作成したapps
を記入します。
version: '2'
services:
nginx:
image: nginx:alpine
container_name: apps-host
ports:
- 80:80 # SSL証明書の取得時に使用
- 443:443
volumes:
- ./config/conf.d:/etc/nginx/conf.d:ro # 設定が書き換えがしやすいように
- /etc/letsencrypt:/etc/letsencrypt:ro # 取得したSSL証明書を読み込むため
- ./data:/data:ro # SSL証明書の取得時に使用
networks:
- apps
restart: unless-stopped
networks:
apps:
external: true
conf.d
ディレクトリのdefailt.conf
を下記のような感じで書きます。
ほぼSSL証明書取得のための記述だけです。
server {
listen 80 default_server;
# 証明書発行時は必ずここにアクセスが来るので、限定的に許可
location ^~ /.well-known/acme-challenge/ {
root /data/webroot;
}
# 上記以外はすべてHTTPSへリダイレクト
location / {
return 301 https://$host$request_uri;
}
}
SSL証明書の取得
アプリの準備をする前にSSL証明書を取得します。
まずはホストコンテナを起動しましょう。
# docker-compose up -d
あとは下記のコマンドで一発です。/path/to
は先にバインドしたディレクトリへのパスです。
# certbot certonly --webroot -w /path/to/data/webroot -d redmine.example.com
アプリコンテナ作成
同じくdocker-compose.yml
を書きます。こちらもapps
のネットワークにリンクさせます。
version: '2'
services:
app:
image: redmine
container_name: redmine # ホスト名を参照するために必ず書きます
restart: unless-stopped
expose:
- 3000 # portsではなくexpose
networks:
- apps
networks:
apps:
external: true
アプリ用のserverディレクティブを書く
先ほどvolumes
で指定したconf.d
直下にredmine.conf
を作成します。
ここで、proxy_pass
にredmine
を直接指定すると、ホストコンテナより先にRedmineのコンテナが起動していないと、ホスト名解決ができなくなってしまいます。
つまりは複数のアプリコンテナを用意した場合に、すべて先に起動する必要がでてきてしまいます。
これを回避するために、リゾルバを指定して動的にホスト名を解決するようにします。
server {
listen 443;
server_name redmine.example.com;
# SSL設定
ssl on;
ssl_certificate /etc/letsencrypt/live/redmine.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/redmine.example.com/privkey.pem;
ssl_session_timeout 10m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers ECDHE+RSAGCM:ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:!EXPORT:!DES:!3DES:!MD5:!DSS;
ignore_invalid_headers off;
location / {
resolver 127.0.0.11 valid=2s; # ここでリゾルバ指定。アドレスが違う場合もあるかも
set $proxy_pass_host redmine:3000; # 動的に指定するには一旦変数に入れないといけない
proxy_pass http://$proxy_pass_host;
# この辺はリバースプロキシのお約束
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
あとはホストコンテナの再起動をして、アプリコンテナを立ち上げて完了です。
# docker-compose restart
# docker-compose up -d
コメント