さくらVPSでSSL対応(Let's Encrypt)した複数ドメイン(WordPress)をDockerで運用する方法

結構、この構成のニーズがあるんじゃないかと思うのでまとめました

目的

1つのさくらVPSで複数のWordPressサイトまたはWebサービスを無料でSSL対応して運用する

背景

可能な限り低コストで複数サイトをHTTPS対応して運用したい

解決策

詳しい説明は省きますが、複数のサイトを同一ホスト上で稼動する場合にはリバースプロキシを使います
それぞれのサイト(サービス)はdockerで立ち上げます

アクセスのイメージとしては、下記のような感じです

e.g. 1つのVPS上にnginx(webサイト)、ghost(ブログサイト)、CMS(wordpress)サービスを展開した場合

WWW <-----> PROXY <-----> example.com(dokcer nginx)
                  <-----> example.net(dokcer ghost)     <-----> mysql(docker)
                  <-----> example.org(dokcer wordpress) <-----> mysql(docker)

実際にはここにSSL対応のためにLet's Encryptを自動更新してくれるdockerコンテナも作って動かします

サンプルファイル

この記事のdocker-composeを含むファイル一式はgithub上に置いてあるので面倒な人はこいつをcloneして編集して使ってください
事前に下記を作っておかないとアクセス権の問題が発生するかもしれません

sandbox.vps.sakura.docker.multi.wordpress/docker/letsencrypt/certs

ドメイン名やパス等の設定を正しいものに置き換えれば使えるはずです
※.envなど各種アカウントはもし公開する場合はかならず設定してください

またこれから記事を読む人は予め

cd ~/
git clone https://github.com/zienchan/sandbox.vps.sakura.docker.multi.wordpress
cd sandbox.vps.sakura.docker.multi.wordpress

しておくと楽できます

0. 全体構成

ここではwordpressを2サイト構成した場合(mysqlは共有しない)で説明しますが、実際には目的のサービスのdockerイメージがあれば(なければ自前で作れば)なんでもOKです

※ここでいう${ROOT}は~/sandbox.vps.sakura.docker.multi.wordpressとします

場所 説明 補足
${ROOT}/docker/letsencrypt/ letsencrypt関連サービス
${ROOT}/letsencrypt/certs letsencryptで出力された鍵など nginx-proxyが参照する
${ROOT}/docker/nginx-proxy/ リバースプロキシ関連サービス
${ROOT}/docker/nginx-proxy/server.conf リバースプロキシ関連の設定ファイル アップロードサイズやバッファの変更が必要であれば記述
${ROOT}/docker/example.net/ 1つ目のwordpressサービス
${ROOT}/docker/example.org/ 2つ目のwordpressサービス

1. dokcerのインストール

こちらのdockerインストール記事を参考にしてください

2. リバースプロキシコンテナ(proxy)の作成

事前準備

先にディレクトリや設定ファイルを作成します
先に作っておかないとディレクトリがrootで作られてしまうので注意してください

server.conf

とりあえずアップロード制限を100MBにして保存します

echo client_max_body_size 100M\; > ~/sandbox.vps.sakura.docker.multi.wordpress/docker/nginx-proxy/server.conf

certディレクトリの作成

mkdir ~/sandbox.vps.sakura.docker.multi.wordpress/docker/letsencrypt/certs

dokcer-composeの作成

下記の内容を~/sandbox.vps.sakura.docker.multi.wordpress/docker/nginx-proxy/docker-compose.ymlとして保存します

version: "2"
services:
  proxy:
    image: jwilder/nginx-proxy
    container_name: proxy
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/tmp/docker.sock:ro
      - ./../letsencrypt/certs:/etc/nginx/certs:ro
      - ./server.conf:/etc/nginx/conf.d/server.conf
      - /etc/nginx/vhost.d
      - /usr/share/nginx/html
    restart: always
    logging:
      options:
        max-size: 5m
        max-file: "10"

networks:
  default:
    external:
      name: shared

※もし下記のようにそんなネットワークがないとか言われたら指示通り作成してください

ERROR: Network shared declared as external, but could not be found. Please create the network manually using `docker network create shared` and try again.

言われるがまま下記のように作成します

docker network create shared

そして下記で作成&開始します

cd ~/sandbox.vps.sakura.docker.multi.wordpress/docker/nginx-proxy/
docker-compose up -d --build

確認

下記でSTATUSがUpになってればOK

docker ps -a

CONTAINER ID        IMAGE                 COMMAND                  CREATED             STATUS              PORTS                                      NAMES
1e23ffb7168f        jwilder/nginx-proxy   "/app/docker-entrypo…"   9 minutes ago       Up 9 minutes        0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp   proxy

また、この状態でブラウザで

http://localhost/

を開くと503エラーが出るはずです

3. SSLを自動で更新するコンテナ(proxy-letsencrypt)の作成

docker-composeの作成

下記の内容を~/sandbox.vps.sakura.docker.multi.wordpress/docker/letsencrypt/docker-compose.ymlとして保存します

version: "2"
services:
  letsencrypt:
    image: jrcs/letsencrypt-nginx-proxy-companion
    container_name: proxy-letsencrypt
    restart: always
    privileged: true
    volumes:
      - ./certs:/etc/nginx/certs:rw
      - /var/run/docker.sock:/var/run/docker.sock:ro
    volumes_from:
      - container:proxy

networks:
  default:
    external:
      name: shared

こちらも下記で作成&開始します

cd ~/sandbox.vps.sakura.docker.multi.wordpress/docker/letsencrypt/
docker-compose up -d --build

確認

下記でSTATUSがUpになってればOK

docker ps -a

```bash
CONTAINER ID        IMAGE                                    COMMAND                  CREATED             STATUS              PORTS                                      NAMES
b9edea1322e0        jrcs/letsencrypt-nginx-proxy-companion   "/bin/bash /app/entr…"   22 seconds ago      Up 21 seconds                                                  proxy-letsencrypt

4. 1つ目のwordpressコンテナとmysqlコンテナの作成

環境ファイルの作成

下記の内容を~/sandbox.vps.sakura.docker.multi.wordpress/docker/example.net/.envとして保存します

WORDPRESS_DB_NAME=wordpress
WORDPRESS_DB_USER=wp_user
WORDPRESS_DB_PASSWORD=hogehoge

MYSQL_RANDOM_ROOT_PASSWORD=yes
MYSQL_DATABASE=wordpress
MYSQL_USER=wp_user
MYSQL_PASSWORD=hogehoge

※必ず適切なものに変更してください

docker-composeの作成

下記の内容を~/sandbox.vps.sakura.docker.multi.wordpress/docker/example.net/docker-compose.ymlとして保存します

version: "2"
services:
    wordpress:
        image: wordpress:latest
        ports:
            - "8000:80"
        depends_on:
            - mysql
        environment:
            VIRTUAL_HOST: example.net,example.net
            LETSENCRYPT_HOST: example.net,www.example.net
            LETSENCRYPT_EMAIL: webmaster@example.net
            WORDPRESS_DB_HOST: "mysql:3306"
        env_file: .env
    mysql:
      image: mysql:5.7
      env_file: .env
      command: mysqld --character-set-server=utf8 --collation-server=utf8_unicode_ci --skip-character-set-client-handshake
      restart: always

networks:
  default:
    external:
      name: shared

LETSENCRYPT_HOST、LETSENCRYPT_HOST、LETSENCRYPT_EMAILは必ず適切なものに変更してください

こちらも下記で作成&開始します

cd ~/sandbox.vps.sakura.docker.multi.wordpress/docker/example.net/
docker-compose up -d --build

確認

下記でexamplenet_wordpress_1とexamplenet_mysql_1がSTATUSがUpになってればOK

CONTAINER ID        IMAGE                                    COMMAND                  CREATED             STATUS              PORTS                                      NAMES
2246881ece1d        wordpress:latest                         "docker-entrypoint.s…"   3 seconds ago       Up 2 seconds        0.0.0.0:8000->80/tcp                       examplenet_wordpress_1
38407aa8f6b7        mysql:5.7                                "docker-entrypoint.s…"   4 seconds ago       Up 3 seconds        3306/tcp                                   examplenet_mysql_1

ブラウザまたはcurl等で確認
WordPressのセットアップ画面が表示されるはず

http://localhost:8000/
https://example.net/

※SSLの反映には少し時間が掛かる場合もある

5. 2つ目のwordpressコンテナとmysqlコンテナの作成

環境ファイルの作成

下記の内容を~/sandbox.vps.sakura.docker.multi.wordpress/docker/example.org/.envとして保存します

WORDPRESS_DB_NAME=wordpress
WORDPRESS_DB_USER=wp_user
WORDPRESS_DB_PASSWORD=hogehoge

MYSQL_RANDOM_ROOT_PASSWORD=yes
MYSQL_DATABASE=wordpress
MYSQL_USER=wp_user
MYSQL_PASSWORD=hogehoge

※必ず適切なものに変更してください

docker-composeの作成

下記の内容を~/sandbox.vps.sakura.docker.multi.wordpress/docker/example.org/docker-compose.ymlとして保存します

version: "2"
services:
    wordpress:
        image: wordpress:latest
        ports:
            - "8001:80"
        depends_on:
            - mysql
        environment:
            VIRTUAL_HOST: example.org,example.org
            LETSENCRYPT_HOST: example.org,www.example.org
            LETSENCRYPT_EMAIL: webmaster@example.org
            WORDPRESS_DB_HOST: "mysql:3306"
        env_file: .env
    mysql:
      image: mysql:5.7
      env_file: .env
      command: mysqld --character-set-server=utf8 --collation-server=utf8_unicode_ci --skip-character-set-client-handshake
      restart: always

networks:
  default:
    external:
      name: shared

LETSENCRYPT_HOST、LETSENCRYPT_HOST、LETSENCRYPT_EMAILは必ず適切なものに変更してください

こちらも下記で作成&開始します

cd ~/sandbox.vps.sakura.docker.multi.wordpress/docker/example.org/
docker-compose up -d --build

確認

下記でexampleorg_wordpress_1とexampleorg_mysql_1がSTATUSがUpになってればOK

docker ps -a

CONTAINER ID        IMAGE                                    COMMAND                  CREATED             STATUS              PORTS                                      NAMES
e73d678ddd40        wordpress:latest                         "docker-entrypoint.s…"   35 seconds ago      Up 34 seconds       0.0.0.0:8001->80/tcp                       exampleorg_wordpress_1
8819775692fd        mysql:5.7                                "docker-entrypoint.s…"   35 seconds ago      Up 35 seconds       3306/tcp                                   exampleorg_mysql_1

ブラウザまたはcurl等で確認
WordPressのセットアップ画面が表示されるはず

http://localhost:8001/
https://example.org/

※SSLの反映には少し時間が掛かる場合もある

注意事項

この記事の通りにやれば恐らく公開できますが、特にセキュリティ面に気をつけて下さい
docker-composeも開発向けなので別のものを使うことをお勧めします