今年もあと僅か。
来年こそは記録をつける癖が付きますように。という願いを込めてブログを構築。
要件
- 静的サイト
- 記事はmarkdown形式
- gitで管理
- masterにpushしたら静的サイトを自動でリリース
- サーバを持たない
- 独自ドメイン
- HTTPS
- お財布に優しい
方式
- Hugoで静的サイトを作成
- GitHub上のリポジトリでソースを管理
- CircleCIで自動ビルド
- AWS S3へ静的サイトを配置
- AWS Route53でドメイン管理
- AWS CloudFrontで独自ドメインかつHTTPSで静的サイトを配信
静的サイトでカスタムドメイン&HTTPS化を実現する場合、GitHub PagesとCDNの組み合わせという方式もあるが今回はなるべくAWSを活用したかった為この構成とした。
構築の流れ
構築は以下の流れで実施。
Hugoで静的サイトを作成
まずはローカル環境にHugoを入れて静的サイトのテンプレート、スタイル作成やル記事の読み書きができるようにする。
インストール
Homebrewでインストール。
$ brew update && brew install hugo
Gitリポジトリの作成
今回はGitHub上にプライベートリポジトリを用意。以降作成する静的サイトはこのリポジトリで管理する。
静的サイトの作成
https://gohugo.io/overview/quickstart/ を見ながら静的サイトのひな形を作成。
$ cd ~/Workspaces/nijohando
$ hugo new site blog
config.toml を修正。
baseurl = "https://blog.nijohando.jp/"
title = "二畳半堂"
languageCode = "ja-jp"
hasCJKLanguage = true
Themeの適用
を参考にはThemeをインストール、有効にする。
今回は自作テーマ 『六角』を適用する。
記事の作成とプレビュー
動作確認用の記事を作成。
$ hugo new post/sample.md
content/post/sample.md
ファイルが作成されるので記事を編集。
あとはHugoサーバを起動する事で編集中の記事をブラウザからリアルタイムにプレビューする事ができる。
-D
をつけることでドラフト版の記事もプレビュー対象としている。
$ hugo server -D
ブラウザから http://localhost:1313/ へアクセス。
静的サイトのスタイル、テンプレートを調整する。
S3の準備
静的サイト用バケットの作成
Hugoで生成した静的サイトの格納先となるバケットを作成する。 AWS マネージメントコンソールから S3 を開き バケット作成 を実施。
- バケット名
blog.nijohando.jp
バケット名はblogサイトの独自ドメイン名と同じにする。- リージョン
Tokyo
静的ウェブサイトホスティングを有効にする
作成したバケットの プロパティ から 静的ウェブサイトホスティング を選択し静的ウェブサイトホスティングを有効にする。
インデックスドキュメントに index.html
を指定。
CloudFrontとS3の連携自体は静的ウェブサイトホスティングが無効でも可能だが、ルート以外のディレクトリにアクセスした際に当該ディレクトリのindex.htmlへの読み替えは行われない。 このため静的ウェブサイトホスティングを有効にしておき、ClouldFrontからはS3バケットとしてではなく、静的ウェブサイトホスティングのエンドポイントとしてアクセスする。
バケットポリシーの編集
同じく プロパティ から アクセス許可 、バケットポリシーの編集 からバケットポリシーを編集する。バケット内の全リソースを表示できるアクセス許可を全ての閲覧者へ付与する。
{
"Version": "2008-10-17",
"Id": "Allow Public Access to All Objects",
"Statement": [
{
"Sid": "1",
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::blog.nijohando.jp/*"
}
]
}
IAMグループの作成
静的サイト用バケットへ読み書きできる権限を持つIAMグループを作成する。
このグループはCircleCIで自動リリースする際に利用する。
AWS マネージメントコンソールから IAM を開き グループ から 新しいグループの作成 を実施。
- グループ名
BlogManager
ポリシーのアタッチは何も選択せずに 次のステップ 、グループの作成
作成したグループを選択し、アクセス許可 タブから インラインポリシー -> カスタムポリシー を選択。
- ポリシー名
BlogManagement
ポリシードキュメントには以下を設定する。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "1",
"Effect": "Allow",
"Action": [
"s3:GetBucketLocation",
"s3:GetObject",
"s3:GetObjectVersion",
"s3:ListBucket",
"s3:ListObjects",
"s3:PutObject",
"s3:DeleteObject"
],
"Resource": [
"arn:aws:s3:::blog.nijohando.jp",
"arn:aws:s3:::blog.nijohando.jp/*"
]
}
]
}
ポリシーの検証 、ポリシーの適用 を押下して完了。
※ 2017/01/08 s3:DeleteObject
が不足していたので追加。
IAMユーザの作成
静的サイト用バケットへ読み書きできる権限を持つIAMユーザを作成する。
このユーザはCircleCIから自動リリースする際に利用する。
AWS マネージメントコンソールから IAM を開き ユーザ から 新しいグループの作成 を押下する。
- ユーザ名
circleci
- アクセスの種類
プログラムによるアクセス
次のステップ:アクセス権限 へ。
ユーザをグループに追加 で先ほど作成した BlogManager を選択。次のステップ:確認 -> ユーザの作成
アクセスキーIDとシークレットアクセスキーが表示される。
これらはCircleCI側の設定に必要となるのでメモしておく。
自動リリースジョブ作成
Gitリポジトリのmasterへのプッシュに反応して静的サイトを生成し、S3へ配置するCircleCIジョブを作成する。
プロジェクト追加
CircleCIにログインし ADD PROJECTS から対象のgitリポジトリを追加。
AWSアクセスキーの指定
BUILDS タブからプロジェクト設定を選択し、PERMISSIONS から AWS Permissions 画面でS3バケットを読み書きするためのIAMユーザのアクセスキーIDとシークレットアクセスキーを設定する。
ビルド定義の作成
ビルド定義をcircle.ymlにまとめてgitリポジトリの直下へ置く。 最初の試行錯の誤段階で都度このファイルを編集、pushするのは効率が悪いためCircleCIの管理画面からビルドコマンドを直接記述して正しく動くことを確認してからcircle.ymlを作成した方が良い。
BUILDS タブからプロジェクト設定を選択、TEST COMMANDS から Dependency commands または Test commands 画面でコマンドを試していく。その際はyaml形式をテキストを直接指定するのではなく各コマンドを列挙する。
コマンドの動作を確認しつつ最終的に組み上がった以下のcircle.ymlをgitリポジトリに直下に配置する。
dependencies:
override:
# Hugoのバイナリを取得
- wget https://github.com/spf13/hugo/releases/download/v0.21/hugo_0.21_Linux-64bit.deb
# Hugoをインストール
- sudo dpkg -i hugo_0.21_Linux-64bit.deb
# AWS コマンドラインインターフェイスのインストール
- pip install awscli
# AWS CLIでCloudfrontの扱いを有効に
- aws configure set preview.cloudfront true
test:
override:
# 静的サイトを生成。
- hugo
deployment:
production:
branch: master
commands:
# 生成した静的サイトをS3に同期
- aws s3 sync --exact-timestamps public/ s3://blog.nijohando.jp/ --delete
# CloudFrontのキャッシュをクリア
- aws cloudfront create-invalidation --distribution-id <ディストリビューションID> --paths '/*'
※ 2017/06/11 hugoのバージョンを0.21へアップ
SSL/TLS証明書の発行
後述のAWS CloudFrontでHTTPSを利用するために必要となるSSL/TLS証明書をCertificate Managerで発行しておく。
事前確認
Certification Managerで証明書のリクエストを行う際に所有確認のためAWSから以下のメールアドレスに一気にメールが送信される。
- WhoisのDomain registrant, Technical contact, Administrative contact
- administrator@your_domain
- hostmaster@your_domain
- postmaster@your_domain
- webmaster@your_domain
- admin@your_domain
独自ドメインのWhoisの登録情報が代行になっている場合は上記のいずれかのメールアドレスでメールを受信できるようにしておく必要がある。
証明書のリクエスト
AWSマネージメントコンソールから Certificate Manager を開く。
リージョンを バージニア北部 に切り替え、証明書のリクエスト を押下。
注意点としては東京リージョンではなく、バージニア北部リージョンで証明書を作成する必要がある。
これはCloudFrontにはリージョンの概念は無いが管理上バージニア北部リージョンに属するため東京リージョンで作成した証明書はCloudFront側から利用できない。
- ドメイン名
blog.nijohando.jp
確認とリクエストボタンを押下。
前述のメールアドレスに確認メールが来るのでメール文中のリンクを踏んで承認する。
AWSマネージメントコンソールに戻り続行ボタンを押して証明書の発行が完了。
CloudFrontでブログを配信
ディストリビューションの作成
AWS マネージメントコンソールから CloudFront を開き Create Distribution を押下。
Web の Get Started を押下。
- Original Domain Name
blog.nijohando.jp.s3-website-ap-northeast-1.amazonaws.com
静的ウェブサイトホスティングのエンドポイントを指定する- Viewer Protocol Policy
Redirect HTTP to HTTPS
- Object Caching
Customize
- Default TTL
31536000
CircleCIからS3にリリースする際に明示的にキャッシュをクリアするので実質TTLは不要に。1年にしておく。- Compress Objects Automatically
Yes
ダウンロード時間とデータ転送コスト削減のため。
参考:圧縮ファイルの供給- Price Class
Use All Edge Locations (Best Performance)
一旦これ。- Alternate Domain Names
blog.nijohando.jp
独自ドメイン。- SSL Certificate
Custom SSL Certificate
事前にCertificate Managerで作成したSSL/TLS証明書を選択- Default Root Object
index.html
Create Distribution でディストリビューションを作成。
statusがInProgressからDeployedになるまでしばらくかかる。
IAMグループにキャッシュ削除権限を追加
IAMグループ BlogManager
にCloudFrontのキャッシュ削除権限を付与する。AWSマネージメントコンソールから IAM を開き、グループ BlogManager を選択。 グループポリシーの作成 、 カスタムポリシー を選択し、以下のポリシーを追加。
- ポリシー名
BlogCacheManagement
ポリシードキュメントには以下を設定する。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "1",
"Effect": "Allow",
"Action": [
"cloudfront:CreateInvalidation"
],
"Resource": "*"
}
]
}
Route 53に独自ドメインを登録
Hosted zones から自ドメインを選択、Create Record Set でレコードを作成する。
- Name
blog
- Type
A IPv4 address
- Alias
Yes
- Alias target
- Cloudfrontで作成したディストリビューションのFQDN
Create でレコードを作成。
最後に
以上で構築作業は完了。
以降は記事を書いてmasterへpushすれば自動で配信されるようになる。