Skip to content

feat(nginx-proxy): Implement ssl_reject_handshake for missing certificates - #300

Merged
mrrobot47 merged 5 commits into
developfrom
feat/nginx-proxy-ssl-reject-handshake
Nov 4, 2026
Merged

mrrobot47 merged 5 commits into
developfrom
feat/nginx-proxy-ssl-reject-handshake

Conversation

@mrrobot47

@mrrobot47 mrrobot47 commented Jan 16, 2026 •

Copy link
Copy Markdown
Member

Summary

Changes the per-vhost HTTPS fallback in nginx-proxy/nginx.tmpl for vhosts that have no certificate of their own, including HTTPS_METHOD=nohttps vhosts (EasyEngine sets that on every site without SSL).

Problem

On develop, an HTTPS request for a vhost without its own certificate:

  • gets the default certificate and a 500 when /etc/nginx/certs/default.crt and .key exist;
  • gets the certificate of the first HTTPS vhost in the config, and is proxied to that vhost's backend, when there is no default certificate (no fallback block is rendered, so nginx picks the first listen 443 ssl server).

Change

The fallback server block is now rendered for every vhost without a certificate, whether or not a default certificate exists:

  1. Default certificate exists: serves it and returns 503 (same status as the default server).
  2. No default certificate: ssl_reject_handshake on;, so the client gets a TLS alert instead of another site's certificate. This directive needs no certificate (nginx 1.19.4+).

Keeping the block for nohttps vhosts matters: without an exact-name block, HTTPS for a nohttps sub.example.com would match an HTTPS *.example.com vhost and reach its backend.

README: new "SSL Certificate Handling" section.

Testing

Built nginx-proxy from this branch (jwilder/nginx-proxy 1.11.6, nginx 1.31.3) and ran it with docker-gen against test backends in a throwaway Docker-in-Docker container, compared with develop's template:

Case develop this PR
vhost without cert, default cert present default cert, 500 default cert, 503
vhost without cert, no default cert first HTTPS vhost's cert and backend handshake rejected
vhost with its own cert own cert own cert
nohttps vhost, default cert present default cert, 500 default cert, 503
nohttps sub.ms.test next to an HTTPS ms.test,*.ms.test vhost, default cert present default cert, 500 default cert, 503
same, no default cert wildcard vhost's cert and backend handshake rejected
unknown host unchanged unchanged

nginx -t passes in every combination. Unknown hosts are unchanged: without a default certificate they still reach the first HTTPS vhost (EasyEngine always has one, so its default server answers 503). EasyEngine always creates default.crt when it starts the proxy, so on EE hosts the visible change is 500 → 503.

Release

Needs a dockerfiles tag and an nginx-proxy bump in core img-versions.json to reach users.

…cates

Instead of serving 500 errors with default certificates when a vhost
has no valid SSL certificate, nginx now:

1. Uses default certificate (if available) and returns 503
2. Rejects the SSL/TLS handshake entirely (if no default cert)

Benefits:
- Prevents certificate warning dialogs in browsers
- More secure - doesn't expose invalid/default certificates
- Cleaner failure mode for unknown hosts
- Matches upstream jwilder/nginx-proxy behavior

Changes:
- Updated fallback HTTPS server block to use ssl_reject_handshake
- Added condition to check for default certificate availability
- Changed status code from 500 to 503 for better HTTP semantics
- Documented SSL certificate handling behavior in README
Copilot AI review requested due to automatic review settings January 16, 2026 07:59

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This pull request implements the ssl_reject_handshake directive for vhosts without valid SSL certificates, improving security and user experience when accessing non-existent vhosts over HTTPS.

Changes:

  • Modified the fallback HTTPS server block to conditionally use ssl_reject_handshake when no default certificate is available
  • Changed the outer condition from checking default certificate existence to checking HTTPS method configuration
  • Updated error response from 500 to 503 for vhosts without certificates
  • Added comprehensive documentation about SSL certificate handling behavior

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
nginx-proxy/nginx.tmpl Updated fallback HTTPS server block logic to use ssl_reject_handshake when no default certificate exists, and changed condition logic to create the server block based on HTTPS method rather than certificate existence
nginx-proxy/README.md Added new "SSL Certificate Handling" section documenting certificate lookup and fallback behavior

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread nginx-proxy/nginx.tmpl Resolved
Without it, an HTTPS request for a nohttps vhost matches a wildcard HTTPS vhost (e.g. sub.example.com against *.example.com) and is proxied to that site's backend. EasyEngine sets HTTPS_METHOD=nohttps on every site without SSL.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Changes recommended

Removing the exact-name fallback allows HTTPS requests for nohttps hosts to reach a wildcard vhost’s backend instead of returning 503 when a default certificate is present.

1 open issue

Review effort: Balanced

Comment thread nginx-proxy/nginx.tmpl Resolved

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟢 Approval recommended

No active review issues are recorded for the HTTPS fallback changes.

No open issues 🎉

1 resolved since last review

Review effort: Balanced

@mrrobot47
mrrobot47 merged commit e9d44f7 into develop Nov 4, 2026
19 of 20 checks passed
@mrrobot47
mrrobot47 deleted the feat/nginx-proxy-ssl-reject-handshake branch November 4, 2026 11:32
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.

2 participants