1
0
mirror of https://github.com/thib8956/nginx-proxy synced 2025-08-23 07:51:56 +00:00

Merge pull request #2602 from p12tic/acme-unknown-virtual-host

feat: support ACME challenges for unknown virtual hosts
This commit is contained in:
Nicolas Duchon
2025-05-20 00:04:14 +02:00
committed by GitHub
7 changed files with 108 additions and 0 deletions

View File

@@ -459,6 +459,8 @@ By default nginx-proxy generates location blocks to handle ACME HTTP Challenge.
- `false`: do not handle ACME HTTP Challenge at all.
- `legacy`: legacy behavior for compatibility with older (<= `2.3`) versions of acme-companion, only handle ACME HTTP challenge when there is a certificate for the domain and `HTTPS_METHOD=redirect`.
By default, nginx-proxy does not handle ACME HTTP Challenges for unknown virtual hosts. This may happen in cases when a container is not running at the time of the renewal. To enable handling of unknown virtual hosts, set `ACME_HTTP_CHALLENGE_ACCEPT_UNKNOWN_HOST` environment variable to `true` on the nginx-proxy container.
### Diffie-Hellman Groups
[RFC7919 groups](https://datatracker.ietf.org/doc/html/rfc7919#appendix-A) with key lengths of 2048, 3072, and 4096 bits are [provided by `nginx-proxy`](https://github.com/nginx-proxy/nginx-proxy/dhparam). The ENV `DHPARAM_BITS` can be set to `2048` or `3072` to change from the default 4096-bit key. The DH key file will be located in the container at `/etc/nginx/dhparam/dhparam.pem`. Mounting a different `dhparam.pem` file at that location will override the RFC7919 key.

View File

@@ -28,6 +28,7 @@
{{- $_ := set $config "enable_debug_endpoint" ($globals.Env.DEBUG_ENDPOINT | default "false") }}
{{- $_ := set $config "hsts" ($globals.Env.HSTS | default "max-age=31536000") }}
{{- $_ := set $config "acme_http_challenge" ($globals.Env.ACME_HTTP_CHALLENGE_LOCATION | default "true") }}
{{- $_ := set $config "acme_http_challenge_accept_unknown_host" ($globals.Env.ACME_HTTP_CHALLENGE_ACCEPT_UNKNOWN_HOST | default "false" | parseBool) }}
{{- $_ := set $config "enable_http2" ($globals.Env.ENABLE_HTTP2 | default "true") }}
{{- $_ := set $config "enable_http3" ($globals.Env.ENABLE_HTTP3 | default "false") }}
{{- $_ := set $config "enable_http_on_missing_cert" ($globals.Env.ENABLE_HTTP_ON_MISSING_CERT | default "true") }}
@@ -861,6 +862,16 @@ server {
ssl_reject_handshake on;
{{- end }}
{{- if $globals.config.acme_http_challenge_accept_unknown_host }}
location ^~ /.well-known/acme-challenge/ {
auth_basic off;
allow all;
root /usr/share/nginx/html;
try_files $uri =404;
break;
}
{{- end }}
{{- if (exists "/usr/share/nginx/html/errors/50x.html") }}
error_page 500 502 503 504 /50x.html;
location /50x.html {

View File

@@ -0,0 +1,34 @@
def test_redirect_acme_challenge_location_enabled(docker_compose, nginxproxy, acme_challenge_path):
r = nginxproxy.get(
f"http://web1.nginx-proxy.tld/{acme_challenge_path}",
allow_redirects=False
)
assert r.status_code == 200
def test_redirect_acme_challenge_location_disabled(docker_compose, nginxproxy, acme_challenge_path):
r = nginxproxy.get(
f"http://web2.nginx-proxy.tld/{acme_challenge_path}",
allow_redirects=False
)
assert r.status_code == 301
def test_noredirect_acme_challenge_location_enabled(docker_compose, nginxproxy, acme_challenge_path):
r = nginxproxy.get(
f"http://web3.nginx-proxy.tld/{acme_challenge_path}",
allow_redirects=False
)
assert r.status_code == 200
def test_noredirect_acme_challenge_location_disabled(docker_compose, nginxproxy, acme_challenge_path):
r = nginxproxy.get(
f"http://web4.nginx-proxy.tld/{acme_challenge_path}",
allow_redirects=False
)
assert r.status_code == 404
def test_unknown_domain_acme_challenge_location_default_enabled(docker_compose, nginxproxy, acme_challenge_path):
r = nginxproxy.get(
f"http://web-unknown.nginx-proxy.tld/{acme_challenge_path}",
allow_redirects=False
)
assert r.status_code == 200

View File

@@ -0,0 +1,40 @@
services:
nginx-proxy:
environment:
ACME_HTTP_CHALLENGE_ACCEPT_UNKNOWN_HOST: "true"
web1:
image: web
expose:
- "81"
environment:
WEB_PORTS: "81"
VIRTUAL_HOST: "web1.nginx-proxy.tld"
web2:
image: web
expose:
- "82"
environment:
WEB_PORTS: "82"
VIRTUAL_HOST: "web2.nginx-proxy.tld"
ACME_HTTP_CHALLENGE_LOCATION: "false"
web3:
image: web
expose:
- "83"
environment:
WEB_PORTS: "83"
VIRTUAL_HOST: "web3.nginx-proxy.tld"
HTTPS_METHOD: noredirect
web4:
image: web
expose:
- "84"
environment:
WEB_PORTS: "84"
VIRTUAL_HOST: "web4.nginx-proxy.tld"
HTTPS_METHOD: noredirect
ACME_HTTP_CHALLENGE_LOCATION: "false"

View File

@@ -25,3 +25,10 @@ def test_noredirect_acme_challenge_location_enabled(docker_compose, nginxproxy,
allow_redirects=False
)
assert r.status_code == 200
def test_unknown_domain_acme_challenge_location_disabled(docker_compose, nginxproxy, acme_challenge_path):
r = nginxproxy.get(
f"http://web-unknown.nginx-proxy.tld/{acme_challenge_path}",
allow_redirects=False
)
assert r.status_code == 503

View File

@@ -25,3 +25,10 @@ def test_noredirect_acme_challenge_location_disabled(docker_compose, nginxproxy,
allow_redirects=False
)
assert r.status_code == 404
def test_unknown_domain_acme_challenge_location_default_enabled(docker_compose, nginxproxy, acme_challenge_path):
r = nginxproxy.get(
f"http://web-unknown.nginx-proxy.tld/{acme_challenge_path}",
allow_redirects=False
)
assert r.status_code == 503

View File

@@ -11,3 +11,10 @@ def test_noredirect_acme_challenge_location_legacy(docker_compose, nginxproxy, a
allow_redirects=False
)
assert r.status_code == 404
def test_unknown_domain_acme_challenge_location_legacy(docker_compose, nginxproxy, acme_challenge_path):
r = nginxproxy.get(
f"http://web-unknown.nginx-proxy.tld/{acme_challenge_path}",
allow_redirects=False
)
assert r.status_code == 503