個人ブログを動かすなら、Docker・Kubernetes・サーバーレス…と選択肢はいくらでもある。 しかし今回はあえて Nginx直置きの静的配信 を選んだ。 理由と、構築までの手順を残しておく。

この記事の要点
  • メモリ1GBのVPSでは、あえてDockerを使わずNginx直置きが軽くて速い
  • Let's EncryptでHTTPS化し、GitHub Actions + rsyncで自動デプロイ
  • 最終的にAstroの静的サイトへ移行した
BUILDAstroで静的ビルド
→
SYNCGitHub Actions + rsync
→
SERVENginxが直配信 (HTTPS)

なぜDockerを使わなかったか

使っているさくらVPSは メモリ1GBプラン。 Dockerを動かせなくはないが、

  • 静的HTMLを配るだけの用途にコンテナのオーバーヘッドが見合わない
  • 常駐デーモン、image cache、ログでメモリと容量を地味に食う
  • 1GBクラスではswap頼みが増えて反応が落ちやすい
  • Nginxを直接いじったほうがログ追跡や設定が単純

ということで、コンテナ化するメリットより、シンプルさのメリットが上回ると判断した。 Dockerはチーム開発・複数サービス同居・CI/CDが欲しい時に強いが、 「個人ブログ1つだけ」のステージでは持ち込みすぎになる。

Nginxで静的サイトを配信する

Ubuntu 24.04 でのインストールは apt 一発。

sudo apt update
sudo apt install -y nginx

公開ディレクトリを切って、所有権を作業ユーザーに渡しておく。 サーバー上で直接ファイルを書き換える運用にしないので、 あくまで rsyncの送り先 として用意する。

sudo mkdir -p /var/www/fecot.net/html
sudo chown -R ubuntu:ubuntu /var/www/fecot.net/html

/etc/nginx/sites-available/fecot.net に最小構成のserverブロックを書く:

server {
    listen 80;
    server_name fecot.net;
    root /var/www/fecot.net/html;
    index index.html;

    location / {
        try_files $uri $uri/ =404;
    }
}
sudo ln -s /etc/nginx/sites-available/fecot.net /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

この時点で、HTMLを置けばHTTPで見える状態になる。

Let's Encrypt でHTTPS化

certbot をインストールして、Nginxプラグイン経由で証明書を取得する。

sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d fecot.net

certbot がserverブロックを書き換えて、 自動的に listen 443 ssl; や http→https リダイレクトを追加してくれる。 便利だが、後から自分で設定を読みやすく整える。

certbot.timer による自動更新

Let's Encryptの証明書は90日で切れる。 Ubuntu 24.04では、certbot パッケージを入れるだけで certbot.timer が自動的に有効化される。

systemctl list-timers | grep certbot

cronで自前ループを書く必要はない。 動作確認は --dry-run でOK:

sudo certbot renew --dry-run

GitHub Actions + rsync によるデプロイ

「サーバー上で直接ファイルを編集しない」を運用ルールにしている。 代わりに、GitHubの main ブランチに push されたら、 GitHub Actions から rsync over SSH でVPSに同期する構成にした。

GitHub Secretsには次を登録:

  • VPS_HOST :VPSのIPアドレス
  • VPS_USER :ubuntu
  • VPS_PORT :51022
  • VPS_SSH_KEY :デプロイ用の秘密鍵(GitHub Actions専用に発行)
  • VPS_DEPLOY_PATH :/var/www/fecot.net/html/

.github/workflows/deploy.yml の中身は、ざっくり以下の流れ:

- Checkout
- Node.jsセットアップ
- npm ci
- npm run build           # Astroで dist/ を生成
- SSH鍵をRunnerに展開
- rsync -avz --delete ./dist/ user@host:/var/www/fecot.net/html/

ポイントは --delete オプション。 これでローカルから消したファイルがサーバー側にも反映される。 いわゆる「サーバー上に古いファイルが残る問題」が起きない。

Astroへ移行した理由

最初は単一の index.html を直接置いていた。 しかし、記事を増やしていくと素のHTMLでは限界がすぐ来る:

  • ヘッダー・フッター・ナビが各ページで重複
  • メタタグやOGPの管理がコピペ運用になる
  • 記事一覧の生成も手動

そこで Astro に移行した。Astroを選んだ理由は、

  • ビルド出力は完全に静的(Nginx直置きと相性◎)
  • JSをほとんど吐かない(Islands Architecture)
  • ビルドが速い(Vite基盤)
  • 必要になればReact / Vue / Svelteを部分導入できる

デプロイ先がNginx直置きの静的サーバーであることは変わらない。 rsyncの送り元が public/ から Astroのビルド出力 dist/ に変わっただけ。

まとめ

個人サイト規模なら、

  • 1GB VPS + Nginx直置き
  • Let's Encrypt + certbot.timerで自動更新
  • GitHub Actions + rsyncでデプロイ
  • 静的サイトジェネレータ(Astro)でビルド

という構成が、シンプルで・安くて・運用が破綻しにくい。 もう一段スケールしたいタイミングで初めてDockerやマネージドサービスを検討する、 くらいの順番がちょうど良いと思う。