Skip to content

Fix: SSL toggles reset to off when requesting a new certificate on host creation#5701

Open
adman234 wants to merge 1 commit into
NginxProxyManager:developfrom
adman234:fix/ssl-toggles-lost-on-new-cert-create
Open

Fix: SSL toggles reset to off when requesting a new certificate on host creation#5701
adman234 wants to merge 1 commit into
NginxProxyManager:developfrom
adman234:fix/ssl-toggles-lost-on-new-cert-create

Conversation

@adman234

@adman234 adman234 commented Jul 10, 2026

Copy link
Copy Markdown

Human edit: I apologize for the AI vibe PR, but this is a bug that has bothered me for a while, so hopefully this PR makes sense and is helpful and easy to review. I am not a developer, so I apologize if any of this is not formatted correctly.

Why

When creating a Proxy Host (also affects Redirection Hosts and 404 Hosts) and requesting a brand new Let's Encrypt certificate in the same submission, any SSL-related toggles enabled on the form — Force SSL, HTTP/2 Support, HSTS Enabled, HSTS Subdomains — are silently discarded and saved as false. The certificate itself is created successfully, but the toggles have to be re-enabled manually afterwards.

Root cause

The whole "create host + request cert" flow happens inside a single create() call (e.g. backend/internal/proxy-host.js):

  1. certificate_id is "new" at this point (not a real ID yet), so it's deleted from the payload before the initial row insert.
  2. Immediately before that insert, internalHost.cleanSslHstsData() runs. Its job is to enforce "if there's no certificate, ssl_forced/http2_support/hsts_* must be false" — a legitimate invariant, but it fires here even though a certificate is about to be created a few lines later in the same request. The user's true toggle values get zeroed out, and that zeroed-out row is what actually gets inserted.
  3. After the certificate is created, the code calls update() again to attach the new certificate_id to the host — but that follow-up call only passes { id, certificate_id }. The user's original SSL toggle choices are never re-sent, so they remain false permanently.

Editing an existing host while simultaneously requesting a new certificate does not hit this bug — that code path happens to keep the original submitted data object intact through the certificate-creation step, so the toggles survive. It's specifically the "create a new host + request a new cert" combination that's broken.

The identical defect pattern exists in backend/internal/dead-host.js (404 Hosts) and backend/internal/redirection-host.js (Redirection Hosts), so this PR fixes all three.

What changed

  • Skip the premature cleanSslHstsData() call during the initial insert when a certificate is about to be created (the invariant doesn't apply yet — the certificate is guaranteed to exist by the time the request finishes).
  • Forward the originally-submitted ssl_forced / http2_support / hsts_enabled / hsts_subdomains values in the follow-up update() call that attaches the freshly created certificate_id, so cleanSslHstsData() re-validates them once a real certificate exists.

No API contract changes — the fields accepted/returned are unchanged, only the values actually persisted are corrected.

Testing

  • Verified the corrected logic with a standalone simulation of cleanSslHstsData() reproducing both the old broken output (all SSL fields false after create) and the new correct output (all fields preserved as submitted, once the certificate is attached).
  • biome lint passes clean on all three changed files.
  • Did not run the full Cypress e2e suite (requires a Docker-based ACME/DNS test environment).

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

…ng a new certificate on host creation

When creating a Proxy Host, Redirection Host, or 404 Host and requesting
a brand new Let's Encrypt certificate in the same submission, the
ssl_forced/http2_support/hsts_enabled/hsts_subdomains fields the user
enabled on the form were silently discarded and saved as false.

Root cause: certificate_id is deleted from the payload before the
initial insert (since "new" is not a real certificate id yet), so
cleanSslHstsData() sees no certificate_id and zeroes the SSL toggles
under its "no cert means SSL can't be forced" invariant - even though
a certificate is about to be created moments later in the same
request. The follow-up update() call that attaches the freshly
created certificate_id only passed { id, certificate_id }, so the
user's original toggle values were never re-applied.

Fix: skip the premature cleanSslHstsData() zeroing during the initial
insert when a certificate is being created, and forward the originally
submitted ssl_forced/http2_support/hsts_enabled/hsts_subdomains values
in the follow-up update() call, once the real certificate exists to
validate them against.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@nginxproxymanagerci

Copy link
Copy Markdown

Docker Image for build 1 is available on DockerHub:

nginxproxymanager/nginx-proxy-manager-dev:pr-5701

Note

Ensure you backup your NPM instance before testing this image! Especially if there are database changes.
This is a different docker image namespace than the official image.

Warning

Changes and additions to DNS Providers require verification by at least 2 members of the community!

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