docker-composeで複数のWebサイトをHTTPS対応する話

Posted by jolantern on Thursday, November 16, 2017

TOC

当ブログもそうですが、私はWordPressでブログを建てることがあります。ブログを作っては破壊する事が多くて、なんでかというと長続きしないからなんですが一々構築するのがいい加減面倒になってきました。 はてなブログとか使えばいいじゃんという話はあるのですが、あのブログどこのサービスで書いたっけ…忘れた、もういいや。みたいな経験を既に学生の頃しきっているのでもう良いです。

本題ですが、たくさんのブログを作ろうと思った時にWordPressをインストールしたりnginxの設定を変えるのはまあまだ出来るとしても、HTTPS化したりするのは面倒です。Let’s Encryptという素晴らしいプロダクトがあるのでよっぽど楽になったのですが、もっと簡単にやれる方法がありそうなので考えてみたのがこの記事です。

dockerでSSL証明書を取得する

さっきも出ましたが、Let’s Encryptという無料でSSL証明書を発行してもらえるサービスが有ります。これを使って今までもSSL証明書を取得していました。 docker化する知見を探し始めてすぐに、もう既にdocker化されていることを知りました。

SteveLTN/https-portal: A fully automated HTTPS server powered by Nginx, Let’s Encrypt and Docker.

便利。まずはQuickStartをやってみると

<code class="yml">https-portal:
  image: steveltn/https-portal:1
  ports:
    - '80:80'
    - '443:443'
  links:
    - wordpress
  restart: always
  environment:
    DOMAINS: 'wordpress.example.com -> http://wordpress'
    STAGE: 'production'
    # FORCE_RENEW: 'true'

wordpress:
  image: wordpress
  links:
    - db:mysql

db:
  image: mariadb
  environment:
    MYSQL_ROOT_PASSWORD: '<a secure password>'

</code>

こんなdocker-compose.ymlを書きます。 wordpress.example.com をこのdocker-compose.ymlを設置するサーバのIPを引けるように別途設定したりする必要はありますが、たったこれだけでHTTPS化済みのWordPressが手に入ります。便利すぎる。 FORCE_RENEWは場合によってはtrueにしておく必要がありますが上記例ではコメントアウトしておきます。なんでかというとLet’s Encrypyでは証明書の更新は週5回までなのでガンガン docker-compose down docker-compose up -d とかするとあっという間に上限まで行きます。僕は目的のものを手に入れる過程で1回やらかしました()

複数ブログを運営することを考える

この構造だと、1つしかブログを運営できません。 wordpress セクションをコピペして増やしても良いんですが、1ファイルで複数のブログを管理するのがどうも僕には気持ち悪く思えたのでファイル構造をこのようにしました。

<code>    +-----------------+
    |                 |
    |  https-portal   |
    |                 |
    |                 |
    ++---------------++
     |               |
     |               |
     |               |
     |               |
+----+----+     +----+----+
|         |     |         |
|  Blog1  |     |  Blog2  |
|         |     |         |
+---------+     +---------+
</code>

こんな感じ。各枠ごとに docker-compose.yml を分けます。こうすることで、BlogだけじゃなくていろんなサービスをHTTPS化できるんじゃないかな。

実際に構築する

実際にじゃあどう構築するんだっていう話をしていきます。

https-portal

<code class="yml">version: '3'
services:
  https-portal:
    image: steveltn/https-portal:1.0.0
    ports:
      - '80:80'
      - '443:443'
    restart: always
    environment:
      DOMAINS: 'www.blog1.com -> http://blog1_wordpress,  www.blog2.com -> http://blog2_wordpress'
      STAGE: 'production'
      FORCE_RENEW: 'true'
    networks:
      - default
      - blog1_default
      - blog2_default

networks:
  blog1_default:
    external: true
  blog2_default:
    external: true
</code>

DOMAINSには複数指定することができます。 networksで他のdocker-composeで作ったdockerのネットワークに接続します。試してないんですが、こうしておくと接続先のネットワークを先に作っておく必要があるんですかね。そんな気がします。構造は雑な図ですがこんなかんじ。

<code>-- root
       |
       |---docker-compose.yml
       ----blog1---wordpress
       |                   |
       |                   --docker-compose.yml
       |
       ----blog2---wordpress
                           |
                           --docker-compose.yml
</code>

blog1を作る

<code class="yml">version: '3'
services:
  blog1_wordpress:
    image: wordpress
    container_name: blog1_wordpress
    depends_on:
      - db
    volumes:
      - ./wordpress:/var/www/html
    links:
      - db:mysql
    env_file: .env

  db:
    image: mariadb
    environment:
      MYSQL_ROOT_PASSWORD: 'LOOOOOONGPASSWORD'
    volumes:
      - blog1-db-volume:/usr/lib/mysql
     env_file: .env

volumes:
  blog1-db-volume:
    driver: local
</code>

volumesで ./wordpress をマウントしているのは、僕がこの構造に移行する時にファイルを丸っとコピーしたかったからなので無くてもいいです。データベースの永続化も行っています。このdocker-compose.ymlがあるディレクトリとDBのボリュームをバックアップすれば簡単にブログのバックアップとれますね。 .env も使っていて、下記のような感じ。

<code>WORDPRESS_DB_NAME=wordpress
WORDPRESS_DB_USER=wp_user
WORDPRESS_DB_PASSWORD=LONGLONGPASS

MYSQL_RANDOM_ROOT_PASSWORD=yes
MYSQL_DATABASE=wordpress
MYSQL_USER=wp_user
MYSQL_PASSWORD=LONGLONGPASS
</code>

.env は便利ですが平文なのであんまりおすすめできる手段ではないですね。まあ、DBへの接続情報は wp-config.php にも記述されてるんですが。平文で。 この .env のパーミッションはよく考えたほうが良いかも。もしくは別の手段を使うべきですが、ブログで記事にする上で楽なのでこんな感じにしてます。

blog2を作る

ほとんどblog1と同じ。別のディレクトリに同じようにdocker-compose.ymlとwordpressディレクトリを作ります。

<code class="yml">version: '3'
services:
  blog2_wordpress:
    image: wordpress
    container_name: blog2_wordpress
    depends_on:
      - db
    volumes:
      - ./wordpress:/var/www/html
    links:
      - db:mysql
    env_file: .env

  db:
    image: mariadb
    environment:
      MYSQL_ROOT_PASSWORD: 'LOOOOOONGPASSWORD'
    volumes:
      - blog1-db-volume:/usr/lib/mysql
     env_file: .env

volumes:
  blog2-db-volume:
    driver: local
</code>

使い方

まず各ブログでdocker-compose up -dして、最後にrootディレクトリに置いたdocker-compose.ymlでdocker-compose up -dするといいです。すると、設定した各URLにアクセスするとHTTPS化されたwordpressが見えると思います。 たくさんブログを運営する必要がある人とかは便利かもしれない。僕はもうLet’s Encryptの証明書更新がこけてるとかで悲しい思いをしなくて済むだけで十分。