tl;dr
方法として2つあるが、設定がシンプルであることと、エッジ-オリジン間もHTTPS化できるため後者がオススメ。
- CNAME を有効のままで、CloudFrontで
Host
ヘッダを転送する設定とする - CNAME を無効にして、
https://example.github.io/reponame/
でアクセスするようにし、/reponame/
をOriginのパスとして利用する
Zone Apex (サブドメイン無し) の場合でも、どちらでも可能。
共通
以下の例で進めていきます。
-
Default Page Domain:
username.github.io
-
Repository Name:
reponame
-
CNAME:
reponame.example.jp
-
SSL証明書は、事前にACMで用意しておいてください。
- ACMで証明書を作成する際は
us-east-1
(N.Virginia) リージョンで作る必要があるのでお忘れなく。
- ACMで証明書を作成する際は
-
また、Route53でDNSを管理していることを前提として説明しますが、別のDNSサービスでも手順は変わるものの実現可能です。
-
切り替えるレコードのTTLは切り替えがなる早で反映されるように一時的に短くしておいてください
CNAMEを有効のまま設定する
GitHub Pages 側をCNAMEを有効にしたままでCloudFrontを設定し切り変えます。
http://reponame.example.jp
で GitHub Pages が開ける状態となっている前提で進めていきます。
- CloudFrontディストリビューションを
Host
ヘッダを転送する設定で作成する - Route53のレコードをCloudFrontに向ける
CloudFrontディストリビューションの作成
Origin Domain Name を username.github.io
に
Behavior Settingsでは、
-
Redirect HTTP to HTTPS
で HTTP でアクセスしたときに HTTPS にリダイレクトするようにする -
Forward Headers
でWhitelist
を設定し、Host
を追加する - Compress Object Automatically はお好みで。静的テキストコンテンツが多くなる傾向があると思うので有用だと思います
そして、Distribution Setting では、予めACMに作成しておいたCNAMEにマッチする証明書を設定します。
これでディストリビューションを作成し、利用可能になるまでしばし待ちます。
作成したDistributionのドメイン名で、 https://dxxxxxxxxxxxxx.cloudfront.net
という形でアクセスできるようになります。
動作確認
ドメインの名前解決先を切り替えてしまうと、問題があった場合に困ったことになるので動作確認します。
Hostsで確認
先程作成したDistributionのドメイン名 (dxxxxxxxxxxxxx.cloudfront.net
の形式) をnslookupします。
nslookup dxxxxxxxxxxxxx.cloudfront.net
Server: 192.168.179.1
Address: 192.168.179.1#53
Non-authoritative answer:
Name: dxxxxxxxxxxxxx.cloudfront.net
Address: 13.32.230.52
Name: dxxxxxxxxxxxxx.cloudfront.net
Address: 13.32.230.163
Name: dxxxxxxxxxxxxx.cloudfront.net
Address: 13.32.230.25
Name: dxxxxxxxxxxxxx.cloudfront.net
Address: 13.32.230.78
Name: dxxxxxxxxxxxxx.cloudfront.net
Address: 13.32.230.12
Name: dxxxxxxxxxxxxx.cloudfront.net
Address: 13.32.230.186
Name: dxxxxxxxxxxxxx.cloudfront.net
Address: 13.32.230.102
Name: dxxxxxxxxxxxxx.cloudfront.net
Address: 13.32.230.208
1つ適当に選んで、Hostsに書きます。
reponame.example.jp 13.32.230.52
ブラウザを開いて http://reponame.example.jp
にアクセスし、HTTPSにリダイレクトされること、HTTPSで正常にアクセスできることを確認します。
CloudFrontのIPは逐次変わるため、永続的にこのIPで動作確認できるわけではないことにご注意ください。
動作確認が終わったら確実にHostsエントリを削除しましょう。
curlで確認
--connect-to
が便利です!
-
-v
: デバッグ表示 -
--silent
: プログレスバーを表示しない -
--location
: リダイレクトに従う -
--connect-to:HOST1:PORT1:HOST2:PORT2
:HOST1:PORT1
へのリクエストをHOST2:PORT2
に送る。この例では、reponame.example.jp
へのリクエストをdxxxxxxxxxxxxx.cloudfront.net
に送る。
リダイレクトして、HTTPSでレスポンスがCloudFrontから返却されていることを確認する。
curl -v --silent --location --connect-to "reponame.example.jp::dxxxxxxxxxxxxx.cloudfront.net:" http://reponame.example.jp/ > /dev/null
* Connecting to hostname: dxxxxxxxxxxxxx.cloudfront.net
* Trying 13.32.230.25...
* TCP_NODELAY set
* Connected to dxxxxxxxxxxxxx.cloudfront.net (13.32.230.25) port 80 (#0)
> GET / HTTP/1.1
> Host: reponame.example.jp
> User-Agent: curl/7.54.0
> Accept: */*
>
< HTTP/1.1 301 Moved Permanently
< Server: CloudFront
< Date: Sun, 10 Sep 2017 10:06:49 GMT
< Content-Type: text/html
< Content-Length: 183
< Connection: keep-alive
< Location: https://reponame.example.jp/
< X-Cache: Redirect from cloudfront
< Via: 1.1 78dc5acc7fb7b026e9215d8188becd98.cloudfront.net (CloudFront)
< X-Amz-Cf-Id: ymg3bDg7MThc2VVOuIpOC3r42GyuRDXJUS0HnB9cKnWWTnRjWD-e_g==
<
* Ignoring the response-body
{ [183 bytes data]
* Connection #0 to host dxxxxxxxxxxxxx.cloudfront.net left intact
* Issue another request to this URL: 'https://reponame.example.jp/'
* Connecting to hostname: dxxxxxxxxxxxxx.cloudfront.net
* Trying 13.32.230.25...
* TCP_NODELAY set
* Connected to dxxxxxxxxxxxxx.cloudfront.net (13.32.230.25) port 443 (#1)
* TLS 1.2 connection using TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
* Server certificate: reponame.exmple.jp
* Server certificate: Amazon
* Server certificate: Amazon Root CA 1
* Server certificate: Starfield Services Root Certificate Authority - G2
> GET / HTTP/1.1
> Host: reponame.example.jp
> User-Agent: curl/7.54.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Content-Type: text/html; charset=utf-8
< Content-Length: 18280
< Connection: keep-alive
< Server: GitHub.com
< Last-Modified: Sat, 09 Sep 2017 13:30:08 GMT
< Access-Control-Allow-Origin: *
< Expires: Sun, 10 Sep 2017 10:04:44 GMT
< Cache-Control: max-age=600
< X-GitHub-Request-Id: F24E:8856:173BB3:19374E:59B50BE4
< Accept-Ranges: bytes
< Date: Sun, 10 Sep 2017 09:54:44 GMT
< Via: 1.1 varnish, 1.1 45b893b1fe0ecafde6bfa63bc4abc859.cloudfront.net (CloudFront)
< X-Served-By: cache-nrt6125-NRT
< X-Cache-Hits: 0
< X-Timer: S1505037284.497836,VS0,VE232
< X-Fastly-Request-ID: 27614a7c60d3bb6edab88b25f86c9a21cc4b3899
< Vary: Accept-Encoding
< Age: 92
< X-Cache: Hit from cloudfront
< X-Amz-Cf-Id: My_BZNmrPJFeHIZsTST_5gc5A5jvk7XXVSdErVcAxhvxtfUAVud4PQ==
<
{ [15630 bytes data]
* Connection #1 to host dxxxxxxxxxxxxx.cloudfront.net left intact
Route53の変更
example.jp
のHosted Zoneを開いて、reponame.example.jp
のエントリを更新します。
また、AAAAレコードも同様に設定することで、IPv6対応になります。
CNAMEを無効にするパターン
こちらはGitHub PagesでCNAMEが有効になっているのを無効にする方法です。
停止期間が無いように、一時的にリポジトリをコピーし、また、別ドメインでテストをできるようにします。
- GitHubのリポジトリを一時的に作成した別のリポジトリにコピーし、GitHub Pagesを表示できるようにする
- CloudFrontディストリビューションを作成
- Route53でテストドメインの設定
- テストドメインで動作確認
- Route53で本番の切り替え
リポジトリのコピー
やり方はいろいろありますが、一例。
- 対象のリポジトリ (
reponame
) をローカルにcloneする - GitHubで新しいリポジトリを作る (
reponame-https-tmp
) - リモートを追加する
git add remote https git@github.com:username/reponame-https-tmp.git
- 適宜ブランチを変更する (
gh-pages
を表示する設定であれば、gh-pages
に変更) - 新しいリポジトリにpushする
-
git push --set-upstream https gh-pages
(gh-pages
の場合)
-
-
CNAME
ファイルが存在する場合は、新しいリポジトリ側で削除する
Settings で GitHub Pages が表示されるよう設定し、https://username.github.io/reponame-https-tmp/
で表示できることを確認する。
(リンクや埋め込んだ画像等が /hoge
とか絶対パスになって、うまく表示できないかもしれないですが、それらは一旦スルー)
CloudFrontディストリビューションの作成
まず、新しく作成したリポジトリに向けたディストリビューションを作成します。
Origin Settings では
- Origin Domain Name を
username.github.io
に - Origin Path を 、
/reponame-https-tmp/
に - Origin Protocol Policy は HTTPS Only にします
Behavior Settingsでは、
-
Redirect HTTP to HTTPS
で HTTP でアクセスしたときに HTTPS にリダイレクトするようにする - Compress Object Automatically はお好みで。静的テキストコンテンツが多くなる傾向があると思うので有用だと思います
そして、Distribution Setting では、CNAMEs に切り替え予定の reponame.example.jp
とは別に動作確認用の reponame-test.example.jp
といったCNAMEも付与します。
そして、ACMに作成しておいたCNAMEにマッチする証明書を設定しますが、この証明書は *.example.jp
のワイルドカードかAdditonal Namesを使って両方をカバーしたものを用意、適用します。
これでディストリビューションを作成し、利用可能になるまでしばし待ちます。
Route53でテストドメインの設定
- Route53で先ほど作成した動作確認用のアドレス (
reponame-test.example.jp
) からCloudFrontディストリビューションへのエイリアスを作成します。
動作確認
http://reponame-test.example.jp/
がHTTPSにリダイレクトされること、https://reponame-test.example.jp/
が表示されることを確認する。
wgetでクロールさせて、デッドリンクや、github.io
側に移動してしまったりが無いかを確認するのもよいです。
wget --spider --recursive --no-directories --no-verbose https://reponame-test.example.jp/
Route53で本番の切り替え
続いて、一時的に https://reponame.example.jp
を、 reponame-https-tmp
側を表示するよう切り替えます。
- Route53で本番のドメイン (
reponame.example.jp
) から作成したCloudFrontディストリビューションへのエイリアスを作成します。
元リポジトリの設定変更
reponame.example.jp
がCloudFrontに向くようになって、切り替える前のレコードのTTLが十分経過してから、元リポジトリの設定を変更し、https://username.github.io/reponame/
でアクセスできるようにします。
- CNAME ファイルがあれば削除する
- Settings で独自ドメインの設定を無効にする
CloudFrontのオリジンの追加、設定変更
- OriginsタブのCreate Originから
https://username.github.io/reponame/
を指すオリジンを新しく作成する。 - Behaviorsタブで、デフォルトのBehaviorにチェックを入れて、Editをクリックし、Origin を新しく作った本番 (
reponame
) に向いたものに変更し、"Yes, Edit" で反映する - 設定が反映されるのを待ち、その後、変わらずにページが表示できることを確認する
- 最初に作ったオリジンを削除する
後片付け
- Route53のテストドメインを削除する
- 一時的に作ったリポジトリを削除する
備考
GitHub Pages 以外のサイトにも応用可能ですが、CNAMEが正しく設定しているか定期的に確認し、設定されていないと独自ドメイン設定を解除するサービスでは、CNAME設定のまま切り替えをするパターンだと後々表示されなくなるので注意です。
設定画面でCNAMEが正しく設定されているか確認してくれるサイトは、この可能性が高いです。
また、独自ドメインでない場合にページ内のリンクのURLが変わってしまうようなサービスでは、上記「CNAMEを無効にして切り替える」は難しい認識です。