AWS for WordPress の CloudFront をエラーなく使う設定方法

WordPress の AWS for WordPress プラグインに CloudFront を設定できる画面がありますが、画面の指示通りにやってもエラーが出ます。
この画面でエラーなく設定する方法は以下の通りです。

origin も dest も普通の WordPress サイトとして表示できるようにする。

origin も (取りあえず)dest も EC2 の IP アドレスを指すように、DNS サーバの設定で A レコードの設定をします。

Apache の httpd.conf で、origin も dest も同じサイトを指すように設定します。

<VirtualHost *:80>
  DocumentRoot "/home/{your-home-directory}/wordpress"
  Servername "orgin.bass-world.net"
  ServerAlias "origin.bass-world.net"
  ServerAlias "dest.bass-world.net"
  (以下略)
</VirtualHost>

origin と dest の両方を含む SSL 認証書を取得する

# certbot certonly --webroot -w /home/{your-home-directory}/wordpress
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator webroot, Installer None
Please enter in your domain name(s) (comma and/or space separated)  (Enter 'c' to cancel): 
origin.bass-world.net dest.bass-world.net
(以下略)

取得したら、origin/dest の両方でウェブサイトが表示できるか確認する。

確認したら、dest の A レコードを DNS 設定から削除する。

AWS for WordPress の CloudFront を実行する

origin の WordPress の AWS 設定画面で、CloudFront の設定をする。(画面に書かれてある 3 ステップ)

CloudFront のディストリビューションアドレスを dest の CNAME に設定する。

WordPress のサイトアドレスを dest に変更する

WordPress 設定画面の「設定」→「一般」で、「WordPress アドレス (URL)」「サイトアドレス (URL)」を、dest の URL に変更する。

追記・マルチサイト化

サブディレクトリ型のマルチサイト化は無理。

CloudFront の設定が終わってからマルチサイト化すると、サブドメイン型しか選択できなくなる。

先にサブドメイン型のマルチサイトを作っておいて CloudFront を設定すると、一見できたように思えるが、色々バグってる。

CloudFront の設定 (php ファイル対応編)

AWS CloudFront の Behavior の設定。サイトに php ファイルがある場合。

Path PatternDefault (*)*.php
Viewer Protocol PolicyRedirect HTTP to HTTPSRedirect HTTP to HTTPS
Allowed HTTP MethodsGET, HEADGET, HEAD, OPTIONS, PUT, POST, PATCH, DELETE
Cached HTTP MethodsGET, HEADGET, HEAD
Cache Based on
Selected
Request Headers
None (Imrpoves Caching)None (Improves Caching)
Object CachingUse Origin Cache HeadersUse Origin Cache Headers
Minimum TTL00
Maximum TTL3153600031536000
Default TTL8640086400
Forward CookiesNone (Improves Caching)All
Query String
Forwarding
and Caching
None (Improves CachingForward all, cache based on all

Amazon Web Service を無料枠で使う際の雑記

  • EC2 インスタンス作成時、ストレージのボリュームを、EBS 無料枠の 30GB まで増やす。
  • Amazon Linux 2 ではスワップファイルを初期状態では持っていないので、スワップファイルを作成する。
  • amazon-linux-extras で lamp-mariadb10.2-php7.2=latest をインストールする。
  • yum install httpd する。
  • yum install mod_ssl する。
  • VirtualHost で /home/hoge/www を指定した場合、エラーログに「Permission denied」が出る場合、多くの原因は、/home/hoge ディレクトリのパーミッションが 775 になっていない。
  • Amazon SES を使う場合、まずは Postfix でメールをローカル配送できるようにする。
    そして、SES から認証メールが着たら Maildir/new のファイルを cat して、認証 URL をブラウザにコピペする。
    認証が終わったら、Postfix の設定を SES に転送するように変更する。
  • CloudFront でディストリビューションする場合、オリジンは http でも https でも見られるようにする。
    Redirect https かけると、後でブラウザから「TOO MUCH REDIRECT」と怒られることがある。
  • RDS で作るユーザは、@以降のアドレスに EC2 のプライベートアドレスを付ける。
  • メモリは使用率 92% ぐらいからスワップファイル使い出すから、CloudWatch Agent 入れて 90% で再起動だと WordPress とかの大物が一時的に大きなメモリサイズ使ってそこで再起動かかっちゃうし、95% だとそもそもその値にならない。
    スワップファイルの空き容量までわかる方法ないかなー。
  • WordPress でユーザ権限を与えるのは wp.* にだ。wpl.localhost ではない。
  • AWS for WordPress の CloudFront 機能は、特にマルチサイトだと使い物にならない。

Amazon Linux 2 で Segmentation Fault

GMO クラウドで動かしていた、ツイートを一覧表示するプログラム、AWS の Amazon Lunux 2 に持って行って動かすと 10 回ぐらい動かすと「Segmentation Fault」でエラーになる。
それでもリスタートしないでおくと、順に

  1. WordPress がエラー画面
  2. Apache が落ちる
  3. SSH も繋がらなくなる

GMO クラウドでは1年間リスタートなしで動いているのに、Amazon Linux 2 では1週間と経たずに落ちる。メモリリークかと思って色々調べていたんだけど、原因は PHP のプログラムにあるっぽい。

PHP のガベージコレクションを信じるな。

使い終わったオブジェクトを unset するようにプログラムを書き換えたら、2 日経った今のところ、大丈夫そう。

WordPressの引っ越し

WordPress を CentOS7.6 + PHP7.2.9 + MySQL8.0.16 から AWS(EC2 + RDS) PHP7.2.27 + MariaDB10.2.21 に引っ越しました。
そこでの引っ越し方法とつまづきポイントを書きます。

データベースのエクスポート

mysqldump -u pocolog -p -h localhost -A -n > pocolog.sql

エクスポートしたデータで、旧URLから新URLに変換

エクスポートした SQL で、’https://{今までのブログのURL}’ を ‘https://{新しいブログのURL}’ にひたすら置換。

新サーバに上記データをコピー

mysql -h maria.xxxxxxxxxx.ap-northeast-1.rds.amazonaws.com -P 3306 -u admin -p < pocolog.sql

Access denied エラーをひたすら潰す

ERROR 1227 (42000) at line xx: Access denied; you need (at least one of) the SUPER privilege(s) for this operation をひたすら潰す。

新しいURLに変更

mysql コンソール上で update wp_blogs set domain = ‘{新しいブログのURL}’;

MediaWikiをAWSのEC2+RDS構成で動かす方法

MediaWikiに限らないかも知れませんが、Amazon Web Service の EC2 + RDS構成で動作させる方法です。

  1. MariaDB にはホストを指定して接続する。
    mysql -h maria.xxxxxx.ap-northeast-1.rds.amazonaws.com -P 3306 -u admin -p
  2. データベースを作成する。
    create database [データベース名];
  3. ユーザを作成する。
    create user ‘[ユーザ名]’@'[EC2 のプライベート IP アドレス]’ identified by ‘[パスワード]’;
  4. ユーザにデータベース操作の権限を与える。ここで、[ユーザ名]@[EC2のプライベートIPアドレス]を指定する。
    grant all privileges on [データベース名].* to ‘[ユーザ名]’@'[EC2のプライベートIPアドレス]’ identified by ‘[パスワード]’;

以上の設定をした後にMediaWikiをインストールすれば、正しく動作するはず。

Twitter API で特定のアカウントのツイートを取得する方法、修正版

Twitter API で特定のアカウントのツイートを取得する方法」ですが、タイムアウトして情報が取れないことがあり、その辺りを改良しました。

<?php
require_once 'TwistOAuth.phar';

$consumer_key = '{your-consumer-key}';
$consumer_secret = '{your-consumer-secret}';
$access_token = '{your-access-token}';
$access_token_secret = '{your-access-token-secret}';

$connection = new TwistOAuth($consumer_key, $consumer_secret, $access_token, $access_token_secret);
$count = 3;
$max_length = 25;

function get_tweet($screen_name){
  global $connection, $count, $max_length;
  $ret = "";

	// connect
	try{
		$user = $connection->get('statuses/user_timeline',
    array('screen_name' => $screen_name,
      'count' => $count,
      'exclude_replies' => 'false',
      'include_rts' => 'false',)
    );
	} catch (TwistException $e) {
		fputs(STDERR, "Error : $screen_name , " . date("Y/m/d H:i:s") . "\n");
		$text = '<h4><a href = "https://twitter.com/@' . $screen_name . '">@' . $screen_name . '</a></h4>';
		$text .= '<ul class = "tweet"><li>取得失敗</li></ul>' . "\n";
		return $text;
	}

	// get user names.
	$screen_name = htmlspecialchars($user[0]->user->screen_name, ENT_QUOTES, 'UTF-8', false);
  $names = "<h4>" . htmlspecialchars($user[0]->user->name, ENT_QUOTES, 'UTF-8', false) 
      . ' <a href = "https://twitter.com/@' . $screen_name . '">@' . $screen_name . "</a></h4>\n";
  $ret .= $names;

  $ret .= '<ul class = "tweet">';

  // get tweets.
  foreach ($user as $value){
    $screen_name = htmlspecialchars($value->user->screen_name, ENT_QUOTES, 'UTF-8', false);
    $post_date_utc = htmlspecialchars($value->created_at, ENT_QUOTES, 'UTF-8', false);
    $post_date = timezone_change_ja($post_date_utc);
    $text = htmlspecialchars(mb_substr($value->text, 0, $max_length, 'UTF-8'), ENT_QUOTES, 'UTF-8', false);
    $link = '<a href = "https://twitter.com/' . $screen_name . '/status/' . $value->id_str . '">';
    $ret .= "<li>" . $post_date . " " . $link . $text . "</a></li>\n";
  }

  $ret .= "</ul>\n";
  return $ret;
}

/*
	Twitterからのタイムゾーンを日本時間(東京)に変換するq
         $time = timezone_change('Tue Jul 12 06:27:46 +0000 2011');
         echo $time{"tm_year"};
         
*/

function timezone_change_ja($timezone = null){

	$year = $month = $day = $hour = $minute = $second = null;
	if(!empty($timezone)){

		$date_arr = explode(" ", $timezone);
		$year = intval($date_arr[5]);
		
		if($date_arr[1] == "Jan"){
			$month = 1;
		}else if($date_arr[1] == "Feb"){
			$month = 2;
		}else if($date_arr[1] == "Mar"){
			$month = 3;
		}else if($date_arr[1] == "Apr"){
			$month = 4;
		}else if($date_arr[1] == "May"){
			$month = 5;
		}else if($date_arr[1] == "Jun"){
			$month = 6;
		}else if($date_arr[1] == "Jul"){
			$month = 7;
		}else if($date_arr[1] == "Aug"){
			$month = 8;
		}else if($date_arr[1] == "Sep"){
			$month = 9;
		}else if($date_arr[1] == "Oct"){
			$month = 10;
		}else if($date_arr[1] == "Nov"){
			$month = 11;
		}else if($date_arr[1] == "Dec"){
			$month = 12;
		}

		$day = intval(sprintf("%d", $date_arr[2]));

		$arr = explode(":", $date_arr[3]);
		
		$hour = intval(sprintf("%d", $arr[0]));
		$minute = intval(sprintf("%d", $arr[1]));
		$second = intval(sprintf("%d", $arr[2]));

		$time = mktime($hour, $minute, $second, $month, $day, $year);
		$time = $time + 60 * 60 * 9; # 9時間進める
    //$date = localtime($time, true);
    return date("Y-m-d H:i", $time);
		//return $date;
	}else{
                  return false;
         }
}

?>

取得失敗の例外発生時に、スクリーンネームと「取得失敗」を戻り値にして返して、標準エラー出力にエラー内容を出力するようにしました。

このため PHP の実行文も変わります。
エラー内容を itawoerror.log に追記していきます。

php ./itawotweet/itwt_cjpn.php > ./www/itawotweet/itwt_cjpn.html 2>> itawoerror.log

ログは定期的に自分のメールアドレスに送るようにシェルスクリプトを書きました。

#!/bin/sh
if [ -s ./itawoerror.log ]; then
	cat -v ./itawoerror.log | mail -s "itawotweet error log" {your-mail-address}
	rm -f itawoerror.log
fi

これを cron に登録します。

AWS の CloudFront で WordPress を稼働してて、かつ ec2 間に SSL 通信をしている場合

Amazon Web Service で ec2 と CloudFront で WordPress を稼働している、かつ Let’s Encrypt で CloudFront – ec2 間を SSL 通信している場合。

これはハマる気がした。
certbot renew が失敗する。
WordPress が勝手にリダイレクトするから。

3ヶ月に1回、ダミーの静的ウェブサイトに接続先変えて証明書を取得するもの面倒くさいなー。