mainvisual

みなさんはサーバーの管理、どうしてますか?
こんな悩み、抱えていませんか?

  • サイトをSSL化したいけど、管理が大変
  • SSL証明書を買うのにお金がかかる
  • そもそも、方法が複雑でわからない
  • 1台のサーバーで複数のサイトを運用するのが面倒
  • 脆弱性を意識して、常に情報収集するのが大変

1つでも、当てはまった人、必見です。

今回は、静的なページを公開する手順を紹介しますが、 Dockerのコンテナと設定を変更することで応用出来ます。

Dockerで管理をすれば簡単

自分は、サイトの運用をDockerメインで行っています。 主に使っているコンテナは、

  • nginx
  • jwilder/nginx-proxy
  • jrcs/letsencrypt-nginx-proxy-companion

この3つです。

構成図はこんな感じです。

“構成図を書く”

Docker コンテナjwilder/nginx-proxyについて

このコンテナの特徴は以下の点です

  • Dockerコンテナのプロキシとして機能すること
  • 新しいドメイン(http://example.comなど)が別のコンテナに割り当てられた時に、 それを検知して、Nginxの設定を自分で更新 すること
  • 特定のドメインにBasic認証を施す事が出来ること
  • コンテナ自体の更新を行なうことで、Nginxのバージョンを上げる事が出来る こと
  • 他のコンテナと組み合わせることにより、SSL暗号化(Let’s Encrypt)を簡単に扱うことが出来ること
  • SSL暗号化が利用可能な場合は、自動的にhttpsにリダイレクト(リダイレクトを無効化することも可) すること

この他に、ユーザー独自に設定を追加したり変更したりすることが出来ます。

内部の構成は、jwilder/docker-genと、 nginxの組み合わせのようです。

仕組みとしては、/var/run/docker.sockを監視して、 何かしらの変更があった場合に、Nginxの設定を変更するようです。

Docker コンテナjrcs/letsencrypt-nginx-proxy-companionについて

このコンテナの特徴は以下の点です

  • 上記のjwilder/nginx-proxyと組み合わせて、通信をLet’s Encryptで暗号化することが出来る
  • 暗号化で必要なのは、「ドメイン名」「任意のe-mailアドレス」のみ
  • 有効期限になったら、自動的に更新してくれる

これも、jwilder/nginx-proxyと同様なしくみで動いているようです。

Nginxプロキシで通信を暗号化してみよう

まずは、プロキシを立てましょう

以下のファイルをdocker-compose.ymlという名前で保存して、次のコマンドを実行します。

$ docker-compose up -d
nginx-proxy:
  image: jwilder/nginx-proxy
  privileged: true
  ports:
    - 80:80
    - 443:443
  volumes:
    - ./docker-compose.d/certs:/etc/nginx/certs:ro
    - ./docker-compose.d/htpasswd:/etc/nginx/htpasswd
    - /etc/nginx/vhost.d
    - /usr/share/nginx/html
    - /var/run/docker.sock:/tmp/docker.sock:ro

letsencrypt-nginx-proxy-companion:
  image: jrcs/letsencrypt-nginx-proxy-companion
  privileged: true
  volumes:
    - ./docker-compose.d/certs:/etc/nginx/certs:rw
    - /var/run/docker.sock:/var/run/docker.sock:ro
  volumes_from:
    - nginx-proxy

内容の解説

自分は、このコンテナを動かした際に出てくる証明書や、 basic認証のパスワードなどは、同じディレクトリのdocker-compose.dというディレクトリにまとめています。

  • 証明書はこちらに: ./docker-compose.d/certs/
  • basic認証のファイルはこちらに: ./docker-compose.d/htpasswd/

そして、最も大事なのが、/var/run/docker.sock:/tmp/docker.sock:roという設定です。 これを指定することにより、変更を検知することが出来ます。

ちなみに、volumes:の要素の最後に時々出てくる:rw,:roですが、これは、 書き込み読み込み両方可か、読み込み専用 かを表しています。

  • :rw(read write の略): 書き込み読み込み両方可
  • :ro(read only の略): 読み込み専用

静的なページを公開しよう

まず最初に自分のドメインを取得する必要があります。 ドメインの取得が済んだら、DNSを自分のサーバーを見つけられるようにして下さい。

仮にサーバーに指定されているあなたのドメインが、 hackerslog.netと、www.hackerslog.netとします。

公開するリソースと、証明書、basic認証ファイルを入れるディレクトリやリソースを作成します。

$ tree -L 2

├── docker-compose.d
│   ├── certs
│   └── htpasswd
├── docker-compose.yml
└── hackerslog.net
    ├── docker-compose.yml
    ├── nginx
    │   ├── conf.d
            └── server.conf
    │   └── log
    └── src
        └── html
            └── index.html

docker-compose.ymlは、hackerslog.netを公開するためのものです

nginx:
    image: nginx
    privileged: true
    ports:
        - 80
    volumes:
        - ./nginx/conf.d:/etc/nginx/conf.d
        - ./src/html:/usr/share/nginx/html:ro
    environment:
        NGINX_ROOT: /usr/share/nginx
        VIRTUAL_HOST: hackerslog.net,www.hackerslog.net
        LETSENCRYPT_HOST: hackerslog.net,www.hackerslog.net
        LETSENCRYPT_EMAIL: kosuke19952000@gmail.com

VIRTUAL_HOSTは、jwilder/nginx-proxyに変更を伝えるためのもので、 LETSENCRYPT_HOSTjrcs/letsencrypt-nginx-proxy-companionに変更を伝えるためのものです。

サイト名のディレクトリ(hackerslog.net)の下にnginxの設定などを入れるファイルがあります。 srcには、公開するための静的ファイルが格納されます。

今回、hackerslog.net/nginx/conf.d/server.confは以下のようにしました

server {
    listen       80;
    server_name  hackerslog.net;

    charset utf-8;

    root   /usr/share/nginx/html;
    index  index.html index.htm;

    location / {
        try_files $uri $uri/ $uri.html $uri.htm =404;
        if ($request_uri ~ ^.*/index.html$){
	          rewrite ^(.*)/index.html$ $1/ permanent;
        }
    }

    error_page  404 403          /404.html;
    error_page  500 502 503 504  /50x.html;
}

server {
    listen       80;
    server_name  www.hackerslog.net;
    return 301 https://hackerslog.net$request_uri;
}

hackerslog.net/sec/html/index.htmlはこのようになりました

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>Hello hackerslog.net</title>
</head>
<body>
  <p>Hello hackerslog.net</p>
</body>
</html>

ここで、次のコマンドを実行します。

$ cd hackerslog.net && docker-compose up -d

しばらくすると、docker-compose.d/certsに証明書が作成され、SSLで通信することが出来るようになります。

まとめ

手順は3ステップです

  1. jwilder/nginx-proxyと、jrcs/letsencrypt-nginx-proxy-companionのコンテナを立てる
  2. ファイルの作成
  3. プロキシするコンテナを立てる

Dockerコンテナを使うと、証明書を取得するために中間証明書を取得したり、 期限により更新をしたり知る必要がありません。

また、コンテナの更新により、Nginxのバージョンも自動的に上がるため、 手軽にセキュアな環境を手に入れることが出来ます。

是非、挑戦してみてはいかがでしょうか?