【nginx】設定ファイルのroot htmlってどこ？

# 目次
[「root html」の実際のパスの調べ方](#root-htmlの実際のパスの調べ方)
[参考にした記事](#参考にした記事)
[実際に調べてみた](#実際に調べてみた)

# 「root html」の実際のパスの調べ方
結論
* 「root html」は、`--prefix`の値からの相対パスである。変更されていなければ、デフォルト値は`/usr/local/nginx`。その場合、「root html」の実際のパスは`/usr/local/nginx/html`となる。`--prefix`の値は`nginx -V`で確認できる。`nginx -V`はコンパイル時のオプションを表示する
* `--prefix`の値は、nginxのインストール方法やディストリビューションによって異なるものが設定されている
* 「root html」は、`root`ディレクティブのデフォルト値

# 参考にした記事
この記事に全てが書いてあります。

https://serverfault.com/questions/1080498/what-does-root-html-mean-in-nginx-config#:~:text=root%20html%20defines%20the%20relative,html

> **`root html` defines the relative path, relative to the value of `--prefix` in Nginx configuration.** In your case, the value of `--prefix` is `/usr/share/nginx`. So, `root html` means, the directory named "html" inside `/usr/share/nginx` is parsed to serve the requested file (50x.html). In the end, the request will look for the file at `/usr/share/nginx/html/50x.html`. **`root html` is also the default value when no root is defined in a Nginx configuration.**

* （訳）
**`root html`は、Nginxの設定において`--prefix`の値からの相対パスを定義する。** あなたのケースでは、`--prefix`の値は`/usr/share/nginx`。なので、`root html`は`/usr/share/nginx`にある"html"という名のディレクトリを解析して、リクエストされたファイル（`50x.html`）を提供することを意味する。最終的にそのリクエストは、`/usr/share/nginx/html/50x.html`のファイルを探す。**`root html`は、nginxの設定の中で`root`ディレクティブが定義されていない場合のデフォルト値でもある。**

より詳しい情報として、以下の2つの記事を紹介しています。1つ目は、`--prefix`についての説明です。

https://nginx.org/en/docs/configure.html


> --prefix=path
defines a directory that will keep server files. **This same directory will also be used for all relative paths set by configure (except for paths to libraries sources) and in the nginx.conf configuration file. It is set to the `/usr/local/nginx` directory by default.**

* （訳）
サーバファイルを保存するディレクトリを定義する。**同名のディレクトリは、`nginx.conf`設定ファイルで設定された全ての相対パスにも使用される（ライブラリソースへのパスは除く）。デフォルトで`/usr/local/nginx`ディレクトリに設定される**。

2つ目は、`root`ディレクティブについての説明です。「root htmlが`root`ディレクティブのデフォルト値であること」が分かります。

https://nginx.org/en/docs/http/ngx_http_core_module.html#root

以下の記事でも同じようなことが書いてありました。新たに、`--prefix`の値は「nginxのインストール方法やディストリビューションによって異なる」ことが分かりました。

https://stackoverflow.com/questions/10674867/nginx-default-public-www-location

> If your configuration does not include a root /some/absolute/path; statement, or it includes one that uses a relative path like root some/relative/path;, then **the resulting path depends on compile-time options.** Probably the only case that would allow you to make an educated guess as to what this means for you would be, if you downloaded and compiled the source yourself. In that case, **the paths would be relative to whatever `--prefix` was used.** **If you didn't change it, it defaults to `/usr/local/nginx`.** **You can find the parameters nginx was compiled with via `nginx -V`**, it lists `--prefix` as the first one. Since **the `root` directive defaults to `html`**, this would, of course, result in `/usr/local/nginx/html` being the answer to your question. **However, if you installed nginx in any other way, all bets are off. Your distribution might use entirely different default paths.** Learning to figure out what kind of defaults your distribution of choice uses for things is another task entirely.

* （訳）
設定が`root /some/absolute/path;`ステートメントを含んでいないか、`root some/relative/path;`のような相対パスを使っているステートメントを含む場合、**結果のパスはコンパイル時のオプションに依存する**。おそらく、これが意味することについて、自分でソースをダウンロードしてコンパイルした場合のみ、経験に基づく推測が可能だろう。その場合、**パスは`--prefix`が使用されたものからの相対パス**となる。**もしそれを変更していなければ、デフォルトは`/usr/local/nginx`** になる。**`nginx -V`を用いて、nginxがコンパイルされたパラメータを見つけることができる。** `--prefix`が最初のものとしてリストされている。**`root`ディレクティブのデフォルトは`html`** なので、`/usr/local/nginx/html`が質問の答えになる。**しかし、それ以外の方法でnginxをインストールした場合、すべての賭けは失敗する。あなたのディストリビューションでは、まったく異なるデフォルトパスが使用されているかもしれない。** 選択したディストリビューションがどのようなデフォルトを使用しているかを把握するのとは、まったく別の仕事だ。

# 実際に調べてみた
私は**Dockerのnginxコンテナ**を使用しています。以下は設定ファイルの一部です。

```nginx:/etc/nginx/conf.d/default.conf
server {
    listen       80;
    listen  [::]:80; 
    server_name  localhost;
    # 省略
    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }
    # 省略
    location ~ \.php$ {
        root           html;
        # 省略
    }
    # 省略
}
```
ここに「root html」があります。

nginxコンテナの中で`nginx -V`を実行したところ、こうなりました。
```
configure arguments: --prefix=/etc/nginx  .....省略
```
つまり「root html」の実際のパスは`/etc/nginx/html`となります。

## 自分の目で確かめてみる

自分の目で確かめたくて、少し実験をしました。設定ファイルを以下のように変更します。

```nginx:/etc/nginx/conf.d/default.conf
server {
    # 省略
    location / {
        root   html;
    }
    # 省略
}
```
「root html」の実際のパスは`/etc/nginx/html`であると仮定して、nginxコンテナ内の`/etc/nginx/html`に`index.html`を置きます。これが正しければ、`index.html`をリクエストした時に表示されるはずです。

詳しい手順は以下です。

* ①[環境を準備する](#環境を準備する)
* ②[設定ファイルを変更する](#設定ファイルを変更する)
* ③[コンテナ内に/etc/nginx/html/index.htmlを用意する](#コンテナ内にetcnginxhtmlindexhtmlを用意する)
* ④[新しい内容でコンテナを起動し直す](#新しい内容でコンテナを起動し直す)
* ⑤[index.htmlにアクセスする](#indexhtmlにアクセスする)

### ①環境を準備する
ホスト側に以下の構造を作ります。
* `default.conf`
設定ファイルを変更するには、**コンテナ内の設定ファイルをホスト側にコピーし、自分のエディタ（私はVSCode）で編集します。** 今回変更するのは`default.conf`なので、このファイルをホスト側にコピーします。
```
.
|____nginx
|      |____default.conf    <-----ここにコピーする
|      |____Dockerfile
|
|____public
       |____index.html      <-----中身は適当に。これが表示されるかの実験。
       
```
これはコンテナが存在している状態でないとできないので、初めての場合はとりあえずコンテナを起動します。[初めの方に簡単なセットアップが書かれています](https://hub.docker.com/_/nginx)。適宜書き換えて実行します。
↓
`docker run --name nginx-container -v ./public:/usr/share/nginx/html:ro -d nginx:1.25`
・docker hubの「`nginx:1.25`」イメージを使用します。

`index.html`も適当に作成します。
### ②設定ファイルを変更する

コンテナが起動できたので、コンテナ内の`default.conf`をホスト側にコピーします。

* コンテナの外で`docker cp nginx-container:/etc/nginx/conf.d/default.conf ./nginx/default.conf`を実行。

構文は`docker cp コンテナ名またはコンテナID:コピー元のパス コピー先のパス`です。

コピーされるので、`default.conf`を変更します。

```nginx:default.conf
server {
    # 省略
    location / {
        root   html;
    }
    # 省略
}
```
### ③コンテナ内に`/etc/nginx/html/index.html`を用意する
「root html」の実際のパスは`/etc/nginx/html`と仮定しています。しかし、デフォルトのnginxコンテナには、この **`html`ディレクトリが存在しません**（コンテナの中に入って確かめることができます。コンテナに入るには`docker exec -it nginx-container /bin/bash`を実行）。

nginxコンテナの`/etc/nginx`にあるのは、以下のディレクトリとファイルです。
```
/etc/nginx   ls

conf.d  fastcgi_params  mime.types  modules  nginx.conf  scgi_params  uwsgi_params
```

このままでは実験ができないので、あらかじめDockerfileで`html`ディレクトリを作成します。
* Dockerfile
```Dockerfile:Dockerfile
FROM nginx:1.25
RUN mkdir -p /etc/nginx/html
```
Dockerfileはイメージの設計書みたいなものです。Dockerifleを基にイメージを作成し、そのイメージを基にコンテナが作成されます。

`index.html`は適当に作成しておきます。このファイルを`html`ディレクトリに置くには、**コンテナ起動時にバインドマウントする**ことで実現できます（次で説明）。
### ④新しい内容でコンテナを起動し直す

今nginxコンテナを起動しているのは、「コンテナ内の設定ファイルをホスト側にコピーしたかったから」というだけです。公式のnginxイメージ「`nginx:1.25`」をそのまま使いました。しかし、ここまでで、コンテナ内に新たなディレクトリを作ったり、設定ファイルを変更したので、新しい内容が反映されたコンテナを使いたいです。
1. `docker stop nginx-container`で現在のコンテナ停止
1. `docker rm nginx-container`で現在のコンテナ削除
1. 自作のDockerfileからイメージを作成
`docker build -t nginx-image ./nginx`を実行。
・`-t イメージ名:タグ名`でイメージ名をつける。タグ名を指定しなければ、自動で`latest`がつく。
・`./nginx`はDockerfileのあるディレクトリ。
1. イメージからコンテナを起動
`docker run --name new-nginx-container -v ./public:/etc/nginx/html -v ./nginx/default.conf:/etc/nginx/conf.d/default.conf -d -p 8080:80 nginx-image`を実行。

長いコマンドですが、これがとても便利です。

このコマンドは、新しいコンテナの名前を`new-nginx-container`とし、2つのバインドマウント（`-v`）と、8080番でアクセスできるようにしています。イメージは自作した「`nginx-image`」を使います。コマンド実行後の状態↓↓
```
ホスト側                              コンテナ側
.                                         :
|____nginx                                |__etc
|      |                                  |   |__nginx
|      |                                  :         |__conf.d
|   ***|************************************************|**********************
|   *  |___default.conf       バインドマウント           |___default.conf      *
|   ***************************************************************************
|      |___Dockerfile                               :
|                                                   |                
|____public *************************************** |__html *******************
    *  |____index.html        バインドマウント             |____index.html     *
    *                                                                         *
    ***************************************************************************
```
* `default.conf`・・・ファイル同士のバインドマウント
* `index.html`・・・ディレクトリ同士のバインドマウント

バインドマウントは、ファイル単位でもディレクトリ単位でもできます。
**バインドマウントは、ホスト側にあるファイルをコンテナ側に「見せる」。ホスト側の内容を「被せる」イメージです。まるでコピーしたように見えます。** 

ディレクトリ単位の場合、コンテナ側に既存のファイルがあっても、ホスト側とまるっきり同じ内容になります。なのでファイルが消えたように思うのですが、消えておらずマウントを解除すると元に戻ります。
#### ファイルの変更をリアルタイムで反映するバインドマウント
バインドマウントをしなければ、新たにファイルの内容を変更しても反映されません。反映させるには、そのファイルをコンテナ側にコピーするか、イメージのビルドからし直す必要があり、逐一手間がかかります。ただのタイプミスでもこれをしないといけません。

ファイルの内容を変更したらリアルタイムで反映されたら便利です。そこでバインドマウントをしました。これで、**`index.html`と設定ファイル`default.conf`を自由に変更できます。** 

:::note warn
忘れずに
`default.conf`を変更したら、**コンテナ内で`nginx -s reload`を実行**し、設定ファイルをリロードします。
:::

### ⑤index.htmlにアクセスする
ブラウザから、`http://localhost:8080/index.html`でアクセス（リクエストを送信）します。「root html」が`/etc/nginx/html`と解釈されるならば、私のリクエストは`/etc/nginx/html/index.html`となり、そこに用意してある`index.html`が返ってくるはずです。


<img width="400" alt="スクリーンショット 2024-02-06 195058.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3118500/e88137ee-aa0a-a209-4a0b-584bc685042d.png">

作成したファイルが表示され、意図した結果になりました。つまり、
**「root html」は`--prefix=/etc/nginx`からの相対パスです。**

※`/etc/nginx`は設定ファイルが入っている場所なので、その中にドキュメントルートがあるのは適切でないと思います。絶対パスを使った方がいいと思いました。