Skip to content

fix(proxy): preserve client ports in forwarded Host headers - #5934

Open
lennondotw wants to merge 1 commit into
NginxProxyManager:developfrom
lennondotw:fix/preserve-host-port
Open

lennondotw wants to merge 1 commit into
NginxProxyManager:developfrom
lennondotw:fix/preserve-host-port

Conversation

@lennondotw

Copy link
Copy Markdown

Why

NPM currently forwards Host: $host, which strips the client-facing port. A browser visiting https://router.example.test:233 therefore sends a Host, Origin and Referer containing :233, but the upstream receives a Host without it. Applications that compare these values can reject authenticated requests even though the proxy connects successfully.

This was reproduced on an ASUS router: read/save endpoints returned HTTP 200 with an HTML script redirecting to the login page, instead of reading or persisting settings. Preserving $http_host fixed the requests; restoring the old header in the same session reproduced the failure.

Changes

  • Preserve the incoming Host authority, including its port, by default. An HTTP-level map uses $http_host when present and falls back to $host when absent.
  • Use the same mapped value in the shared default-location proxy include and the generated custom-location template.
  • Add a built-image regression test and run it after the image build in scripts/ci/test-and-build. It renders an actual proxy host through the backend generator and sends GET/POST requests to a synthetic HTTPS upstream that validates Host against Origin and Referer.

The upstream connection address/port remains independently configured. This forwards the port actually present in the request; it does not append a configured public port to every Host. No UI option, API field or database migration is added.

Compatibility

This changes the default forwarded Host for requests with explicit ports; original hostname casing is preserved as well. Host values without a port remain without a port, and HTTP/1.0 requests without Host retain a nonempty $host fallback. Existing full location / overrides continue to control their own headers. Generated configurations pick up the change when created or regenerated.

Related work

Validation

  • 34 built-image request cases passed against the current branch's backend/rootfs layered onto the official v2.16.0 amd64 runtime: HTTP and HTTPS; default and custom locations; implicit and explicit default ports; 232/233; mixed-case names; IPv6 authorities; GET/POST paths, query parameters and bodies; and HTTP/1.0 without Host.
  • The synthetic upstream checks response content, not just HTTP status. The same test against the original Host configuration reproduced the HTTP-200 login-page failure on an explicit-port request.
  • nginx -t, Python syntax, CI shell syntax and git diff --check passed. The new built-image check is wired into upstream CI; upstream Jenkins results remain separate from local validation.

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update
  • Code refactoring
  • API changes
  • Performance improvement
  • Test addition or update

AI Usage

  • AI was used to write this
  • AI was used to review this

Keep the incoming Host authority for default and custom locations, with the existing hostname fallback when Host is absent. Add a built-image regression that validates Host against Origin and Referer and run it after the CI image build.
@nginxproxymanagerci

Copy link
Copy Markdown

CI Error:

/bin/bash: warning: setlocale: LC_ALL: cannot change locale (en_US.UTF-8): No such file or directory
certbot-node: Pulling from nginxproxymanager/nginx-full
Digest: sha256:b577c9ca9a04a63b6e67f667db4092d188fe97589e63b1a18776ed9b9bd561cf
Status: Image is up to date for nginxproxymanager/nginx-full:certbot-node
docker.io/nginxproxymanager/nginx-full:certbot-node
�[1;34m❯ �[1;36mTesting backend ...�[0m
yarn install v1.22.22
[1/4] Resolving packages...
[2/4] Fetching packages...
warning bare-fs@4.8.0: The engine "bare" appears to be invalid.
warning lru.min@1.1.4: The engine "bun" appears to be invalid.
warning lru.min@1.1.4: The engine "deno" appears to be invalid.
warning sql-escaper@1.5.1: The engine "bun" appears to be invalid.
warning sql-escaper@1.5.1: The engine "deno" appears to be invalid.
[3/4] Linking dependencies...
warning " > @apidevtools/json-schema-ref-parser@16.0.2" has unmet peer dependency "@types/json-schema@^7.0.15".
warning " > mysql2@3.24.4" has unmet peer dependency "@types/node@>= 8".
warning " > @apidevtools/swagger-parser@13.0.0" has unmet peer dependency "openapi-types@>=7".
[4/4] Building fresh packages...
Done in 10.96s.
yarn run v1.22.22
$ biome lint .
setup.js:9:8 lint/correctness/noUnusedImports  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

  ! This import is unused.
  
     7 │ import userModel from "./models/user.js";
     8 │ import userPermissionModel from "./models/user_permission.js";
   > 9 │ import fs from "node:fs/promises";
       │        ^^
    10 │ 
    11 │ export const isSetup = async () => {
  
  i Unused imports might be the result of an incomplete refactoring.
  
  i Unsafe fix: Remove the unused imports.
  
      7   7 │   import userModel from "./models/user.js";
      8   8 │   import userPermissionModel from "./models/user_permission.js";
      9     │ - import·fs·from·"node:fs/promises";
     10   9 │   
     11  10 │   export const isSetup = async () => {
  

Checked 92 files in 47ms. No fixes applied.
Found 1 warning.
Done in 0.11s.
�[1;34m❯ �[1;32mTesting Complete�[0m
�[1;34m❯ �[1;36mBuilding ...�[0m
#0 building with "default" instance using docker driver

#1 [internal] load build definition from Dockerfile
#1 transferring dockerfile: 2.35kB done
#1 DONE 0.0s

#2 [internal] load metadata for docker.io/nginxproxymanager/testca:latest
#2 ...

#3 [internal] load metadata for docker.io/nginxproxymanager/nginx-full:certbot-node
#3 DONE 1.0s

#2 [internal] load metadata for docker.io/nginxproxymanager/testca:latest
#2 DONE 1.4s

#4 [internal] load .dockerignore
#4 transferring context: 2B done
#4 DONE 0.0s

#5 [internal] load build context
#5 transferring context: 4.94MB 0.1s done
#5 DONE 0.1s

#6 [testca 1/1] FROM docker.io/nginxproxymanager/testca:latest@sha256:3e23c78c64789b8e95126589dd502127e57bbad6091a5a88a67ffb87a16f6b6a
#6 resolve docker.io/nginxproxymanager/testca:latest@sha256:3e23c78c64789b8e95126589dd502127e57bbad6091a5a88a67ffb87a16f6b6a 0.0s done
#6 DONE 0.1s

#7 [stage-1  1/13] FROM docker.io/nginxproxymanager/nginx-full:certbot-node@sha256:b577c9ca9a04a63b6e67f667db4092d188fe97589e63b1a18776ed9b9bd561cf
#7 resolve docker.io/nginxproxymanager/nginx-full:certbot-node@sha256:b577c9ca9a04a63b6e67f667db4092d188fe97589e63b1a18776ed9b9bd561cf 0.0s done
#7 DONE 0.2s

#8 [stage-1  2/13] RUN echo "fs.file-max = 65535" > /etc/sysctl.conf 	&& apt-get update 	&& apt-get install -y --no-install-recommends jq logrotate 	&& apt-get clean 	&& rm -rf /var/lib/apt/lists/*
#8 0.359 Get:1 http://deb.debian.org/debian trixie InRelease [140 kB]
#8 0.371 Get:2 http://deb.debian.org/debian trixie-updates InRelease [47.3 kB]
#8 0.371 Get:3 http://deb.debian.org/debian-security trixie-security InRelease [43.4 kB]
#8 0.389 Get:4 http://deb.debian.org/debian trixie/main amd64 Packages [9678 kB]
#8 0.437 Get:5 https://deb.nodesource.com/node_22.x nodistro InRelease [12.1 kB]
#8 0.460 Get:6 https://deb.nodesource.com/node_22.x nodistro/main amd64 Packages [12.5 kB]
#8 0.472 Get:7 http://deb.debian.org/debian trixie-updates/main amd64 Packages [4412 B]
#8 0.475 Get:8 http://deb.debian.org/debian-security trixie-security/main amd64 Packages [265 kB]
#8 1.002 Fetched 10.2 MB in 1s (15.4 MB/s)
#8 1.002 Reading package lists...
#8 1.409 Reading package lists...
#8 1.785 Building dependency tree...
#8 1.876 Reading state information...
#8 2.012 jq is already the newest version (1.7.1-6+deb13u4).
#8 2.012 The following additional packages will be installed:
#8 2.013   cron cron-daemon-common libapparmor1 libpopt0 libsystemd-shared
#8 2.013   sensible-utils systemd
#8 2.014 Suggested packages:
#8 2.014   anacron checksecurity supercat bat libarchive13t64 libbpf1 libcryptsetup12
#8 2.014   libdw1t64 libelf1t64 libip4tc2 libpwquality1 libqrencode4 libtss2-rc0t64
#8 2.014   bsd-mailx | mailx systemd-container systemd-homed systemd-userdbd
#8 2.014   systemd-boot systemd-resolved systemd-repart libtss2-tcti-device0 polkitd
#8 2.014 Recommended packages:
#8 2.014   default-mta | mail-transport-agent libkmod2 default-dbus-system-bus
#8 2.014   | dbus-system-bus linux-sysctl-defaults systemd-timesyncd | time-daemon
#8 2.014   systemd-cryptsetup
#8 2.088 The following NEW packages will be installed:
#8 2.089   cron cron-daemon-common libapparmor1 libpopt0 libsystemd-shared logrotate
#8 2.089   sensible-utils systemd
#8 2.115 0 upgraded, 8 newly installed, 0 to remove and 2 not upgraded.
#8 2.115 Need to get 5528 kB of archives.
#8 2.115 After this operation, 18.1 MB of additional disk space will be used.
#8 2.115 Get:1 http://deb.debian.org/debian trixie/main amd64 libsystemd-shared amd64 257.13-1~deb13u1 [2155 kB]
#8 ...

#6 [testca 1/1] FROM docker.io/nginxproxymanager/testca:latest@sha256:3e23c78c64789b8e95126589dd502127e57bbad6091a5a88a67ffb87a16f6b6a
#6 sha256:f19dea81e0af6255cb52700a24ca2dec7ff42c12c20486f1bd6e7fac5c735db3 16.68MB / 16.68MB 1.2s done
#6 sha256:02f8984a1ccdd4c2c8252b3702bce71f3baaaf94f2663c910316b8a3e17bc16d 5.79MB / 5.79MB 1.2s done
#6 sha256:59043673e5af8c5511ac545b23eb3e1d018bd25a54698cc89c668e6be7cd82e5 14.58MB / 14.58MB 1.2s done
#6 sha256:3882371c5807b6189df26b2c3139baab81e7ceee303ec493ac1c9f8445fb7171 9.38MB / 9.38MB 1.2s done
#6 sha256:3fa522a93ff59fea4d76dd73dee00a40066f8ee2485138605e9f177fd52df526 7.03MB / 7.03MB 0.8s done
#6 sha256:589002ba0eaed121a1dbf42f6648f29e5be55d5c8a6ee0f8eaa0285cc21ac153 3.86MB / 3.86MB 0.9s done
#6 extracting sha256:589002ba0eaed121a1dbf42f6648f29e5be55d5c8a6ee0f8eaa0285cc21ac153 0.1s done
#6 extracting sha256:3fa522a93ff59fea4d76dd73dee00a40066f8ee2485138605e9f177fd52df526 0.1s done
#6 DONE 2.4s

#8 [stage-1  2/13] RUN echo "fs.file-max = 65535" > /etc/sysctl.conf 	&& apt-get update 	&& apt-get install -y --no-install-recommends jq logrotate 	&& apt-get clean 	&& rm -rf /var/lib/apt/lists/*
#8 2.133 Get:2 http://deb.debian.org/debian trixie/main amd64 libapparmor1 amd64 4.1.0-1 [43.7 kB]
#8 2.133 Get:3 http://deb.debian.org/debian trixie/main amd64 systemd amd64 257.13-1~deb13u1 [3094 kB]
#8 2.157 Get:4 http://deb.debian.org/debian trixie/main amd64 cron-daemon-common all 3.0pl1-197 [17.8 kB]
#8 2.158 Get:5 http://deb.debian.org/debian trixie/main amd64 sensible-utils all 0.0.25 [25.0 kB]
#8 2.158 Get:6 http://deb.debian.org/debian trixie/main amd64 cron amd64 3.0pl1-197 [87.4 kB]
#8 2.159 Get:7 http://deb.debian.org/debian trixie/main amd64 libpopt0 amd64 1.19+dfsg-2 [43.8 kB]
#8 2.159 Get:8 http://deb.debian.org/debian trixie/main amd64 logrotate amd64 3.22.0-1 [62.0 kB]
#8 2.270 debconf: unable to initialize frontend: Dialog
#8 2.270 debconf: (TERM is not set, so the dialog frontend is not usable.)
#8 2.270 debconf: falling back to frontend: Readline
#8 2.278 debconf: unable to initialize frontend: Readline
#8 2.278 debconf: (This frontend requires a controlling tty.)
#8 2.278 debconf: falling back to frontend: Teletype
#8 2.282 debconf: unable to initialize frontend: Teletype
#8 2.282 debconf: (This frontend requires a controlling tty.)
#8 2.282 debconf: falling back to frontend: Noninteractive
#8 2.679 Fetched 5528 kB in 0s (89.1 MB/s)
#8 2.694 Selecting previously unselected package libsystemd-shared:amd64.
#8 2.695 (Reading database ... 
(Reading database ... 5%
(Reading database ... 10%
(Reading database ... 15%
(Reading database ... 20%
(Reading database ... 25%
(Reading database ... 30%
(Reading database ... 35%
(Reading database ... 40%
(Reading database ... 45%
(Reading database ... 50%
(Reading database ... 55%
(Reading database ... 60%
(Reading database ... 65%
(Reading database ... 70%
(Reading database ... 75%
(Reading database ... 80%
(Reading database ... 85%
(Reading database ... 90%
(Reading database ... 95%
(Reading database ... 100%
(Reading database ... 25073 files and directories currently installed.)
#8 2.727 Preparing to unpack .../libsystemd-shared_257.13-1~deb13u1_amd64.deb ...
#8 2.728 Unpacking libsystemd-shared:amd64 (257.13-1~deb13u1) ...
#8 2.808 Selecting previously unselected package libapparmor1:amd64.
#8 ...

#6 [testca 1/1] FROM docker.io/nginxproxymanager/testca:latest@sha256:3e23c78c64789b8e95126589dd502127e57bbad6091a5a88a67ffb87a16f6b6a
#6 extracting sha256:59043673e5af8c5511ac545b23eb3e1d018bd25a54698cc89c668e6be7cd82e5 0.2s done
#6 extracting sha256:4f4fb700ef54461cfa02571ae0db9a0dc1e0cdb5577484a6d75e68dc38e8acc1 done
#6 extracting sha256:f19dea81e0af6255cb52700a24ca2dec7ff42c12c20486f1bd6e7fac5c735db3 0.2s done
#6 extracting sha256:3882371c5807b6189df26b2c3139baab81e7ceee303ec493ac1c9f8445fb7171 0.1s done
#6 extracting sha256:987ab97de7c8e28cebb6b45a2546298654c7d25b24720c371d04838152bb3e95 0.0s done
#6 extracting sha256:87bb61d514f352ddbfaeda815962d65f539bf694020edbdc3d6999bd44d3e850 done
#6 extracting sha256:ae0d12ef9e143f283accd0e8eee98e0829bc912246bf1ca4656335338b55894d done
#6 extracting sha256:38343e689e15c8e5e806a81f5d267ebc654a64c4ba8710bb40c6f8dee3251e5a done
#6 extracting sha256:02f8984a1ccdd4c2c8252b3702bce71f3baaaf94f2663c910316b8a3e17bc16d 0.1s done
#6 DONE 3.1s

#8 [stage-1  2/13] RUN echo "fs.file-max = 65535" > /etc/sysctl.conf 	&& apt-get update 	&& apt-get install -y --no-install-recommends jq logrotate 	&& apt-get clean 	&& rm -rf /var/lib/apt/lists/*
#8 2.809 Preparing to unpack .../libapparmor1_4.1.0-1_amd64.deb ...
#8 2.811 Unpacking libapparmor1:amd64 (4.1.0-1) ...
#8 2.827 Setting up libsystemd-shared:amd64 (257.13-1~deb13u1) ...
#8 2.844 Selecting previously unselected package systemd.
#8 2.844 (Reading database ... 
(Reading database ... 5%
(Reading database ... 10%
(Reading database ... 15%
(Reading database ... 20%
(Reading database ... 25%
(Reading database ... 30%
(Reading database ... 35%
(Reading database ... 40%
(Reading database ... 45%
(Reading database ... 50%
(Reading database ... 55%
(Reading database ... 60%
(Reading database ... 65%
(Reading database ... 70%
(Reading database ... 75%
(Reading database ... 80%
(Reading database ... 85%
(Reading database ... 90%
(Reading database ... 95%
(Reading database ... 100%
(Reading database ... 25086 files and directories currently installed.)
#8 2.851 Preparing to unpack .../systemd_257.13-1~deb13u1_amd64.deb ...
#8 2.862 Unpacking systemd (257.13-1~deb13u1) ...
#8 3.276 Selecting previously unselected package cron-daemon-common.
#8 3.278 Preparing to unpack .../cron-daemon-common_3.0pl1-197_all.deb ...
#8 3.279 Unpacking cron-daemon-common (3.0pl1-197) ...
#8 3.292 Selecting previously unselected package sensible-utils.
#8 3.293 Preparing to unpack .../sensible-utils_0.0.25_all.deb ...
#8 3.294 Unpacking sensible-utils (0.0.25) ...
#8 3.310 Setting up libapparmor1:amd64 (4.1.0-1) ...
#8 3.311 Setting up systemd (257.13-1~deb13u1) ...
#8 3.325 Created symlink '/etc/systemd/system/getty.target.wants/getty@tty1.service' → '/usr/lib/systemd/system/getty@.service'.
#8 3.329 Created symlink '/etc/systemd/system/multi-user.target.wants/remote-fs.target' → '/usr/lib/systemd/system/remote-fs.target'.
#8 3.333 Created symlink '/etc/systemd/system/sysinit.target.wants/systemd-pstore.service' → '/usr/lib/systemd/system/systemd-pstore.service'.
#8 3.336 Initializing machine ID from random generator.
#8 3.352 Creating group 'systemd-journal' with GID 999.
#8 3.352 Creating group 'systemd-network' with GID 998.
#8 3.352 Creating user 'systemd-network' (systemd Network Management) with UID 998 and GID 998.
#8 3.360 /usr/lib/tmpfiles.d/legacy.conf:14: Duplicate line for path "/run/lock", ignoring.
#8 3.369 Setting up cron-daemon-common (3.0pl1-197) ...
#8 3.378 Creating group 'crontab' with GID 997.
#8 3.401 Selecting previously unselected package cron.
#8 3.401 (Reading database ... 
(Reading database ... 5%
(Reading database ... 10%
(Reading database ... 15%
(Reading database ... 20%
(Reading database ... 25%
(Reading database ... 30%
(Reading database ... 35%
(Reading database ... 40%
(Reading database ... 45%
(Reading database ... 50%
(Reading database ... 55%
(Reading database ... 60%
(Reading database ... 65%
(Reading database ... 70%
(Reading database ... 75%
(Reading database ... 80%
(Reading database ... 85%
(Reading database ... 90%
(Reading database ... 95%
(Reading database ... 100%
(Reading database ... 26068 files and directories currently installed.)
#8 3.409 Preparing to unpack .../cron_3.0pl1-197_amd64.deb ...
#8 3.411 Unpacking cron (3.0pl1-197) ...
#8 3.424 Selecting previously unselected package libpopt0:amd64.
#8 3.426 Preparing to unpack .../libpopt0_1.19+dfsg-2_amd64.deb ...
#8 3.426 Unpacking libpopt0:amd64 (1.19+dfsg-2) ...
#8 3.440 Selecting previously unselected package logrotate.
#8 3.442 Preparing to unpack .../logrotate_3.22.0-1_amd64.deb ...
#8 3.442 Unpacking logrotate (3.22.0-1) ...
#8 3.458 Setting up sensible-utils (0.0.25) ...
#8 3.460 Setting up libpopt0:amd64 (1.19+dfsg-2) ...
#8 3.461 Setting up cron (3.0pl1-197) ...
#8 3.478 invoke-rc.d: could not determine current runlevel
#8 3.482 invoke-rc.d: policy-rc.d denied execution of start.
#8 3.561 Created symlink '/etc/systemd/system/multi-user.target.wants/cron.service' → '/usr/lib/systemd/system/cron.service'.
#8 3.564 Setting up logrotate (3.22.0-1) ...
#8 3.646 Created symlink '/etc/systemd/system/timers.target.wants/logrotate.timer' → '/usr/lib/systemd/system/logrotate.timer'.
#8 3.649 Processing triggers for libc-bin (2.41-12+deb13u4) ...
#8 DONE 3.8s

#9 [stage-1  3/13] COPY docker/scripts/install-s6 /tmp/install-s6
#9 DONE 0.0s

#10 [stage-1  4/13] RUN /tmp/install-s6 "linux/amd64" && rm -f /tmp/install-s6
#10 0.149 �[1;34m❯ �[1;36mInstalling S6-overlay v3.2.3.0 for �[1;33mlinux/amd64 (x86_64)�[0m
#10 0.158   % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
#10 0.158                                  Dload  Upload   Total   Spent    Left  Speed
#10 0.158 
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
#10 0.721 
100  6968  100  6968    0     0  12391      0 --:--:-- --:--:-- --:--:-- 12391
100  6968  100  6968    0     0  12388      0 --:--:-- --:--:-- --:--:--     0
#10 0.729   % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
#10 0.729                                  Dload  Upload   Total   Spent    Left  Speed
#10 0.729 
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
#10 1.293 
100  705k  100  705k    0     0  1250k      0 --:--:-- --:--:-- --:--:-- 1250k
#10 1.343 �[1;34m❯ �[1;32mS6-overlay install Complete�[0m
#10 DONE 1.4s

#11 [stage-1  5/13] COPY backend       /app
#11 DONE 0.0s

#12 [stage-1  6/13] COPY frontend/dist /app/frontend
#12 DONE 0.0s

#13 [stage-1  7/13] COPY docker/rootfs /
#13 DONE 0.0s

#14 [stage-1  8/13] COPY --from=testca /home/step/certs/root_ca.crt /etc/ssl/certs/NginxProxyManager.crt
#14 DONE 0.0s

#15 [stage-1  9/13] WORKDIR /etc/ssl/certs
#15 DONE 0.0s

#16 [stage-1 10/13] RUN ln -s NginxProxyManager.crt 1d0e3f10.0 && update-ca-certificates
#16 0.156 Updating certificates in /etc/ssl/certs...
#16 0.725 0 added, 0 removed; done.
#16 0.725 Running hooks in /etc/ca-certificates/update.d...
#16 0.726 done.
#16 DONE 0.7s

#17 [stage-1 11/13] WORKDIR /app
#17 DONE 0.0s

#18 [stage-1 12/13] RUN yarn install 	&& yarn cache clean
#18 0.315 yarn install v1.22.22
#18 0.346 [1/4] Resolving packages...
#18 0.406 [2/4] Fetching packages...
#18 5.922 warning bare-fs@4.8.0: The engine "bare" appears to be invalid.
#18 5.923 warning lru.min@1.1.4: The engine "bun" appears to be invalid.
#18 5.923 warning lru.min@1.1.4: The engine "deno" appears to be invalid.
#18 5.923 warning sql-escaper@1.5.1: The engine "bun" appears to be invalid.
#18 5.923 warning sql-escaper@1.5.1: The engine "deno" appears to be invalid.
#18 5.925 [3/4] Linking dependencies...
#18 5.926 warning " > @apidevtools/json-schema-ref-parser@16.0.2" has unmet peer dependency "@types/json-schema@^7.0.15".
#18 5.926 warning " > mysql2@3.24.4" has unmet peer dependency "@types/node@>= 8".
#18 5.926 warning " > @apidevtools/swagger-parser@13.0.0" has unmet peer dependency "openapi-types@>=7".
#18 6.722 [4/4] Building fresh packages...
#18 11.00 Done in 10.69s.
#18 11.11 yarn cache v1.22.22
#18 11.58 success Cleared cache.
#18 11.58 Done in 0.47s.
#18 DONE 11.7s

#19 [stage-1 13/13] RUN rm -rf /etc/s6-overlay/s6-rc.d/user/contents.d/frontend /etc/nginx/conf.d/dev.conf 	&& chmod 644 /etc/logrotate.d/nginx-proxy-manager
#19 DONE 0.2s

#20 exporting to image
#20 exporting layers
#20 exporting layers 4.5s done
#20 exporting manifest sha256:2e97a03ba1ece76f18968f5d8c79659fb222dc312446a7e9448fa6885151110d done
#20 exporting config sha256:6f18502b42d5f8d881cc7e29991ba720a7633e6ebb8280c9e497fec37256aae0 done
#20 exporting attestation manifest sha256:e60f21ef930117202ef200699a9afa77ef2ac4296d2d495a60d2a386d1de79a0 done
#20 exporting manifest list sha256:4900c4ecdec18fb2acf41c06ce4fefd91c639fb0ddb06a3e1a2f04befe09fbe3 done
#20 naming to docker.io/library/nginx-proxy-manager:pr-5934-ci-1 done
#20 unpacking to docker.io/library/nginx-proxy-manager:pr-5934-ci-1
#20 unpacking to docker.io/library/nginx-proxy-manager:pr-5934-ci-1 1.4s done
#20 DONE 6.0s
�[1;34m❯ �[1;32mBuilding Complete�[0m
[10/8/2026] [7:53:56 AM] [Migrate  ] › ℹ  info      [settings] Migrating Up...
[10/8/2026] [7:53:56 AM] [Migrate  ] › ℹ  info      [settings] setting Table created
[10/8/2026] [7:53:56 AM] [Migrate  ] › ℹ  info      [access_list_client] Migrating Up...
[10/8/2026] [7:53:56 AM] [Migrate  ] › ℹ  info      [access_list_client] access_list_client Table created
[10/8/2026] [7:53:56 AM] [Migrate  ] › ℹ  info      [access_list_client] access_list Table altered
[10/8/2026] [7:53:56 AM] [Migrate  ] › ℹ  info      [access_list_client_fix] Migrating Up...
[10/8/2026] [7:53:56 AM] [Migrate  ] › ℹ  info      [access_list_client_fix] access_list Table altered
[10/8/2026] [7:53:56 AM] [Migrate  ] › ℹ  info      [pass_auth] Migrating Up...
[10/8/2026] [7:53:56 AM] [Migrate  ] › ℹ  info      [pass_auth] access_list Table altered
[10/8/2026] [7:53:56 AM] [Migrate  ] › ℹ  info      [redirection_scheme] Migrating Up...
[10/8/2026] [7:53:56 AM] [Migrate  ] › ℹ  info      [redirection_scheme] redirection_host Table altered
[10/8/2026] [7:53:56 AM] [Migrate  ] › ℹ  info      [redirection_status_code] Migrating Up...
[10/8/2026] [7:53:56 AM] [Migrate  ] › ℹ  info      [redirection_status_code] redirection_host Table altered
[10/8/2026] [7:53:56 AM] [Migrate  ] › ℹ  info      [stream_domain] Migrating Up...
[10/8/2026] [7:53:56 AM] [Migrate  ] › ℹ  info      [stream_domain] stream Table altered
[10/8/2026] [7:53:56 AM] [Migrate  ] › ℹ  info      [stream_domain] Migrating Up...
[10/8/2026] [7:53:56 AM] [Migrate  ] › ℹ  info      [stream_ssl] Migrating Up...
[10/8/2026] [7:53:56 AM] [Migrate  ] › ℹ  info      [stream_ssl] stream Table altered
[10/8/2026] [7:53:56 AM] [Migrate  ] › ℹ  info      [redirect_auto_scheme] Migrating Up...
[10/8/2026] [7:53:56 AM] [Migrate  ] › ℹ  info      [redirect_auto_scheme] redirection_host Table altered
[10/8/2026] [7:53:56 AM] [Migrate  ] › ℹ  info      [trust_forwarded_proto] Migrating Up...
[10/8/2026] [7:53:56 AM] [Migrate  ] › ℹ  info      [trust_forwarded_proto] proxy_host Table altered
[10/8/2026] [7:53:56 AM] [Setup    ] › ℹ  info      Default settings added
[10/8/2026] [7:53:56 AM] [Setup    ] › ℹ  info      Logrotate Timer initialized
[10/8/2026] [7:53:56 AM] [Setup    ] › ℹ  info      Logrotate completed.
[10/8/2026] [7:53:56 AM] [Global   ] › ℹ  info      IP Ranges fetch is disabled by environment variable
[10/8/2026] [7:53:56 AM] [SSL      ] › ℹ  info      Let's Encrypt Renewal Timer initialized
[10/8/2026] [7:53:56 AM] [SSL      ] › ℹ  info      Renewing SSL certs expiring within 30 days ...
[10/8/2026] [7:53:56 AM] [SSL      ] › ℹ  info      Completed SSL cert renew process
[10/8/2026] [7:53:56 AM] [Global   ] › ℹ  info      Backend PID 230 listening on port 3000 ...
Traceback (most recent call last):
  File "/var/lib/jenkins-npm-node/workspace/nginx-proxy-manager_PR-5934/test/host-header-smoke.py", line 167, in <module>
    check_image(sys.argv[1])
    ~~~~~~~~~~~^^^^^^^^^^^^^
  File "/var/lib/jenkins-npm-node/workspace/nginx-proxy-manager_PR-5934/test/host-header-smoke.py", line 103, in check_image
    raise AssertionError("Manager health endpoint did not become ready")
AssertionError: Manager health endpoint did not become ready

@greptile-apps

greptile-apps Bot commented Oct 8, 2026 •

Copy link
Copy Markdown

RetriggerConfidence Score: 4/5

[High risk] Changes how the proxy forwards Host headers to upstreams.

Update the asset cache key before merging so different client ports cannot receive each other's cached files.

Findings

  1. P1 Cached files cross ports ▶
  2. P2 Correct builds can fail ▶

Summary

Preserves the incoming Host, including its port and casing, for default and custom proxy locations. Requests without Host fall back to $host.

  • Adds a built-image test with 34 HTTP and HTTPS request cases.
  • Runs the test after the CI image build.
  • Asset caching needs a matching cache-key change.
  • The new test should wait for the generated host rather than sleep for one second.
Diagram
%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[Client request] --> B{Host present?}
  B -->|Yes| C[Use incoming Host]
  B -->|No| D[Use nginx host fallback]
  C --> E[forward_host]
  D --> E
  E --> F[Default or custom location]
  F --> G[Upstream receives Host]
  F --> H[Cached asset location]
  H --> I[Cache key still excludes client port]
Loading

Reviews (1) · Last reviewed commit: "fix(proxy): preserve client ports in for..." · Reviewed by Greptile

@@ -1,5 +1,5 @@
add_header X-Served-By $host;
proxy_set_header Host $host;
proxy_set_header Host $forward_host;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Cached files cross ports

With asset caching enabled, this include now forwards a port-specific Host, but assets.conf still uses proxy_cache_key $host$request_uri. Requests for the same JavaScript file at example.test:232 and example.test:233 therefore share a cache entry. If the upstream returns port-specific links, users on one port can receive links pointing to the other.

Include the forwarded authority in the asset cache key and add a two-port cache test.

Comment thread test/host-header-smoke.py
Comment on lines +115 to +116
docker("exec", name, "nginx", "-s", "reload")
time.sleep(1)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Correct builds can fail

The test waits one second after signaling an Nginx reload, then rejects the first unexpected response. Reloading does not wait for the new workers to serve the generated host, so a busy CI machine can still return the old default page and fail a correct build.

Replace the fixed sleep with a bounded readiness check for the generated host and upstream before running the assertions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant