Open2

Nginx勉強用スクラップ

YozakuraYozakura

はじめに

業務ではk8sを使用しているが、最近Nginxで静的コンテンツを表示することが多く、
なんとなくで使用していたNginxを本格的にものにしてみたくなった。

Udemyで海外講義を見たりしたが、なかなか英語が入ってこないので、
Kindleで0円だったnginxプロキシ構築完全マスター で基本から勉強してみたいと思う。

Dockerfileの作成

手元のNginx設定は汚したくないのでDockerでNginxを起動しようと思う。
設定ファイルもローカルから見れるようにしていじれるようにしたいので、
リポジトリ内で下記コマンド実行。

docker cp sample-container:/etc/nginx ./nginx-config
FROM nginx:latest as production

# 設定ファイルもCOPYする
COPY ./nginx-config /etc/nginx
COPY ./pages /var/www/html

EXPOSE 3333

ポートを3333にしているので、
default.confのserver設定を修正。

server {
    # これはDockerで起動しているポートを指定
    listen       3333;
    listen  [::]:3333;

dockerコマンドを毎回打ち込むのは面倒なので、
よく使いそうなコマンドをMakefileに記載。

restart:
	docker rm -f sample-container && docker build -t sample-container . && docker run -d --name sample-container -p 3333:3333 sample-container

container:
	docker exec -it sample-container /bin/bash

ps:
	docker ps

down:
	docker rm -f sample-container

logs:
	docker logs sample-container

起動

make restart

これで無事にhttp://localhost:3333でデフォルトのNginx画面が表示。

YozakuraYozakura

現在のディレクトリ構造が下記のような感じ。

tree
.
├── Dockerfile
├── Makefile
├── nginx-config
│   ├── conf.d
│   │   └── default.conf
│   ├── fastcgi_params
│   ├── mime.types
│   ├── modules -> /usr/lib/nginx/modules
│   ├── nginx.conf
│   ├── scgi_params
│   └── uwsgi_params
└── pages
    ├── index.html
    └── test-page
        └── sample
            └── index.html

aliasとrootの違い

default.conf

# リクエストで/testから始まる時のもの
location /test {
    # 表示したいindex.htmlは/var/www/htmlの直下に存在する
    # この場合rootにするとtestディレクトリを探すので、ディレクトリがない場合はaliasでパスを指定する
    # aliasはディレクトリ自体を指定する
    alias /var/www/html;
    index index.html;
}

# リクエストで/test-pageから始まる時のもの
location /test-page {
    # この場合/special配下のディレクトリ内のindex.htmlを探す
    # rootはlocationのパスをrootディレクトリに付加する
    root /var/www/html;
    index index.html;        
}

リクエスト

リクエストパス 結果
/test ①301 /test/最後にスラッシュがついたパスへリダイレクト
②/test/で200
/test/ 200

この最後にスラッシュがない場合の挙動を詳しく調べてみる

301 Moved Permanentlyについて。

$ curl -I http://localhost:3333/test

> HTTP/1.1 301 Moved Permanently
Server: nginx/1.27.3
Date: Sat, 01 Feb 2025 11:43:05 GMT
Content-Type: text/html
Content-Length: 169
Location: http://localhost:3333/test/ 👈 ここでスラッシュがついている
Connection: keep-alive

この場合、Location: http://localhost:3333/test/ ここに完全に移動したということか。

これはNginx、ブラウザどっちの挙動なのか??

ChatGPTに聞いてみる。

最後にスラッシュがない場合http://localhost:3333/test/に完全に移動されるがこれを行なっているのは
ブラウザ?それともNginx??
このリダイレクトを行っているのはNginxです。

具体的には、Nginxの設定ファイルにおいて、
ディレクトリパスにスラッシュ(/)がない場合に自動的にリダイレクトを行う設定がされているためです。
Nginxは、リクエストされたURLがディレクトリパスである場合、最後にスラッシュを追加するリダイレクトを自動で行います。
これにより、http://localhost:3333/testがhttp://localhost:3333/test/にリダイレクトされます。

どうしてNginxがこのリダイレクトを行うのか?
HTTP仕様: URLがディレクトリを指している場合、そのディレクトリにはスラッシュが必要であると認識されます。スラッシュがないURLは、リソース(例えばファイル)とディレクトリの間で混乱が生じる可能性があります。
Nginx設定: Nginxの設定で、URLがディレクトリを示している場合に末尾のスラッシュを強制するようにリダイレクトする設定がよく使われます。

どうやらNginxのデフォルトの挙動らしい。
でも、リバースプロキシの場合はこうならない。
静的コンテンツを表示させるときのみで、スラッシュがない場合ディレクトリと認識して最後に/をつけるらしい。
確かに、この記事のURLhttps://zenn.dev/zaki_dev/scraps/0a0cf676d4f690で読み込んで、
ネットワークタブを見ても最後に/はついていない。
ちなみに最後についているスラッシュのことをトレイングスラッシュというらしい。

なんだか頭が追いつかないので、
Nginxでトレイリングスラッシュとファイル拡張子を削除する秘伝わざをちょっと熟読してみる。

うーん。。。
301でトレイングスラッシュのパスにリダイレクトして200になるのが正しい挙動だが、
本番環境で、307 Internal Redirect (from disk cache) でLocationはトレイングスラッシュ付きのパスだが、
Request URLがhttpとhttpsから始まるリクエストがある。

うーん。。。
こんがらがってくる。
最終的には200になるので画面上は正常に表示される。
なぜ、httpとhttpsのそれぞれからリクエストを飛ばすのか??

トレイリングスラッシュの件は別のスクラップに移します。
https://zenn.dev/zaki_dev/scraps/06bc3202e09450