From 023a3d17daa7c274b57af9089bca236c617491c0 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Sun, 3 Nov 2024 21:06:23 +0100 Subject: [PATCH] fix: force enable HTTP when both vhost and default cert are missing --- docs/README.md | 10 ++++------ nginx.tmpl | 6 ++++-- test/test_fallback.data/nohttp-on-app.yml | 2 +- .../nohttp-with-missing-cert.yml | 2 +- test/test_fallback.data/nohttp.yml | 2 +- test/test_fallback.py | 16 ++++++++-------- 6 files changed, 19 insertions(+), 19 deletions(-) diff --git a/docs/README.md b/docs/README.md index 2ee008a..0462922 100644 --- a/docs/README.md +++ b/docs/README.md @@ -580,13 +580,11 @@ By default, [HTTP Strict Transport Security (HSTS)](https://developer.mozilla.or ### Missing Certificate -If no matching certificate is found for a given virtual host, nginx-proxy will: +If no matching certificate is found for a given virtual host, nginx-proxy will configure nginx to use the default certificate (`default.crt` with `default.key`). -- configure nginx to use the default certificate (`default.crt` with `default.key`), -- force enable HTTP; i.e. `HTTPS_METHOD` will switch to `noredirect` if it was set to `nohttp` or `redirect`. - If this switch to HTTP is not wanted set `ENABLE_HTTP_ON_MISSING_CERT=false` (default is `true`). - -If the default certificate is also missing, nginx-proxy will configure nginx to reject the SSL handshake. Client browsers will render a TLS error page. As of October 2024, web browsers display the following error messages: +If the default certificate is also missing, nginx-proxy will: +- force enable HTTP; i.e. `HTTPS_METHOD` will switch to `noredirect` if it was set to `nohttp` or `redirect`. If this switch to HTTP is not wanted set `ENABLE_HTTP_ON_MISSING_CERT=false` (default is `true`). +- configure nginx to reject the SSL handshake for this vhost. Client browsers will render a TLS error page. As of October 2024, web browsers display the following error messages: #### Chrome: diff --git a/nginx.tmpl b/nginx.tmpl index b9b0598..42b9911 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -681,8 +681,10 @@ proxy_set_header Proxy ""; {{- $default := eq $globals.config.default_host $hostname }} {{- $https_method := groupByKeys $vhost_containers "Env.HTTPS_METHOD" | first | default $globals.config.https_method }} {{- $enable_http_on_missing_cert := groupByKeys $vhost_containers "Env.ENABLE_HTTP_ON_MISSING_CERT" | first | default $globals.config.enable_http_on_missing_cert | parseBool }} - {{- /* When the certificate is missing we want to ensure that HTTP is enabled; hence switching from 'nohttp' or 'redirect' to 'noredirect' */}} - {{- if (and $enable_http_on_missing_cert (not $cert_ok) (or (eq $https_method "nohttp") (eq $https_method "redirect"))) }} + {{- /* When both the vhost and default certificates are missing we want to ensure that HTTP is enabled; hence switching from 'nohttp' or 'redirect' to 'noredirect' */}} + {{- $https_method_disable_http := list "nohttp" "redirect" | has $https_method }} + {{- $no_vhost_or_default_cert := or $cert_ok $globals.config.default_cert_ok | not }} + {{- if and $https_method_disable_http $no_vhost_or_default_cert $enable_http_on_missing_cert }} {{- $https_method = "noredirect" }} {{- end }} {{- $http2_enabled := groupByLabel $vhost_containers "com.github.nginx-proxy.nginx-proxy.http2.enable" | keys | first | default $globals.config.enable_http2 | parseBool }} diff --git a/test/test_fallback.data/nohttp-on-app.yml b/test/test_fallback.data/nohttp-on-app.yml index b6ca82a..6d6e390 100644 --- a/test/test_fallback.data/nohttp-on-app.yml +++ b/test/test_fallback.data/nohttp-on-app.yml @@ -5,7 +5,7 @@ services: image: nginxproxy/nginx-proxy:test volumes: - /var/run/docker.sock:/tmp/docker.sock:ro - - ./withdefault.certs:/etc/nginx/certs:ro + - ./nodefault.certs:/etc/nginx/certs:ro environment: HTTPS_METHOD: redirect diff --git a/test/test_fallback.data/nohttp-with-missing-cert.yml b/test/test_fallback.data/nohttp-with-missing-cert.yml index 70ece7b..eb54584 100644 --- a/test/test_fallback.data/nohttp-with-missing-cert.yml +++ b/test/test_fallback.data/nohttp-with-missing-cert.yml @@ -5,7 +5,7 @@ services: image: nginxproxy/nginx-proxy:test volumes: - /var/run/docker.sock:/tmp/docker.sock:ro - - ./withdefault.certs:/etc/nginx/certs:ro + - ./nodefault.certs:/etc/nginx/certs:ro environment: HTTPS_METHOD: nohttp diff --git a/test/test_fallback.data/nohttp.yml b/test/test_fallback.data/nohttp.yml index 9d47d51..0f9db05 100644 --- a/test/test_fallback.data/nohttp.yml +++ b/test/test_fallback.data/nohttp.yml @@ -5,7 +5,7 @@ services: image: nginxproxy/nginx-proxy:test volumes: - /var/run/docker.sock:/tmp/docker.sock:ro - - ./withdefault.certs:/etc/nginx/certs:ro + - ./nodefault.certs:/etc/nginx/certs:ro environment: HTTPS_METHOD: nohttp diff --git a/test/test_fallback.py b/test/test_fallback.py index 13af825..019eafc 100644 --- a/test/test_fallback.py +++ b/test/test_fallback.py @@ -43,7 +43,7 @@ INTERNAL_ERR_RE = re.compile("TLSV1_UNRECOGNIZED_NAME") ("withdefault.yml", "https://https-only.nginx-proxy.test/", 200, None), ("withdefault.yml", "http://http-only.nginx-proxy.test/", 200, None), ("withdefault.yml", "https://http-only.nginx-proxy.test/", 503, None), - ("withdefault.yml", "http://missing-cert.nginx-proxy.test/", 200, None), + ("withdefault.yml", "http://missing-cert.nginx-proxy.test/", 301, None), ("withdefault.yml", "https://missing-cert.nginx-proxy.test/", 200, None), ("withdefault.yml", "http://unknown.nginx-proxy.test/", 503, None), ("withdefault.yml", "https://unknown.nginx-proxy.test/", 503, None), @@ -58,24 +58,24 @@ INTERNAL_ERR_RE = re.compile("TLSV1_UNRECOGNIZED_NAME") ("nodefault.yml", "https://missing-cert.nginx-proxy.test/", None, INTERNAL_ERR_RE), ("nodefault.yml", "http://unknown.nginx-proxy.test/", 503, None), ("nodefault.yml", "https://unknown.nginx-proxy.test/", None, INTERNAL_ERR_RE), - # HTTPS_METHOD=nohttp on nginx-proxy, HTTPS_METHOD unset on the app container. + # HTTPS_METHOD=nohttp on nginx-proxy, no default.crt, HTTPS_METHOD unset on the app container. ("nohttp.yml", "http://https-only.nginx-proxy.test/", 503, None), ("nohttp.yml", "https://https-only.nginx-proxy.test/", 200, None), ("nohttp.yml", "http://unknown.nginx-proxy.test/", 503, None), - ("nohttp.yml", "https://unknown.nginx-proxy.test/", 503, None), - # HTTPS_METHOD=redirect on nginx-proxy, HTTPS_METHOD=nohttp on the app container. + ("nohttp.yml", "https://unknown.nginx-proxy.test/", None, INTERNAL_ERR_RE), + # HTTPS_METHOD=redirect on nginx-proxy, no default.crt, HTTPS_METHOD=nohttp on the app container. ("nohttp-on-app.yml", "http://https-only.nginx-proxy.test/", 503, None), ("nohttp-on-app.yml", "https://https-only.nginx-proxy.test/", 200, None), ("nohttp-on-app.yml", "http://unknown.nginx-proxy.test/", 503, None), - ("nohttp-on-app.yml", "https://unknown.nginx-proxy.test/", 503, None), - # Same as nohttp.yml, except there is a vhost with a missing cert. This causes its + ("nohttp-on-app.yml", "https://unknown.nginx-proxy.test/", None, INTERNAL_ERR_RE), + # Same as nohttp.yml, except there is a vhost with a missing cert. This causes its # HTTPS_METHOD=nohttp setting to effectively become HTTPS_METHOD=noredirect. ("nohttp-with-missing-cert.yml", "http://https-only.nginx-proxy.test/", 503, None), ("nohttp-with-missing-cert.yml", "https://https-only.nginx-proxy.test/", 200, None), ("nohttp-with-missing-cert.yml", "http://missing-cert.nginx-proxy.test/", 200, None), - ("nohttp-with-missing-cert.yml", "https://missing-cert.nginx-proxy.test/", 200, None), + ("nohttp-with-missing-cert.yml", "https://missing-cert.nginx-proxy.test/", None, INTERNAL_ERR_RE), ("nohttp-with-missing-cert.yml", "http://unknown.nginx-proxy.test/", 503, None), - ("nohttp-with-missing-cert.yml", "https://unknown.nginx-proxy.test/", 503, None), + ("nohttp-with-missing-cert.yml", "https://unknown.nginx-proxy.test/", None, INTERNAL_ERR_RE), # HTTPS_METHOD=nohttps on nginx-proxy, HTTPS_METHOD unset on the app container. ("nohttps.yml", "http://http-only.nginx-proxy.test/", 200, None), ("nohttps.yml", "https://http-only.nginx-proxy.test/", None, INTERNAL_ERR_RE),