ローカル起動

Hugo ローカルサーバの起動は非常に簡単で、以下のコマンドを実行するだけです。規定のポートは1313であるため http://localhost:1313にアクセスすれば編集中のサイトをリアルタイムに閲覧することができます。エディタで編集中の文書を保存すれば閲覧中のページがリロードなしで更新されます (データバインディング)。

$ hugo serve -D

静的コンテンツ生成

生成

また、サーバー機能は不要なので生成されたWebコンテンツだけが欲しいという場合もあると思います。その場合は以下のコマンドを入力することで、直下の publicディレクトリ配下にHTML等のWebコンテンツが出力されます。

$ hugo

提供

例えば、この状態でpublicディレクトリをマウントさせた Nginxを起動させれば http://localhost:80 でコンテンツを提供することができます。

$ docker run -p 80:80 -v $(pwd)/public:/usr/share/nginx/html nginx

これを利用して、以下の様な Dockerfileを用意し DockerImage内にコンテンツを固めたものをDockerベースで配信というのも一つの考えです。


FROM nginx:1.19-alpine

COPY ./public /usr/share/nginx/html

EXPOSE 80

CMD ["nginx", "-g", "daemon off;"]

$ docker build -t nginx-hugo .

$ docker container run --rm --name nginx-hugo -p 80:80 nginx-hugo

ただ今回は、配信の度に以下の作業を行うのが少々面倒かも知れないと考え、Dockerベースの配信(当初CloudRunを想定)を止めました。とはいえ構成はシンプルなのでアイデアとしては悪くないと思います。

  1. コンテンツの生成
  2. イメージのビルド
  3. イメージのレジストリ登録
  4. サービスの参照先イメージの変更

実は、Hugoのデプロイ先は、GitHubPagesが有名なのですが、今回試したら生成されたリンクのURLに問題があり(一部URL要素が重複生成された)上手くページ遷移できないという問題があったため、その他の手段を探したという経緯があります。


GCS

今回着目したのは GCS (GoogleCloudStorage) による提供です。GCSは Amazon S3の様なオブジェクトストレージで、S3同様に静的コンテンツをインターネット公開する機能も備わっています。またS3同様にランニングコストが非常に低価格です。長期的な視野で考えるとこの点は魅力です。

プロジェクト作成

GCSでのサイト管理をすると決めたら、GCPプロジェクトを作成します。GCSの世界ではプロダクト毎にプロジェクトを作成するというのがベストプラクティスになっているため、静的サイトの構築程度でも1プロジェクトを用意します。一度GCPを使った事があるのであれば決済手段の登録等が不要ですので簡易的な手続きのみで完了します。

ドメイン取得

プロジェクトが登録できたら、ドメインを取得します。元々はGCSが提供してくれるアドレスのみで静的サイトを配信できると思っていたのですが (事実ある程度は出来るのですが)、実際に作成してみると一部のURLが解釈できないという問題がありました。具体的には https://(Bucket名)/my-site/dir/といったURLにアクセスすると内部に存在する index.htmlを参照してくれず、404コードと共に謎のXMLを返すのです。

後で分かったことですが、コレには以下の手続きが必要でした。

  • index.html, 404.html を暗黙的に呼び出す為には GCSバケット上でウェブサイトの構成を編集を行う必要がある
  • ウェブサイトの構成を編集を バケット操作メニュー上に表示させるには バケット名にドメインを含めないといけない (*1)
  • ドメインを含めたGCSバケットの作成には、ドメインの所有権をGoogleに確認させる 必要がある

*1) gcloudコマンドでも同等の操作を実施できてしまうがドメイン名が含まれていない限り無効 (成功ステータスが返るが index.html等は呼ばれない)

正直こんな複雑なの誰が分かるかよ…という思いで一杯なのでブログに書いています。

さて、肝心のドメインは Google Domainで取得しても良かったのですが、何故か高価だったので今回はお名前.comで取得しました。

Cloud DNS

ドメインの取得が完了したら、そのドメインを管理するネームサーバを用意する必要があります。ネームサーバの機能はお名前.com上でも提供していますが、今回はGCP上のCloudDNSを利用します。GCPの管理コンソール上から取得したドメインを登録し、NSレコードに表示されているデータをメモします。

  • ns-cloud-a1.googledomains.com.
  • ns-cloud-a2.googledomains.com.
  • ns-cloud-a3.googledomains.com.
  • ns-cloud-a4.googledomains.com.

次に、お名前.com上の「ドメイン」メニューから「ネームサーバの選択」で「お名前.com」ではなく「その他」を選択し、上記ネームサーバを登録してください。これにより CloudDNS側にネームサーバ機能が移管されます。

ドメイン検証 (TXTレコードの修正)

ドメイン取得と DNSサーバの登録が終わったら、ドメインの検証を行う必要があります。これは該当のドメインが自身のものだと証明するプロセスで、該当ドメインのTXTレコードを操作することで編集権限のある所有者であることを証明します。

  1. まず最初に Google Search Console にいきます。次にプロパティタイプとして「ドメイン」と「URLプレフィックス」が提示されますので「ドメイン」側に取得したドメインを入力して「続行」を押してください。すると googleサイトが認証用のトークンを発行します。コレをコピーしてください。

  2. 続けて、Cloud DNS上でレコードセットを追加し ルートのドメイン名に対し TXTレコードを追加し、指定された値を入力してください。

    DNS名 種類
    example.com. TXT “google-site…….”
  3. 再び Google Search Console に戻って検証を完了します。この検証プロセスの結果は裏でGCS側にも連携されています。

ストレージ作成 (w/ドメイン名)

以上のプロセスを経た後に、ドメインを含めたバケット名を作成します。例えば example.com ドメインを取得し、サイトを www.example.comで提供する予定であれば、作成するバケット名は www.example.comとします。これは前述のドメイン検証を終わらせておく必要があり、そうでないと作成時にエラーとなります。

以降、example.com を取得したドメインの例として提示してゆきますが、ご自身のドメインに読み替えてください。

権限付与 (allUsers)

バケットの作成が完了したら全てのインターネットユーザが閲覧できるように権限を付与します。対象のバケットを選択して「権限」タブより権限を追加してください。新しいメンバーとしてallUsersを入力しロールにはCloud Storageから Storageオブジェクト閲覧者を選択してください。これで全てのユーザが Cloud Storageのコンテンツを閲覧出来るようになります。

IAMサービスアカウント作成

必要に応じて、コンテンツをアップロードする側のPC/サーバに IAMのサービスアカウントを発行しておきます。ロールにはCloud Storageから Storageオブジェクト管理者を選択します。これで hugoコマンドから public ディレクトリ内のコンテンツを Cloud Storageにアップロード出来るようになります。

config.yaml (toml)

deployment:
  targets:
    name: "gcs-deployment"
    URL: "gs://www.example.com
$ hugo deploy --force

index.html, 404.html

GCSバケット名にドメインが含まれている場合、対象バケットの右横の「…(縦)」からウェブサイトの構成を編集を選択出来るようになります。(バケット名にドメインが含まれない場合はメニューに表示されません) ここでは以下の指定をします。

  • インデックス (メイン) ページサフィックス
    • index.html
  • エラー (404見つかりません) ページ
    • 404.html

この設定により URLにディレクトリが指定された場合はその直下の index.htmlを、コンテンツが見つからない場合は 404.htmlを返すようになります。このhtmlファイル名は hugoが固定で出力するものなので、上の例の様に合わせる必要があります。

この設定をしても、設定が有効になるのは CNAME経由でコールされる場合と CloudLoadBalancing経由でコールされる場合に限定されます。つまりGCS側で提供しているURLに直接アクセスした場合、ディレクトリのパスを呼び出しても index.htmlはコールされません。

DNSにCNAME登録

以上の設定が済んでいれば、Cloud DNSの向き先に GCSを設定するだけです。例えば以下の設定を追加します。(www.example.com 部分は自身のサーバー名.ドメイン名に置き換えてください)

DNS名 種類
www.example.com CNAME c.storage.googleapis.com.

以上で、http://www.example.com(例)でサイトを閲覧出来るようになります。


GCS + Cloud Load Balancing

上記の手続きでWeb公開は出来ますが、http限定での公開となります。昨今はhttpsベースのサイト提供が標準となっていますが、その実現には証明書を用意しなければなりません。お名前.comでの証明書提供は年額2万円以上掛かりますし、Let’s Encrypt での無償発行を活用すると証明書の更新の仕組みを用意しなければなりません。

Cloud Load Balancing

そこで GCSのフロントに Cloud Load Balancingを配置し、そこにGoogle自動管理の証明書を貼り付け、バックエンドとしてGCSを参照させるという構成に変更します。

Backend

LBの BackendにはGCSバケットが選択可能です。ここで先のドメイン名を含めたGCSを指定します。

Frontend

LBの Frontendには以下の設定を行います。

項目名 設定値
名前 任意
プロトコル HTTPS (HTTP/2を含む)
ネットワークサービス階層 プレミアム
IPバージョン IPv4
IPアドレス IPアドレスを作成
ポート 443
証明書 新しい証明書の作成

IPアドレスと証明書が生成されますので、IPアドレスをメモしておきます。

DNSを更新 CNAME -> Aレコードの静的IPへ

最後に、先に登録したDNSのCNAMEを破棄し、新たな内容で上書きします。

(↓破棄内容)

DNS名 種類
www.example.com CNAME c.storage.googleapis.com.

(↓上書き内容)

DNS名 種類
www.example.com A (Cloud Load Balancingの Frontendで自動生成された IPの値)

1時間前後放置し、DNSサーバの情報が伝播し終えると、以下のURLでサイトにアクセス可能となる筈です。

https://www.example.com