Skip to content

feat: support public ports in redirects and host links - #5933

Open
lennondotw wants to merge 1 commit into
NginxProxyManager:developfrom
lennondotw:feat/public-facing-ports
Open

lennondotw wants to merge 1 commit into
NginxProxyManager:developfrom
lennondotw:feat/public-facing-ports

Conversation

@lennondotw

@lennondotw lennondotw commented Oct 7, 2026 •

Copy link
Copy Markdown

Why

Some deployments run in network environments that do not allow incoming connections to TCP ports 80 and 443. They can expose NPM on permitted public ports through Docker mappings or router forwarding, but Force SSL redirects and the manager's host links still assume the standard ports. The generated URLs then point clients at an inaccessible port.

For example, with 232:80 and 233:443, this change makes an HTTP request to http://example.com:232/path?x=1 redirect to https://example.com:233/path?x=1, and makes the manager display and open example.com:233 for a certificate-enabled host.

Changes

  • Add deployment-wide PUBLIC_HTTP_PORT and PUBLIC_HTTPS_PORT, defaulting to 80/443, with validation and support for the existing __FILE mechanism.
  • Keep internal listeners unchanged. Generate the public HTTPS suffix at startup, retain Force SSL's 301 status and ACME/trusted-forwarded-protocol exceptions, and handle HTTP sent to an SSL listener with a 307 redirect for a nonstandard public HTTPS port.
  • Include an additive public_ports object in the existing health response. Proxy, Redirection and 404 Host links select HTTPS when a certificate is configured, otherwise HTTP; nonstandard ports appear in both the label and URL. Certificate-list links retain their existing behavior.
  • Document configuration and add backend, rendered frontend, and disposable-container regression coverage. No database migration or settings form is needed. ACME validation requirements and explicit redirection destinations are unchanged.

This addresses public/client-facing ports, unlike #5212 and #4127, which change Nginx's internal listening ports for host networking. It does not add fork-specific image publishing or deployment automation.

Validation

  • Backend port configuration tests: 4 passed; wired into the existing backend CI script.
  • Full frontend suite: 29 tests passed, including 6 rendered host-link cases; frontend lint and TypeScript/production build passed.
  • Runtime smoke test with the PR files layered onto the official v2.16.0 amd64 image: custom 232/233, defaults 80/443, and file-based 232/233 all passed. Checks cover startup health, nginx -t, GET/POST redirect targets with paths and queries, the ACME exception, trusted forwarded HTTPS, and HTTP sent to the nonstandard SSL port. Run with python3 test/public-ports-smoke.py <built-image>.
  • The core direct-environment-variable implementation is also deployed on a homelab with 27 existing proxy hosts: regenerated proxy configuration, HTTPS response status/Location and certificate fingerprints matched the pre-upgrade baseline, apart from replacing an existing custom 307 Force SSL override with the upstream 301 status.

Related Host-header fix

Related: #5934 preserves the client-facing port in forwarded Host headers, including custom locations and the missing-Host fallback. This PR handles redirects and manager links; #5934 handles upstream request authority. The two changes are based independently on develop and can be reviewed/merged separately.

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

Use client-facing deployment ports in Force SSL redirects and manager host links when default ports are inaccessible. Validate runtime configuration, honor file-based environment variables, and retain standard-port behavior.
@greptile-apps

greptile-apps Bot commented Oct 7, 2026 •

Copy link
Copy Markdown

RetriggerConfidence Score: 4/5

[High risk] Adds port configuration to the web server and API.

The PR is not ready to merge until the SSL-listener redirect works for hosts with custom error pages.

Findings

  1. P1 SSL listener redirect can disappear ▶
  2. P2 Built-image test is omitted ▶

Summary

This PR adds deployment-wide public HTTP and HTTPS ports to Force SSL redirects, SSL-listener redirects, the health response, and manager host links. It also adds documentation and tests.

  • The HTTP-level 497 handler is not reliably inherited by hosts with server-level custom error pages.
  • The new built-image smoke test is not part of the updated backend CI workflow.
Diagram
%%{init: {'theme': 'neutral'}}%%
flowchart LR
  E[Public-port environment] --> P[Container preparation]
  P --> N[Generated Nginx suffix and 497 handler]
  E --> H[Health API]
  H --> L[Manager host links]
  N --> R[Force SSL and SSL-listener redirects]
Loading

Reviews (1) · Last reviewed commit: "feat: support public HTTP and HTTPS port..." · Reviewed by Greptile

"map $host $npm_public_https_port_suffix {",
`\tdefault "${suffix}";`,
"}",
...(ports.https === 443 ? [] : ["error_page 497 =307 https://$host$npm_public_https_port_suffix$request_uri;"]),

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 SSL listener redirect can disappear

If a host’s advanced configuration defines a server-level error_page, such as one for 404 responses, Nginx does not inherit this HTTP-level 497 handler. With a nonstandard public HTTPS port, plain HTTP sent to that host’s SSL listener returns the default error instead of the intended 307 redirect.

Comment thread scripts/ci/test-and-build
-w /app \
"${TESTING_IMAGE}" \
sh -c 'yarn install && yarn lint . && rm -rf node_modules'
sh -c 'yarn install && yarn lint . && node --test lib/public-ports.test.js && rm -rf node_modules'

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 Built-image test is omitted

This CI command runs the new backend unit test, but it never runs the disposable-container smoke test against the image it builds. CI can therefore pass without checking that the image starts with the generated Nginx configuration or serves the new redirects. Adding the smoke test to this workflow would cover those integration failures.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

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