リバプロ+HTTP/2+Let’s EncryptなWordPressを作る。インフラ編

投稿者:

ただひたすらにナレッジを残していくサイト「みるらじ」のみるみるです。
今回から複数回に渡って、掲題の構築手順を記載します。
Twitterでは言ってましたが、今年の夏休みの課題デス。

では早速今回の構成から説明します。
ワンライナーで書くと、「WordPressで常時SSLなhttp2対応したヤツ作りたい。」

材料はコチラ
・リバースプロキシサーバの素
・WordPressサーバの素
※今回は我が家の仮想化基盤に構築していきます。リアルサーバでやる人は若干手順違うと思います。
・CentOS7(1810)
・WordPress最新版
あとめんどくさいので手順で書きます。

構成図はコチラ
リバプロ→WordPress間がSSLなし、HTTP/1.1なのは証明書発行できないから、と
そもそもSSL複合化負荷をWordPress側にかけたくない。h2cでエンドまでSSLしたい方はこの記事ではやってないので悪しからず。

リバプロ:Nginx
WordPress:Apache

上記の構成で作っていきます。

◆仮想マシン構築
自宅KVMにサーバを建てます。お遊びでやりたい人はVMwarePlayerとかVirtualBoxとか使いましょう。
使い方は先人の方々が説明していますのでググってください。

AWSでやる人はこんなクソ構成しないでCloudFrontALB使ってください。
蛇足ですがリバプロでセキュリティ上がるとか眉唾です。そんなことしてる暇あったらXSSとかDoS喰らわないぐらいコードを綺麗にしてガバガバアクセス制御を見直してください。
リバプロ入れてもサーバ自身が見えなくなってるだけで潜在的な脅威は治ってませんよ!

スペックは以下の通りで作成
【リバースプロキシ】
CPU:2Core
Mem:2GB
Disk:15GB

【Wordpressサーバ】
CPU:1Core
Mem:2GB
Disk:100GB

インストールオプションは最小インストール、ストレージは自由に切って使ってください。
WordPressはDBが入るので変な切り方してDB容量で枯渇しないように。
各サーバのプライベートIPアドレスは固定でちゃんと割り当てましょうね。

◆インストール直後からの設定(リバプロ、Wordpress共通)

・必要な管理ツールのインストールとSELinuxの無効化処理
Permissiveになってればおk ※この後の再起動でdisabledになります。

yum groupinstall -y Base "Development tools"
getenforce
cp -ip /etc/selinux/config /root/selinux_config_bk; setenforce 0;  sed -i -e '7s/enforcing/disabled/g' /etc/selinux/config
getenforce; diff /etc/selinux/config /root/selinux_config_bk
rm -rf /root/selinux_config_bk

◆基本的なUpdateのインストール(監視:ZabbixAgent含む)(共通)

yum -y update
yum -y install http://repo.zabbix.com/zabbix/4.4/rhel/7/x86_64/zabbix-release-4.4-1.el7.noarch.rpm
yum -y install zabbix-agent

◆ファイアーウォール穴あけ(リバプロ)
※最後のsed文はサービス起動時のエラーメッセージ抑止

firewall-cmd --add-port=10051/tcp --zone=public --permanent
firewall-cmd --add-service=http --zone=public --permanent
firewall-cmd --add-service=https --zone=public --permanent

firewall-cmd --reload
sed -i -e 's/^AllowZoneDrifting=yes/AllowZoneDrifting=no/g' /etc/firewalld/firewalld.conf

◆ファイアーウォール停止(WordPress)

systemctl stop firewalld
systemctl disable firewalld
systemctl status firewalld

◆時刻同期設定(共通)
※時刻ずれてるとこの後のSSL証明書取得に失敗します。
この例では内部の時刻サーバを参照していますがなければ外部NTPを参照しましょう。

内部NTPを利用の場合

cp -ip /etc/chrony.conf /root/chrony.conf_bk
sed -i -e '/^server/d' /etc/chrony.conf
sed -i -e "2a server 「内部NTPサーバのIPアドレス」 iburst" /etc/chrony.conf
diff /etc/chrony.conf /root/chrony.conf_bk
systemctl enable chronyd
systemctl stop chronyd
systemctl start chronyd

外部NTP利用の場合
パブリックNTPサーバなどで検索して外部NTPサーバ名を入れて実行
例:ntp.nict.jp

cp -ip /etc/chrony.conf /root/chrony.conf_bk
sed -i -e '/^server/d' /etc/chrony.conf
sed -i -e "2a server 「外部NTPサーバ名(ntp.nict.jp等)」 iburst" /etc/chrony.conf
diff /etc/chrony.conf /root/chrony.conf_bk
systemctl enable chronyd
systemctl stop chronyd
systemctl start chronyd

5分ほど待って時刻同期がとれているか確認。

chronyc sources
systemctl status chronyd


以下の通りにならない場合はもうしばらく待ってから確認
サーバ名左に「^*」が付く

MS Name/IP address         Stratum Poll Reach LastRx Last sample
===============================================================================
^* <サーバ名かIP>             2   8   377   250    +14us[  +53us] +/- 6857us

問題がなければ再起動しちゃいましょう。

rm -rf /root/chrony.conf_bk
reboot

◆リバースプロキシ構築(リバプロ)

yum install epel-release -y
cat /etc/yum.repos.d/epel.repo | grep enable
sed -i -e 's/enabled=1/enabled=0/g' /etc/yum.repos.d/epel.repo
cat /etc/yum.repos.d/epel.repo | grep enable
yum --enablerepo=epel install certbot -y

cat << EOF > /etc/yum.repos.d/nginx.repo
[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/mainline/centos/7/\$basearch/
enabled=0
gpgcheck=0
EOF
yum -y --enablerepo=nginx install nginx

ここまで完了したら、リバースプロキシサーバのプライベートIPに対してHTTPポート(80)を開けます。
自宅鯖なら自宅ルーターのポート、AWSならインスタンスのSG。
意味がわからなかったらルーター製品名+ポート開放などで参考例を探しましょう。
AWSなら公式のココみて勉強。

ここからSSLの有効化をします。(Let’s Encrypt)
Let’s Encrypt
無料のちゃんとしたSSL証明書を発行してくれるサービス。(更新期間短いよ!)
法人の方はちゃんとした証明書の購入をドゾ

SSLって何って方はいないと思うけど、アクセスしているサーバが本当に正しいサーバなのか、第三者の機関が証明してくれるサービスです。

【前提条件】
独自ドメインもしくはDDNSサービスなどでドメイン名が登録され、名前解決できること。
DNS?名前解決?わからない人はこの辺みて勉強。

要は、ドメイン(アドレス)で行きたいところ(自宅なりクラウドなり)に行ける状態になっていること。

以下のコマンド実行時にはLet’s Encryptに登録するメールアドレスとドメイン名が必要
それぞれコマンドを書き換えて実行する。

systemctl start nginx
certbot certonly --webroot -w /usr/share/nginx/html/ -m 「メールアドレス」 -d 「ドメイン名」 --agree-tos

最初に利用規約っぽいのが表示され入力待ちになるのでキーボードでAを入力。
その他何か聞かれたらYes(Y回答)で良いです。
ババっと文字が出て、その中に「Congratulations!」と書かれていれば正常。
なんかエラーっぽい感じなら、サイトにアクセスできないかドメインとかが誤ってる可能性がある。

特にDNSの登録直後だとDNS情報が伝搬されていない為、できないことがあります。
15分ぐらいで大体通るようになりますが、ダメなら一日待ってからやりましょう。

成功したらSSL証明書があることを確認しましょう。

ls -l /etc/letsencrypt/live/「ドメイン名」/

fullchain.pem と privkey.pemがあることを確認します。

◆SSL有効化&セキュリティレベル強化&http/2有効化
コンフィグをエディタで編集し以下の例の通り編集する。
※ドメイン名、WordpressのIPは置き換えて実行すること

・/etc/nginx/nginx.conf

user  nginx;
worker_processes      auto;
worker_cpu_affinity   auto;
worker_rlimit_nofile  4096;
error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;

events {
  worker_connections  1024;
}
http {
  include        /etc/nginx/mime.types;
  default_type   application/octet-stream;
  index          index.html index.php;
  server_tokens  off;
  access_log     off;
  charset        UTF-8;

  add_header  X-Content-Type-Options nosniff;
  add_header  X-XSS-Protection "1; mode=block";

  sendfile    on;
  tcp_nopush  on;
  etag off;
  if_modified_since off;
  keepalive_timeout  60;

  gzip  on;
  gzip_disable  "msie6";
  gzip_min_length  1024;
  gzip_types  text/css
              image/gif
              image/png
              image/jpeg
              application/javascript;

  server {
    listen  80 default_server;
    return  444;
    log_not_found  off;
  }

  include /etc/nginx/conf.d/*.conf;
}

・/etc/nginx/conf.d/proxy.conf

server {
  listen 443 ssl http2;
  server_name 「自分のドメイン」;
  ssl_certificate /etc/letsencrypt/live/「自分のドメイン」/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/「自分のドメイン」/privkey.pem;
  client_max_body_size 20M;
  ssl_prefer_server_ciphers on;
  ssl_protocols TLSv1.2 TLSv1.3;
  ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-EC$';
  add_header Strict-Transport-Security "max-age=31536000; includeSubdomains";


  location / {
    proxy_pass http://「WordPressサーバのIPアドレス」;
    proxy_redirect off;
    proxy_set_header Host $http_host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Forwarded-Host $http_host;
    proxy_set_header X-Forwarded-Server $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
  location /xmlrpc.php {
    deny all;
}
}

server{
    if ($host = 「自分のドメイン」) {
    return 301 https://$host$request_uri;
    }
    listen 80;
    server_name 「自分のドメイン」;
    return 404;
}

コンフィグの編集が終わったらサービスを再起動&自動起動にする。

systemctl restart nginx
systemctl enable nginx

◆SSL証明書更新自動化
Let’s Encryptで証明書を発行した場合、証明書の有効期間が短いため、定期的に更新するスクリプトを仕込む。
以下を新規作成。

・/etc/cron.monthly/certbot

#!/bin/bash
log=`mktemp`
code=0

which certbot > /dev/null 2>&1
if [ $? -eq 0 ]; then
    CERTBOT=`which certbot`
else
    CERTBOT=`which certbot-auto`
fi

# cert renew
for conf in `ls /etc/letsencrypt/renewal/`
do
    domain=`echo ${conf}|sed -e 's/\([^ ]*\)\.conf/\1/p' -e d`
    authenticator=`grep authenticator /etc/letsencrypt/renewal/${conf}|awk '{print $3}'`

    if [ ${authenticator} = 'webroot' ]; then
        webroot=`grep webroot_path /etc/letsencrypt/renewal/${conf}|grep =|awk '{print $3}'|awk -F '[,]' '{print $1}'`
        ${CERTBOT} certonly --webroot \
        -w ${webroot} -d ${domain} --renew-by-default >> ${log} 2>&1
        [ $? -ne 0 ] && cat ${log}
    else

        lsof -i:80 > /dev/null 2>&1
        if [ $? -eq 0 ]; then
            echo 'fail of standalone'
        else
            ${CERTBOT} certonly -a standalone \
            -d ${domain} --renew-by-default >> ${log} 2>&1
            [ $? -ne 0 ] && cat ${log}
        fi
    fi


find /etc/letsencrypt/archive/${domain}/ -mtime +30 -delete

done

# httpdreload

lsof -i:443 > /dev/null 2>&1
if [ $? -eq 0 ]; then
    rpm -q systemd > /dev/null 2>&1
    if [ $? -eq 0 ]; then
        systemctl reload nginx
    else
        /etc/rc.d/init.d/nginx reload > /dev/null 2>&1
    fi
fi

# log
cat ${log}|logger -t `basename ${0}` ; rm -f ${log}

実行権限をつけてあげる。これで月1回更新がされる。

chmod -x /etc/cron.monthly/certbot

◆WordPressサーバ構築(WordPress)
ここからWordPressサーバの構築を行う。
必要なパッケージのインストールと初期設定を行う。

yum install epel-release -y
cat /etc/yum.repos.d/epel.repo | grep enable
sed -i -e 's/enabled=1/enabled=0/g' /etc/yum.repos.d/epel.repo
cat /etc/yum.repos.d/epel.repo | grep enable

yum --enablerepo=epel install httpd mod_ssl libraqm -y
yum install mariadb mariadb-server -y
yum install https://rpms.remirepo.net/enterprise/remi-release-7.rpm -y
sed -i -e 's/enabled=1/enabled=0/g' /etc/yum.repos.d/remi*.repo
yum --enablerepo=remi install oniguruma5php libsodium23 libtool-ltdl -y
yum install --enablerepo=remi-php74,epel,remi php-gd -y
yum install --enablerepo=remi-php74 php php-mbstring php-mysqlnd php-opcache php-pecl-apcu -y

apacheの不要ファイルの削除と起動モードの変更を行う。
※MPMで動作させたほうがパフォーマンスいいです。

rm -f /etc/httpd/conf.d/welcome.conf
cat << EOF > /etc/httpd/conf.d/autoindex.conf
<Directory "/usr/share/httpd/icons">
    Options MultiViews
    AllowOverride None
    Require all granted
</Directory>
EOF
cat /etc/httpd/conf.d/autoindex.conf

mv /etc/httpd/conf.modules.d/00-mpm.conf /root/00-mpm.conf.org
cat /root/00-mpm.conf.org | sed -e 's/LoadModule\smpm_prefork_module/#LoadModule mpm_prefork_module/g' -e 's/#LoadModule\smpm_event_module/LoadModule mpm_event_module/g' > /etc/httpd/conf.modules.d/00-mpm.conf
cat /etc/httpd/conf.modules.d/00-mpm.conf

MPMがコメントアウトされていることを確認して正常終了。

・DB準備

systemctl enable mariadb
systemctl start mariadb
systemctl status mariadb
sed -i -e "10 s/^/character-set-server=utf8\n/" /etc/my.cnf
systemctl restart mariadb

mysql_secure_installation

DBのインストール初期設定は以下の通り入力

・Enter
・Enter
・DBのRootパスワード設定
・DBのRootパスワード設定(再入力)
・Enter
・Enter
・Enter
・Enter

※DBの起動に初回は少し時間かかるかも。コマンドは一気に流さないで一行ずつやったほうがいいかもね。

・DBログイン
DBのRootパスワードを入力してDBにログインする。

mysql -u root -p

・DBユーザー追加
作成したいユーザー名、パスワードを以下のコマンドを書き換えて実行

grant all privileges on wp.* to 「ユーザー名」@localhost identified by '「パスワード」';

・ユーザー確認
ユーザー情報が表示されればおk

select user from mysql.user where user='「ユーザー名」';
exit

・WordPress用テーブルの作成
DBユーザーでログインしてWordPress用のテーブルを作成する。
データベース情報が表示されていればおk

mysql -u 「ユーザー名」 -p
create database wp;
show databases;
exit

・PHPの設定
PHPのチューニング&セキュリティ設定を行う。

cp /etc/php.ini /root/php.ini_org

cat << 'EOS' | sed -i '1652r /dev/stdin' /etc/php.ini
zend_extension=opcache
opcache.enable=1
opcache.enable_cli=1
opcache.blacklist_filename=/etc/php.d/opcache*.blacklist
opcache.huge_code_pages=0
EOS

sed -i -e 's*expose_php\ =\ On*expose_php = off*g' -e 's*upload_max_filesize\ =\ 2M*upload_max_filesize = 64M*g' -e 's*post_max_size\ =\ 8M*post_max_size = 96M*g' -e 's*memory_limit\ =\ 128M*memory_limit = 256M*g' -e 's*log_errors_max_len\ =\ 1024*log_errors_max_len = 2048*g' -e 's*;error_log\ =\ syslog*error_log = syslog*g' -e 's*;date.timezone\ =*date.timezone = "Asia/Tokyo"*g' -e 's*;mbstring.language\ =\ Japanese*mbstring.language = Japanese*g' /etc/php.ini

diff /etc/php.ini /root/php.ini_org

・apacheのコンフィグ設定&SSL無効化
※一番最後のコマンドは自分のドメインに置き換えること

cat << 'EOS' | sed -i '216r /dev/stdin' /etc/httpd/conf/httpd.conf
SetEnvIf Request_URI "default\.ida" no_log
SetEnvIf Request_URI "cmd\.exe" no_log
SetEnvIf Request_URI "root\.exe" no_log
SetEnvIf Request_URI "Admin\.dll" no_log
SetEnvIf Request_URI "NULL\.IDA" no_log
CustomLog logs/access_log reverse-proxy
EOS

cat << 'EOS' | sed -i '195r /dev/stdin' /etc/httpd/conf/httpd.conf
LogFormat "%{X-Forwarded-For}i %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" reverse-proxy
EOS

sed -i -e 's*CustomLog\ \"logs\/access_log\"\ combined*CustomLog logs/access_log combined env=!no_log*g' -e 's*AddDefaultCharset\ UTF-8*#AddDefaultCharset UTF-8*g' /etc/httpd/conf/httpd.conf
sed -i -e '$ a TraceEnable off' /etc/httpd/conf/httpd.conf
sed -i -e 's/^SSLEngine\ on/#SSLEngine on/g' -e 's/^Listen 443\ https/#Listen 443 https/g' /etc/httpd/conf.d/ssl.conf

sed -i 's*"/var/www/html"*"/var/www/wordpress"*g' /etc/httpd/conf/httpd.conf
sed -i -e 's*#ServerName\ www.example.com:80*ServerName 「ドメイン名」:80*g' /etc/httpd/conf/httpd.conf

・WordPress設置
WordPress公式より最新をダウンロードしてきて設置する。

cd /var/www
wget https://ja.wordpress.org/latest-ja.tar.gz
tar xvf latest-ja.tar.gz
cd /var/www/wordpress
cp wp-config-sample.php ../wp-config.php
mv wp-config-sample.php /root/
cd ../
chown -R apache:apache .
chmod 600 wp-config.php

・wp-config.phpの編集
/var/www/wp-config.phpをエディタで編集する。
編集箇所だけ抜粋する。

/** WordPress のためのデータベース名 */
define( 'DB_NAME', 'wp' );

/** MySQL データベースのユーザー名 */
define( 'DB_USER', '「DBユーザー名」' );

/** MySQL データベースのパスワード */
define( 'DB_PASSWORD', '「DBパスワード」' );

認証用ユニークキーを以下のサイトで発行する。
https://api.wordpress.org/secret-key/1.1/salt/
以下を発行されたキーに置き換える。

define('AUTH_KEY',         'key');
define('SECURE_AUTH_KEY',  'key');
define('LOGGED_IN_KEY',    'key');
define('NONCE_KEY',        'key');
define('AUTH_SALT',        'key');
define('SECURE_AUTH_SALT', 'key');
define('LOGGED_IN_SALT',   'key');
define('NONCE_SALT',       'key');

・apache起動

systemctl enable httpd
systemctl start httpd

◆リバプロサーバ再起動(リバプロ)
リバースプロキシサーバの再起動をする。
※以降の構築がうまくいかなくなっちゃうよ!

reboot

◆HTTPS(443)ポート開放
80ポート開放と同様に443のポートを開放する。

◆外部インターネットからwebページにアクセス
自宅サーバだとローカルアクセスして初期設定するとWordPressの設定がめんどいことになるので、モバイル通信でスマホだったり、PCだったりで自分のページにアクセスする。
※この設定は時間置いてやらないこと、誰かに勝手に初期設定されて使われちゃいますよ

https://「自分のドメイン名」

アクセスができると崩れまくった表示だが初期設定画面が表示されるので、必要項目入力してインストールして完了

◆WordPressSSL化プラグインの導入
表示が崩れたままだが、WordPress管理画面にログインして、プラグインのインストール。
「SSL Insecure Content Fixer」
をインストールする。
有効化を行うと設定項目が表示されるので、「すべてキャプチャ」を選択して適用をする。

※ここまで終わった段階で、ローカルPCから設定を行う場合はHostsか内部DNSにドメインの名前解決を登録する必要があります。
理由はSSLが有効になるので、ローカルIPでアクセスすると弾かれます。

HOSTSの設定や内部DNSなどの設定は頑張って調べてみてください。
「windows hosts 編集」とかでググればいっぱいあります。

自宅で利用しているルーターやネットワークの環境によっては、何もしなくてもアクセスできるかも。。。

以上で基本的な設定は終わりました。
あとはお好きなセキュリティを入れて、テーマを入れて編集してお楽しみください。


返信を残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です