Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions nginx-proxy/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,28 @@ deny all;

---

## SSL Certificate Handling

### Certificate Lookup

The proxy automatically detects SSL certificates from `/etc/nginx/certs/`:

```bash
/etc/nginx/certs/example.com.crt
/etc/nginx/certs/example.com.key
```

### Fallback Certificate Behavior

When a vhost is accessed via HTTPS but no matching certificate is found:

1. **If default certificate exists:** Uses `/etc/nginx/certs/default.crt` and returns 503
2. **If no default certificate:** Rejects the SSL/TLS handshake

This prevents certificate warning dialogs in browsers and improves security by not exposing invalid certificates.

---

## Environment Variables

| Variable | Description | Default |
Expand Down
11 changes: 9 additions & 2 deletions nginx-proxy/nginx.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -554,7 +554,7 @@ server {
{{ end }}
}

{{ if (and (not $is_https) (exists "/etc/nginx/certs/default.crt") (exists "/etc/nginx/certs/default.key")) }}
{{ if (and (not $is_https) (ne $https_method "nohttps")) }}
Copy link

Copilot AI Jan 16, 2026

Choose a reason for hiding this comment

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

The condition change creates a server block for all vhosts where $is_https is false and $https_method is not 'nohttps', regardless of whether any certificates exist. This means a fallback HTTPS server block will be created even when $https_method is 'redirect' or 'noredirect' and no default certificate exists. When ssl_reject_handshake on; is used, the server block still requires listen 443 ssl, but nginx may fail to start if there's no certificate at all to bind to the SSL context. The old condition ensured this block was only created when default certificates existed, preventing this issue.

Suggested change
{{ if (and (not $is_https) (ne $https_method "nohttps")) }}
{{ if (and (not $is_https) (ne $https_method "nohttps") (exists "/etc/nginx/certs/default.crt") (exists "/etc/nginx/certs/default.key")) }}

Copilot uses AI. Check for mistakes.
Copy link
Member Author

Choose a reason for hiding this comment

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

Thank you for catching this! You're absolutely right - ssl_reject_handshake on; still requires a valid SSL context to bind the socket, so nginx would fail to start without any certificate.

I've applied your suggested fix in commit 9b7fb39:

  • Restored the default certificate check to the outer condition
  • Removed the ssl_reject_handshake logic entirely
  • Simplified to always use default cert when available

The behavior is now:

  • Default cert exists: Uses it as fallback and returns 503
  • No default cert: No HTTPS server block created for that vhost

This prevents nginx startup failures while maintaining the improved 503 status code.

server {
server_name {{ $host }};
listen 443 ssl {{ $default_server }};
Expand All @@ -563,10 +563,17 @@ server {
listen [::]:443 ssl {{ $default_server }};
http2 on;
{{ end }}
return 500;

{{ if (and (exists "/etc/nginx/certs/default.crt") (exists "/etc/nginx/certs/default.key")) }}
# Use default certificate as fallback
ssl_certificate /etc/nginx/certs/default.crt;
ssl_certificate_key /etc/nginx/certs/default.key;
{{ else }}
# No valid certificate for this vhost nor default certificate found, so reject SSL handshake
ssl_reject_handshake on;
{{ end }}

return 503;
}
{{ end }}

Expand Down
Loading