Hugoを導入してWebサイトをGitHub Pagesで公開してみた話

何番煎じか分かりませんが、**静的サイトジェネレーター**の**Hugo**を使ってWebサイトの構築を行ってみましたので、作業ログを残しておきます。

## 静的サイトジェネレーターとは

従来WordPressのようなCMSを使ってサーバーサイドで動的に生成していたブログやWikiのようなサイトを、HTML、CSS、JavaScriptなどの静的なファイルのみでの構築を自動化するツールです。

### 利点
- サーバーサイド処理を行わず、事前に生成された静的ファイルにのみアクセスするので高速
- CMSのような統一的なデザインのページを、Markdown記法などで最小限の作業量で作成・管理できる
- 静的ファイルホスティング機能のみあればよいので、運用コストが非常に低い (PHP、CGI、データベースなどは一切不要)
  - 特にGitHub Pagesが無料で使えるようになってから、爆発的に利用者が増えた模様

### 欠点
- ページ数が数十万以上などの相当規模になるとサイト再構築のコストが無視できなくなってくるかも  
  (ページ数が数千未満ならかなり短時間で再構築できる)
- 静的サイトジェネレーターのツールが多すぎて、どれを選ぶとよいか判断が難しいかも
- 各ツールで使い方や流儀は少しずつ違うので、多少の学習コストはかかる (が、他の手段での作業量に比べたら遥かに楽なはず)

### 参考

- https://www.staticgen.com/  
  - 主要な静的サイトジェネレーターの概要を分かりやすくまとめたサイト  
  - OSSとしての人気度や成熟度がパッと見でつかみやすい

## Hugoとは

静的サイトジェネレーターの代表格のひとつ。
[StaticGen](https://www.staticgen.com/)のサイトでの人気度は現在3位の模様。(2020年7月12日現在、1位はNext.js、2位はGatsby)

### 利点・特徴

- プログラムがGoで書かれており、**非常に高速** (他のツールはJavaScriptやRubyなどのスクリプト言語で作られている)
  - おそらく**最速クラス**で、数千ページの生成も数秒～数分程度で終わる模様
- ローカルサーバー機能も有しており、Go製なので立ち上がりも非常に高速
- Front Matterと呼ばれる属性情報をMarkdownの冒頭に書くスタイルとなっており、例えば下書き状態から公開状態への変更が一瞬で可能
- ショートコードという機能でMarkdownに独自タグを導入できて便利
- 別名(alias)機能でリダイレクトを容易に作れる
- テーマの作成やカスタマイズの方法が比較的分かりやすく簡単 (多分)

### 欠点

- 強いて言うなれば、エラーが起きた時の原因が分かりにくいかも

### なぜHugoを採用するか

- 元々クラウドサーバーとWordPressで簡単なレジュメなどのWebページを運用していたけど、GitHubの方が安定してそうだし、「勉強も兼ねて静的サイトジェネレーターに移行してみるかー」と思い決断
- 知名度も高く超高速らしいので、とりあえずHugoを使ってみたらいい感じだった

### 採用したテーマについて

- https://themes.gohugo.io/hugo-future-imperfect-slim/  
  既存テーマの、これ(**Hugo Future Imperfect Slim**)を導入してみることにしました
- https://themes.gohugo.io/  
  このサイト(**Hugo Themes**)から、Responsive Designに対応していてBlogとGoogle Analyticsに向いているテーマを絞り込んで、なんとなく見た目がよさそうだったので決めました
  - もちろん今後変更する可能性はあります

## 作業メモ

### 概要

- **GitHub Pages**を使って静的ウェブサイトの運用をしてみます
- GitHubでは2019年くらいから無料でもprivateリポジトリを無制限に作れるようになりましたが、どうやら現状無料アカウントのprivateリポジトリでWebホスティングには対応していない模様です
  - 無料privateリポジトリだと、"Upgrade or make this repository public to enable Pages"（リポジトリを公開するか、有料アカウントにアップグレードしてね）と表示される
  - \# <span style="color: gray;">有料アカウントでも月4ドルでいいので安いっちゃ安い<span>
  - 取り急ぎ、Webサイト運営上、見られたらまずい情報とかを置く予定は無いため、今回はpublicリポジトリでWebページも公開することに

### 作業環境

- 静的ファイルの生成などはローカルで行います。シェルが使えれば基本的になんでもよさそう
- OS: Windows 10 (Pro Edition, OSビルド: 19041.329)
  - Homeエディションでも全然問題無いはず。後述のWSLを使うならWindows 8.1以前は無理。LinuxやmacOSならもっと簡単なはず。
- シェル環境: WSL(Windows Subsystems for Linux)のUbuntu 20.04 LTS環境を利用
  - Ubuntuは単純に使い慣れているから採用した
  - WSL2ではなくWSL1を使ったけど、今回の用途ではどちらでも全然問題無いはず
  - WSLのインストール方法を説明すると長くなるので割愛します
    - インストールがまだの方は、 https://qiita.com/Aruneko/items/c79810b0b015bebf30bb あたりを参考にしてみてください

### 作業手順

#### Homebrewのインストール

- まず、Hugoをインストールしたいのですが、その前準備としてmacOSで定番のパッケージマネージャーHomebrewをインストールしておきます
  - なぜなら、最近のUbuntuなら `apt-get install hugo` で一発インストールできるものの、Ubuntu公式の安定版APTリポジトリだとHugoのバージョンが古く、新しいテーマが使えない場合があるようなので（使えませんでした）……

  ```bash
  $ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"
  ==> Select the Homebrew installation directory
  - Enter your password to install to /home/linuxbrew/.linuxbrew (recommended)
  - Press Control-D to install to /home/orenoaccount/.linuxbrew
  - Press Control-C to cancel installation
  [sudo] password for orenoaccount:  # ← Ctrl+Dを入力（今回は個人向けにインストール)
  ==> This script will install:
  /home/orenoaccount/.linuxbrew/bin/brew
  (中略)
  /home/orenoaccount/.linuxbrew/Homebrew
  ==> The following new directories will be created:
  /home/orenoaccount/.linuxbrew/bin
  (中略)
  /home/orenoaccount/.linuxbrew/Frameworks

  Press RETURN to continue or any other key to abort # ← ここでEnterキーを押下して続行
  ==> /bin/mkdir -p /home/orenoaccount/.linuxbrew
  (中略)
  ==> Homebrew is run entirely by unpaid volunteers. Please consider donating:
    https://github.com/Homebrew/brew#donations

  ==> Next steps:
  - Run `brew help` to get started
  - Further documentation: 
      https://docs.brew.sh
  - Install the Homebrew dependencies if you have sudo access:
    Debian, Ubuntu, etc.
      sudo apt-get install build-essential
    Fedora, Red Hat, CentOS, etc.
      sudo yum groupinstall 'Development Tools'
    See https://docs.brew.sh/linux for more information.
  - Configure Homebrew in your /home/orenoaccount/.profile by running
      echo 'eval $(/home/orenoaccount/.linuxbrew/bin/brew shellenv)' >> /home/orenoaccount/.profile
  - Add Homebrew to your PATH
      eval $(/home/orenoaccount/.linuxbrew/bin/brew shellenv)
  - We recommend that you install GCC by running:
      brew install gcc
  ```

  - 10分くらい待ったらコマンドが終了して、Homebrewがインストールされるかと思います

- 続いて、Homebrewインストール時の最後に出てきたガイダンスに従って、ビルド環境と環境変数の設定をしておきます

  ```bash
  $ sudo apt-get install -y build-essential
  (実行結果省略)
  $ echo 'eval $(~/.linuxbrew/bin/brew shellenv)' >> ~/.bashrc
  $ source ~/.bashrc
  ```

  - これで、`brew` コマンドが使えるようになりました。

#### Hugoのインストール

- `brew` コマンドが使えれば一発です

  ```bash
  $ brew install hugo
  sleep: cannot read realtime clock: Invalid argument
  Updating Homebrew...
  ==> Downloading https://linuxbrew.bintray.com/bottles/patchelf-0.10.x86_64_linux.bottle.1.tar.gz
  ==> Downloading from https://akamai.bintray.com/7f/7f19eacef4e3d18d9c82a4f4060bd86abeb912a4a76fa37c29f0bb104a38b2a2?__gda__=exp=1594574801~hmac=1476b7c47848ac0ec0165f2a9175e14fd49a6721cf02d7d
  ######################################################################## 100.0%
  ==> Downloading https://linuxbrew.bintray.com/bottles/hugo-0.73.0.x86_64_linux.bottle.tar.gz
  ==> Downloading from https://akamai.bintray.com/ed/ede625da7ae5bdfb7380a0045dc8705e2a2fd4b689dcb7f3e33d439f61b2a67a?__gda__=exp=1594574802~hmac=79bed8e85642d1bdc48b8ea89fe3e9df67f90e963fd7073
  ######################################################################## 100.0%
  ==> Installing dependencies for hugo: patchelf
  ==> Installing hugo dependency: patchelf
  ==> Pouring patchelf-0.10.x86_64_linux.bottle.1.tar.gz
  🍺  /home/orenoaccount/.linuxbrew/Cellar/patchelf/0.10: 8 files, 879.5KB
  ==> Installing hugo
  ==> Pouring hugo-0.73.0.x86_64_linux.bottle.tar.gz
  ==> Caveats
  Bash completion has been installed to:
    /home/orenoaccount/.linuxbrew/etc/bash_completion.d
  ==> Summary
  🍺  /home/orenoaccount/.linuxbrew/Cellar/hugo/0.73.0: 40 files, 65.5MB
  ==> Caveats
  ==> hugo
  Bash completion has been installed to:
    /home/orenoaccount/.linuxbrew/etc/bash_completion.d
  ```

- 余裕ですね。`hugo` コマンドが使えるようになったので、バージョンでも確認しておきましょう。

  ```bash
  $ hugo version
  Hugo Static Site Generator v0.68.3/extended linux/amd64 BuildDate: 2020-03-25T06:15:45Z
  ```

  - バージョン: 0.68.3
    - ビルド日が既に4ヶ月くらい前ですが、半年以上前とかじゃないし、多分大丈夫でしょう

#### Hugoで新しいサイトを作る

- GitHub Pagesでサイトをホスティングする流れですので、GitHubにてリポジトリを作成しておきます
- リポジトリで公開Webページを丸々ホスティングするので、分かりやすいようそのままドメイン名 (ここでは仮に `orenoblog.com` とします) をリポジトリ名として作成しました
  - 今回は独自ドメインを用いた例を示していますが、例えばGitHubアカウント名をベースにしたサブドメイン(無料)の直下でホスティングするのであれば、リポジトリ名 `<アカウント名>.github.io` として作成する必要があります
  - 無料アカウントでホスティングを行う場合には、現状ですとリポジトリはPublic(公開)である必要があります
    - 有料アカウント(最安のプランでよい)ならPrivate(非公開)でもホスティング可能です

- サイト管理用のリポジトリを作成したら、早速 `hugo` コマンドを使って新しいサイトの雛形を作ってみましょう

  ```
  $ mkdir -p ~/git ; cd ~/git # Git管理用ディレクトリを作っておく
  $ hugo new site orenoblog.com # 新しいサイトを指定したディレクトリ名で作成
  Congratulations! Your new Hugo site is created in /home/orenoaccount/git/orenoblog.com.

  Just a few more steps and you're ready to go:

  1. Download a theme into the same-named folder.
    Choose a theme from https://themes.gohugo.io/ or
    create your own with the "hugo new theme <THEMENAME>" command.
  2. Perhaps you want to add some content. You can add single files
    with "hugo new <SECTIONNAME>/<FILENAME>.<FORMAT>".
  3. Start the built-in live server via "hugo server".

  Visit https://gohugo.io/ for quickstart guide and full documentation.
  ```

  - 無事にサイトの雛形ができました

- 試しに作成されたファイルの一覧を確認してみましょう

  ```bash
  $ tree ~/git/orenoblog.com # treeコマンドを入れていないなら、代わりにfindコマンドなどを使う
  /home/orenoaccount/git/orenoblog.com
  ├── archetypes
  │   └── default.md
  ├── config.toml
  ├── content
  ├── data
  ├── layouts
  ├── resources
  │   └── _gen
  │       ├── assets
  │       └── images
  ├── static
  └── themes

  10 directories, 2 files
  ```

  - ディレクトリが幾つか作られていましたが、ほとんど空っぽで、実質的に作成されたファイルは`config.toml` と `archetypes/default.md` のみですね

- 作成したサイトのディレクトリに入って、Git管理の初期化をしておきます

  ```bash
  $ cd ~/git/orenoblog.com
  $ git init
  Initialized empty Git repository in /home/orenoaccount/git/orenoblog.com/.git/
  ```

- サイトの雛形ができたので、このままMarkdownでコンテンツを作成していきたいところですが、現時点ではHTMLファイルを生成する上でのテンプレートとなるようなファイル群(`layouts` ディレクトリ内に配置)が足りていません
  - 完全に思い通りのデザインをしたいのであれば、Hugoの仕様を確認した上でHTMLテンプレートやスタイルシート、JavaScriptなどを自前で編集することも可能ですが、Responsive Designなどを一から頑張るのは骨が折れると思いますので(自分はそう)、既存のテーマを利用することで楽をしてみます

- 今回は [Hugo Future Imperfect Slim](https://github.com/pacollins/hugo-future-imperfect-slim) テーマを取り込んで使ってみます

  ```bash
  $ cd ~/git/orenoblog.com/themes
  $ git submodule add git@github.com:pacollins/hugo-future-imperfect-slim.git
  Cloning into '/home/orenoaccount/git/orenoblog.com/themes/hugo-future-imperfect-slim'...
  remote: Enumerating objects: 16, done.
  remote: Counting objects: 100% (16/16), done.
  remote: Compressing objects: 100% (11/11), done.
  remote: Total 2538 (delta 1), reused 7 (delta 0), pack-reused 2522
  Receiving objects: 100% (2538/2538), 22.08 MiB | 5.97 MiB/s, done.
  Resolving deltas: 100% (1411/1411), done.
  ```

  - テーマの取り込みが完了しました。簡単ですね

- テーマを取り込んだら、テーマの `README.md` などのファイルを読んで扱い方を把握しておく必要があります
  - 具体的には `config.toml` などに設定を書いていきますが、設定内容などを把握しておきましょう

- 今回は手っ取り早くWebサイトを構築してみるために、サンプルファイルをコピーしてきて使ってみましょう

```bash
$ cd ~/git/orenoblog.com
$ cp -r themes/hugo-future-imperfect-slim/exampleSite/* ./
```

  - コピーしたファイルには、Hugoの設定ファイル(`config.toml`)、Markdownで書かれたサンプルコンテンツや、サンプルCSS、サンプル画像などが含まれています

- 取り急ぎサイト構築に必要そうなリソースは用意できましたが、最低限、`config.toml` の設定項目のうち、`baseurl` という項目だけは適切なベースアドレス(ホスティング先のルートアドレス)に設定してやる必要があります

  ```bash
  $ grep baseurl config.toml # baseurlの設定値を確認
  baseurl                 = "https://example.com/"
  $ sed -Ee 's|^(baseurl\s*=)(.*)$|\1 "https://orenoblog.com/"|' -i config.toml # baseurlの設定値を書き換える
  $ grep baseurl config.toml # baseurlの設定値を再度確認
  baseurl                 = "https://orenoblog.com/"
  ```

- また、Hugoはデフォルトでは生成した静的ファイルは全て `public` というディレクトリの中に配置しますが、GitHub PagesでWebホスティングをする場合は `docs` というディレクトリの中に公開ファイルを配置することが推奨されています
  - この設定を変更するには `config.toml` の中に `publishDir` という項目でディレクトリパスを設定することで、静的ファイルの出力先を変更することができます
  - 今回コピーしてきた `config.toml` の中には `publishDir` という項目が書かれていないため、`baseurl` の次の行にでも追加してあげるとよいでしょう

  ```bash
  $ grep publishDir config.toml # publishDirの設定が無いことを確認
  $ sed -Ee 's/^baseurl   (\s*)=.*$/\0\npublishDir\1= "docs"/' -i config.toml # publishDirの設定を追加
  $ grep publishDir config.toml # publishDirの設定値を再度確認 
  publishDir              = "docs"
  ```

- 取り急ぎサイト構築に必要なファイル群が用意できたので、サイトの構築を行ってみます

  ```bash
  $ hugo
  Building sites …
                     | EN | FR | PL | PT | DE | ES | ZH-CN | ZH-TW | JA  
  -------------------+----+----+----+----+----+----+-------+-------+-----
    Pages            | 37 | 32 |  8 |  8 |  7 |  7 |     7 |     7 |  7  
    Paginator pages  |  2 |  0 |  0 |  0 |  0 |  0 |     0 |     0 |  0  
    Non-page files   |  0 |  0 |  0 |  0 |  0 |  0 |     0 |     0 |  0  
    Static files     | 28 | 28 | 28 | 28 | 28 | 28 |    28 |    28 | 28  
    Processed images |  0 |  0 |  0 |  0 |  0 |  0 |     0 |     0 |  0  
    Aliases          | 22 | 15 |  4 |  4 |  1 |  1 |     1 |     1 |  1  
    Sitemaps         |  2 |  1 |  1 |  1 |  1 |  1 |     1 |     1 |  1  
    Cleaned          |  0 |  0 |  0 |  0 |  0 |  0 |     0 |     0 |  0  
  
  Total in 868 ms
  ```

  - Hugoと利用テーマが多言語に対応しているということもあり、何やらたくさんのファイルが `docs` ディレクトリの中に生成されました (実際にコンテンツが用意されているのは英語とフランス語だけですが……)
  - なんと生成にかかった時間は 868ミリ秒 = 0.868秒。速い…… (もちろん環境依存ですが、当方はCore i3の貧弱環境で動かしています)
    - #ちなみに、再度 `hugo` コマンドを実行するとサイトの再構築が行われますが、おそらくキャッシュが効いているようで、2回目以降は 439ミリ秒 など、さらに大幅に短い時間で再構築が完了するのを確認しました

#### Webサイトを公開する

- それでは、編集・コピー・生成されたファイル群をGitHubにアップロードして、ホスティングの設定をしてみましょう

```bash
$ git add
$ git commit -m "Initial Commit"
$ git remote add origin git@github.com:orenoaccount/orenoblog.com.git
$ git push -u origin master
Enumerating objects: 381, done.
Counting objects: 100% (381/381), done.
Delta compression using up to 8 threads
Compressing objects: 100% (287/287), done.
Writing objects: 100% (381/381), 4.68 MiB | 2.38 MiB/s, done.
Total 381 (delta 145), reused 0 (delta 0)
remote: Resolving deltas: 100% (145/145), done.
To github.com:orenoaccount/blog.git
 * [new branch]      master -> master
Branch 'master' set up to track remote branch 'master' from 'origin'.
```

- いよいよGitHubでのWebページ公開手順です

- 独自ドメインで公開したい場合、まずはDNSのエントリーを設定してWebアクセス時にGitHubのサーバーを参照させる必要があります

  - 今回の `orenoblog.com` のような APEX(頂点)ドメインの場合は、AレコードとしてGitHubの複数のホスティングサーバーのアドレス `185.199.108.153` `185.199.109.153` `185.199.110.153` `185.199.111.153` を設定する必要があります

    ![Domain Setting](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104262/1b30c753-b643-ee21-7df9-0c55de5765eb.png)

  - ドメイン管理側の設定はこれだけです

- 続いてGitHub側の設定です

- まずはWebブラウザでGitHubで該当リポジトリのページを開きます

- 表示されたページで **Settings** と表示されているリンクを探してクリックします

  ![GitHub Repository Page](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104262/75f8b266-956e-8e70-3fbf-252fec4678a2.png)


- 表示されたページの下の方で **GitHub Pages** という大項目を見つけ、その中の **Source** という項目のプルダウンメニューを確認します

  ![GitHub Pages Source: None](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104262/b5bc77d2-4f10-b69d-e361-a0190c05acb2.png)

- デフォルトでは **None**、つまりWebでは公開しない設定になっていますので、ここから **master branch/docs folder** という選択肢をクリックします

  ![GitHub Pages Source: docs](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104262/76d42eb8-f2d1-91be-00d5-97eaba3d7de6.png)

  - そうすると設定が即時に変更され、画面がリロードされますので、再度画面を下の方にスクロールして **GitHub Pages** の項目を探します

- 再度 **GitHub Pages** の欄を見ると、幾つかの設定項目が追加されているのを確認できます
  - この時点では独自ドメインは設定されておらず、`https://<アカウント名>.github.com/` または `https://<アカウント名>.github.io/<リポジトリ名>/` という独自のURLからアクセスできるようになっています(独自ドメインの設定をしない人はこれで公開設定完了です)

- 独自ドメインを設定する場合には、**Custom Domain** といいう設定項目を探します

  - デフォルトでここは空欄になっているはずですので、ここに準備しておいた独自ドメインを入力して、**Save** ボタンを押します

  ![GitHub Pages Domain: blank](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104262/5b281692-1c9b-9ade-cf57-634403cea244.png)

  - そうすると再度設定が変更され、画面がリロードされますので、また **GitHub Pages** の項目を表示します

- DNS側の設定の反映まで時間がかかる可能性がありますが、無事に設定が完了したら、**"Your site is published at https://orenoblog.com/"** のように表示されているはずです

  ![GitHub Pages Domain: done](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104262/77a0afde-2630-0f87-8af7-544a852ff8e2.png)

  - これで設定は完了です。おそらくこれで表示されたURLで正常にアクセス可能になっているはずです

  - また、下の方に **Enforce HTTPS** という設定項目があり、✓がついていることを確認します（チェックを外すとHTTPでの公開になります）

  - しばらくは、このままHTTPSでアクセスするとWebブラウザで **「保護されていない通信」** などの警告メッセージが表示されますが、数時間～半日程度待つと、警告が表示されなくなるかと思います

  - これで一通りの設定は完了です。お疲れ様でした！

## 後日談

- 頑張ってGitHub Pagesでのホスティングの設定を行ったけど、Firebaseを使ったホスティングに移行しようか検討中です……