はじめに

このブログを作った時のことも忘れないうちに書いておくことにしました。 気軽に技術をアウトプットできるようにするという目的で作ったのでみんなもブログ作ろう

前提

開発環境はVscodeで完結すること+いちいちhtmlやcssは書きたくなかったのでmarkdownで簡単に書けるということを前提としました。
ホスティングするサーバーは自宅にあるproxmox上のlinuxコンテナにデプロイし、デプロイも自動化することを目的としました。

最終的に選定したのがHugoという静的サイト作成ツールとGitHub Actionsです。

Hugo

Hugoは、高速で柔軟な静的サイトジェネレーターで、Go言語で書かれています。
Hugoはブログ、ポートフォリオ、ドキュメントサイトなど、様々なタイプのウェブサイトを迅速かつ効率的に作成するためのツールです。
利点は非常に多いのですが中でも

  • 高速でビルドができる
  • テーマをいろいろ選べる
  • markdownからhtmlとcssに変換できる
  • カスタマイズしやすい

という理由でhugoを使うことにしました。

GitHub Actions

GitHubでソースコードを管理するのでPushするついでにデプロイも自動でできるGitHub Actionsを使うことにしました。 デプロイする流れとしては

  • ソースコードを書きGitにPush
  • Pushしたものをビルド
  • ビルドしたファイルをサーバー上にsshして設置
  • サーバー上のnginxを再起動

というような流れです。 この流れをActionsで全部自動化しました。
適当に記事を書いて適当にPushしたらサイト上に反映されるという非常に使いやすい環境ができます。
今回は自宅にあるサーバーにデプロイしますがレンタルサーバーにすればもっと楽に出来ると思います。

環境構築

Hugoでのブログの立ち上げ方は記事が死ぬほど多くインターネット上に存在しているので気が向いたら書きます。

GitHub Acitonの設定

今回のメインです。 以下のようなdeploy.ymlファイルを作成しました。

name: Deploy to Home Server

on:
  push:
    branches:
      - main  # Set a branch name to trigger deployment

jobs:
  deploy:
    runs-on: ubuntu-22.04

    env:  # ジョブ全体で共通の環境変数を設定
      SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
      USERPWD: ${{ secrets.USERPWD }}
      DDNS_HOSTNAME: ${{ secrets.DDNS_HOSTNAME }}
      CONTAINER_USER: ${{ secrets.CONTAINER_USER }}
      SSH_PORT: ${{ secrets.SSH_PORT }}

    steps:
      - name: Checkout repository
        uses: actions/checkout@v2
        with:
          submodules: true  # Fetch Hugo themes (true OR recursive)
          fetch-depth: 0    # Fetch all history for .GitInfo and .Lastmod

      - name: List files for debugging
        run: |
          cd bibouroku
          ls -la          

      - name: Setup Hugo
        uses: peaceiris/actions-hugo@v2
        with:
          hugo-version: '0.126.1'

      - name: Build
        run: |
          cd bibouroku
          hugo --minify          

      - name: List files in public directory for debugging
        run: |
          cd bibouroku/public
          ls -la          

      - name: Prepare Server Directory
        run: |
          echo "$SSH_PRIVATE_KEY" > private_key
          chmod 600 private_key
          ssh -i private_key -p $SSH_PORT -o StrictHostKeyChecking=no $CONTAINER_USER@$DDNS_HOSTNAME << EOF
          echo "$USERPWD" | sudo -S mkdir -p /var/www/html
          echo "$USERPWD" | sudo -S chown $CONTAINER_USER:$CONTAINER_USER /var/www/html
          EOF          

      - name: Deploy to Server
        run: |
          cd bibouroku
          echo "$SSH_PRIVATE_KEY" > private_key
          chmod 600 private_key
          rsync -avz --no-perms --no-owner --no-group --omit-dir-times -e "ssh -i private_key -p $SSH_PORT -o StrictHostKeyChecking=no" --delete public/ $CONTAINER_USER@$DDNS_HOSTNAME:/var/www/html          

      - name: Restart Nginx
        run: |
          echo "$SSH_PRIVATE_KEY" > private_key
          chmod 600 private_key
          ssh -i private_key -p $SSH_PORT -o StrictHostKeyChecking=no $CONTAINER_USER@$DDNS_HOSTNAME << EOF
          echo "$USERPWD" | sudo -S systemctl restart nginx
          EOF          

nameでDeploy to Home Serverというワークフロー全体の名前を定義しています。

on:push:branchでgitのmainブランチにpushしたときにワークフローがトリガされるように定義しています。

次にjobsセクションを定義しています

jobs:
  deploy:
    runs-on: ubuntu-22.04

複数のジョブを実行できるように定義しますが、今回は deploy という1つのジョブを持つワークフローです。 runs-onでジョブを実行する環境を指定します。今回はGitHub Actions上のランナーのUbuntu-22.04を指定しています。

    env:  # ジョブ全体で共通の環境変数を設定
      SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
      USERPWD: ${{ secrets.USERPWD }}
      DDNS_HOSTNAME: ${{ secrets.DDNS_HOSTNAME }}
      CONTAINER_USER: ${{ secrets.CONTAINER_USER }}
      SSH_PORT: ${{ secrets.SSH_PORT }}

envセクションでジョブ全体で使用する環境変数をまとめて定義しています。
SSHの秘密鍵等をコード上にベタ打ちする訳には行かないのでリポジトリのGitHub Actionsのシークレットに登録した値を取得して利用しています。

stepセクションでは先ほど設定した環境で実際にビルドなどを行います。

      - name: Checkout repository
        uses: actions/checkout@v2
        with:
          submodules: true  # Fetch Hugo themes (true OR recursive)
          fetch-depth: 0    # Fetch all history for .GitInfo and .Lastmod

最初にリポジトリのチェックアウトを行います。
uses:actions/checkout@v2 は、GitHub Actionsの公式アクションで、リポジトリをクローンしてワークフロー内で使用できるようにするものです。

submodules: trueHugoを利用するにあたりテーマをサブモジュールとして登録しています。リポジトリ内にサブモジュールが存在する場合はサブモジュールを含めてクローンします。

fetch-depth: 0リポジトリの履歴全体を取得するために0を指定しています。

      - name: List files for debugging
        run: |
          cd bibouroku
          ls -la          

run:を使用してワークフローで直接シェルコマンドを実行します。
リポジトリ内のHugoのメインのフォルダ名がbibourokuなのでそこに移動してファイルの一覧を表示させています。(デバッグ用です)

      - name: Setup Hugo
        uses: peaceiris/actions-hugo@v2
        with:
          hugo-version: '0.126.1'

Hugoをセットアップするアクションです。 セットアップするアクションとしてuses:peaceiris/actions-hugo@v2を指定します。
その後hugo-version:でHugoのバージョンを指定します。現段階では直接0.126.1に指定しています。

      - name: Build
        run: |
          cd bibouroku
          hugo --minify          

実際にビルドを行うセクションです。
bibourokuディレクトリに移動してhugo --minifyコマンドを実行します。
--minifyオプションを使用して出力を圧縮して最適化しています。

      - name: List files in public directory for debugging
        run: |
          cd bibouroku/public
          ls -la          

ビルドが終了したらpublicディレクトリの中身を表示しています。これもデバッグ用です。

      - name: Prepare Server Directory
        run: |
          echo "$SSH_PRIVATE_KEY" > private_key
          chmod 600 private_key
          ssh -i private_key -p $SSH_PORT -o StrictHostKeyChecking=no $CONTAINER_USER@$DDNS_HOSTNAME << EOF
          echo "$USERPWD" | sudo -S mkdir -p /var/www/html
          echo "$USERPWD" | sudo -S chown $CONTAINER_USER:$CONTAINER_USER /var/www/html
          EOF          

サーバーディレクトリの準備を行うためのセクションです。
先ほどと同様にrun:でシェルコマンドを実行します。
SSHでリモートサーバーに接続し、ウェブサイトをホストするディレクトリ(/var/www/html)を作成します。その後、そのディレクトリの所有者を指定したユーザーに変更します。

      - name: Deploy to Server
        run: |
          cd bibouroku
          echo "$SSH_PRIVATE_KEY" > private_key
          chmod 600 private_key
          rsync -avz --no-perms --no-owner --no-group --omit-dir-times -e "ssh -i private_key -p $SSH_PORT -o StrictHostKeyChecking=no" --delete public/ $CONTAINER_USER@$DDNS_HOSTNAME:/var/www/html                    

rsyncを使用してビルドしたファイルを自宅サーバー上のLXC(Linux container)の/var/www/htmlディレクトリと同期します。
--deleteオプションを使ってリモート側で存在しないファイルを削除しています。

      - name: Restart Nginx
        run: |
          echo "$SSH_PRIVATE_KEY" > private_key
          chmod 600 private_key
          ssh -i private_key -p $SSH_PORT -o StrictHostKeyChecking=no $CONTAINER_USER@$DDNS_HOSTNAME << EOF
          echo "$USERPWD" | sudo -S systemctl restart nginx
          EOF          

systemctl restart nginxコマンドを実行して、Nginxを再起動して新しいコンテンツを配信できるようにします。

以上でデプロイが完了します。 これらを自動で行ってくれるので記事を書いてGitHubにPushするだけで勝手にデプロイが完了します。