シングルページアプリケーション(SPA)のURLには、ハッシュ(#)を使う方法と、History APIを使う方法の2種類があります。前者はブラウザのサポートが万全で、サーバ側の設定不要という利点がありますが、URLに「#」が含まれるため見た目がやや野暮ったいです。後者はURLがクリーンでSEOにも有利ですが、ブラウザをリロードした際に404が返るという落とし穴があります。
この記事では、History APIルーティングを採用したSPAをNginxでホスティングする際に、404を回避するための設定を解説します。
locationディレクティブの動作原理
Nginxの設定ファイル内で、http → server ブロックの中に記述する location は、リクエストURIごとに処理を振り分ける役割を担います。
location [修飾子] パターン {
# 処理
}
修飾子には次の4種類があり、優先順位が定められています。
=… 完全一致が最優先- 修飾子なし … 前方一致でより長いパスが優先
^~… 前方一致だが正規表現より優先~(大小区別あり)/~*(大小区別なし) … 正規表現マッチ
try_filesで「ファイルが無いときのフォールバック」を実現
History APIルーティングを使うと、https://example.com/article/123 のようなパスにアクセスしても、実際のファイルシステムには article/123 というディレクトリやファイルは存在しません。Nginxはデフォルトで「ファイルが無い → 404」を返すため、リロードするとエラー画面が表示されます。
これを回避するには try_files を使います。
server {
listen 80;
server_name example.com;
root /var/www/app/dist;
location / {
# 1. ファイルが存在すれば返す
# 2. ディレクトリが存在すれば返す
# 3. 両方とも存在しなければ /index.html を返す
try_files $uri $uri/ /index.html;
}
# 静的アセットは長期キャッシュ
location ~* \.(js|css|png|jpg|svg|woff2)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
}
上記設定により、/article/123 にリロードしても index.html が返され、クライアント側のルーターが該当画面を描画します。
aliasでパス差分を吸収するケース
ビルド成果物を /var/www/app/dist に配置しているのに、URL上は /app/ 配下で配信したい場合、alias を使ってパスをマッピングします。
location /app/ {
alias /var/www/app/dist/;
}
alias の末尾にスラッシュを付ける/付けないで挙動が変わるため注意が必要です。
動作検証手順
nginx -tで設定ファイルの構文チェックnginx -s reloadで設定を反映- ブラウザで直接
/any/pathを開き、404にならないことを確認 - 開発者ツールの Network タブで
index.htmlが返却されていることを確認