このブログをGoogle Cloud Platformに移行した話


このブログを動かしているサーバをGoogle Cloud Platformに移行させたので、その作業ログを記録に残しておく意味で、記事にまとめました。

はじめに

もともとこのブログはさくらのクラウドに立てたサーバ上で運用していました。

さくらのクラウドに立てていた理由は、ちょうど移行先を探していたときにイベントでさくらのクラウドのクーポンを貰ったため、ブログだけならオーバースペック気味でしたが、同時に他のことにも使うときには良さそうと思い、さくらのクラウドに立てていました。

しかし、ここ最近ではあまり別目的で利用するでもなく、オーバースペックを持て余し気味でした。

そこに来て、使用していた石狩第1ゾーン 旧プランの環境閉鎖、使用していたUbuntu14.04LTSのサポート終了、WordPress 5.2以降ではPHP 5.6.20以上が必須(Ubuntu14.04はPHP 5.5.9まで)等の問題が発生しておりました。

1つ目の問題については、公式に移行ツールが提供されていましたが、他の問題を考えると単純な移行ではなく、新しくサーバを立て直してそこにデータ移行したほうが良いため、今回完全に別の場所に移行することを考えていました。

その中で、以下の記事を見かけました。

Google Cloud Platformを前から試してみたかったことや、ブログ以外のことをこのサーバですることが減った & 違うことをするなら違うインスタンス or コンテナを立てて行うほうがいいのではという気持ちになり、この記事を参考にGoogle Cloud Platformに移行するにしました。

概ねの手順は上記のQiitaの記事ほぼそのまま参考にしましたが、個人的に気になった点などは逐次修正して行っていました。

Google Cloud Platformとは

移行するGoogle Cloud Platformについて、軽く説明します。

Google Cloud PlatformはGoogleが提供するクラウドコンピューティングサービスです。
Googleが提供するクラウドサーバサービスのGoogle Compute Engine(GCE)や、BiqqueryなどもGCPのサービス郡の1つです。

今回はこの中のいくつかのサービスを利用して、wordpressが動く環境を構築していきます。

GCP Marketplaceで環境を構築

GCP Marketplaceではすでに設定済みの環境を自身のCGPに展開することができます。
今回は、Bitnamiが提供する「WordPress with NGINX and SSL Certified by Bitnami」を使用します。

ここで「COMPUTE ENGINE上で起動」をクリックすれば、Zoneやmachine設定を選択する画面になります。

この画面でCGPのAlways Free プロダクトに収まる範囲内で必要に応じた設定を行います。

  • CCE: 1 f1-micro インスタンス(1 か月あたり、北バージニア [us-east4] を除く米国リージョンのみ)
  • GCE: 30 GB/月の HDD
  • GCS: 5GB/月の Regional Storage(1 か月あたり、北バージニア [us-east4] を除く米国リージョンのみ)

設定後、「デプロイ」を押せば環境構築が始まり、数分後にはWordpress構築済みのインスタンスが立ち上がります。

旧Wordpressからのデータ移行

既存のWordpressからの移行なので、新しく建てたWordpressに対してデータの移行を行います。
今回は、参考元のQiita記事で紹介されていた「All-in-One WP Migration」というプラグインを試してみました。

All-in-One WP Migrationのインストール

All-in-One WP Migrationは移行元、移行先どちらにも必要なので両方にインストールします。

データのエクスポート

移行元のインストール後にAll-in-One WP Migration→エクスポート→適切な保存先を選択します。
今回はローカルへのDL(ファイル)を選択しました。

データのインポート

移行先にAll-in-One WP Migrationのインストールが終わったら、インポート→を選択します。

しかしながら、All-in-One WP Migrationの無料版のアップロードサイズは環境の最大POSTサイズに依存し、今回構築した環境のデフォルトでは40MBでした。

しかし、今回エクスポートしたデータは5GB(!?)もあり、当然そのままではアップロードできません。

元のQiitaでも、アップロード容量を上げるワンライナーが書いてありますが、プラグインの提供元が公式に出しているガイドを元にトライしてみました。

基本的にどれか1つ上げれば反映されそうなのですが、手元の環境ではそれではうまく行かなかっため、以下のようにnginxの設定、php.ini、wp-config.phpのすべての設定を変更してました。

~/apps/wordpress/htdocs/wp-config.phpに以下を追記

~/apps/wordpress/conf/nginx-app.confに以下を追記

/opt/bitnami/php/etc/php.ini を以下のdiffのように修正

設定変更後、nginxとphp-fpmを再起動します。

sudo /opt/bitnami/ctlscript.sh restart nginx && sudo /opt/bitnami/ctlscript.sh restart php-fpm

これで、10GBのアップロードができるようになったため、実行します。
アップロード及び移行が終わったら、基本的に大きなサイズのPOSTは必要ないため、変更した設定は元に戻しておきます。

All-in-One WP Migrationでの移行の注意点

この段階で移行作業をした場合、元のサイトのドメイン名が現在のサイトのドメイン名に書き換わります。ダウンタイムなしで移行するためには事前のデータ移行が必要ですが、このとき書き換わるのは、サイトURL等ではなく、ほとんどのドメイン名が置換されます。

たとえば、ブログのドメイン名と同じドメインでメールを利用して、それをユーザーのメールアドレスに登録していた場合、そこも置換されてしまします。さらにこの段階では基本的にIPアドレスでアクセスしているため、以下のようになります。

旧: [email protected] → 新: [email protected]

移行プラグインなので、ほぼすべての範囲で置換が行われていると思いますので、意図していない箇所が置換されていないかチェックしておきましょう。

レイアウトが崩れた問題

データの移行自体は問題なく終わりましたが、その状態でページを開くとレイアウトが崩れていました。

おそらくphp7化の影響かと思いましたが、ほぼ環境を一新しているため、1から調べることにしました。

最初に、Wordpressのオフィシャルテーマである「Twenty Eleven」に変更しました。オフィシャルテーマであるため、これでも崩れるのであれば、wordpressの標準以外のところで問題が起きている可能性が高いためです。
結果は崩れたままでした。

次にプラグインを調べます。はじめにすべてのプラグインを無効化します。
この時点でレイアウトが治ったため、プラグインの問題と絞り込めました。
次にどのプラグインが悪さをしているかを調べるため、1つずつ有効化していきまいた。

その結果、「Head Cleaner」というヘッダーの最適化を行うプラグインが原因でした。
このプラグインは昔、表示速度が遅いときに入れてみたプラグインでしたが、更新が2年前から止まっていることや、今回の問題から最新の環境に対応できていないと思い、また移行で環境も大きく変わっているため、削除しました。

合わせて他の使用していないプラグインも削除しました。

  • WP Product Review
    • 前に使っていたテーマの推奨プラグインだった
    • 今回移行に合わせてテーマも変えたので削除
  • SEO Slugs
    • 12年前から更新されてない & SEO系プラグイン入れまくりなので削除
  • Pagebar2
    • 更新されてないし、個人的にPagebarの必要性も薄くなってきたので削除
  • Orbit Fox Companion
    • 前に使っていたテーマの推奨プラグイン
  • kk-blog-card
    • 同種のPz-LinkCardを入れているため整理
  • Head, Footer and Post Injections
    • Header Footerに共通のものを入れることを今はしていない
    • 後ほど、AdSenseでHeaderに共通JSを入れるが、推奨の別のプラグインに切り替えた
  • All-in-One WP Migration
    • 移行が終われば不要
  • Google AdSense

IPアドレスの固定

現在の状態ではIPアドレスが固定化されていないため、静的IPに切り替えます。

CGPの外部 IP アドレスのページから、先程作成したプロジェクトのIPアドレスを「エフェメラル」→「静的」に変更してください。

Google Cloud Storageに画像を保存するようにする

WordPressに投稿した画像をGoogle Cloud Storage(GCS)に保存、そちらから表示するように変更します。

パケットの作成

元のQiitaではバケット名をサイトドメインではなく別名にしていますが、サイトドメインにすることでサイトドメインとして配信ができるようになるため、今回はそちらを選択します。

GCSのパケット名にドメイン名を使用するにはそのGoogleアカウントに対してGoogle Search Consoleでそのドメイン名の登録が終わっている必要があります。今回私は設定済みだったため省略しますが、「Google Search Console 登録」で検索すればやり方はいっぱい出てきます。

定済みであれば、特に制約なくドメイン名を含めたパケット名が設定できます。ここではサブドメインにstorageをつけたドメイン名で設定します。

パケットが作成されたら、WordPressから触るためのサービスアカウントを作成します。
IAMの管理ページから「サービスアカウント」を選び、あたらしいサービスアカウントを作成します。

このとき、権限設定を聞かれますが、今回は使用させたいパケットが決まっているので、ここからでは設定しません。

その後、作成したパケットのページに戻ります。
作成したパケットを選択し、「メンバーを追加」から、先程追加したアカウントを「ストレージ管理者」として追加します。

これでこのサービスアカウントがこのパケットを操作できるようになりました。個人的には基本書き込みだけなので、書き込み権限だけでいいのではと思い、一時はそう設定しましたが、後述のプラグイン上でエラーになり(設定後に権限を落としても、暫く経つとエラーになった)、さらにエラーになると、GCSを使わない設定に書き換わってしまうので、今回は公式にあるように「ストレージ管理者」を設定しました。

DNSの設定

GCSを独自ドメインで運用するには、DNSの設定が必要です。
公式のドキュメントにあるように、設定したいドメインに対してCNAME レコードで c.storage.googleapis.com. を設定する必要があります。

WP-Statelessの設定

次にWordPress側でもGCSを使うように設定をします。今回はWP-Statelessというプラグインを使用します。

プラグインをインストール後、設定画面にて設定を行います。

まずModeをCDN に設定します。

次にGCSのパケット名、サービスアカウントの認証用JSONデータを設定します。

後者は、先程作成したサービスアカウントのデータを使用します。
IAMの画面から、サービス アカウントをクリックして、サービス アカウントの詳細を開き、キーの作成から作成可能です。

次にドメイン名を設定します。このときhttpsでの指定をしていますが、GCSの独自ドメインは単体ではhttpsの配信に対応していません。(CNAME リダイレクトがhttpのみ)そのため、後述のCloudFlare経由でhttps配信をするようにしています。

これで配信設定は完了です。これ移行にアップロードされたものはCGS経由で配信されますが、以前のものも配信したい場合は、WP-Statelessの「Sync」タブからすべてのファイルの同期が可能です。

このあたりの設定は下記のサイトも参考にさせてもらいました。

CDNを使用する

CDNを利用して配信の最適化を試みます。
今回は元のQiitaで紹介されているCloudflareを使用します。

Cloudflareに登録後、「Add a Website」からサイトのドメインを登録します。

登録するとネームサーバの変更が求められるので、ドメインを購入したサイトの管理画面等から、ネームサーバを変更します。変更完了後はCloudflareでDNSレコードの編集等ができるようになります。

変更反映まではそこそこ時間がかかりますが、しばらく待っても反映されない場合、反映待ちの画面にRecheck のボタンが出てきているのでそれを押すと反映されることもあります。(もちろんちゃんとネームサーバ変更が反映されていれば)

反映後は、以下の設定を行います

  • Always Use HTTPSをOnに
    • HTTPSの常時利用
  • Automatic HTTPS RewritesをOnに
    • HTTPへの参照を自動でHTTPSに書き換え
  • SSLをFullに
    • Cloudflareとホストサーバー感の通信もHTTPSに

Google Public DNSのキャッシュ更新

Cloudflareとは、直接関係ないのですが、ネームサーバの切り替えや、CloudflareのDNSレコードを書き換えた際、反映が遅く、ネットワーク上のnslookupサービス等では更新済みのレコードが見えるのですが、自宅では見えないということが続いていました。

調べていくうちにGoogle Public DNSが更新されていないと気付き(自宅ではプロバイダのDNSが不安定なので、Google Public DNSを優先にしている)、その更新方法を調べていると、webサイトからキャッシュクリアのリクエストができました。

こちらでキャッシュクリアリクエストをしたところ、即座に反映され、無事に自宅からレコードが更新された状態が見えました。

各種プラグインのインストール

もともと入れていたプラグインとは別に、追加でいくつかのプラグインを入れました。

  • SiteGuard WP Plugin
    • WPのセキュリティプラグイン
    • いくつかの機能はこの環境で動かないので無効化
      • ログインページ変更
      • 画像認証
  • Advanced noCaptcha & invisible Captcha (v2 & v3)
    • GoogleのReCaptchaを入れられるプラグイン
    • v3はユーザーのスコアで判定するのでチェックボックスなし
    • コメント系ページに導入
  • IP Geo Block
    • IP制限をできるプラグイン
    • 元にしたQiitaで紹介されており、そこを元に導入
  • WP Optimize
    • WordPressのDBを最適化してくれるプラグイン
    • 古いリビジョンの削除等してくれるが、自分は残したかったので、「データベーステーブルの最適化」のみ利用
  • AMP
    • AMP対応するためのプラグイン
    • 非対応のタグ等を対話式に変更するか否か選択可能
    • 対応完了したページのみ公開できる
    • AMP用の広告タグは、Insert Headers and Footersを利用して、ヘッダーにhead用amp広告タグ、フッターに 本文用amp広告タグを挿入

bitnamiのロゴを消す

この方法で設定した環境では常にbitnamiのロゴが表示されておりますが、ワンライナーで消すことができます。(元にしたQiitaに書いてあったワンライナーが何故か途中で改行されてそのままコピペができなかったので編集リクエストを送りました)

sudo /opt/bitnami/apps/wordpress/bnconfig --disable_banner 1 && sudo /opt/bitnami/ctlscript.sh restart nginx

また、このロゴに関する設定は ~/apps/wordpress/conf/nginx-app.confから読み込まれている以下の2ファイルから読み込まれているのでそこをコメントアウト or 削除でもOKです。
私は今後nginxの設定を見るときのノイズになりそうなので、こちらをコメントアウトしました。

  • /opt/bitnami/apps/bitnami/banner/conf/banner-substitutions.conf
  • /opt/bitnami/apps/bitnami/banner/conf/banner.conf

WordPressのサイトアドレスをhttpsにする

WordPressで設定されているサイトアドレスがhttp固定のため、httpsでアクセスしても一部のエンドポイントがhttpのままになっていることがあり、一部のプラグインやプレビューがうまく動作しませんでした。
そのため、~/apps/wordpress/htdocs/wp-config.phpを以下のように編集してhttpsに変更します。

サーバ自体もletsencryptでhttps化

基本的にCloudFlareでhttps化されていますが、この構成ではletsencryptでSSL証明書を発行する方法も用意されています。

公式や元のQiitaでは以下のコマンドが紹介されています。

sudo /opt/bitnami/letsencrypt/scripts/generate-certificate.sh -m YOURMAIL -d YOURDOMAIN

ただしここで注意しないといけないのが、このコマンドを実行するときはcloudflareのCDN設定を外しておかないといけません。
外しておかないと以下のようなエラーになります。

2019/07/12 10:02:59 Could not obtain certificates:
	acme: Error -> One or more domains had a problem:
[ik-fib.com] acme: error: 403 :: urn:ietf:params:acme:error:unauthorized :: Cannot negotiate ALPN protocol "acme-tls/1" for tls-alpn-01 challenge, url:

Error: Something went wrong when running the following command:

 $ "$LEGO_BIN" --path "/opt/bitnami/letsencrypt" --tls --email="${email}" ${domain_args} run

Please check our documentation or open a ticket in our community forum, our team will be more than happy to help you!

wp-admin以下をサーバからのアクセス専用にする

本来はSiteGuardがいくつかadminに対するアクセスを塞いでくれるようになっていますが、この構成で動かないため、無効にしています。

そのため、セキュリティ対策として、wp-admin以下は、wordpressが動いているサーバ経由のアクセスでしかアクセス出来ないようにします。

~/apps/wordpress/conf/nginx-app.confに以下の設定を追記します。

このうち前半はCloudFlare経由のアクセスから元のIPアドレスを取得する処理です。CloudFlareからのアクセスは元のIPアドレスがX-Forwarded-Forヘッダーに入れれています。しかし、これはあくまでHTTPヘッダなので自由に追加でき、そのままでは信頼性はありません。そのため、CloudFlare のIPアドレス帯からのアクセスのみX-Forwarded-Forを使用するように設定しています。

これで、CloudFlare のIPアドレスからのアクセス時はnginxの各種処理は、X-Forwarded-Forヘッダーを元にした元のIPアドレスを使用するようになります。

また、これら管理ページの情報がCloudFlareにキャッシュされては困るため、除外設定を入れておきます。(CloudFlareは基本的にページ自体はキャッシュしないうえに、サーバ側でのキャッシュ設定が適切でヘッダーに設定されていればキャッシュされません。そのため、通常利用でキャッシュされることはないはずですが、今後何かしらの変更を加えたときに誤ってキャッシュされないように)

CloudFlareの「Page Rules」から、 “*[ドメイン名]/wp-login.php“と、”*[ドメイン名]/wp-admin/*” に対して以下の設定を行います。

  • “Cache Level” を “Bypass”に
  • “Disable Performance” を選択
  • “Disable Security” を選択

この設定を反映後、nginxを再起動 or 設定のreloadをすることでサーバからのアクセスでしか、wp-adminにはアクセスできないようになります。

ブラウザの接続をサーバ経由にする

ブラウザ上でサーバ経由のアクセスをするのはsshのDオプションを使い、簡易プロキシにするのが手っ取り早いです。GCEの場合は、gcloudコマンドで同じオプションを渡すことができます。

以下のコマンドを実行後、ブラウザのプロキシ設定を SOCKSのlocalhost:1080に設定することでサーバ経由でアクセスが可能です。

gcloud beta compute --project "プロジェクト名" ssh --zone "ゾーン" "VM名" -- -D 1080

サーバの監視を行う

CGPにはStackDriverという監視ツールがあります。これはGCEのモニタリングや特定のURLの外形監視など、様々な監視ができるサービスです。

以下を参考にモニタリング設定と、トップページの死活監視設定を行いました。

また、サーバ内のlogfileを元に定期監視→情報送信をしてくれるlogwatchをインストールしました。

$ sudo apt install logwatch

デフォルトではnginxの設定が入っていないので以下を参考に修正しました。

また、MarketPlaceから構築したこの環境のデフォルトでは、nginxのアクセスログが、/opt/bitnami/nginx/logs/access.logに保存されるようになっています。
そのため、エラーログの出力設定と合わせて /opt/bitnami/nginx/conf/nginx.conf を以下のように編集します。

メール送信をできるようにする

元にしたQiitaの記事ではメール送信にWPのプラグインを使用してSendGridを使う方法を紹介していましたが、今回サーバレベルでメールを送れるようにしたいため(前述のlogwatchやcrontab等のメールも飛ぶようにしたい)、サーバ自体がメール送受信できる状態にします。

GCEではいくつかのメール送信サービスがサードパーティパートナーになっています。今回は元ににしたQiitaの記事で紹介されていたSendGridを使用します。ただし同じSendGrid使用ですが、Google公式にGCE上でのSendGrid でのメールの送信のドキュメントが用意されており、これに従い、サーバから直でSendGrid経由でメールが送れるように設定します。

Google Cloud Platform Marketplace からSendGridのaccountを作成後、SendGridの管理画面より「Settings」 →「API Keys」からAPIキーを作成します。
今回必要なのはメール送信だけなので、APIの権限も送信のみに指定して作成します。

この後APIキーが発行されますが、値が確認できるのはこの画面のみでこれ以降は確認できないので注意してください。

キー作成後はPostfixのインストール→設定を行います。

Postfixのインストール

$ sudo su -
% umask 077
% apt-get update && apt-get install postfix libsasl2-modules -y
# プロンプトが表示されたら、[Local Only] の構成を選択

設定ファイルの調整

/etc/postfix/main.cf の以下の行をコメントアウトして、 末尾にrelayhostの設定及び、SSL / TLSの利用設定を追加

以下のコマンドでパスワードの設定を追加して、postfixを再起動させます。

% echo [smtp.sendgrid.net]:2525 apikey:[YOUR_API_KEY] >> /etc/postfix/sasl_passwd
% postmap /etc/postfix/sasl_passwd
% rm /etc/postfix/sasl_passwd
% chmod 600 /etc/postfix/sasl_passwd.db
% /etc/init.d/postfix restart

メール送信のテスト

設定完了後、正しくメールが送信できるかをテストします。

% apt-get install mailutils -y
% echo '[MESSAGE]' | mail -s [SUBJECT] [[email protected]]

送信完了後、ログを確認して正しいレスポンス(250)が帰ってきてるかを確認します。

% tail -n 5 /var/log/syslog

ただ、自分がハマったポイントとして、ドキュメント最初の「Google Cloud Platform Marketplace を使用して、SendGrid Email サービスに登録」を見逃しており、SendGridの公式サイトから登録していました。

最初、自分がそちらのアカウントではSMTPやweb APIを使っても一切メールが飛ばず、おそらく何らかの制限にかかっていると思われれますが、レスポンス的にも正常系が帰ってきていたため、詳細がわかりませんでした。(サポートに問い合わせたところ、やはりアカウントの認証周りだったとのことでした。)

root宛のメールを転送する

メール送信ができるようになった状態で、下記のようにroot宛のメールを個人メールアドレスに転送するようにすればこれらのメールが個人アドレスにメールされるようになります。

CGP自体のファイアーウォールでも特定国をブロックするように(2019/07/16追記)

最初は元記事にあったGeo IP Blockを使用していましたが、考えてみるとCloudfireを使用している以上、基本的なアクセスはCloudfire経由になります。しかし直接IP指定等で来られると、Cloudfireを通さないため課金対象 & 直接IP指定で来る以上アタックの可能性が高いため、下記のQiita記事にあるようにCGP自体のファイアーウォールでブロックするようにしました。

対象となるIPアドレスの数が多いため、↓のスクリプトをもとにfilterを追加しました。(1ルールで255個までしかレンジを指定できない)
しかし、このスクリプトもアドレスはローカルのファイル参照で未更新だったため、更新するシェルスクリプトを追加しました。(近い内にPR送りたい)

また、IP帯の変更に合わせて定期的な更新も必要なためその処理もちょっと考えているところです。

fail2banを入れる(2019/07/16追記)

logwatchでログを確認しているとやはりアタックっぽいアクセスがそこそこあり、おそらくGCEのアドレス帯に適当にアクセスして穴を探しているものだと思います。

基本的にssh以外は開放していないため、そこさえ注意していれば大丈夫のはずですが、なにかしらの予防措置は必要 & 上記IPブロックのレンジ外(更新前等) & 対象国からアタックされた場合請求対象になるので、fail2banを入れておきます。

基本的に下記の記事を参考にfail2banの設定をしました。

$ sudo apt install fail2ban

/etc/fail2ban/jail.localを以下のように作成します。

次に、/etc/fail2ban/action.d/iptables-common.localにBANされたパケットを拒否せずにドロップ(破棄)する設定を行います。

設定後、fail2banの起動 & 自動起動設定をすれば完了です。これで自動ブロック及びブロック時メール通知が来るようになります。

% sudo systemctl restart fail2ban
% sudo systemctl enable fail2ban

総評

これで今回のブログの移行作業は完了しました。やった作業のメモ書きという記事なので、今回は省略した箇所も多々あります。(なぜか移行作業中にAMPプラグイン試すとかおかしなことを始めたりしてた)

CGPを使ったWordpress環境の構築自体は元にしたQiitaの記事が非常にわかりやすく進んだのですが、自分の場合は↑の脱線や、移行ということもあり、サーバ内でもあれこれやろうとしたためそこそこに時間がかかってしまいました。(とくにSendGrid周りはエラー原因がわからなかったため悪戦苦闘してしまった)

これで溜まっていたタスクになっていた環境更新系が一掃できたため、いろいろ手を伸ばしていこうとおもいます。(CGP等もっと触っていきたい)


コメントを残す

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

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください