WordPressをDockerで運用する方法

WordPressをDockerで運用してるので、その方法を公開します。

前置きがすごいですが、内容はすごくありません。(笑)

  • ベースはwordpressの最新版
  • wp-cliをインストール
  • WebP Expressプラグインとimage/webpのフォーマット対応

詳しくは、
WordpressをDockerで起動して、WP2StaticでAWS S3で静的ファイル化にして転送してます。

Dockerfile

FROM wordpress:latest

# Update Package
RUN apt-get update;

# WP CLI
WORKDIR /tmp
RUN curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar
RUN chmod +x wp-cli.phar
RUN mv wp-cli.phar /usr/local/bin/wp

# WebP Express PLUGIN & image/webp FORMAT
RUN apt-get install -y \
    libfreetype6-dev \
    libjpeg62-turbo-dev \
    libmcrypt-dev \
    libwebp6 libwebp-dev \
    libpng-dev \
    libxpm-dev \
    libzip-dev
RUN apt-get -y install gcc make
WORKDIR /tmp
RUN curl -L -O https://github.com/libgd/libgd/releases/download/gd-2.3.0/libgd-2.3.0.tar.gz
RUN tar vxzf ./libgd-2.3.0.tar.gz
WORKDIR /tmp/libgd-2.3.0
RUN ./configure
RUN make && make install
RUN docker-php-ext-configure gd --with-freetype --with-webp --with-webp-dir --with-jpeg --with-xpm && \
    docker-php-ext-install -j4 gd
RUN echo 'image/webp' >> /etc/mime.types

# PHP INI
COPY php.ini /usr/local/etc/php/php.ini
RUN chown root:staff /usr/local/etc/php/php.ini

WORKDIR /var/www/html

静的ファイル生成

$ docker exec -it docker_blog_wordpress /usr/local/bin/wp wp2static generate --path=/var/www/html/ --allow-root
Success: Generated static site archive in 362.119167 seconds
$ docker exec -it docker_blog_wordpress /usr/local/bin/wp wp2static deploy --path=/var/www/html/ --allow-root
Deploying static site via: s3
Success: Deployed to: s3 in 00:09:06

phpをCLIで実行する

php -r "command" で可能

root@f1eb1edceb79:/var/www/html# php -r "print_r(gd_info());"
Array
(
    [GD Version] => bundled (2.1.0 compatible)
    [FreeType Support] =>
    [GIF Read Support] => 1
    [GIF Create Support] => 1
    [JPEG Support] =>
    [PNG Support] => 1
    [WBMP Support] => 1
    [XPM Support] =>
    [XBM Support] => 1
    [WebP Support] => 1
    [BMP Support] => 1
    [JIS-mapped Japanese Font Support] =>
)

Microsoft AutoUpdate app(Mac)の更新をOFFにする方法

Microsoft AutoUpdate app(Mac)の更新をOFFにする方法

なんかやたら出るようになったので
通知をOFFにする方法を探しました。

参考元はここです

Macを起動した際にOFF

sudo defaults write /Library/LaunchAgents/com.microsoft.update.agent.plist Disabled -bool YES
sudo defaults write /Library/LaunchAgents/com.microsoft.update.agent.plist RunAtLoad -bool NO
sudo chflags schg /Library/LaunchAgents/com.microsoft.update.agent.plist

フィードバックや他のMSアプリを起動した際にOFF

sudo defaults write com.microsoft.autoupdate2 'MAUFeedbackEnabled' -bool FALSE
sudo defaults write com.microsoft.autoupdate2 'SendAllTelemetryEnabled' -bool FALSE
sudo defaults write com.microsoft.autoupdate2 'StartDaemonOnAppLaunch' -bool FALSE

戻すとき

TRUE ← → FALSE
にする

SNSとSESのLamdaをテストするためのイベントサンプル

はじめに

AWSでSESを使用していると、バウンス対応などが必要になります。

SESのバウンスをSNSで通知させる

AWSのドキュメント
にあるとおり、
SESのNotificationsにSNSのTopicのARNをアタッチします。

arn:aws:sns:us-east-1:123456789012:ses-bounces-topic

といった感じになります。

バウンスメールを取得、保存

SNSのSubscribeで、Lambdaを実行し処理するケースが多いと想定しています。

Lambdaのコードは、AWS Serverless Application Repository に

  • ses-notification-python
  • ses-notification-nodejs
  • ses-notification-to-s3

色々とあるので各々カスタマイズし
S3に保存やDynamoDBに保存などしていくのがいいでしょう。

Lambdaを作った後

Lambdaを作った後は、テストで実行する流れになります。
テスト実行するには、テストイベントを用意する必要があります。
Lambdaでは、テストイベントでSNSのイベントのサンプルはありますが
SNSのメッセージにSESを含んだものはありません。

Amazon SES の Amazon SNS 通知の内容

を見て作るのですが
SNSのMessageに
SESの通知内容を文字列でエスケープしたり、用意するのに手間がかかります。
毎度忘れるので、忘備録として今回書き起こしました。

SNS通知にSESの内容を含むテストイベント

Bounce, Complaint, Deliveryも適当に入れてます。
このJSONをコピペして、必要に応じ削って使用する想定です。

{
  "Records": [
    {
      "EventSource": "aws:sns",
      "EventVersion": "1.0",
      "EventSubscriptionArn": "arn:aws:sns:us-east-1:{{{accountId}}}:ExampleTopic",
      "Sns": {
        "Type": "Notification",
        "MessageId": "95df01b4-ee98-5cb9-9903-4c221d41eb5e",
        "TopicArn": "arn:aws:sns:us-east-1:123456789012:ExampleTopic",
        "Subject": "example subject",
        "Message": "{ \"notificationType\": \"Bounce\", \"mail\": {  \"timestamp\": \"2018-10-08T14:05:45 +0000\",  \"messageId\": \"000001378603177f-7a5433e7-8edb-42ae-af10-f0181f34d6ee-000000\",  \"source\": \"sender@example.com\",  \"sourceArn\": \"arn:aws:ses:us-west-2:888888888888:identity/example.com\",  \"sourceIp\": \"127.0.3.0\",  \"sendingAccountId\": \"123456789012\",  \"destination\": [      \"recipient@example.com\"  ],  \"headersTruncated\": false,  \"headers\": [      {          \"name\": \"From\",          \"value\": \"\\\"Sender Name\\\" \"      },      {          \"name\": \"To\",          \"value\": \"\\\"Recipient Name\\\" \"      },      {          \"name\": \"Message-ID\",          \"value\": \"custom-message-ID\"      },      {          \"name\": \"Subject\",          \"value\": \"Hello\"      },      {          \"name\": \"Content-Type\",          \"value\": \"text/plain; charset=\\\"UTF-8\\\"\"      },      {          \"name\": \"Content-Transfer-Encoding\",          \"value\": \"base64\"      },      {          \"name\": \"Date\",          \"value\": \"Mon, 08 Oct 2018 14:05:45 +0000\"      }  ],  \"commonHeaders\": {      \"from\": [          \"Sender Name \"      ],      \"date\": \"Mon, 08 Oct 2018 14:05:45 +0000\",      \"to\": [          \"Recipient Name \"      ],      \"messageId\": \" custom-message-ID\",      \"subject\": \"Message sent using Amazon SES\"  }}, \"bounce\": {  \"bounceType\": \"Permanent\",  \"bounceSubType\": \"General\",  \"bouncedRecipients\": [      {          \"status\": \"5.0.0\",          \"action\": \"failed\",          \"diagnosticCode\": \"smtp; 550 user unknown\",          \"emailAddress\": \"recipient1@example.com\"      },      {          \"status\": \"4.0.0\",          \"action\": \"delayed\",          \"emailAddress\": \"recipient2@example.com\"      }  ],  \"reportingMTA\": \"example.com\",  \"timestamp\": \"2012-05-25T14:59:38.605Z\",  \"feedbackId\": \"000001378603176d-5a4b5ad9-6f30-4198-a8c3-b1eb0c270a1d-000000\",  \"remoteMtaIp\": \"127.0.2.0\"}, \"complaint\": {  \"userAgent\": \"AnyCompany Feedback Loop (V0.01)\",  \"complainedRecipients\": [      {          \"emailAddress\": \"recipient1@example.com\"      }  ],  \"complaintFeedbackType\": \"abuse\",  \"arrivalDate\": \"2009-12-03T04:24:21.000-05:00\",  \"timestamp\": \"2012-05-25T14:59:38.623Z\",  \"feedbackId\": \"000001378603177f-18c07c78-fa81-4a58-9dd1-fedc3cb8f49a-000000\"}, \"delivery\": {  \"timestamp\": \"2014-05-28T22:41:01.184Z\",  \"processingTimeMillis\": 546,  \"recipients\": [      \"success@simulator.amazonses.com\"  ],  \"smtpResponse\": \"250 ok:  Message 64111812 accepted\",  \"reportingMTA\": \"a8-70.smtp-out.amazonses.com\",  \"remoteMtaIp\": \"127.0.2.0\"} }",
        "Timestamp": "1970-01-01T00:00:00.000Z",
        "SignatureVersion": "1",
        "Signature": "EXAMPLE",
        "SigningCertUrl": "EXAMPLE",
        "UnsubscribeUrl": "EXAMPLE",
        "MessageAttributes": {
          "Test": {
            "Type": "String",
            "Value": "TestString"
          },
          "TestBinary": {
            "Type": "Binary",
            "Value": "TestBinary"
          }
        }
      }
    }
  ]
}

S3の静的ウェブサイトホスティングのインデックスドキュメントの挙動を、CloudFrontのデフォルトルートオブジェクトをLambda Edgeを使って処理する方法

はじめに

今のブログはAWS S3の静的サイトで運用していますが、サイトの構築には

  • Docker
  • WordPress
  • WP2Static
  • S3
  • Cloud Front
  • AWS Certificate Manager
  • Lambda Edge

となってます。

2つの機能を確認

S3の静的ウェブサイトホスティングのインデックスドキュメントの挙動

AWS ドキュメントはこちらです。

https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/dev/IndexDocumentSupport.html

CloudFrontのデフォルトのルートオブジェクトの挙動

AWS ドキュメントはこちらです。

https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/DefaultRootObject.html

WordPressからの静的サイト生成プラグイン「WP2Static」

S3へのアップロードとCloudFrontのInvalidationが欲しかったので下記を使ってます。

アクセスの挙動の整理

こちらのプラグインで静的サイトが生成されます。HTMLのリンク(aタグ)は
https://example.com/hogehoge/
となります。
こちらはwordpress上では当たり前ですが、動きます。

s3だと
https://example.com/hogehoge/
は
https://example.com/hogehoge/index.html
にインデックスドキュメントがあればアクセスされます。

CloudFrontの場合
https://example.com/hogehoge/
にはリダイレクトしません。

Lambda Edgeを使ってリクエストを変換します。

Lambdaでは、/(スラッシュ)で終わってる場合/index.htmlにアクセスするように変換するシンプルなものです。

'use strict';

exports.handler = (event, context, callback) => {
    var request = event.Records[0].cf.request;
    console.log(request.uri)

    if ( request.uri.match(/.*\/$/)) {
        request.uri += "index.html"
    }
    callback(null, request);
}

最後に

ローカル環境でDockerのWordpressを立ち上げ、記事を書き、静的サイトを出力すると、S3にアップしCloudFrontがInvalidationされデプロイが完了します。これで静的サイトが望み通り挙動するようになりました。

FirebaseでCI用のトークンを生成する方法

AWS CodeBuildやCircleCI, Azure DevOpsでFirebaseデプロイを使用する機会があったので、トークンを利用する方法をメモしておきます。

login:ciを使用してトークンを生成します。

[f_prg@XXXX-XXXX-XXXX] $ firebase login:ci

Visit this URL on any device to log in:
https://accounts.google.com/o/oauth2/auth?XXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Waiting for authentication...

✔  Success! Use this token to login on a CI server:

FIREBASE_TOKENFIREBASE_TOKENFIREBASE_TOKENFIREBASE_TOKEN

Example: firebase deploy --token "$FIREBASE_TOKEN"

トークンを無効にする方法

https://github.com/firebase/firebase-tools#using-with-ci-systems

こちらにあるように、ログアウトを実行すればトークンは無効になります

firebase logout --token 

まとめ

CIツールで使う時には、環境変数や設定ファイルなどに組み込めば使用できます。

treeコマンドで文字化けしたので対応した

あるフォルダの一覧を作ろうとしていて
treeコマンドでいいだろうと思っていたら
文字化けしまくってしまったので、コマンドのメモです。
-Nオプションが必要でした。
tree -N .

まとめ

簡単にできると思っていたら、全然できなかった話。勉強になりました。

ACMの更新の連絡がきたので対応しました。

「Action Required - Your certificate renewal」という件名のメールが届きました。

メールの本文はこちらです。

Greetings from Amazon Web Services,

You have an AWS Certificate Manager (ACM) SSL/TLS certificate in your AWS account that expires on May 28, 2019 at 12:00:00 UTC. That certificate includes the primary domain blog.star-flare.com and a total of 1 domains.

AWS account ID: 123456789012
AWS Region name: us-east-1
Certificate identifier: arn:aws:acm:us-east-1:123456789012:certificate/AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEE

ACM was unable to automatically renew your certificate. The domain owner or someone authorized by the domain owner must take one of the following actions before May 28, 2019 at 12:00:00 UTC. If no action is taken, the certificate will expire, which might cause your website or application to become unreachable.

1. If you can write records into your DNS configuration, create and install DNS-validated certificates to replace all of your existing email-validated certificates. After you add a CNAME record to your DNS configuration, ACM can automatically renew your certificate as long as the record remains in place. You can learn more about DNS validation in the ACM User Guide.[1]

2. If you want to continue using email validation to renew this certificate, the domain owners must use the approval link that was sent in a separate validation request email. That email was last sent on Apr 13, 2019 at 12:38:10 UTC. The link in that email is valid for three days from the time the email was sent. If you did not use the link within three days, go to the ACM console to have AWS resend the validation email. For instructions, see the AWS Support website.[2]

If you have questions about this process, contact the AWS Support Center[3]. If you don’t have an AWS support plan, post a new thread in the AWS Certificate Manager discussion forum.[4]

[1] https://docs.aws.amazon.com/acm/latest/userguide/gs-acm-validate-dns.html
[2] https://aws.amazon.com/premiumsupport/knowledge-center/resend-email-ssl/.
[3] https://console.aws.amazon.com/support
[4] https://forums.aws.amazon.com/forum.jspa?forumID=206
Sincerely,
Amazon Web Services

ACMを更新します。

新しい証明書を作成します。

古いのはemailでの認証をしており、whois公開を外す手間がありましたので
新しいのはDNS認証に変更しました。楽チンです。

AWS CLIで更新します。

configファイルを作成します。

aws cloudfront --region us-east-1 get-distribution-config --id "AAAAAAAAAAAAAA" | jq '.DistributionConfig' > AAAAAAAAAAAAAA-us-east-1.conf

configファイルを編集します。

$ vscode ./AAAAAAAAAAAAAA-us-east-1.conf
ACMCertificateArnCertificateARNを新しく発行したものに編集します。
ViewerCertificateの部分を変更しました。
  "ViewerCertificate": {
    "ACMCertificateArn": "arn:aws:acm:us-east-1:123456789012:certificate/NEWAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEE",
    "SSLSupportMethod": "sni-only",
    "MinimumProtocolVersion": "TLSv1.1_2016",
    "Certificate": "arn:aws:acm:us-east-1:123456789012:certificate/NEWAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEE",
    "CertificateSource": "acm"
  },

ETagを確認して、保存します。

aws cloudfront --region us-east-1 get-distribution-config --id "AAAAAAAAAAAAAA" | jq '.ETag'

ETagを使って、更新します。

EEEEEEEEEEEEは取得したETagです。
aws cloudfront --region us-east-1 update-distribution --id "AAAAAAAAAAAAAA" --distribution-config file://AAAAAAAAAAAAAA-us-east-1.conf --if-match EEEEEEEEEEEE

これで終了です。

古い証明書は、しばらくしたら破棄する予定です。

まとめ

AWSからの通知の対処はしっかりとやっておきましょう。