PR
PR

【Astro入門】PodmanとNginxで本番環境を構築!VPSへのサイト公開手順

記事内に広告が含まれています。

前回からの続きです。

【Astro入門】トップページに新着記事一覧を表示!getCollectionを使ったデータ取得と並び替え

今回は、作成したサイトをインターネットに公開するための本番環境を構築していきます。

本番環境の構成内容

本番環境は以下の構成で構築します。

Astro開発用コンテナ(いままで使用していたもの)
開発環境として使用していたもので、HTMLやCSSなどの静的ファイルをビルド(作成)する際にも使用します。
Podmanのコンテナとして作成されています。
コンテンツ公開用Nginxコンテナ(新規作成)
Astroが作成したHTMLやCSSなどの静的ファイルを公開するために使用します。
Podmanのコンテナで新規に作成します。
リバースプロキシ用Nginx(新規作成)
インターネットからの通信をコンテンツ公開用Nginxに振り分けたり、HTTPS接続の処理を行います。
新規でホストに直接インストールします。

Astroコンテナでの作業

開発用として使用していたAstroで以下の作業を行います。

  • astro.config.mjsへ本番環境で使用するFQDN設定
  • 静的ファイルのビルド(生成)

Astro設定(本番で使用するFQDN設定)

本番環境に向けて、プロジェクトの一番上の階層にある「astro.config.mjs」に、本番環境で使用するFQDNの設定を行います。

設定内容

「gamelife.server-memo.net」を、本番環境で使用するFQDNとして設定を行っていきます。

変更前

初期状態の「astro.config.mjs」は以下の通りです。

// @ts-check
import { defineConfig } from 'astro/config';

// https://astro.build/config
export default defineConfig({});
変更後

「export default defineConfig({});」の({})内に、FQDNを「site: 'https://gamelife.server-memo.net',」といったように追加します。

// @ts-check
import { defineConfig } from 'astro/config';

// https://astro.build/config
export default defineConfig({
  site: 'https://gamelife.server-memo.net',
});

サブディレクトリで公開したい場合

もしサイトを「https://vpslife.server-memo.net/」ではなく、「https://vpslife.server-memo.net/gamelife/」といったように「特定のフォルダの中(サブディレクトリ)」で公開したい場合は、「site」とセットで「base」という設定も追加します。

export default defineConfig({
  site: 'https://vpslife.server-memo.net',
  base: '/gamelife', // サブディレクトリの場合はこれを追加
});

Astroで静的ファイルをビルド(作成)

HTMLやCSSファイルなどの静的ファイルを作成するために、以下のコマンドを実行してビルド作業を行います。

コマンドを実行することで、distディレクトリの中にディレクトリやファイルが生成されます。

$ npm run build

今回はAstroがPodmanのコンテナとして構築されているため、「compose.yaml」があるディレクトリで以下のコマンドを実行します。

$ podman-compose exec コンテナ名 npm run build

実際にビルドを行ってみます。

$ podman-compose exec astro-dev npm run build
podman-compose version: 1.0.6
['podman', '--version', '']
using podman version: 4.9.3
podman exec --interactive --tty astro-dev npm run build

> build
> astro build

### 中略 ###
13:13:58 ▶ src/pages/index.astro
13:13:58   └─ /index.html (+22ms) 
13:13:58 ✓ Completed in 272ms.

 generating optimized images 
13:13:58   ▶ /_astro/20250321-01.BaDWPF5Q_1pEGEg.webp (before: 150kB, after: 40kB) (+510ms) (1/2)
13:13:58   ▶ /_astro/20250321-02.yWHbI897_Zknfaw.webp (before: 155kB, after: 43kB) (+527ms) (2/2)
13:13:58 ✓ Completed in 531ms.

13:13:58 [build] 10 page(s) built in 6.26s
13:13:58 [build] Complete!
exit code: 0

ビルドが完了すると、「dist」ディレクトリが作成されます。

$ ls -l | grep dist
drwxr-xr-x   6 tamohiko tamohiko   4096  3月 26 22:13 dist

distディレクトリの中には、HTMLファイル等が生成されています。

$ ls -l dist/
合計 28
drwxr-xr-x 2 tamohiko tamohiko 4096  3月 26 22:13 _astro
drwxr-xr-x 2 tamohiko tamohiko 4096  3月 26 22:13 about
drwxr-xr-x 7 tamohiko tamohiko 4096  3月 26 22:13 blog
-rw-r--r-- 1 tamohiko tamohiko  655  3月 26 22:13 favicon.ico
-rw-r--r-- 1 tamohiko tamohiko  749  3月 26 22:13 favicon.svg
drwxr-xr-x 3 tamohiko tamohiko 4096  3月 26 22:13 game
-rw-r--r-- 1 tamohiko tamohiko 2395  3月 26 22:13 index.html

コンテナの停止

静的ファイルのビルドが完了したら、現在起動している開発環境のコンテナは起動させておく必要はないので、以下のコマンドで停止しておきます。

$ podman-compose down

コンテンツ公開用Nginxコンテナ作業

コンテンツ公開用Nginxコンテナを構築していくために、以下の作業を行います。

  • 設定ファイル(default.conf)の作成
  • compose.yamlにNginxのコンテナ設定追加
  • コンテナ起動
  • 動作確認

設定ファイル(default.conf)の作成

Astroのプロジェクトのディレクトリに、コンテンツ公開用のNginx設定ファイルを格納するためのディレクトリを準備し、そこに設定ファイルを作成します。

ディレクトリの作成

今回は「~/project/astro-dev/nginx」という名前でディレクトリを作成していきます。

$ mkdir ~/project/astro-dev/nginx

設定ファイル(default.conf)の作成

Nginxの設定ファイルを「default.conf」という名前で作成し、以下の内容を設定します。

キャッシュを保持する時間などは、お好きなように適宜変更してください。

server {
    listen 80;
    
    # サーバーのドメインを指定します
    server_name gamelife.server-memo.net;

    # Astroが生成した静的ファイル(distの中身)を置く場所
    # ※Podmanコンテナ内の標準的なパスを指定しています
    root /usr/share/nginx/html;
    
    # ディレクトリにアクセスされた時に読み込むファイル
    index index.html;

    # 文字コードの設定
    charset utf-8;

    # URLの処理ルール
    location / {
        # $uri   : まずはURLと完全一致するファイルを探す
        # $uri/  : なければ、その名前のディレクトリを探して中の index.html を返す(AstroのURL構造に必須)
        # =404   : どちらもなければ 404 Not Found エラーにする
        try_files $uri $uri/ =404;
    }

    # キャッシュの設定
    # 画像、CSS、JavaScriptファイルなどは、訪問者のブラウザに1日間保存させます
    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|webp|woff|woff2|ttf|eot)$ {
        expires 1d;
        access_log off; # これらのファイルのアクセスログをオフにして負荷を減らす
    }

    # エラーページの設定(Astroで 404.astro を作っている場合)
    error_page 404 /404.html;
    location = /404.html {
        internal;
    }
}

compose.yamlへNginxのコンテナ設定を追加

既存の「compose.yaml」に、以下のコンテンツ公開用Nginxコンテナ(astro-nginx)の設定を追加します。

services:
  astro-dev: 
    ##### 中略 #####


# 追加する部分
  astro-nginx:
    image: docker.io/nginx:alpine
    ports:
      # ホスト側の 8080番ポート と コンテナの 80番ポート を繋ぐ
      - "8080:80" 

    volumes:
      # 静的ファイルが格納されているdistディレクトリをマウント
      - ./dist:/usr/share/nginx/html:ro
      # nginxの設定ファイルをマウント
      - ./nginx/default.conf:/etc/nginx/conf.d/default.conf:ro

コンテナの起動

以下のコマンドで、追加した「astro-nginx」コンテナを起動します。

$ podman-compose up astro-nginx -d

動作確認

実際にWebブラウザから「http://ホスト名:8080」へ接続して、Astroで作成したサイトが表示されるか確認を行ってください。

確認手順

VPSなどにAstroの環境を構築している場合は、以下の方法で動作確認を行うことができます。

hostsへgamelife.server-memo.netを登録

Linux(Ubuntuなど)やmacOSであれば「/etc/hosts」に、Windowsであれば「C:\Windows\System32\drivers\etc\hosts」に以下の内容を追加します。

※「gamelife.server-memo.net」の部分はご自身の環境に合わせて適宜読み替えてください。

127.0.0.1 gamelife.server-memo.net
SSHのポートフォワーディングを設定

手元のPCのターミナル(コマンドプロンプトなど)から、以下のコマンドでVPSへSSH接続し、ポートフォワーディングを行うよう設定します。

$ ssh -L 8080:localhost:8080 ユーザー名@VPSサーバ

これにより、手元のPC(localhost)の8080番ポートへの接続が、自動的にVPSの8080番ポートへ転送されるようになります。

この状態で、ブラウザから以下のURLへアクセスしてサイトが表示されれば成功です。

接続URL例: http://gamelife.server-memo.net:8080

動作確認が終わったら、hostsに追加した設定は忘れずに削除しておいてください。

リバースプロキシ用Nginx

インターネットからの接続をコンテンツ公開用Nginxへ振り分けたり(リバースプロキシ)、HTTPS接続の処理を行うためのNginxを、以下の手順で構築していきます。

Nginxのインストール
Nginxの公式サイトで公開しているリポジトリを使用してインストールします。
Let's EncryptでSSL/TLS証明書の取得
Certbotをインストールし、Let's EncryptでSSL/TLS証明書を取得します。
リバースプロキシ用の設定
コンテンツ公開用Nginxへの振り分け設定を行います。
動作確認
Webブラウザで接続して、Astroで作成したサイトが表示されるかの確認を行います。

なお、インターネットでWebサイトを公開するためには、公開するホストの名前をDNSに設定しておく必要がありますので、こちらの準備も忘れずにしておいてください。

Nginxのインストール

Nginxの公式サイトで公開しているリポジトリを使用してインストールします。

まず、Nginxのインストールに必要となるパッケージをインストールします。

$ sudo apt update
$ sudo apt install curl gnupg2 ca-certificates lsb-release ubuntu-keyring

リポジトリの追加

Nginxの署名鍵をインポートします。

$ curl https://nginx.org/keys/nginx_signing.key | gpg --dearmor \
 | sudo tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null

リポジトリの追加を行います。

$ echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \
http://nginx.org/packages/mainline/ubuntu `lsb_release -cs` nginx" \
 | sudo tee /etc/apt/sources.list.d/nginx.list

Nginxのインストール

aptでNginxをインストールします。

$ sudo apt update
$ sudo apt install nginx

より詳しい手順は以下のページで解説していますので、そちらをご確認ください。

Let's EncryptでSSL/TLS証明書の取得

Let's EncryptでSSL/TLS証明書を取得するためには、まずインターネットから対象のホスト(ドメイン)へHTTPでアクセスできる状態にしておく必要があります。ここでは、そのための最低限のNginx設定を行っていきます。

ルートディレクトリの作成

まずは、Nginxのルートディレクトリとして「/usr/share/nginx/gamelife」を作成し、同時に動作確認用の「index.html」ファイルも作成します。

$ sudo mkdir /usr/share/nginx/gamelife
$ echo gamelife.server-memo.net | sudo tee /usr/share/nginx/gamelife/index.html

Nginx設定ファイルの作成

HTTPで接続するための最低限の設定を記述した設定ファイルを、「gamelife.server-memo.net.conf」という名前で作成します。

$ sudo vi /etc/nginx/conf.d/gamelife.server-memo.net.conf

設定内容は以下のとおりです。

server {
    server_name gamelife.server-memo.net;
    root /usr/share/nginx/gamelife;
    index index.html;
}
設定の反映

設定が完了したら、以下のコマンドを実行して文法エラーがないか確認し、Nginxを再起動して設定を反映させます。

$ sudo nginx -t
$ sudo systemctl restart nginx
動作確認

Webブラウザから「http://gamelife.server-memo.net」にアクセスして、先程作成したindex.htmlの内容(gamelife.server-memo.net)が画面に表示されることを確認してください。

Certbotのインストール

Let's EncryptでSSL/TLS証明書を取得するためのクライアントであるCertbot本体と、Nginx用のプラグインである「python3-certbot-nginx」をインストールします。

$ sudo apt install certbot python3-certbot-nginx

SSL/TLS証明書の取得

certbotコマンドを実行してSSL/TLS証明書の取得作業を行います。

$ sudo certbot --nginx -d ホスト名 -m メールアドレス --agree-tos

今回の場合はホスト名が「gamelife.server-memo.net」なので、「/etc/letsencrypt/live/gamelife.server-memo.net/」ディレクトリ内に証明書が作成されます。

この段階で、Certbotが自動的にHTTPS接続用の設定を、Nginxの設定ファイル(gamelife.server-memo.net.conf)に追記してくれます。

設定が追加されると、自動的にNginxへ設定が反映(リロード)されます。

その後、実際にHTTPS接続が出来るようになっているか、Webブラウザで対象のURL(https://gamelife.server-memo.net)へアクセスして動作確認を行ってください。

詳しい手順は以下のページで解説していますので、そちらもご確認ください。

リバースプロキシ用設定

リバースプロキシ用の設定を行っていきます。

とりあえず最低限の設定だけ行いますので、必要があれば設定を適宜追加してください。

$ cd /etc/nginx
$ sudo vi proxy_params 

設定内容は以下のとおりです。

これで、実際のクライアント情報を、コンテンツ公開用Nginxでログに残すようにすることが出来ます。

この設定がないと、接続クライアントのIPアドレスが、すべてプロキシサーバのものになってしまいます。

proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;

コンテンツ公開用Nginxへの振り分け設定

インターネットからの接続を、コンテンツ公開用Nginxへ振り分けるための設定を追加します。

$ cd conf.d
$ sudo vi gamelife.server-memo.net.conf

そこに、以下の設定を追加します。

  • コンテンツ公開用Nginxへ通信振り分け設定
  • SSL/TLS証明書の自動更新用設定

# コンテンツ公開用Nginxコンテナをastro_nginxという名前で設定
upstream astro_nginx {
    server 127.0.0.1:8080 fail_timeout=0;
}


server {
    server_name gamelife.server-memo.net;
    index index.html;
    charset utf-8;
    root /usr/share/nginx/gamelife;

    access_log /var/log/nginx/gamelife_access.log ;
    error_log /var/log/nginx/gamelife_error.log ;


    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/gamelife.server-memo.net/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/gamelife.server-memo.net/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

    # SSL/TLS更新時に一時ファイルを作成するディレクトリを指定
    # リバースプロキシの設定より前に記述すること
    # gamelife.server-memo.net/.well-known宛の通信は
    # /usr/share/nginx/gamelifeをルートディレクトリとする
    location  ^~ /.well-known {
        root /usr/share/nginx/gamelife;
    }

    # リバースプロキシ設定
    # gamelife.server-memo.net宛の通信は
    # upstreamで設定したastro_nginxへ転送する
    location / {
        include proxy_params;
        proxy_pass http://astro_nginx;
    }

}

server {
    if ($host = gamelife.server-memo.net) {
        return 301 https://$host$request_uri;
    } # managed by Certbot


    listen 80;
    server_name gamelife.server-memo.net;
    return 404; # managed by Certbot

}

設定反映

Nginxを再起動して設定を反映させます。

$ sudo nginx -t
$ sudo systemctl restart nginx

動作確認

実際にWebブラウザで接続して、Astroで作成したサイトが表示されるかの確認を行ってください。

https://gamelife.server-memo.net

自動起動設定

最後に、Astroコンテンツ公開用のNginxコンテナ「astro-nginx」を、サーバー起動時に自動的に起動させるための設定を行います。

今回は、PodmanのRootlessコンテナ運用に最適な「systemdのユーザーサービス」を使用して設定していきます。

設定ファイルの作成

ユーザーサービス用の設定ファイルを格納するためのディレクトリ「~/.config/systemd/user」を作成し、そこに「astro-nginx.service」という名前で設定ファイルを作成します。

$ mkdir -p ~/.config/systemd/user
$ vi ~/.config/systemd/user/astro-nginx.service

設定内容は以下のとおりです。

※「WorkingDirectory」のパスは、ご自身の環境の「compose.yaml」があるディレクトリに書き換えてください。

[Unit]
Description=Astro Nginx Production Container

[Service]
Type=oneshot
RemainAfterExit=yes

WorkingDirectory=/home/tamohiko/project/astro/gamelife

ExecStart=/usr/bin/podman-compose up astro-nginx -d
ExecStop=/usr/bin/podman-compose stop astro-nginx

[Install]
# ユーザーサービスの場合は default.target にします
WantedBy=default.target

設定の読み込み

作成した設定ファイルをsystemdに読み込ませます。ユーザーサービスに対するコマンドなので、「--user」オプションを忘れずにつけてください。

$ systemctl --user daemon-reload

コンテナの起動と常駐設定(Linger有効化)

サーバー再起動後、ユーザーがまだログインしていない状態でもコンテナを自動起動・常駐させるために、以下のコマンドを実行します。

※「tamohiko」の部分は、現在ログインしているご自身のユーザー名に書き換えてください。

$ sudo loginctl enable-linger tamohiko

続いて、コンテナの起動と、自動起動設定(OS起動時の有効化)を同時に行います。

$ systemctl --user enable --now astro-nginx.service

動作確認

「astro-nginx」サービスが正常に起動しているかを、以下のコマンドで確認します。

Active: の部分が active (exited) になっていれば成功です。

$ systemctl --user status astro-nginx
● astro-nginx.service - Astro Nginx Production Container
     Loaded: loaded (/home/tamohiko/.config/systemd/user/astro-nginx.service; enabled; preset: enabled)
     Active: active (exited) since Tue 2026-03-31 17:04:06 JST; 4h 24min ago
    Process: 922 ExecStart=/usr/bin/podman-compose up astro-nginx -d (code=exited, status=0/SUCCESS)
   Main PID: 922 (code=exited, status=0/SUCCESS)
      Tasks: 14 (limit: 1054)
     Memory: 4.9M (peak: 42.7M swap: 2.1M swap peak: 2.1M)
        CPU: 936ms
##### 以下省略 #####

この状態で、Astroで作成したWebサイトにブラウザでアクセスして、正常に表示できるかどうかを確認してください。

問題がなければ、一度サーバー自体を再起動(sudo reboot)し、再起動後に何もコマンドを叩かなくてもWebサイトが表示できること(自動起動が成功していること)を確認してください。

日々の運用方法

最後に、AstroでWebサイトを運用していく場合の、日常的な作業フロー(運用方法)をまとめます。

記事の作成・更新

普段はAstroの開発用コンテナは停止しておき、「src/content」ディレクトリ配下で記事を作成・編集したあとにのみビルドを行い、HTMLファイルなどを生成する運用にします。

実際には、「compose.yaml」があるディレクトリで以下のコマンドを実行します。

$ podman-compose run --rm astro-dev npm run build

この「run --rm」コマンドを使うことで、ビルド処理が終わった直後にAstroコンテナが自動的に停止・削除されます。これにより、VPSの限られたメモリやリソースを無駄に消費せずに済みます。

開発環境を使用する場合

デザインの変更や動作確認など、ブラウザでリアルタイムに編集結果を確認しながら作業したい場合は、以下のコマンドでAstro開発用コンテナを起動して作業を行います。

$ podman-compose up -d astro-dev

作業が終了したら、無駄なリソースを使わないように以下のコマンドでコンテナを停止しておきます。

$ podman-compose down astro-dev

コメント

タイトルとURLをコピーしました