Docker Composeを使ってNginxのSSLリバースプロキシを起動する

Nginxのnginx.confではLuaなどを使わないと環境変数を読み込めません。Dockerのリンクを使う場合はコンテナの起動時に設定された環境変数をsedなどで置換する起動スクリプトを用意してnginx.confを使っていました。Docker Composeのlinksを使うとコンテナの/etc/hostsエントリを作成してくれます。

OpenResty

Nginxのリバースプロキシは後でLuaでHTTPヘッダの制御やAPIのアクセスコントロールをしたいのでOpenRestyを使います。Dockerイメージはtenstartups/openrestyがミニマルで良さそうです。

コンテナを個別に起動する場合

最初にDocker Composeではなく通常のDockerの使い方でリバースプロキシとHTTPサーバーをdocker runでそれぞれ起動します。
OpenRestyで使うSSL証明書はDockerホスト上に自己署名で作成します。

$ mkdir -p /opt/nginx/certs
$ cd /opt/nginx/certs
$ openssl genrsa -out server.key 4096
$ openssl req -new -batch -key server.key -out server.csr
$ openssl x509 -req -days 3650 -in server.csr -signkey server.key -out server.crt

nginx.confも同様にDockerホスト上に用意してコンテナの/opt/nginxディレクトリをコンテナにマウントします。proxy_passのプロキシ先はnode-staticのコンテナを用意します。node-staciはDockerホストにポートマップします。今回は確認用なのでDockerホストを固定で指定しておきます。

/opt/nginx/nginx.conf
daemon off;
worker_processes 1;
events {
worker_connections 256;
}
http {
server {
listen 80;
return 301 https://$host$request_uri;
}
server {
listen 443;
server_name www.example.com;
access_log /proc/self/fd/1;
error_log /proc/self/fd/2;
ssl_certificate /etc/nginx/certs/server.crt;
ssl_certificate_key /etc/nginx/certs/server.key;
ssl on;
ssl_prefer_server_ciphers on;
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";
location / {
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-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://10.3.0.165:8080;
proxy_redirect http:// https://;
}
}
}

HTTPサーバー (node-static)

node-staticのDockerイメージを用意します。

~/node_apps/node-static/Dockerfile
FROM google/nodejs-runtime
VOLUME /app/public

app.jsは8080ポートでLISTENして起動します。

~/node_apps/node-static/app.js
var static = require('node-static');
var file = new static.Server('./public');
require('http').createServer(function (request, response) {
request.addListener('end', function () {
file.serve(request, response);
}).resume();
}).listen(8080);
console.log("Server running at http://localhost:8080");

package.jsonからnode-staticのパッケージをインストールします。

~/node_apps/node-static/package.json
{
"name": "node-static-app",
"description": "node-static app",
"version": "0.0.1",
"private": true,
"dependencies": {
"node-static": "0.7.6"
},
"scripts": {"start": "node app.js"}
}

index.htmlはふつうのHello Worldです。

~/node_apps/node-static/public/index.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>hello world</title>
</head>
<body>
<p>hello world</p>
</body>
</html>

node-staticのイメージをビルドして起動します。

$ cd ~/node_apps/node-static/p
$ docker pull google/nodejs-runtime
$ docker build -t node-static .
$ docker run --name node-static \
-d \
-p 8080:8080 \
-v $PWD/public:/app/public \
node-static

openrestyのコンテナを起動します。

$ docker pull tenstartups/openresty
$ docker run --name nginx \
-d \
-p 80:80 \
-p 443:443 \
-v /opt/nginx:/etc/nginx \
tenstartups/openresty

Dockerコンテナからcurlに--insecureフラグを付けてOpenRestyがSSLターミネーションとリバースプロキシが動作していることを確認します。

$ curl https://localhost --insecure
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>hello world</title>
</head>
<body>
<p>hello world</p>
</body>
</html>

Docker Composeを使う場合

次にDocker Composeを使って2つのコンテナをオーケストレーションしてみます。docker-compose.ymlを用意します。openrestyコンテナにnodestaticコンテナをリンクします。

~/node_apps/node-static/docker-compose.yml
nodestatic:
restart: always
build: .
openresty:
restart: always
image: tenstartups/openresty
ports:
- "80:80"
- "443:443"
volumes:
- /opt/nginx:/etc/nginx
links:
- node-static

Docker Composeのlinksを使うとコンテナの/etc/hosts経由で名前解決できるようになります。nginx.confのプロキシ先のホスト名をDocker Composeでリンクしたコンテナの名前に変更します。

/opt/nginx/nginx.conf
proxy_pass http://nodestatic:8080;

docker-composeコマンドから2つのコンテナをupします。

$ docker-compose up -d
Creating nodestatic_nodestatic_1...
Creating nodestatic_openresty_1...

以下のようにコンテナが起動しました。

$ docker-compose ps
Name Command State Ports
-----------------------------------------------------------------------------------------------------
nodestatic_nodestatic_1 /nodejs/bin/npm start Up 8080/tcp
nodestatic_openresty_1 ./entrypoint nginx -c Up 0.0.0.0:443->443/tcp,
/etc ... 0.0.0.0:80->80/tcp

Dockerホストからcurlでリバースプロキシを確認します。

$ curl https://localhost --insecure
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>hello world</title>
</head>
<body>
<p>hello world</p>
</body>
</html>