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回、ダミーの静的ウェブサイトに接続先変えて証明書を取得するもの面倒くさいなー。

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

Twitter API を使って、特定の(指定した)アカウントのツイートを取得する方法です。
作ってみたのが以下のサイトです。

https://www.bass-world.net/itawotweet/

https://developer.twitter.com/en.html からAPI キーを取得する

https://developer.twitter.com/en.html からアクセスして、

  • consumer_key
  • consumer_secret
  • access_token
  • access_token_secret

を取得します。どんなアプリを作るのか、英作文しないといけないけどがんばって!

TwistOAuth の取得

https://github.com/mpyw/TwistOAuth から TwistOAuth を入手します。
TwistOAuth.phar を今から作るプログラムと同階層においてください。

“Twitter API で特定のアカウントのツイートを取得する方法” の続きを読む

AWS で ec2 + RDS で WordPress 作る時の備忘録

  • amazon-linux-extras で PHP7.2 と MariaDB をインストールする。
  • データベースもユーザも「localhost」で作らない。
  • Amazon Polly + WordPress のアマゾン公式ドキュメントはポリシーの JSON が間違っている。
  • 同じく、プラグインの設定がちょっとおかしい。一周遅れで来る感じ。日英中に翻訳させたいなら、一度日英中で保存した後、日英だけにして保存すると、投稿が日英中になる。

MediaWiki で Can’t contact the database server: Access denied for user ‘wikiuser’@’localhost’ (using password: YES) (localhost))

ちょっと MediaWiki を Amazon EC2 Linux 2 でも動かしてみました。
そしたら

Can't contact the database server: Access denied for user 'wikiuser'@'localhost' (using password: NO) (localhost))

ググってみたところ、どうも mysql がパスワードを保存するのに昔のハッシュと新しいタイプのハッシュが混じっていて、それでエラーを出すっぽい。

そういうわけで、パスワードを以下の通り変更しました。

alter user wikiuser@localhost identified with mysql_native_password by 'mymediawikipassword';

そしたら無事に Wiki が表示されるようになりました。

Apacheウェブサーバで画像ファイル等をブラウザにキャッシュさせる

ブラウザのキャッシュを活用する

Google アナリティクスのレポート→行動→サイトの速度→速度の提案で、

ブラウザのキャッシュを活用する
静的リソースの HTTP ヘッダー内で、有効期日や最大経過時間を設定すると、ブラウザがネットワークからではなくローカル ディスクから以前にダウンロードしたリソースを読み込むようになります。
次のキャッシュ可能なリソースでブラウザのキャッシュを活用してください:

で、どうすればキャッシュさせるか調べてみました。

“Apacheウェブサーバで画像ファイル等をブラウザにキャッシュさせる” の続きを読む

GMOクラウド、CPUとメモリの増設

GMOクラウド ALTUS(アルタス)、Apacheの設定変更とWordPressのプラグイン追加でそこそこ速くなって満足していたんだけど、Kaeriyama Worksの応答速度が3秒程度、あとWordPressの編集画面が遅いので、もっと速くできないか考えてみる。

Kaeriyama Worksと同程度のボリュームの静的ページがロスなく表示されることから、遅い原因はメモリやネットワーク速度でない、CPU速度だと決めつけて、GMOクラウドでCPUを2つにすることに決定。

サポートページをいろいろ調べたのにGMOクラウド ALTUS(アルタス)のCPU追加方法が見つからなくて、サポートに連絡。やっとわかりました。

“GMOクラウド、CPUとメモリの増設” の続きを読む