状況
Dockerでnginxとnode環境(Nuxt.js)を構築して、リバースプロキシを介してNuxtアプリにアクセスすることを試みた。
version: '3.9'
services:
proxy:
image: nginx:1.21.0
volumes:
- ./proxy/nginx.conf:/etc/nginx/nginx.conf
ports:
- '80:80'
web:
build:
context: ./web
dockerfile: Dockerfile
command: yarn dev
volumes:
- ./web:/app
tty: true
environment:
PORT: 3000
HOST: 0.0.0.0
ports:
- '3000:3000'
events {}
http {
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://host.docker.internal:3000/;
}
}
}
この設定で、http://localhost/ へアクセスすると、リバースプロキシを介してNuxtアプリにアクセスできる。
しかし、途中でlocation
を/
から/app/
に変更して、http://localhost/app/ の形でアクセスできるようにしたくなった。
events {}
http {
server {
listen 80;
server_name localhost;
location /app/ { # ここを変更
proxy_pass http://host.docker.internal:3000/;
}
}
}
nginx.conf
を書き換えて、http://localhost/app/ にアクセスしたところ、こんなエラーが発生した。
[error] 25#25: *1 open() "/etc/nginx/html/_nuxt/runtime.js" failed (2: No such file or directory)
ブラウザにはLoading Circleが表示されているので、Nuxtアプリ自体にはアクセスできているようだが、読み込めていないファイルがあるらしい。
エラー表記から_nuxt/runtime.js
の参照先がおかしいことがわかる。
本来であれば、localhost:3000
にホストされている_nuxt/runtime.js
を参照したいところが、localhost
にホストされている_nuxt/runtime.js
を見に行ってしまっている。
解決までの道のり
まず、NuxtのbaseURLを/
から/app/
に変更した。
export default {
// これを追記
router: {
base: '/app/'
}
}
こうすることで、localhost
ではなく、localhost/app
にホストされている_nuxt/runtime.js
を参照することになり、リバースプロキシによってlocalhost/app
からlocalhost:3000
へ飛ばされるので、結果的にlocalhost:3000
にホストされている_nuxt/runtime.js
を見に行くことになる。
よし、解決!
と思ったが、別の問題が発生した。
リダイレクトが無限に繰り返されるようになってしまった。
メカニズムとしてはこんな感じ。
-
localhost/app
にアクセス - リバースプロキシが
localhost:3000
に読み替え - NuxtのbaseURLは
/app/
なので、localhost:3000
からlocalhost:3000/app
にリダイレクト - 結果的にURLは
localhost/app
になる - 1へ戻る
baseURLを書き換えたときにリバースプロキシの設定も書き換える必要があった。
events {}
http {
server {
listen 80;
server_name localhost;
location /app/ {
proxy_pass http://host.docker.internal:3000/app/; # ここを変更
}
}
}
http://localhost/app にアクセスすると、ちゃんとサイトが表示されました。
今度こそ解決!! ٩(ˊωˋ*)و
別解
proxy_pass
を設定するときには、trailing slash(後ろに付けるスラッシュ)に気をつける必要がある。
詳しくはこちら↓の解説記事を参照。
https://www.xmisao.com/2014/05/09/nginx-proxy-pass.html
trailing slashを付けずにproxy_pass
を設定すると、飛び先のURLには、location
の文字列も付与されるようになる。
これを利用して、最後のnginx.conf
の書き換えを以下のようにしてもOK
events {}
http {
server {
listen 80;
server_name localhost;
location /app/ {
# proxy_pass http://host.docker.internal:3000/app/;
proxy_pass http://host.docker.internal:3000; # これでもOK
}
}
}