ブログをHTTPS対応してみた

昨年末に、本ブログをhttps対応をしました。
その時のメモを整理して記事にしてみます。

はじめに

背景

httpsは元々、パスワードなどの機密情報を打ち込むページのみで使用される印象でした。
しかし、最近では常時https化(全ページでhttps化)する流れが一般的になっています。

グーグル、「Chrome」でHTTP接続を「安全でない」として警告表示へ

これだけだとSEOの為だけに見えますが、そうではありません。

なぜ今、常時SSL化なのか | 経革広場

皆で有用な情報を安全なやりとりしましょうね という趣旨です。

Let’s Encryptの登場

安全であるにも関わらずHTTPS対応が避けられていた主な理由は2つあると思っています。

  • 証明書が有料である
  • 仕組み作りが面倒

これらの障壁を取り除くべく、Let’s Encryptというサービスが開始されました。

Let’s Encrypt 総合ポータル

今回はこれを利用します。

想定する読者

  • SSLの基礎知識があること
  • WordPressの利用経験があること
  • Webサーバ(Apacheやnginx)の利用経験があること
  • Dockerおよびdocker-composeの利用経験があること

構成

  • nginxをリバースプロキシサーバとして配置
  • httpsリクエストをDockerコンテナにhttpで流す
`ユーザ` --(https://blog.mamansoft.net/...)---> `nginx` --(http://127.0.0.1:8080)--> `wpコンテナ`
  ^ |
  | `-------(http://blog.mamansoft.net/...)---> `nginx`
  |                                               ↓ (301: https://blog.mamansoft.net/...)
  `------------------------------------------------

環境

WordPress

バージョンは4.6.2です。

OS

CentOS Linux release 7.1.1503 (Core)

必要なパッケージのインストール

以下のパッケージをインストールしています。

パッケージ名 バージョン
nginx 1.10.2
Docker 1.10.3
docker-compose 1.6.2

nginxはepel-releaseを使用する必要があります。

$ yum -y install epel-release
$ yum install -y --enablerepo=epel nginx
$ systemctl enable nginx
$ systemctl start nginx

ファイアウォールの設定変更

httpsが許可されていなかったため許可します。

$ firewall-cmd --add-service=https --zone=public --permanent
$ firewall-cmd --reload

証明書の発行

Let’s Encrypt で無料証明書を作成します。

Let’s Encrypt の使い方 – Let’s Encrypt 総合ポータル

正確な手順は上記を参照してください。
下記は 2016/11/06 時点での作業ログです。

certbotのインストール

$ yum install epel-release
$ yum install -y certbot
$ certbot

画面が表示されたらテスト完了なので、すぐ消します。

証明書の作成

メールアドレスを設定し、規約にAgreeします。
以下の記載に注意してください。

Certbot クライアントは、ドメイン所有者であることの認証に TCP Port 80 と TCP Port 443 を使用しているため、SSL/TLS サーバ証明書を取得プロセスを完了させるためには、Webサーバを一時的に終了させる必要があります。

ドメインの他、使用するサブドメインも全て指定します。

$ certbot certonly --standalone -d mamansoft.net \
                                -d blog.mamansoft.net
IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at
   /etc/letsencrypt/live/mamansoft.net/fullchain.pem. Your cert will
   expire on 2017-02-04. To obtain a new or tweaked version of this
   certificate in the future, simply run certbot again. To
   non-interactively renew *all* of your certificates, run "certbot
   renew"
...

以下のディレクトリに認証情報が生成されます。

/etc/letsencrypt/live/mamansoft.net

ファイル名 内容 Apache2.4.8未満 Apache2.4.8以降 nginx
cert.pem サーバ証明書(公開鍵) 必要
privkey.pem 秘密鍵 必要 必要 必要
chain.pem 中間証明書 必要
fullchain.pem cert.pemchain.pemの結合 必要 必要

最近のWebサーバでは fullchain.pem(公開鍵)privkey(秘密鍵) の組み合わせで認証すればOKですね。

nginxのリバースプロキシ設定

confファイルの追加と修正をします。

  • WordPressに対する設定追加
  • default.conf の修正

WordPress

  • http://blog.mamansoft.net
    • https://blog.mamansoft.netになったよ とリクエスト元に教える
  • https://blog.mamansoft.net
    • 内部で http://127.0.0.1:8080 へ渡す
$ vim /etc/nginx/conf.d/wordpress.conf
server {
  listen 80;
  server_name blog.mamansoft.net;
  return 301 https://$host$request_uri;
}
server {
  listen 443 ssl;
  ssl_certificate /etc/letsencrypt/live/mamansoft.net/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/mamansoft.net/privkey.pem;

  server_name blog.mamansoft.net;

  proxy_set_header Host $host;
  proxy_set_header X-Real-IP $remote_addr;
  proxy_set_header X-Forwarded-Proto https;
  proxy_set_header X-Forwarded-Host $host;
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

  proxy_set_header Host $http_host;
  location / {
    proxy_pass http://127.0.0.1:8080;
  }
}

default.conf

  • listendefault_server を指定
  • ssl_certificatessl_certificate_key の設定
$ vim /etc/nginx/conf.d/default.conf
server {
    listen       80 default_server;
    server_name  localhost;

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }

    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
}

server {
    listen       443 default_server;
    server_name  localhost;

    ssl_certificate /etc/letsencrypt/live/mamansoft.net/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/mamansoft.net/privkey.pem;

    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-Proto https;
    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

    proxy_set_header Host $http_host;

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }

    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
}

default_server の設定をせずにしばらくハマリました。。
以下の記事に助けられました。

nginxがリクエストをどのように処理するか 日本語訳

設定リロード

$ systemctl reload nginx

WordPressコンテナの起動

今回は以下のような docker-compose.yml を使用します。

version: '2'

services:
  mysql:
    image: mysql
    container_name: mysql_wp
    environment:
      MYSQL_ROOT_PASSWORD: hogehoge

  wordpress:
    image: wordpress
    container_name: wp
    ports:
      - 8080:80
    environment:
      VIRTUAL_HOST: blog.mamansoft.net
      WORDPRESS_DB_HOST: mysql
      WORDPRESS_DB_NAME: wpuser
      WORDPRESS_DB_PASSWORD: hogehoge
$ docker-compose up

バックアップとリストア

バックアップ

バックアップとして、DBのdumpと/wp-contentディレクトリをtar.gzで固める方法の一例です。

$ MYSQL_WP_USER=wpuser
$ MYSQL_WP_PASS=hogehoge
$ DST=wordpress
$ docker exec mysql_wp mysqldump $MYSQL_WP_USER --password=$MYSQL_WP_PASS > wordpress.sql
$ docker run --rm --volumes-from wp -v $(pwd):/backup busybox \
  tar cvf /backup/wp-content.tar /var/www/html/wp-content
$ mv wordpress.sql wp-content.tar $DST/
$ tar czvf $DST.tar.gz $DST

ボリュームコンテナをバックアップする方がイケテル感ありますが、考慮すべき点が多かったのでやめました。

リストア

上記の方法で作成したバックアップに対するリストア方法です。
wordpress.tar.gzはカレントディレクトリに解凍しておいてください。

$ docker exec wp rm -rf /var/www/html/wp-content
$ docker run --rm --volumes-from wp -v $(pwd):/restore busybox \
  tar xvf /restore/wp-content.tar

# 起動するまで10秒くらい待つ...

$ MYSQL_WP_USER=wpuser
$ MYSQL_WP_PASS=hogehoge
$ docker exec -i mysql_wp mysql $MYSQL_WP_USER --password=$MYSQL_WP_PASS < wordpress.sql
$ docker exec -i mysql_wp mysql $MYSQL_WP_USER --password=$MYSQL_WP_PASS << EOF
update wp_options set option_value = "https://blog.mamansoft.net" where option_name ='siteurl';
update wp_options set option_value = "https://blog.mamansoft.net" where option_name = 'home';
EOF

トラブルシューティング

一部のURLでドメインが重複する

  • 期待値: https://blog.mamansot.net/wp-admin
  • 実際値: http://blog.mamansoft.net, blog.mamansoft.net/wp-admin/

のようになる場合の話です。

wp-config.php<?php>直後に以下設定を追記して下さい。

$_SERVER['HTTP_HOST'] = $_SERVER['HTTP_X_FORWARDED_HOST'];
$_SERVER['REMOTE_ADDR'] = $_SERVER['HTTP_X_FORWARDED_FOR'];

設定が全てあっているはずなのに期待するURLにアクセスできない

nginxのconfファイルで、serverの設定を修正した場合はブラウザのキャッシュを削除しましょう。
301ステータスを受けたことで、以前に設定したserverのURLをブラウザが記憶している可能性があります。

WordPressのタイトル表示がおかしい

WordPressをバージョンアップすると直ることがあります。

総括

Dockerコンテナで管理されたWordpressブログへのアクセスをnginx経由でhttp化した手順を書きました。
Wordpressに限らずDockerコンテナで起動しているコンテンツにも利用することができます。

はじめは以下を使用してチャレンジしましたが、思うように行かなかったため現在の構成になっています。

個人的にはJenkinsとリバースプロキシサーバはDockerコンテナに含めない方がシンプルだと思っています。
勿論、各設定のバックアップは必要ですが。

コメントを残す