mirror of
https://github.com/Such-Software/wowcheckout.git
synced 2026-10-17 05:51:45 +02:00
With a variable upstream ($ui_upstream, added for docker-DNS re-resolution), a trailing-slash URI in proxy_pass makes nginx forward '/' to the UI for every sub-path, so /_next/static/*.css and /i/<invoice> all return the app index HTML (200 text/html) -> the UI renders unstyled and client routing breaks. Omit the URI to preserve the full request path, matching the /api/ block.
72 lines
2.4 KiB
Plaintext
72 lines
2.4 KiB
Plaintext
limit_req_zone $binary_remote_addr zone=global_rate_limit:10m rate=50r/s;
|
|
|
|
# Docker's embedded DNS (127.0.0.11) lets nginx re-resolve upstream service
|
|
# hostnames. Without `resolver` + a variable-based proxy_pass, nginx resolves
|
|
# `api` / `ui` to an IP once at startup and caches it forever — if the api
|
|
# container is rebuilt and Docker gives it a new IP, nginx keeps hitting the
|
|
# old one and every request returns 502 Bad Gateway until nginx is manually
|
|
# restarted. `valid=10s` bounds the stale window to ~10 seconds.
|
|
resolver 127.0.0.11 valid=10s ipv6=off;
|
|
|
|
# Preserve a trusted outer proxy's HTTPS scheme without reflecting arbitrary
|
|
# client-supplied values into invoice and checkout URLs.
|
|
map $http_x_forwarded_proto $origin_scheme {
|
|
default $scheme;
|
|
http http;
|
|
https https;
|
|
}
|
|
|
|
server {
|
|
listen 80;
|
|
server_name wowcheckout.such.software localhost;
|
|
|
|
limit_req zone=global_rate_limit burst=200 nodelay;
|
|
|
|
if ($request_uri ~* "//+") {
|
|
return 308 $scheme://$host$uri$is_args$args;
|
|
}
|
|
|
|
location /api/ {
|
|
set $api_upstream "api";
|
|
# No URI suffix: nginx preserves the complete /api/v1/... request path.
|
|
proxy_pass http://$api_upstream:8000;
|
|
proxy_http_version 1.1;
|
|
proxy_set_header Host $host;
|
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
proxy_set_header X-Forwarded-Proto $origin_scheme;
|
|
}
|
|
|
|
location /api {
|
|
return 301 /api/;
|
|
}
|
|
|
|
location = /openapi.json {
|
|
set $api_upstream "api";
|
|
proxy_pass http://$api_upstream:8000/openapi.json;
|
|
proxy_http_version 1.1;
|
|
proxy_set_header Host $host;
|
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
proxy_set_header X-Forwarded-Proto $origin_scheme;
|
|
}
|
|
|
|
location /qr/ {
|
|
alias /qr/;
|
|
add_header Cache-Control "public, max-age=31536000, immutable";
|
|
try_files $uri =404;
|
|
}
|
|
|
|
location / {
|
|
set $ui_upstream "ui";
|
|
# No trailing-slash URI: with a VARIABLE upstream, a trailing "/" makes
|
|
# nginx send "/" to the UI for every sub-path (assets, /i/<invoice>), so
|
|
# the app's index HTML is returned for /_next/static/*.css (200 text/html)
|
|
# → the whole UI renders unstyled and client routing dies. Omit the URI so
|
|
# the full request path is preserved, exactly like the /api/ block above.
|
|
proxy_pass http://$ui_upstream:3000;
|
|
proxy_http_version 1.1;
|
|
proxy_set_header Host $host;
|
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
proxy_set_header X-Forwarded-Proto $origin_scheme;
|
|
}
|
|
}
|