👻

インフラ初心者がAWSでWordPress構築してみたら手こずった件(Route53 ALB EC2 docker nginx Mysql)

2022/09/03に公開

AWS構成図

普段はフロントエンド・サーバーサイドの人です。
エンジニアとして、インフラさんが
構築してくれた環境・手順をポチるだけ。

EC2ならそこまで難しくないと聞いて、
勉強がてら、AWSをイチから構築してみたら

インフラ知識ほぼゼロのぼくには
やっぱり強敵でした、という話です。

あまりやらない作業なので
忘備録を兼ねて記事にしました。

①AWSアカウント作成

最初に契約する人は
約1年の無料期間がつくはずです。
ぼくは以前契約していたアカウントを使いました。

rootに設定していたMFAも携帯電話も
機種変にてロストしていたため
ここでけっこうトラブることになりましたが、
本記事では割愛。IAMユーザーがあったので
なんとかなりました。

②EC2インスタンスを作る

②-1 AMIを選ぶ

AMIとは、OSとかサーバーとかアプリケーションとか、
そういうものがよしなにもろもろスターターパックで
まとまっている「ディスクイメージ」みたいなモノです。

LinuxとWordPress(とそれが動くために必要なモノ全部)
がまとまっているBitnamiと呼ばれるイメージも
あるようですが、今回は普通にOS選択からいきます。

OSは無難そうな、
Amazon Linux 2 AMI(HVM)Kernel 5.10を選んで、
「AMIでインスタンスを起動」を選択

②-2 EC2インスタンスタイプを選ぶ

インスタンスとは仮想マシンのことです。
タイプとは、スペック(とレンタル料金)を
ここで選ぶことができます。

無料枠残ってる人は、
デフォルトの「t2.micro」でいいと思います。

ぼくは無料枠切れてたので、
最安の「t2.nano」を選択してみました。

EC2インスタンスタイプ選択

有料なら、m系とかのが無難らしいですが、
たいしてアクセスもない趣味ユースなのでOKです。

AWS管理画面からいつでもカンタンに
増強(スペックアップ)できるらしいのが、
クラウドサーバーのいいところなので
ここは気軽に選んでしまってOKです。

②-3 キーペアを作成

作ってなかったらここでキーペアを作っておきましょう

キーペア作成

③以降の環境構築で実際に
EC2にSSH接続するときに使います。

②-4 セキュリティグループを作成

作ってなかったらセキュリティグループも作成しましょう。
0.0.0.0(どこからでも)で接続可能にするには
非推奨とでているので
自分のIPアドレスからの接続のみを許可します。

もろもろ設定したあと、「インスタンスを起動」を押して
成功すればOKです!

②-5 ElasticIPを設定する

IPを固定する場合は必要です。
ぼくは頻繁にSSH入るので
EC2のIP変わると面倒だったので設定しました。

③みんな大好きLinux環境構築

直にPHPやMySQL、WordPressをインストールしてもいいですが、
Dockerを使うと環境の整備が本格的にできます。

③-1 EC2に ssh接続

「EC2 > インスタンス > (インスタンスID) > インスタンスに接続」
でつなぎ方が書いてあります。

③-2 もろもろインストール

参考にした記事:
https://qiita.com/HyunwookPark/items/92d10899cd19f2f06f91

sudo yum update -y

40秒くらい待つ

dockerインストール

sudo amazon-linux-extras install docker -y

15秒くらい待つ

sudo systemctl start docker
sudo systemctl status docker
sudo usermod -a -G docker ec2-user

docker-composeインストール

sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose

#インストール確認
docker-compose --version

このあと、docker-compose.ymlを編集
最終的には以下のようにしました。

docker-compose.yml
# 構成: mysql5.7 + wordpress + php7.3-fpm + nginx

version: '3'
services:

  # mysql
  db:
    image: mysql:5.7
    environment:
      MYSQL_USER: ${MYSQL_USER}
      MYSQL_PASSWORD: ${MYSQL_PASSWORD}
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
      MYSQL_DATABASE: ${MYSQL_DATABASE}
      TZ: 'Asia/Tokyo'
    restart: always
    volumes:
      - ./docker/mysql:/var/lib/mysql
    ports:
      - "3306:3306"
    command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci


  # wordpress+php
  wordpress:
    image: wordpress:php7.3-fpm
    environment:
      - DB_HOST=${DB_HOST}
      - DB_USER=${DB_USER}
      - DB_PASSWORD=${DB_PASSWORD}
      - DB_NAME=${DB_NAME}
    volumes:
      - ./wordpress:/var/www/html
      - ./docker/php/uploads.ini:/usr/local/etc/php/conf.d/uploads.ini
    depends_on:
      - db
    restart: always

  # nginx
  nginx:
    image: nginx:stable
    ports:
      - '${NGINX_PORT}:80'
    volumes:
      - ./docker/nginx/nginx.conf:/etc/nginx/nginx.conf
      - ./docker/nginx/conf.d:/etc/nginx/conf.d
      - ./docker/nginx/log:/var/log/nginx
      - ./wordpress:/var/www/html
    depends_on:
      - wordpress
    restart: always


docker-compose.ymlは
.envファイルを読み込んでくれます。
${MYSQL_USER}とかは
.envに設定します。

.envは以下を参考に設定。

.env.sample
# mysql
MYSQL_ROOT_PASSWORD=password
MYSQL_USER=root
MYSQL_PASSWORD=password
MYSQL_DATABASE=wordpress

# wordpress
DB_HOST=mysql
DB_USER=root
DB_PASSWORD=password
DB_NAME=wordpress

# nginx
NGINX_PORT=80

準備できたらdocker-composeを起動

docker-compose up --build -d

1分くらい。
docker-compose.ymlと
このコマンドだけで
nginx、mysql、wordpressが

sudo yum install git

10秒未満

https://(EC2のIP)/

で、WordPressのインストール画面が出たら成功です!

その画面からWordPressのインストールは
ドメイン→EC2まで疎通してから、
ドメインから行うのがいいです。

④ドメインをAWSで取得する

別にお名前.com等でとったドメインをEC2系に
割り当てることはできますが、
ぼく的にはまとまって請求きたほうが
よかったので全部AWSで済ませることにしました。

④-1 Route 53にアクセス

・ドメインの登録でドメイン検索、OKなら登録
 続行

・連絡先などをいれるフォームにいれる

・ドメイン登録完了、15分くらい待つ

Route53 登録完了

④-2 その間にALB(アプリケーションロードバランサ)を作る

今回はEC2 1台構成なので必要ないっちゃ必要ないが、
(ACM(Amazonの無料SSL証明書)には
 ALB使うのが手軽かつ推奨(↓)されているので意味はあります)

https://aws.amazon.com/jp/premiumsupport/knowledge-center/configure-acm-certificates-ec2/

ALB自体がEC2の格安インスタンスよりもお値段張りますが、
勉強のために導入しました。
Application Load Blancer選択

ALB選択

ターゲットグループ作成
ACMにSSL証明書をリクエスト
パブリック証明書をリクエスト

ドメイン→ALBの割当

Route53ホストゾーンからドメインを選んで「ホストゾーンの作成」ボタン

レコードの作成

・エイリアスを有効にして先ほど作成したALBのエイリアスを選択するだけ。カンタン

Route53 Aレコードの設定

・お名前.comなどの外部ドメインの割当をするならここらへんを参考に

https://nishinatoshiharu.com/ec2-with-alb-dns-setting/

ALB→tg(ターゲットグループ)

EC2を2つロードバランシング(負荷分散)するとか
設定できるんだけど、今回は1つのEC2を
tgに設定しました。

ALBのURLでEC2インスタンスにアクセスできるか確認する

無事アクセスできました。
あとはドメイン→ALBを疎通させたあと、
SSL証明書を導入するだけです。

④-3 AWS Certificate Manager

ACM証明書はAWSで作れる無料のSSL証明書です。

AWS Certificate Managerを選択
「証明書」→「証明書をリクエスト」
→「パブリック証明書をリクエスト」

で、あっさり作れます。

ACM登録画面

Cレコードを設定

ACM登録画面のところで、レコードを作成ボタンで
サクッと作れます。

httpsとhttp 両方アクセスできる場合に、強制https化する

ALBで80リスナーを443にリダイレクト設定できます。
これだけでhttpアクセスした人は
httpsへリダイレクトされます。便利♪

⑤ WordPressのセットアップ

最初に設定するホスト名がわからず、
だいぶてこずりました。

WordPressセットアップ ホスト名

これはdocker-compose.ymlにある
db:

dbが正解でした。
こんなんわかるか!

強制httpsにしておかないと、mixin問題が
起きるので、設定しておきます。

wp-config.php
/*  強制HTTPS化  */
define( 'WP_HOME', 'https://自分のWPのURL' );
define( 'WP_SITEURL', 'https://自分のWPのURL' );

define('FORCE_SSL_ADMIN', true);
if ( ! empty( $_SERVER['HTTP_X_FORWARDED_PROTO'] )
     && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https' )
{
    $_SERVER['HTTPS']='on';
}

wp-config.phpは書き終わったら
パーミッション600とかにしといた方がいいです。
DB接続情報があるので。

あとuploadsのパーミッションを757にしとかないと
画像アップロード時にエラーでます。

mysqlがなんか良く落ちるんだけど

参考になった記事
https://codelab.website/ec2-mysql/

また、警告どおりスワップファイルパーミッションを600にしとく

sudo chmod 600 /swapfile

あとEC2再起動時に自動でdocker起動する設定を入れておく

https://qiita.com/horikeso/items/2ea0f262deefed56eed3

感想

AWSスキル無し、
インフラ知識もあんまりない状態で
調べ調べで手探りでやったら
トータルで3日以上かかりました

docker-compose.yml
が短い記述なのにいろいろ
できすぎて便利すぎます。

Route53→ホストゾーン→ALB→tg→EC2

というつなぎ方が慣れず、
EC2コンソールから試行錯誤も非常に苦労しました。

でも、これで、ぼくが寝ている間も
稼働してくれる(仮想)サーバーが
この世に誕生したと思うと、ちょっと感慨深いです。

クラウド・コンピューティングの技術に感謝。
インフラasCodeの技術も、ぼくみたいな
インフラミリ知ら勢には贅沢すぎる技術に感謝。

しかし、

これでめでたしめでたし、ではなかった

AWS勉強の必要性を痛感。
Xサーバーのように、
載せといて、あとは放置、というわけには
いきません。

本番環境なら監視ツールや、
再起動する設定などもしないとだし・・・

WordPress初期設定もやること多いです。

・GTM
・GA4
・SearchConsole
・SEOに最適化されたテーマ・プラグインの選定
・子テーマの作成、カスタマイズ
・バックアップの設定

など、このあともやることは多いです、

あとは趣味ユースの割には料金が高いので
外部CAを使うとかして安い方法考えたいです。

何より一番大変なのが

WordPress運用、つまり

「毎日ブログ書く」

ということ!!

が、がんばります(震え声)

追記:Let's Encrypt 導入しました

円安もあってALB維持費高かったので
Let's Encryptを導入してみました。

導入時参考にした記事

https://blog.panicblanket.com/archives/6759

https://paulownia.hatenablog.com/entry/2020/09/12/150658

https://qiita.com/ax_kazz/items/f837e237e968db3d3ab3

https://qiita.com/s-katsumata/items/629222b24113d7a49b79

certbotコマンド時のエラー

「/user/share/nginx/html does not exist or is not a directory」

いやいや、rootは /var/www/htmlにしたいと
言っているのに、、、

しょうがないのでdocker-composeにvolumesを追加しました。

「If you specify multiple webroot paths, one of them must precede all domain flags」

いやいや、webroot一個しか指定してませんがな。
いろいろ試行錯誤しながらやったところ、

--entrypoint '' オプションがうまくいった模様

最終的な設定ファイル

certbotコマンド成功させて、
無事証明書ファイルが入手できたあとの
最終的な設定ファイルをメモっておきます。

nginx/conf.d/default.conf

server {
  listen 80;
  server_name _;

  # redirect https
  location / {
    return 301 https://$host$request_uri;
  }

  #accept from let's encrypt request
  location /.well-known/acme-challenge/ {
    root /var/www/html;
  }

  # root /var/www/html;
  # try_files $uri $uri/ /index.php?$args;
  # index  index.php index.index;
}

server {
  listen 443 ssl;
  server_name _;

  root /var/www/html;

  ssl_certificate      /etc/letsencrypt/live/YOUR_DOMAIN/fullchain.pem;
  ssl_certificate_key  /etc/letsencrypt/live/YOUR_DOMAIN/privkey.pem;
  ssl_session_timeout 1d;
  ssl_session_cache shared:SSL:10m;
  ssl_session_tickets off;

  ssl_protocols TLSv1.3 TLSv1.2;
  ssl_ciphers 'ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-RSA-AES128-GCM-SHA256';
  ssl_trusted_certificate  /etc/letsencrypt/live/YOUR_DOMAIN/chain.pem;
  add_header Strict-Transport-Security "max-age=2592000" always;
  ssl_prefer_server_ciphers on;
  #ssl_stapling on;
  #ssl_stapling_verify on;
  #resolver 8.8.8.8 8.8.4.4 valid=300s;
  #resolver_timeout 5s;

  client_max_body_size 1024M;

  index  index.php index.html;

  access_log /var/log/nginx/access.log;
  error_log /var/log/nginx/error.log;

  location / {
    try_files $uri $uri/ /index.php?$args;
  }

  location ~ \.php$ {
    try_files $uri =404;
    fastcgi_split_path_info ^(.+\.php)(/.+)$;
    fastcgi_pass wordpress:9000;
    fastcgi_index index.php;
    include fastcgi_params;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    fastcgi_param PATH_INFO $fastcgi_path_info;
  }
}
                                                  
docker-compose.yml
# 構成: mysql5.7 + wordpress + php7.3-fpm + nginx + certbot

version: '3'
services:

  # mysql
  db:
    image: mysql:5.7
    environment:
      MYSQL_USER: ${MYSQL_USER}
      MYSQL_PASSWORD: ${MYSQL_PASSWORD}
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
      MYSQL_DATABASE: ${MYSQL_DATABASE}
      TZ: 'Asia/Tokyo'
    restart: always
    volumes:
      - ./docker/mysql:/var/lib/mysql
    ports:
      - "3306:3306"
    command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci


  # wordpress+php.3-fpm
  wordpress:
    image: wordpress:php7.3-fpm
    environment:
      - DB_HOST=${DB_HOST}
      - DB_USER=${DB_USER}
      - DB_PASSWORD=${DB_PASSWORD}
      - DB_NAME=${DB_NAME}
    volumes:
      - ./wordpress:/var/www/html
      - ./docker/php/uploads.ini:/usr/local/etc/php/conf.d/uploads.ini
          depends_on:
      - db
    restart: always

  # nginx
  nginx:
    image: nginx:stable
    ports:
      - '${NGINX_PORT}:80'
      - '${NGINX_S_PORT}:443' # certbotコマンド後追加
    volumes:
      - ./docker/nginx/nginx.conf:/etc/nginx/nginx.conf
      - ./docker/nginx/conf.d:/etc/nginx/conf.d
      - ./docker/nginx/log:/var/log/nginx
      - ./wordpress:/var/www/html
      - /etc/letsencrypt:/etc/letsencrypt
      - /var/lib/letsencrypt:/var/lib/letsencrypt
      - ./public:/user/share/nginx/html/
    depends_on:
      - wordpress
    restart: always

  # ここを追加
  certbot:
    image: certbot/certbot:latest
    volumes:
      - ./wordpress:/var/www/html
      - /etc/letsencrypt:/etc/letsencrypt
      - /var/lib/letsencrypt:/var/lib/letsencrypt
      - ./public:/user/share/nginx/html/
    depends_on:
      - nginx
    entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;'"
    restart: always

インフラ分かってないので無駄な記述も多いと思うけど
記録として設定ファイルの内容を残しておきます。

(ALBは削除しないと課金が続くようなので削除します)

kugyu10

GitHubで編集を提案

Discussion