2016/11/16

DockerでNginxのコンテナを作成し、https化してWebページやサービスを公開する方法

自作Webサービスを公開するために、WebサーバはApacheより人気がでてきているNginxを採用した。しかし普通にCentOSなどにNginxをインストールして設定して、など手動やシェルスクリプトでやりたくなかったので、環境構築にはDockerを使うことにした。

ということで、DockerでNginxのコンテナをつくり、Webページ(サービス)を公開する手順をまとめる。

今回つかう環境は以下のとおり。

  • CentOS 7.2(ホストOS)
  • Docker 1.12.3
  • Nginx 1.11.5


ホストOSの準備


ホストOSは、さくらのクラウドの1コア/1GBプランのCentOS 7.2を使うことにした。
イベントやたまーにWeb上で2万円クーポンを配布しているので、ありがたく使わせてもらう。

CentOSの初期設定などは、以下の記事を参考にしていただければ、スクリプト一発で完了する。

サーバを作成したら、SSHで接続、ログインする。


Dockerのインストール


公式ドキュメントに従い、ホストOSにDockerをインストールする。
今回はrootでログインしているのでsudoは使っていない。もし前述のセットアップスクリプトを使って一般ユーザでログインした場合は、適宜各コマンドの先頭にsudoがつくと読み替えてほしい。
# update
$ yum update -y

# yum repositoryにdockerを追加
$ tee /etc/yum.repos.d/docker.repo <<-'__EOF__'
[dockerrepo]
name=Docker Repository
baseurl=https://yum.dockerproject.org/repo/main/centos/7/
enabled=1
gpgcheck=1
gpgkey=https://yum.dockerproject.org/gpg
__EOF__

$ yum install docker-engine -y
$ systemctl enable docker.service
$ systemctl start docker



設定ファイルやHTMLファイル等の準備


今回は以下のようなディレクトリ構成でファイル等を準備する。
Dockerfileは、Dockerでイメージを作るときの定義ファイル。docker buildコマンドを実行すると、書かれた処理を上から順に実行され、Dockerイメージが作成される。

app.confは、Nginxの設定ファイル。アクセスされたときにどのディレクトリのHTMLファイルを参照するかなどを記述する。

keys配下は、HTTPS接続するためのオレオレ証明書(自己証明)が入っている。
(本来は認証局で発行してもらったサーバ証明書を使う)

www/index.htmlが、今回表示したいHTMLファイル。

.
├── Dockerfile    // <-- Dockerイメージの設計書
├── app.conf     // <-- Nginxの設定ファイル
├── keys
│   ├── server.crt    // <-- サーバ証明書
│   ├── server.csr    // <-- 証明書署名要求ファイル
│   └── server.key    // <-- 秘密鍵
└── www
    └── index.html    // <-- 今回参照するファイル



Nginxの設定ファイルの作成


server {
  listen      80;
  server_name localhost;

  return 301 https://$host$request_uri;
}

server {
  server_tokens off;

  access_log    /root/logs/access.log;
  error_log     /root/logs/error.log;

  listen      443;
  server_name localhost;

  ssl                  on;
  ssl_protocols        TLSv1 TLSv1.1 TLSv1.2;
  ssl_certificate      /etc/nginx/server.crt;
  ssl_certificate_key  /etc/nginx/server.key;

  location / {
    alias /root/www/;
  }
}

今回は、HTTPS対応するためにSSLの設定をしている。
80番ポート(http)でアクセスされた場合は、httpsにリダイレクトする。

location /https://ipaddressでアクセスしたときに表示するパスを指定している。
デフォルトでindex.htmlやindexというファイルを自動で参照してくれるが、index.htmやその他のファイル名(index.phpなど)を使う場合は、index index.htm index.phpと指定する必要がある。



オレオレ証明書(自己証明書)の作成


本来なら認証局が発行した証明書を使うべきなのだが、実験用なのでオレオレ証明書で代用する。(Let's Encryptなら無料で発行することも可能)

証明書を作成するためにはopensslコマンドを使うので、以下の手順でmod_sslをインストールする。
# yum install mod_ssl -y


以下の手順は、./keysに移動して実行しているものとする。


秘密鍵の作成


秘密鍵を暗号化してしまうと、コンテナ起動時(Nginx起動時)に「Enter PEM pass phrase」とパスワードが求められ起動できないので注意。
暗号化しないので、後述するがパーミッションを400などに変更しておく必要がある。

# openssl genrsa 2048 > server.key
Generating RSA private key, 2048 bit long modulus
............................................+++
.........................+++
e is 65537 (0x10001)


証明書署名要求の作成


# openssl req -new -key server.key > server.csr
Enter pass phrase for server.key:
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:JP  // <-- 国名
State or Province Name (full name) []:Tokyo  // <-- 都道府県
Locality Name (eg, city) [Default City]:Ota-ku  // <-- 市区町村
Organization Name (eg, company) [Default Company Ltd]:Black Everyday Company  // <-- 会社名or組織名
Organizational Unit Name (eg, section) []:Blog  // <-- 部署名
Common Name (eg, your name or your server's hostname) []:example.com  // <-- 認証を受けるホスト名
Email Address []:hoge@example.com  // <-- メールアドレス

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:  // <-- パスワードは空白でOK
An optional company name []:   // <-- オプションの会社名も空白でOK

ここで指定した国名、会社名が証明書の詳細情報となる。(ブラウザで確認できる)
サーバ証明書を作ったら、このファイルは不要なので削除しても良い。


サーバ証明書の作成

今回は実験用なので30日間有効なサーバ証明書を作成している。
有効期間を伸ばしたい場合は、「-days <日数>」を好きな期間に変更してほしい。

# openssl x509 -in server.csr -days 30 -req -signkey server.key > server.crt
Signature ok
subject=/C=JP/ST=Tokyo/L=Ota-ku/O=Black Everyday Company/OU=Blog/CN=example.com/emailAddress=hoge@example.com
Getting Private key
Enter pass phrase for server.key:





Dockerfileの作成


FROM nginx

MAINTAINER BcRikko

ADD ./www /root/www
ADD ./app.conf /etc/nginx/conf.d/app.conf
ADD ./keys/server.crt /etc/nginx/server.crt
ADD ./keys/server.key /etc/nginx/server.key

RUN mkdir /root/logs
RUN chmod 755 -R /root
RUN chmod 400 /etc/nginx/server.key

EXPOSE 443
CMD ["nginx", "-g", "daemon off;"]

1行目: FROM nginxでNginxの最新のイメージを取得する。
どんなイメージがあるかはDocker Hubで検索できる。

5行目: ホストOSの./wwwにあるファイルを、コンテナ内の/root/wwwに追加(コピー)する。
6行目: ホストOSの./app.confを、コンテナ内の/etc/nginx/conf.d/app.confに追加する。
nginxは /etc/nginc/conf.d配下の[*.conf]というファイルを読み込むので、app.confでなくともsettings.confとかでもOK。

7行目: ホストOSにあるデジタル証明書(./keys/server.crt)を、コンテナ内の/etc/nginx/server.crtに追加する。
8行目: ホストOSにある秘密鍵(./keys/server.key)を、コンテナ内の/etc/nginx/server.keyに追加する。

11行目: コンテナ内の/root配下のパーミッションを755(所有者はフル権限、それ以外は読み込みと実行権限のみ)に変更する。
これをしないとWebサーバにアクセスしたときに、「403 Forbidden」になってしまうので注意。

12行目: サーバの秘密鍵にパスフレーズをつけていないので、所有者(root)以外は読書不可にする。所有者も読み込み権限しかない。

14行目: ポート443を開放する。

15行目: Nginxを起動するコマンド。ただし、Nginxをそのまま実行するとバックグラウンドで動いてしまいDockerがすぐ止まってしまう。そのため「-g daemon off;」というオプションを付けて、フォアグラウンドで実行するようにしている。



イメージの作成とコンテナ起動


# Dockerfileからイメージを作成
$ docker build -t webapp .

# 作成されたイメージの確認
$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
webapp              latest              c4c1cfa648ef        22 seconds ago      181.4 MB
nginx               latest              e43d811ce2f4        12 days ago         181.4 MB

# コンテナの起動
$ docker run -d -p 443:443 -p 80:80 webapp

# コンテナの起動状況の確認
$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                          NAMES
944913c6e58a        webapp              "nginx -g 'daemon off"   3 seconds ago       Up 2 seconds        0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp   lonely_visvesvaraya

これで「https://IPアドレス」でアクセスすると以下のような警告ページが表示される。
自己証明の場合は、SSL/TLSによる暗号化通信はできるものの中間者攻撃の危険性があるため、このような警告ページが表示されるようになっている。


「詳細情報を表示する」→「IPアドレスにアクセスする(安全ではありません)」をクリックすると、/root/www/index.htmlの内容が表示される。


コンテナが立ち上がらなかった場合は、以下のコマンドで立ち上がらなかった理由を調べる。
# コンテナ一覧(停止中含む)を表示
$docker ps -a

# ログを確認
docker logs <container id>

もしDockerfileやapp.confなどの修正が必要になったら、docker buildでイメージを再作成する。
単純にコンテナを停止、再度起動したいだけなら、以下のコマンドを実行する
# コンテナの停止
$ docker stop <container id>

# コンテナの再起動
$ docker start <container id>

また起動しているコンテナに入りたい場合は、docker execコマンドを利用する。
$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                          NAMES
944913c6e58a        webapp              "nginx -g 'daemon off"   3 seconds ago       Up 2 seconds        0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp   lonely_visvesvaraya

# 起動しているコンテナに入る
$ docker exec -it lonely_visvesvaraya /bin/bash




参考サイト


Dockerについて




Nginxについて





以上

written by @bc_rikko

0 件のコメント :

コメントを投稿