GitHub Pagesで運営していた写真・IT系の当ブログを、Netlifyと独自ドメインに移行しましたので、その時に行った内容やハマった点を備忘録としてまとめたいと思います。

目次

はじめに

今までは、静的サイトジェネレータのHexoで書き出したページをGitHub Pagesにデプロイしていました。静的ジェネレータは色んな物がありますが、代表例を挙げると以下のようなプログラムがあります。2017年現在ではHugoが流行っているようです。

ホスティングサービスの話題に戻りますが、GitHubからNetlifyへの移行後は、Hexoで書き出したサイトをZipファイルで圧縮して送信し、Netlifyへデプロイしています。実際の処理はhexo-deployer-netlifyというプラグインで自動化されています。

GitHub Pagesは、サーバー維持費が無料でありながら、HTTPSやCDNをサポートしており、ブログを運用するには快適な環境でした。ところが、GitHub Pagesは10万リクエスト/月という帯域幅制限などの条件があるので、そろそろその制約に引っかかりそうでした。

ブログの運営も順調に推移しているので、更にページビューが増える前にNetlifyに移行しようと考えました。

不明な点はコミュニティやチャットで質問できる

Netlifyに関して不明な点や、分からない所はコミュニティのGITTER - netlify/communityやNetlifyのチャットで聞くことが出来ます。

GITTERでは、Netlify利用者と情報交換ができる
GITTERでは、Netlify利用者と情報交換ができる ©
Netlifyのページに常設されているチャットからも、直接問い合わせができる
Netlifyのページに常設されているチャットからも、直接問い合わせができる ©

Netlifyのチャットは、1日以内に返事が返ってくるので対応の速さに驚きました。質問は全て英語でやりとりする事になりますが、Google先生の力を借りて分からない内容をなんとか質問しています。

Netlifyのフリープランはどうなの?

Netlifyは、GitHub Pagesと似たような使い方ができ、尚且つフリープランの帯域制限もGitHubより遥かに緩めです。更にはHTTP/2やCI(Netlify CI)による静的サイトの生成自動化も行えるのが特徴です。

Netlify
Terms of Service Agreement
Netlifyフリープランの制約等が記載されている。執筆時現在のところ、ネットワーク転送量:100GB/月. 容量:100GB. デプロイ時のAPIリクエスト:200リクエスト/分. 3デプロイ/分 などの制限が設けられている。

冒頭でも触れた通り、Netlifyには、書き出したサイトをZipファイルで圧縮して送信しています。ここで「なぜCIを使わないの?」と不思議に思った方もいらっしゃるかと思います。

Netlifyというと、GitHubやBitbucketやGitLabのリポジトリをCIで自動ビルド&デプロイできるのが目玉の機能です。しかし、Netlifyでは幾つか制約があるため、自身のブログでCIを使う事ができず、結果的に今回は断念することになりました。

下記では、CIを断念した経緯も踏まえて、移行時にハマった内容も振り返ります。

移行時に行った事

Netlifyと独自ドメインに移行する際に行った内容はこちらです。

Netlifyにデプロイ

まずはNetlifyにブログのページデータをデプロイしました。Netlifyでは、以下の方法でページデータをデプロイできます。

  • GitリポジトリをNetlifyCIがビルド&デプロイ
  • NetlifyにページデータやZipファイルを送る

移行時には上記の項目を順番に試していきましたが、結果的には2番目を採用しました。

GitリポジトリをNetlifyCIがビルド&デプロイ

サイトデータを配置したGitのリポジトリを、Netlifyが自動的にビルドやデプロイを行ってくれます。ビルド&デプロイのタイミングは、リポジトリがPushされた時点を検知してくれます。

また、リポジトリは以下のサービスをサポートしています。

  • GitHubのリポジトリ
  • Bitbucketのリポジトリ(非公開リポジトリ作成可能)
  • GitLabのリポジトリ(非公開リポジトリ作成可能)

ブログサイトのソースを公開したくないというニーズはよくある話かと思います。そんな時は、上記のようにBitbucketやGitLabに非公開のリポジトリを配置するのがおすすめです。

しかし、Netlify CIのビルドプロセスは15分を超えると強制停止する制約がありますので、注意が必要です。サイトの生成に時間を要する方はCIのビルドに失敗します。

Netlify
How Our Build Bots Build Sites
(引用)You’ll probably see a build timeout in these cases - we’ll run your commands but then after 15 minutes, we stop the build process.

実際に自分のNetlify CIでも、この制約に引っかかってしまい、ビルドが約15分で止まってしまいました。Netlify CIのログでは、下記のようにExecution timed outとエラーが表示されます。

netlify-deploy-log
1
2
3
4
5
6
7
00:00:00 AM: Execution timed out
00:00:00 AM: Cleaning up docker container
00:00:00 AM: Build complete: exit code: 137
00:00:00 AM: Error running command: Command did not finish within the time limit
00:00:00 AM: An error occurred while building the site, skipping the deploy and cache refresh.
00:00:00 AM: Command did not finish within the time limit
00:00:00 AM: Finished processing build request in 15m12.213130383s

以下に該当するようなケースでは、ビルドの時間が15分を越えてしまう可能性が高いので、この後で説明する方法で対応するしかありません。(もし他に何か良い回避方法がありましたら是非アドバイスをお待ちしております)

  • CIにインストールするパッケージが多い
  • 記事数が多い
  • 静的ページ生成処理に時間が掛かる

NetlifyにページデータやZipファイルを送る

Netlifyでは前述した通り、Gitリポジトリのビルド&デプロイを行う事ができます。

また、前述の方法以外にも、Netlify APIを使ってサイトデータを送信する方法が提供されています。自身のサイトでは、CIが使えないため、仕方なくAPIを使ってサイトデータをデプロイしています。

例えば一例を上げると、Node.jsでjavascript(ES6)を使って、netlifyにデータを送る方法については以下のコードになります。

netlify-dir-send.js
1
2
3
4
5
6
7
8
9
let netlify = require("netlify")
netlify.deploy({
access_token : "xxx" ,
site_id : "xxx" ,
dir : "/public"
}).then( (deploy) => {
if(deploy.error_message)console.error(`デプロイ中にエラーが発生しました: '${deploy.error_message}`)
else console.log("デプロイに成功しました")
})

上記ではpublicディレクトリ以下の全ファイルをNetlifyに送ります。access_tokensite_idはNetlifyのアカウントページから取得及び確認ができます。

Netlify APIの制約

ただし、Netlify APIは200リクエスト/分という制限が設けられているため、転送するファイル数が多いとAPIエラーになります。

Netlify
Netlify API
(引用)Rate Limiting … The Netlify API is rate limited. You can make up to 200 requests per minute.

ファイル数が多くてエラーが発生する場合は、下記コードのように、サイトのデータをZip圧縮し、一つのファイルにまとめて送信するのがオススメです。

netlify-dir-send.js
1
2
3
4
5
6
7
8
9
let netlify = require("netlify")
netlify.deploy({
access_token : "xxx" ,
site_id : "xxx" ,
zip : "public.zip"
}).then( (deploy) => {
if(deploy.error_message)console.error(`デプロイ中にエラーが発生しました: '${deploy.error_message}`)
else console.log("デプロイに成功しました")
})

静的サイトジェネレータのHexoでは、サイトデータのZipファイル圧縮後、Netlify APIで送信できるプラグインhexo-deployer-netlifyがありますので、宜しければそちらも活用ください^^ Zip圧縮の処理は私が改良しました(笑)

お名前.comで独自ドメイン取得

Netlifyにサイトを配置した後、続いて独自ドメインを取得しました。取得先はお名前.comwww.xxx.comドメインにしました。

独自ドメイン取得後はお名前.comの管理ページからドメイン設定 > DNS関連機能の設定 > DNSレコード設定で以下のように設定しました。

ホスト名 TYPE TTL VALUE
photo-tea.com A 3600 104.198.14.52
www.photo-tea.com CNAME 3600 photo-tea.netlify.com

WWWドメイン無しにした

サイトのアドレスは短い方がいいと思ったので、サブドメインのwwwは付けないhttps://photo-tea.comを使おうと思いました。

こういったケースでは、上記のDNS設定に加えて、Netlifyのカスタムドメインをwww.photo-tea.netlify.comではなく、photo-tea.netlify.comと予め設定しておくのがポイントになります。これでwwwサブドメインにアクセスしても、www無しアドレスにリダイレクトされます。

また、Netlifyの設定でLet’s EncryptによるHTTPS化とForce TLS connectionsを有効にしておきます。

Amazonアソシエイトに新しいサイトURL追加の旨を連絡

Amazonアソシエイト・プログラムのお問い合わせフォームで、新しいドメインを追加して貰うように依頼しました。申請後、1時間後にはAmazonから返信が届き、追加が完了しました。

Google Adsenseに新しいサイトURLを追加

アドセンスで新しいドメインを追加して貰います。Google Adsenesのトップ画面から設定 > 自分のサイト > サイトの管理で新しいドメインを追加します。この手続きで、すぐにAdsenseの広告が新しいドメインでも有効になります。

旧サイトで新しいサイトへリダイレクト・URL正規化する

古いサイトのHTMLにリダイレクトのコードを貼ります。サイトの移転で特に気になったのはページランクの低下でした。そこで参考にしたのが以下の記事です。

海外SEO情報ブログ
301リダイレクトで何%のPageRankが失われるのか?
もっと知りたいリンゴあれこれ
サイト(ブログ)のお引っ越し(移転)は301リダイレクトを。出来ない場合は、メタリフレッシュ(meta refresh)とrel=”canonical”を!
モバイル通信とIT技術をコツコツ勉強する
「ドメイン変更」やURL移転後の「リダイレクト・転送」は,PageRankとSEOに影響する。Google検索順位に若干マイナスなので,Webサイト移転時に要注意

リダイレクトは、.htaccessなどを使って301リダイレクトを行うのが最善の方法であり、Googleでもそのような方法が推奨されています。しかしGitHub Pagesでは.htaccessが使えません。

そこで、旧サイトに<meta http-equiv="refresh" content="秒数;URL=URL">というタグを<head>〜</head>内に記述してリダイレクトする事にしました。

また、新しいサイトと旧サイトでコンテンツの重複が起きてしまうので、URLの正規化も行います。旧サイトの<head>〜</head>内で<link rel="canonical" href="新しいサイトURL">を記述しておきます。

sample.html
1
2
3
4
5
6
<head>
...
<meta http-equiv="refresh" content="秒数;URL=URL">
<link rel="canonical" href="新しいサイトURL">
...
</head>

上記の手順が完了したら、旧サイトをデプロイします。これで古いURLにアクセスされた場合でも新しいURLへリダイレクトされるようになります。

この方法でURLを移転してみて、アクセスを調べてみましたが、2週間ほどで新しいURLへアクセスが切り替わるようになりました。旧サイトのリダイレクトにより、ページビューは以下のように推移しました。

移行後のページビューの変動。赤い箇所はリダイレクトを開始した時期
移行後のページビューの変動。赤い箇所はリダイレクトを開始した時期 ©

リダイレクトを行った直後はPV(ページビュー数)が倍になり、徐々に新しいURLへインデックスが進んで行ったようです。一時的にページビューが落ち込みますが、1ヶ月ほどで従来に近いレベルまで戻りました。

Google AnalyticsでURL変更手続き

続いて、Googleアナリティクスでアクセス解析するURLを、新しいURLに変更します。変更手続きは、アナリティクス設定 > プロパティ > プロパティ設定アナリティクス設定 > ビュー > ビュー設定で行います。トラッキングコードの変更は不要です。

Search Consoleでアドレス変更とURLの正規化

Search Consoleの手続きを行います。まずはアドレス変更を行います。

Search Console
アドレス変更ツールの使用

しかし、301リダイレクトができないGitHub Pagesでは上記の手続きができません。今回は見送りました。続いてURLの正規化を行います。

Pascal コンテンツ・SEOツール
wwwありなしをGoogleサーチコンソールで統一する方法

URLの正規化は上記の記事が参考になります。

トレンドマイクロにWebサイトの安全性を評価してもらう

こちらは不要かもしれませんが、セキュリティソフトのウイルスバスターをインストールしていると、検索結果にサイトの安全性がアイコン表示されます。新しいURLが評価されるには遅延が掛かるので、以下のフォームから評価を依頼しておきました。

ウイルスバスター ヘルプとサポート
Trend Micro Site Safety Center について

ソーシャルボタンの各種URL変更手続き

最後にシェアボタンで幾つかのURL変更手続きを行います。

Twitter Card ValidatorにURLを入力

ツイッターで記事がシェアされた時に表示されるカード表示を有効にしてもらいます。

Twitter Developers
Card Validator

URLを入力すると、シェアされた時のカード表示がプレビューされます。またログ表示でINFO: Card loaded successfullyと表示されればOGPの記述も問題無いことが確認されます。この手順で、入力したURLにおけるカード表示が有効になります。

TwitterのOGPの記述方法は下記が参考になります。

Twitter Developers
Card Types

facebookのApp IDの取得

facebookで記事がシェアされる際には、facebook App IDが必要になります。以下から新しいサイトのURLを登録し、IDを取得しておきましょう。

Facebook for Developers
facebook for developers - Login

HTTP/2サーバプッシュの設定(_headers)

最後に、NetlifyでサポートされているHTTP/2サーバプッシュの設定をしておきます。サーバープッシュを使うと、CSSファイルやJSファイルを従来よりも高速で配信できるようになります。

サーバプッシュについては、以下の記事が分かりやすかったです。一言で言うと、配信する事が予め分かっているファイルは、サーバプッシュしておくとサイトデータの転送時間(RTT=ラウンドトリップタイム)や表示時間が短縮できるようです。

GREE Engineers’ Blog
初めてのHTTP/2サーバプッシュ
Developers Summit 2016 - Publickey
リクエストを待たずに送信を開始する「サーバプッシュ」~奥一穂氏による「HTTPとサーバ技術の最新動向」(中編)。Developers Summit 2016

Netlifyでサーバプッシュする方法は、ドキュメントをご覧ください。

Netlify
Headers & Basic Authentication | Netlify

サーバプッシュする方法を詳しく見ていくと、Netlifyでは、デプロイするディレクトリの直下に、_headersというファイルを作成し、下記のように記述します。

_headers
1
2
3
/*
Link: </css/style.css>; rel=preload; as=stylesheet
Link: </js/script.js>; rel=preload; as=script

上記の記述方法は一例になりますが、/*で示すように、デプロイするサイトのルートディレクトリ以下、全てのパスで、style.cssscript.jsをサーバプッシュする設定です。

また、別のケースを考えてみましょう。デプロイするサイトのパスによって、プッシュしたいファイルを使い分けたい場合は以下のように記述します。

_headers
1
2
3
4
5
6
/categories/*
Link: </css/style-categories.css>; rel=preload; as=stylesheet
Link: </js/script-categories.js>; rel=preload; as=script
/tags/*
Link: </css/style-tags.css>; rel=preload; as=stylesheet
Link: </js/script-tags.js>; rel=preload; as=script

Hexoで_(アンダースコア)から始まるファイルをデプロイ

静的ジェネレータのHexoでは通常、_で始まるファイルをデプロイできません。そこで、以下のようなプラグインを定義しておきます。

themes/your-theme/script.js
1
2
3
4
5
6
7
8
9
10
// netlifyに必要なファイル_headersをpublicで生成する (通常は_で始まるファイルは無視されるが、下記コードでpublicに生成できるようになる)
hexo.extend.generator.register('netlify-headers', function(locals){
var fs = require('hexo-fs');
var pathFn = require('path');
var data = fs.readFileSync( pathFn.join( process.env.PWD || process.cwd() , '_headers'));
return {
path: "_headers",
data: data
};
});

リダイレクトの設定(404)

Netlifyで404リダイレクトやその他のリダイレクトを行いたい時は_redirectsというファイルをルートディレクトリに配置します。

Netlify
Redirect & Rewrite rules | Netlify

例えばルートのパス以下の全てのURLで、ページが見つからない場合に/404/というURLのページを開くには上記のように_redirectsを記述します。

_redirects
1
2
# 404 Redirects
/* /404/ 404

404リダイレクトの他にも、HTTPステータスコードの301・302・200リダイレクトなどを定義する事ができます。

_redirects
1
2
3
4
5
6
7
8
9
10
11
12
13
# 404 Redirects
/* /404/ 404

# その他 HTTPステータスコードの301・302・200リダイレクトなども定義できる

Redirect with a 301
/home / 301

Redirect with a 302
/my-redirect / 302

Rewrite a path
/pass-through /index.html 200

あとは、前述の_headersと同じようにプラグインを新たに定義しておきます。

themes/your-theme/script.js
1
2
3
4
5
6
7
8
9
10
// netlifyに必要なファイル_redirectsをpublicで生成する (通常は_で始まるファイルは無視されるが、下記コードでpublicに生成できるようになる)
hexo.extend.generator.register('netlify-redirects', function(locals){
var fs = require('hexo-fs');
var pathFn = require('path');
var data = fs.readFileSync( pathFn.join( process.env.PWD || process.cwd() , '_redirects'));
return {
path: "_redirects",
data: data
};
});

HTTP/2におけるサイトパフォーマンス向上

また、HTTP/2における配信方法により、HTTP/1.1で行ってきたサイトパフォーマンス向上テクニックが反ってボトルネックになってしまうようです。CSSやJSファイルの結合、画像アセットをスプライト化していた時代は、もはや都市伝説のようです…(汗)

blog.jxck.io
HTTP2 を前提とした HTML+CSS コンポーネントのレンダリングパス最適化について

上記を読みながら、少しづつ改良してみたいと思います。