GitHub Actions から Basic 認証つきの格安環境にデプロイする方法
はじめに
Web ページを GitHub Actions などからデプロイしたいが、社内向けなので Basic 認証なりが欲しいという場合がある。
デプロイするだけなら Netlify が楽で Basic 認証も提供されているが、$19/人/月の有料プランで人数が多いと厳しい。
Vercelではサーバーレス関数で無料プランでもBasic認証を実装できるが、そもそも無料プランは非営利目的での利用に制限されており、最低でも$20/人/月のBasic認証もついたプランから始めることになる。
ちなみにNetlifyでもサーバーレス関数でBasic認証を実装できるが、Vercelのようなルーティングの設定がないため無意味。
これらのサービスはビルドの環境も提供しているが、既にCIなどでビルドしており特に静的ファイルのデプロイ先だけを探しているのなら、レンタルサーバーやVPSを利用したほうが安く済む。
これに関して、ここでは¥524/月で利用できる さくらのレンタルサーバ にGitHub Actionsからデプロイする方法を紹介する。 ちなみに、リポジトリがGitHubにありプライベートでもページは公開してよいならGitHub Pagesにデプロイするのが簡単。
リポジトリがGitLabにあるなら、GitLab Pagesにデプロイして設定から公開範囲をメンバーのみに限定することもできる。
さくらのレンタルサーバの契約と初期設定
まずはレンタルサーバのプランや基本的な仕様などを見ていく。
環境は FreeBSD, csh, Perl 5.14.x, Ruby 2.5.x, Python 2.7.x, PHP 7.x という感じ。
スタンダードプランであれば SSH, CRON, MySQL 5.7 あたりも利用可能になるため、スタンダードプランをお勧めする。
ちなみに さくらのVPS もあるが、静的ファイルのホスティングがメインなら当然レンタルサーバのほうが楽で得。 契約に必要なのはクレジットカードだけで、*.sakura.ne.jp なるドメインも付与される。
申し込みが終わり「仮登録完了のお知らせ」が届いたら初期設定を行う。
example を適宜読み替え、下記のようにSSHで接続し www/.htaccess と www/.ftpaccess を作るだけ。
code:sh
$ ssh-keygen -m PEM -t rsa -b 4096 -f ~/.ssh/sakura
$ ssh-copy-id -i sakura.pub example@example.sakura.ne.jp
$ ssh -i ~/.ssh/sakura example@example.sakura.ne.jp
# Basic 認証を設定する
% htpasswd -bcm www/.htpasswd root passwd
% cat << EOF > www/.htaccess
<Files ~ "^\.ht">
Deny from all
</Files>
AuthType Basic
AuthName "Password Required"
AuthUserFile /home/example/www/.htpasswd
Require valid-user
EOF
# FTP による接続を禁止する
% cat << EOF > www/.ftpaccess
<Limit ALL>
Deny All
</Limit>
EOF
GitHub Actions の設定
次は下記のようにGitHub Actionsの設定をする。
code:.github/workflows/main.yaml
name: main
on: push
jobs:
npm-script:
strategy:
fail-fast: false
matrix:
if: "!contains(github.event.head_commit.message, 'ci skip')" runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
with:
node-version: 14
- uses: actions/cache@v2
with:
path: ~/.cache/yarn
key: yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: yarn-
- run: yarn install --frozen-lockfile
- run: yarn ${{ matrix.script }}
- if: >
matrix.script == 'build' &&
github.event_name == 'push' &&
github.ref == 'refs/heads/master' &&
!contains(github.event.head_commit.message, 'deploy skip') uses: easingthemes/ssh-deploy@v2.1.5
env:
SSH_PRIVATE_KEY: ${{ secrets.SSH_KEY }}
REMOTE_HOST: example.sakura.ne.jp
REMOTE_USER: example
SOURCE: dist/
TARGET: /home/example/www/
ARGS: -avhz --delete --exclude '.hft*' 2020/03/23 追記
公式で [ci skip] がサポートされたため、runs-on の前の if は不要になった。
デプロイ以外の部分は strategy で script の要素の数だけジョブを複製し yarn build などを実行しているだけ。
SSH経由でデプロイを行うActionはいくつかあるが、今回は rsync ベースでシンプルな ssh-deploy を利用した。 secrets.SSH_KEY には ~/.ssh/sakura の内容を設定する。
PRのマージも含む master への push で、コミットメッセージが [deploy skip] を含まない場合にデプロイが走る。
そもそも yarn build で失敗した場合は、以降のステップが実行されないのでデプロイもされない。
ちなみに github コンテキストの中身は、run: echo '${{ toJSON(github) }}' などで確認できる。
renovateによる push を無視する場合は github.event.head_commit.author.name != 'renovate[bot]' も追加する。
renovate[bot] などは curl https://api.github.com/repos/{owner}/{repo}/commits を叩くと確認できる。
PRを手動でマージした場合、github.event.pusher.name はマージした人の名前になるようなのでこの場合は使えない?
yarn でなく npm を利用する場合は、.github/workflows/main.yaml を以下のように書き換える。
code:diff
- uses: actions/cache@v2
with:
- path: ~/.cache/yarn
- key: yarn-${{ hashFiles('**/yarn.lock') }}
- restore-keys: yarn-
- - run: yarn install --frozen-lockfile
- - run: yarn ${{ matrix.script }}
+ path: ~/.npm
+ key: npm-${{ hashFiles('**/package-lock.json') }}
+ restore-keys: npm-
+ - run: npm ci
+ - run: npm run ${{ matrix.script }}
プライベートリポジトリであっても一切のアクセス制限はつかないが、GitHub Pagesにデプロイするならこう書き換える。
secrets.GITHUB_TOKEN は勝手に設定されるのでこれだけでよい。
code:diff
- uses: easingthemes/ssh-deploy@v2.1.5
- env:
- SSH_PRIVATE_KEY: ${{ secrets.SSH_KEY }}
- REMOTE_HOST: example.sakura.ne.jp
- REMOTE_USER: example
- SOURCE: dist/
- TARGET: /home/example/www/
- ARGS: -avhz --delete --exclude '.hft*' + uses: peaceiris/actions-gh-pages@v3
+ with:
+ github_token: ${{ secrets.GITHUB_TOKEN }}
+ publish_dir: ./dist
デプロイの部分を別のジョブに分離することも可能だが、ジョブ間でファイルを受け渡すには artifact を経由する必要があり、設定が無駄に複雑になるのとストレージの無料枠を簡単に超過してしまうのとでお勧めしない。
ちなみに strategy で作ったジョブを needs で指定する場合は、普通に npm-script のようにする。