From 73ba28091a8b0bad96ee1f6b02a016c33900bd69 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Fri, 1 Nov 2024 20:32:00 +0100 Subject: [PATCH 01/27] fix: use sha1 hash for config files when using regex host --- nginx.tmpl | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/nginx.tmpl b/nginx.tmpl index 59e35732c..2348ea70b 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -289,7 +289,7 @@ auth_basic "Restricted {{ .Host }}{{ .Path }}"; auth_basic_user_file {{ (printf "/etc/nginx/htpasswd/%s_%s" .Host (sha1 .Path)) }}; {{- else if (exists (printf "/etc/nginx/htpasswd/%s" .Host)) }} - auth_basic "Restricted {{ .Host }}"; + auth_basic "Restricted {{ .HostIsRegexp | ternary "access" .Host }}"; auth_basic_user_file {{ (printf "/etc/nginx/htpasswd/%s" .Host) }}; {{- end }} @@ -570,7 +570,9 @@ proxy_set_header Proxy ""; {{- /* Loop over $globals.vhosts and update it with the remaining informations about each vhost. */}} {{- range $hostname, $vhost_data := $globals.vhosts }} + {{- $is_regexp := hasPrefix "~" $hostname }} {{- $vhost_containers := list }} + {{- range $path, $vpath_data := $vhost_data.paths }} {{- $vpath_containers := list }} {{- range $port, $vport_containers := $vpath_data.ports }} @@ -644,6 +646,7 @@ proxy_set_header Proxy ""; "https_method" $https_method "http2_enabled" $http2_enabled "http3_enabled" $http3_enabled + "is_regexp" $is_regexp "acme_http_challenge_legacy" $acme_http_challenge_legacy "acme_http_challenge_enabled" $acme_http_challenge_enabled "server_tokens" $server_tokens @@ -785,6 +788,23 @@ server { {{- end }} server { + {{- if $vhost.is_regexp }} + {{- if or + (printf "/etc/nginx/vhost.d/%s" $hostname | exists) + (printf "/etc/nginx/vhost.d/%s_location" $hostname | exists) + (printf "/etc/nginx/vhost.d/%s_location_override" $hostname | exists) + (printf "/etc/nginx/htpasswd/%s" $hostname | exists) + }} + # https://github.com/nginx-proxy/nginx-proxy/issues/2529#issuecomment-2437609249 + # Support for vhost config file(s) named like a regexp ({{ $hostname }}) has been removed from nginx-proxy. + # Please name your vhost config file(s) with the sha1 of the regexp instead ({{ $hostname }} -> {{ sha1 $hostname }}) : + # - /etc/nginx/vhost.d/{{ sha1 $hostname }} + # - /etc/nginx/vhost.d/{{ sha1 $hostname }}_location + # - /etc/nginx/vhost.d/{{ sha1 $hostname }}_location_override + # - /etc/nginx/htpasswd/{{ sha1 $hostname }} + {{- end }} + {{- end }} + server_name {{ $hostname }}; {{- if $vhost.server_tokens }} server_tokens {{ $vhost.server_tokens }}; @@ -865,8 +885,10 @@ server { {{- end }} {{- end }} - {{- if (exists (printf "/etc/nginx/vhost.d/%s" $hostname)) }} - include {{ printf "/etc/nginx/vhost.d/%s" $hostname }}; + {{- $vhostFileName := $vhost.is_regexp | ternary (sha1 $hostname) $hostname }} + + {{- if (exists (printf "/etc/nginx/vhost.d/%s" $vhostFileName)) }} + include {{ printf "/etc/nginx/vhost.d/%s" $vhostFileName }}; {{- else if (exists "/etc/nginx/vhost.d/default") }} include /etc/nginx/vhost.d/default; {{- end }} @@ -874,7 +896,8 @@ server { {{- range $path, $vpath := $vhost.paths }} {{- template "location" (dict "Path" $path - "Host" $hostname + "Host" $vhostFileName + "HostIsRegexp" $vhost.is_regexp "VhostRoot" $vhost.vhost_root "VPath" $vpath ) }} From 5baf4a163f4747827e50b29576d70d232fa70f2b Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Fri, 1 Nov 2024 21:36:00 +0100 Subject: [PATCH 02/27] docs: update docs regex file name change --- docs/README.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/docs/README.md b/docs/README.md index 080b86b7e..3990a7a4d 100644 --- a/docs/README.md +++ b/docs/README.md @@ -181,8 +181,9 @@ In this example, the incoming request `http://example.tld/app1/foo` will be prox ### Per-VIRTUAL_PATH location configuration The same options as from [Per-VIRTUAL_HOST location configuration](#Per-VIRTUAL_HOST-location-configuration) are available on a `VIRTUAL_PATH` basis. -The only difference is that the filename gets an additional block `HASH=$(echo -n $VIRTUAL_PATH | sha1sum | awk '{ print $1 }')`. This is the sha1-hash of the `VIRTUAL_PATH` (no newline). This is done filename sanitization purposes. -The used filename is `${VIRTUAL_HOST}_${HASH}_location` +The only difference is that the filename gets an additional block `HASH=$(echo -n $VIRTUAL_PATH | sha1sum | awk '{ print $1 }')`. This is the sha1-hash of the `VIRTUAL_PATH` (no newline). This is done for filename sanitization purposes. + +The used filename is `${VIRTUAL_HOST}_${PATH_HASH}_location`, or when `VIRTUAL_HOST` is a regex, `${VIRTUAL_HOST_HASH}_${PATH_HASH}_location`. The filename of the previous example would be `example.tld_8610f6c344b4096614eab6e09d58885349f42faf_location`. @@ -328,7 +329,7 @@ See the [nginx keepalive documentation](https://nginx.org/en/docs/http/ngx_http_ ## Basic Authentication Support -In order to be able to secure your virtual host, you have to create a file named as its equivalent `VIRTUAL_HOST` variable in directory +In order to be able to secure your virtual host, you have to create a file named as its equivalent `VIRTUAL_HOST` variable (or if using a regex `VIRTUAL_HOST`, as the sha1 hash of the regex) in directory `/etc/nginx/htpasswd/{$VIRTUAL_HOST}` ```console @@ -738,7 +739,7 @@ docker run -d -p 80:80 -p 443:443 -v /path/to/my_proxy.conf:/etc/nginx/conf.d/my ### Per-VIRTUAL_HOST -To add settings on a per-`VIRTUAL_HOST` basis, add your configuration file under `/etc/nginx/vhost.d`. Unlike in the proxy-wide case, which allows multiple config files with any name ending in `.conf`, the per-`VIRTUAL_HOST` file must be named exactly after the `VIRTUAL_HOST`. +To add settings on a per-`VIRTUAL_HOST` basis, add your configuration file under `/etc/nginx/vhost.d`. Unlike in the proxy-wide case, which allows multiple config files with any name ending in `.conf`, the per-`VIRTUAL_HOST` file must be named exactly after the `VIRTUAL_HOST`, or if `VIRTUAL_HOST` is a regex, after the sha1 hash of the regex. In order to allow virtual hosts to be dynamically configured as backends are added and removed, it makes the most sense to mount an external directory as `/etc/nginx/vhost.d` as opposed to using derived images or mounting individual configuration files. @@ -762,7 +763,7 @@ If you want most of your virtual hosts to use a default single configuration and ### Per-VIRTUAL_HOST location configuration -To add settings to the "location" block on a per-`VIRTUAL_HOST` basis, add your configuration file under `/etc/nginx/vhost.d` just like the previous section except with the suffix `_location`. +To add settings to the "location" block on a per-`VIRTUAL_HOST` basis, add your configuration file under `/etc/nginx/vhost.d` just like the per-`VIRTUAL_HOST` section except with the suffix `_location` (like this section, if your `VIRTUAl_HOST` is a regex, use the sha1 hash of the regex instead, with the suffix `_location` appended). For example, if you have a virtual host named `app.example.com` and you have configured a proxy_cache `my-cache` in another custom file, you could tell it to use a proxy cache as follows: @@ -790,7 +791,7 @@ The `${VIRTUAL_HOST}_${PATH_HASH}_location`, `${VIRTUAL_HOST}_location`, and `de /etc/nginx/vhost.d/${VIRTUAL_HOST}_${PATH_HASH}_location_override ``` -where `${VIRTUAL_HOST}` is the name of the virtual host (the `VIRTUAL_HOST` environment variable) and `${PATH_HASH}` is the SHA-1 hash of the path, as [described above](#per-virtual_path-location-configuration). +where `${VIRTUAL_HOST}` is the name of the virtual host (the `VIRTUAL_HOST` environment variable), or the sha1 hash of `VIRTUAL_HOST` when it's a regex, and `${PATH_HASH}` is the SHA-1 hash of the path, as [described above](#per-virtual_path-location-configuration). For convenience, the `_${PATH_HASH}` part can be omitted if the path is `/`: From 1cd7b97e8f6ae014cd2cb1d88447d274642a0850 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Fri, 1 Nov 2024 21:37:29 +0100 Subject: [PATCH 03/27] test: regex vhost file names --- test/test_custom/test_location-per-vhost.py | 7 +++++++ test/test_custom/test_location-per-vhost.yml | 9 +++++++++ test/test_custom/test_per-vhost.py | 7 +++++++ test/test_custom/test_per-vhost.yml | 9 +++++++++ .../561032515ede3ab3a015edfb244608b72409c430 | 1 + .../test_htpasswd_regex_virtual_host.py | 13 +++++++++++++ .../test_htpasswd_regex_virtual_host.yml | 17 +++++++++++++++++ 7 files changed, 63 insertions(+) create mode 100644 test/test_htpasswd/htpasswd/561032515ede3ab3a015edfb244608b72409c430 create mode 100644 test/test_htpasswd/test_htpasswd_regex_virtual_host.py create mode 100644 test/test_htpasswd/test_htpasswd_regex_virtual_host.yml diff --git a/test/test_custom/test_location-per-vhost.py b/test/test_custom/test_location-per-vhost.py index 53a146b55..8218ed073 100644 --- a/test/test_custom/test_location-per-vhost.py +++ b/test/test_custom/test_location-per-vhost.py @@ -12,6 +12,13 @@ def test_custom_conf_applies_to_web1(docker_compose, nginxproxy): assert "X-test" in r.headers assert "f00" == r.headers["X-test"] +def test_custom_conf_applies_to_regex(docker_compose, nginxproxy): + r = nginxproxy.get("http://regex.foo.nginx-proxy.example/port") + assert r.status_code == 200 + assert r.text == "answer from port 83\n" + assert "X-test" in r.headers + assert "bar" == r.headers["X-test"] + def test_custom_conf_does_not_apply_to_web2(docker_compose, nginxproxy): r = nginxproxy.get("http://web2.nginx-proxy.example/port") assert r.status_code == 200 diff --git a/test/test_custom/test_location-per-vhost.yml b/test/test_custom/test_location-per-vhost.yml index 52943086e..5a6164c53 100644 --- a/test/test_custom/test_location-per-vhost.yml +++ b/test/test_custom/test_location-per-vhost.yml @@ -6,6 +6,7 @@ services: volumes: - /var/run/docker.sock:/tmp/docker.sock:ro - ./my_custom_proxy_settings.conf:/etc/nginx/vhost.d/web1.nginx-proxy.example_location:ro + - ./my_custom_proxy_settings_bar.conf:/etc/nginx/vhost.d/561032515ede3ab3a015edfb244608b72409c430_location:ro web1: image: web @@ -22,3 +23,11 @@ services: environment: WEB_PORTS: 82 VIRTUAL_HOST: web2.nginx-proxy.example + + regex: + image: web + expose: + - "83" + environment: + WEB_PORTS: 83 + VIRTUAL_HOST: ~^regex.*\.nginx-proxy\.example$ diff --git a/test/test_custom/test_per-vhost.py b/test/test_custom/test_per-vhost.py index 6a85e6948..7394472d2 100644 --- a/test/test_custom/test_per-vhost.py +++ b/test/test_custom/test_per-vhost.py @@ -12,6 +12,13 @@ def test_custom_conf_applies_to_web1(docker_compose, nginxproxy): assert "X-test" in r.headers assert "f00" == r.headers["X-test"] +def test_custom_conf_applies_to_regex(docker_compose, nginxproxy): + r = nginxproxy.get("http://regex.foo.nginx-proxy.example/port") + assert r.status_code == 200 + assert r.text == "answer from port 83\n" + assert "X-test" in r.headers + assert "bar" == r.headers["X-test"] + def test_custom_conf_does_not_apply_to_web2(docker_compose, nginxproxy): r = nginxproxy.get("http://web2.nginx-proxy.example/port") assert r.status_code == 200 diff --git a/test/test_custom/test_per-vhost.yml b/test/test_custom/test_per-vhost.yml index 63d33b2b1..337fc56f9 100644 --- a/test/test_custom/test_per-vhost.yml +++ b/test/test_custom/test_per-vhost.yml @@ -6,6 +6,7 @@ services: volumes: - /var/run/docker.sock:/tmp/docker.sock:ro - ./my_custom_proxy_settings.conf:/etc/nginx/vhost.d/web1.nginx-proxy.example:ro + - ./my_custom_proxy_settings_bar.conf:/etc/nginx/vhost.d/561032515ede3ab3a015edfb244608b72409c430:ro web1: image: web @@ -22,3 +23,11 @@ services: environment: WEB_PORTS: 82 VIRTUAL_HOST: web2.nginx-proxy.example + + regex: + image: web + expose: + - "83" + environment: + WEB_PORTS: 83 + VIRTUAL_HOST: ~^regex.*\.nginx-proxy\.example$ diff --git a/test/test_htpasswd/htpasswd/561032515ede3ab3a015edfb244608b72409c430 b/test/test_htpasswd/htpasswd/561032515ede3ab3a015edfb244608b72409c430 new file mode 100644 index 000000000..336275a1b --- /dev/null +++ b/test/test_htpasswd/htpasswd/561032515ede3ab3a015edfb244608b72409c430 @@ -0,0 +1 @@ +vhost:$2a$13$/aPYmoK0mmgyAI4TpKdFY.6441Ugo39MdXjhpm.Pp6D15rbz9tvz. diff --git a/test/test_htpasswd/test_htpasswd_regex_virtual_host.py b/test/test_htpasswd/test_htpasswd_regex_virtual_host.py new file mode 100644 index 000000000..1b169d001 --- /dev/null +++ b/test/test_htpasswd/test_htpasswd_regex_virtual_host.py @@ -0,0 +1,13 @@ +import pytest + +def test_htpasswd_regex_virtual_host_is_restricted(docker_compose, nginxproxy): + r = nginxproxy.get("http://regex.htpasswd.nginx-proxy.example/port") + assert r.status_code == 401 + assert "WWW-Authenticate" in r.headers + assert r.headers["WWW-Authenticate"] == 'Basic realm="Restricted access"' + + +def test_htpasswd_regex_virtual_host_basic_auth(docker_compose, nginxproxy): + r = nginxproxy.get("http://regex.htpasswd.nginx-proxy.example/port", auth=("vhost", "password")) + assert r.status_code == 200 + assert r.text == "answer from port 80\n" diff --git a/test/test_htpasswd/test_htpasswd_regex_virtual_host.yml b/test/test_htpasswd/test_htpasswd_regex_virtual_host.yml new file mode 100644 index 000000000..7f0d1bc96 --- /dev/null +++ b/test/test_htpasswd/test_htpasswd_regex_virtual_host.yml @@ -0,0 +1,17 @@ +version: "2" + +services: + regex: + image: web + expose: + - "80" + environment: + WEB_PORTS: 80 + VIRTUAL_HOST: ~^regex.*\.nginx-proxy\.example$ + + sut: + container_name: sut + image: nginxproxy/nginx-proxy:test + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro + - ./htpasswd:/etc/nginx/htpasswd:ro From 4c67b2455280d30c70447334548640933e38ad5a Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Fri, 1 Nov 2024 21:54:59 +0100 Subject: [PATCH 04/27] test: rename file for clarity --- ...om_proxy_settings.conf => my_custom_proxy_settings_f00.conf} | 0 test/test_custom/test_defaults-location.yml | 2 +- test/test_custom/test_defaults.yml | 2 +- test/test_custom/test_location-per-vhost.yml | 2 +- test/test_custom/test_per-vhost.yml | 2 +- test/test_custom/test_proxy-wide.yml | 2 +- 6 files changed, 5 insertions(+), 5 deletions(-) rename test/test_custom/{my_custom_proxy_settings.conf => my_custom_proxy_settings_f00.conf} (100%) diff --git a/test/test_custom/my_custom_proxy_settings.conf b/test/test_custom/my_custom_proxy_settings_f00.conf similarity index 100% rename from test/test_custom/my_custom_proxy_settings.conf rename to test/test_custom/my_custom_proxy_settings_f00.conf diff --git a/test/test_custom/test_defaults-location.yml b/test/test_custom/test_defaults-location.yml index 9a3ab44f3..6e8965057 100644 --- a/test/test_custom/test_defaults-location.yml +++ b/test/test_custom/test_defaults-location.yml @@ -5,7 +5,7 @@ services: image: nginxproxy/nginx-proxy:test volumes: - /var/run/docker.sock:/tmp/docker.sock:ro - - ./my_custom_proxy_settings.conf:/etc/nginx/vhost.d/default_location:ro + - ./my_custom_proxy_settings_f00.conf:/etc/nginx/vhost.d/default_location:ro - ./my_custom_proxy_settings_bar.conf:/etc/nginx/vhost.d/web3.nginx-proxy.example_location:ro web1: diff --git a/test/test_custom/test_defaults.yml b/test/test_custom/test_defaults.yml index d6a959a48..2f25387ba 100644 --- a/test/test_custom/test_defaults.yml +++ b/test/test_custom/test_defaults.yml @@ -5,7 +5,7 @@ services: image: nginxproxy/nginx-proxy:test volumes: - /var/run/docker.sock:/tmp/docker.sock:ro - - ./my_custom_proxy_settings.conf:/etc/nginx/proxy.conf:ro + - ./my_custom_proxy_settings_f00.conf:/etc/nginx/proxy.conf:ro web1: image: web diff --git a/test/test_custom/test_location-per-vhost.yml b/test/test_custom/test_location-per-vhost.yml index 5a6164c53..71e606ab4 100644 --- a/test/test_custom/test_location-per-vhost.yml +++ b/test/test_custom/test_location-per-vhost.yml @@ -5,7 +5,7 @@ services: image: nginxproxy/nginx-proxy:test volumes: - /var/run/docker.sock:/tmp/docker.sock:ro - - ./my_custom_proxy_settings.conf:/etc/nginx/vhost.d/web1.nginx-proxy.example_location:ro + - ./my_custom_proxy_settings_f00.conf:/etc/nginx/vhost.d/web1.nginx-proxy.example_location:ro - ./my_custom_proxy_settings_bar.conf:/etc/nginx/vhost.d/561032515ede3ab3a015edfb244608b72409c430_location:ro web1: diff --git a/test/test_custom/test_per-vhost.yml b/test/test_custom/test_per-vhost.yml index 337fc56f9..0795cef17 100644 --- a/test/test_custom/test_per-vhost.yml +++ b/test/test_custom/test_per-vhost.yml @@ -5,7 +5,7 @@ services: image: nginxproxy/nginx-proxy:test volumes: - /var/run/docker.sock:/tmp/docker.sock:ro - - ./my_custom_proxy_settings.conf:/etc/nginx/vhost.d/web1.nginx-proxy.example:ro + - ./my_custom_proxy_settings_f00.conf:/etc/nginx/vhost.d/web1.nginx-proxy.example:ro - ./my_custom_proxy_settings_bar.conf:/etc/nginx/vhost.d/561032515ede3ab3a015edfb244608b72409c430:ro web1: diff --git a/test/test_custom/test_proxy-wide.yml b/test/test_custom/test_proxy-wide.yml index 1322bcde7..22e5c1857 100644 --- a/test/test_custom/test_proxy-wide.yml +++ b/test/test_custom/test_proxy-wide.yml @@ -5,7 +5,7 @@ services: image: nginxproxy/nginx-proxy:test volumes: - /var/run/docker.sock:/tmp/docker.sock:ro - - ./my_custom_proxy_settings.conf:/etc/nginx/conf.d/my_custom_proxy_settings.conf:ro + - ./my_custom_proxy_settings_f00.conf:/etc/nginx/conf.d/my_custom_proxy_settings_f00.conf:ro web1: image: web From 8fed348ff729f3ae70a9d78c61648e8ced5e1a65 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Wed, 9 Oct 2024 20:01:01 +0200 Subject: [PATCH 05/27] refactor: move global config properties to a sub dict --- nginx.tmpl | 96 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 50 insertions(+), 46 deletions(-) diff --git a/nginx.tmpl b/nginx.tmpl index 2348ea70b..d9b758f9f 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -11,15 +11,19 @@ {{- $_ := set $globals "Env" $.Env }} {{- $_ := set $globals "Docker" $.Docker }} {{- $_ := set $globals "CurrentContainer" (where $globals.containers "ID" $globals.Docker.CurrentContainerID | first) }} -{{- $_ := set $globals "default_cert_ok" (and (exists "/etc/nginx/certs/default.crt") (exists "/etc/nginx/certs/default.key")) }} -{{- $_ := set $globals "external_http_port" (coalesce $globals.Env.HTTP_PORT "80") }} -{{- $_ := set $globals "external_https_port" (coalesce $globals.Env.HTTPS_PORT "443") }} -{{- $_ := set $globals "sha1_upstream_name" (parseBool (coalesce $globals.Env.SHA1_UPSTREAM_NAME "false")) }} -{{- $_ := set $globals "default_root_response" (coalesce $globals.Env.DEFAULT_ROOT "404") }} -{{- $_ := set $globals "trust_downstream_proxy" (parseBool (coalesce $globals.Env.TRUST_DOWNSTREAM_PROXY "true")) }} -{{- $_ := set $globals "access_log" (or (and (not $globals.Env.DISABLE_ACCESS_LOGS) "access_log /var/log/nginx/access.log vhost;") "") }} -{{- $_ := set $globals "enable_ipv6" (parseBool (coalesce $globals.Env.ENABLE_IPV6 "false")) }} -{{- $_ := set $globals "ssl_policy" (or ($globals.Env.SSL_POLICY) "Mozilla-Intermediate") }} + +{{- $config := dict }} +{{- $_ := set $config "default_cert_ok" (and (exists "/etc/nginx/certs/default.crt") (exists "/etc/nginx/certs/default.key")) }} +{{- $_ := set $config "external_http_port" (coalesce $globals.Env.HTTP_PORT "80") }} +{{- $_ := set $config "external_https_port" (coalesce $globals.Env.HTTPS_PORT "443") }} +{{- $_ := set $config "sha1_upstream_name" (parseBool (coalesce $globals.Env.SHA1_UPSTREAM_NAME "false")) }} +{{- $_ := set $config "default_root_response" (coalesce $globals.Env.DEFAULT_ROOT "404") }} +{{- $_ := set $config "trust_downstream_proxy" (parseBool (coalesce $globals.Env.TRUST_DOWNSTREAM_PROXY "true")) }} +{{- $_ := set $config "access_log" (or (and (not $globals.Env.DISABLE_ACCESS_LOGS) "access_log /var/log/nginx/access.log vhost;") "") }} +{{- $_ := set $config "enable_ipv6" (parseBool (coalesce $globals.Env.ENABLE_IPV6 "false")) }} +{{- $_ := set $config "ssl_policy" (or ($globals.Env.SSL_POLICY) "Mozilla-Intermediate") }} +{{- $_ := set $globals "config" $config }} + {{- $_ := set $globals "vhosts" (dict) }} {{- $_ := set $globals "networks" (dict) }} # Networks available to the container running docker-gen (which are assumed to @@ -347,19 +351,19 @@ upstream {{ $vpath.upstream }} { # If we receive X-Forwarded-Proto, pass it through; otherwise, pass along the # scheme used to connect to this server map $http_x_forwarded_proto $proxy_x_forwarded_proto { - default {{ if $globals.trust_downstream_proxy }}$http_x_forwarded_proto{{ else }}$scheme{{ end }}; + default {{ if $globals.config.trust_downstream_proxy }}$http_x_forwarded_proto{{ else }}$scheme{{ end }}; '' $scheme; } map $http_x_forwarded_host $proxy_x_forwarded_host { - default {{ if $globals.trust_downstream_proxy }}$http_x_forwarded_host{{ else }}$host{{ end }}; + default {{ if $globals.config.trust_downstream_proxy }}$http_x_forwarded_host{{ else }}$host{{ end }}; '' $host; } # If we receive X-Forwarded-Port, pass it through; otherwise, pass along the # server port the client connected to map $http_x_forwarded_port $proxy_x_forwarded_port { - default {{ if $globals.trust_downstream_proxy }}$http_x_forwarded_port{{ else }}$server_port{{ end }}; + default {{ if $globals.config.trust_downstream_proxy }}$http_x_forwarded_port{{ else }}$server_port{{ end }}; '' $server_port; } @@ -440,7 +444,7 @@ access_log off; * if at least one vhost use a TLSv1 or TLSv1.1 policy * so TLSv1 and TLSv1.1 can be enabled on those vhosts */}} -{{- $httpContextSslPolicy := $globals.ssl_policy }} +{{- $httpContextSslPolicy := $globals.config.ssl_policy }} {{- $inUseSslPolicies := groupByKeys $globals.containers "Env.SSL_POLICY" }} {{- range $tls1Policy := list "AWS-TLS13-1-1-2021-06" "AWS-TLS13-1-0-2021-06" "AWS-FS-1-1-2019-08" "AWS-FS-2018-06" "AWS-TLS-1-1-2017-01" "AWS-2016-08" "AWS-2015-05" "AWS-2015-03" "AWS-2015-02" "Mozilla-Old" }} {{- if has $tls1Policy $inUseSslPolicies }} @@ -518,7 +522,7 @@ proxy_set_header Proxy ""; {{- end }} {{- $_ := set $vhost_data "paths" $paths }} {{- $is_regexp := hasPrefix "~" $hostname }} - {{- $_ := set $vhost_data "upstream_name" (when (or $is_regexp $globals.sha1_upstream_name) (sha1 $hostname) $hostname) }} + {{- $_ := set $vhost_data "upstream_name" (when (or $is_regexp $globals.config.sha1_upstream_name) (sha1 $hostname) $hostname) }} {{- $_ := set $globals.vhosts $hostname $vhost_data }} {{- end }} {{- end }} @@ -564,7 +568,7 @@ proxy_set_header Proxy ""; {{- end }} {{- $_ := set $vhost_data "paths" $paths }} {{- $is_regexp := hasPrefix "~" $hostname }} - {{- $_ := set $vhost_data "upstream_name" (when (or $is_regexp $globals.sha1_upstream_name) (sha1 $hostname) $hostname) }} + {{- $_ := set $vhost_data "upstream_name" (when (or $is_regexp $globals.config.sha1_upstream_name) (sha1 $hostname) $hostname) }} {{- $_ := set $globals.vhosts $hostname $vhost_data }} {{- end }} @@ -700,30 +704,30 @@ proxy_set_header Proxy ""; server { server_name _; # This is just an invalid value which will never trigger on a real hostname. server_tokens off; - {{ $globals.access_log }} + {{ $globals.config.access_log }} http2 on; {{- if $fallback_http }} - listen {{ $globals.external_http_port }}; {{- /* Do not add `default_server` (see comment above). */}} - {{- if $globals.enable_ipv6 }} - listen [::]:{{ $globals.external_http_port }}; {{- /* Do not add `default_server` (see comment above). */}} + listen {{ $globals.config.external_http_port }}; {{- /* Do not add `default_server` (see comment above). */}} + {{- if $globals.config.enable_ipv6 }} + listen [::]:{{ $globals.config.external_http_port }}; {{- /* Do not add `default_server` (see comment above). */}} {{- end }} {{- end }} {{- if $fallback_https }} - listen {{ $globals.external_https_port }} ssl; {{- /* Do not add `default_server` (see comment above). */}} - {{- if $globals.enable_ipv6 }} - listen [::]:{{ $globals.external_https_port }} ssl; {{- /* Do not add `default_server` (see comment above). */}} + listen {{ $globals.config.external_https_port }} ssl; {{- /* Do not add `default_server` (see comment above). */}} + {{- if $globals.config.enable_ipv6 }} + listen [::]:{{ $globals.config.external_https_port }} ssl; {{- /* Do not add `default_server` (see comment above). */}} {{- end }} {{- if $http3_enabled }} http3 on; - listen {{ $globals.external_https_port }} quic reuseport; {{- /* Do not add `default_server` (see comment above). */}} - {{- if $globals.enable_ipv6 }} - listen [::]:{{ $globals.external_https_port }} quic reuseport; {{- /* Do not add `default_server` (see comment above). */}} + listen {{ $globals.config.external_https_port }} quic reuseport; {{- /* Do not add `default_server` (see comment above). */}} + {{- if $globals.config.enable_ipv6 }} + listen [::]:{{ $globals.config.external_https_port }} quic reuseport; {{- /* Do not add `default_server` (see comment above). */}} {{- end }} {{- end }} ssl_session_cache shared:SSL:50m; ssl_session_tickets off; {{- end }} - {{- if $globals.default_cert_ok }} + {{- if $globals.config.default_cert_ok }} ssl_certificate /etc/nginx/certs/default.crt; ssl_certificate_key /etc/nginx/certs/default.key; {{- else }} @@ -759,10 +763,10 @@ server { {{- if $vhost.server_tokens }} server_tokens {{ $vhost.server_tokens }}; {{- end }} - {{ $globals.access_log }} - listen {{ $globals.external_http_port }} {{ $default_server }}; - {{- if $globals.enable_ipv6 }} - listen [::]:{{ $globals.external_http_port }} {{ $default_server }}; + {{ $globals.config.access_log }} + listen {{ $globals.config.external_http_port }} {{ $default_server }}; + {{- if $globals.config.enable_ipv6 }} + listen [::]:{{ $globals.config.external_http_port }} {{ $default_server }}; {{- end }} {{- if (or $vhost.acme_http_challenge_legacy $vhost.acme_http_challenge_enabled) }} @@ -778,10 +782,10 @@ server { {{- end }} location / { - {{- if eq $globals.external_https_port "443" }} + {{- if eq $globals.config.external_https_port "443" }} return 301 https://$host$request_uri; {{- else }} - return 301 https://$host:{{ $globals.external_https_port }}$request_uri; + return 301 https://$host:{{ $globals.config.external_https_port }}$request_uri; {{- end }} } } @@ -809,14 +813,14 @@ server { {{- if $vhost.server_tokens }} server_tokens {{ $vhost.server_tokens }}; {{- end }} - {{ $globals.access_log }} + {{ $globals.config.access_log }} {{- if $vhost.http2_enabled }} http2 on; {{- end }} {{- if or (eq $vhost.https_method "nohttps") (eq $vhost.https_method "noredirect") }} - listen {{ $globals.external_http_port }} {{ $default_server }}; - {{- if $globals.enable_ipv6 }} - listen [::]:{{ $globals.external_http_port }} {{ $default_server }}; + listen {{ $globals.config.external_http_port }} {{ $default_server }}; + {{- if $globals.config.enable_ipv6 }} + listen [::]:{{ $globals.config.external_http_port }} {{ $default_server }}; {{- end }} {{- if (and (eq $vhost.https_method "noredirect") $vhost.acme_http_challenge_enabled) }} @@ -830,17 +834,17 @@ server { {{- end }} {{- end }} {{- if ne $vhost.https_method "nohttps" }} - listen {{ $globals.external_https_port }} ssl {{ $default_server }}; - {{- if $globals.enable_ipv6 }} - listen [::]:{{ $globals.external_https_port }} ssl {{ $default_server }}; + listen {{ $globals.config.external_https_port }} ssl {{ $default_server }}; + {{- if $globals.config.enable_ipv6 }} + listen [::]:{{ $globals.config.external_https_port }} ssl {{ $default_server }}; {{- end }} {{- if $vhost.http3_enabled }} http3 on; - add_header alt-svc 'h3=":{{ $globals.external_https_port }}"; ma=86400;'; - listen {{ $globals.external_https_port }} quic {{ $default_server }}; - {{- if $globals.enable_ipv6 }} - listen [::]:{{ $globals.external_https_port }} quic {{ $default_server }}; + add_header alt-svc 'h3=":{{ $globals.config.external_https_port }}"; ma=86400;'; + listen {{ $globals.config.external_https_port }} quic {{ $default_server }}; + {{- if $globals.config.enable_ipv6 }} + listen [::]:{{ $globals.config.external_https_port }} quic {{ $default_server }}; {{- end }} {{- end }} @@ -871,7 +875,7 @@ server { } add_header Strict-Transport-Security $sts_header always; {{- end }} - {{- else if $globals.default_cert_ok }} + {{- else if $globals.config.default_cert_ok }} # No certificate found for this vhost, so use the default certificate and # return an error code if the user connects via https. ssl_certificate /etc/nginx/certs/default.crt; @@ -903,9 +907,9 @@ server { ) }} {{- end }} - {{- if and (not (contains $vhost.paths "/")) (ne $globals.default_root_response "none")}} + {{- if and (not (contains $vhost.paths "/")) (ne $globals.config.default_root_response "none")}} location / { - return {{ $globals.default_root_response }}; + return {{ $globals.config.default_root_response }}; } {{- end }} } From ebed622fd76dbe3e34681348fde4565c2b87375d Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Wed, 16 Oct 2024 22:06:32 +0200 Subject: [PATCH 06/27] feat: nginx-proxy debug endpoint --- nginx.tmpl | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/nginx.tmpl b/nginx.tmpl index d9b758f9f..2202a85eb 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -13,6 +13,7 @@ {{- $_ := set $globals "CurrentContainer" (where $globals.containers "ID" $globals.Docker.CurrentContainerID | first) }} {{- $config := dict }} +{{- $_ := set $config "nginx_proxy_version" $.Env.NGINX_PROXY_VERSION }} {{- $_ := set $config "default_cert_ok" (and (exists "/etc/nginx/certs/default.crt") (exists "/etc/nginx/certs/default.key")) }} {{- $_ := set $config "external_http_port" (coalesce $globals.Env.HTTP_PORT "80") }} {{- $_ := set $config "external_https_port" (coalesce $globals.Env.HTTPS_PORT "443") }} @@ -22,6 +23,7 @@ {{- $_ := set $config "access_log" (or (and (not $globals.Env.DISABLE_ACCESS_LOGS) "access_log /var/log/nginx/access.log vhost;") "") }} {{- $_ := set $config "enable_ipv6" (parseBool (coalesce $globals.Env.ENABLE_IPV6 "false")) }} {{- $_ := set $config "ssl_policy" (or ($globals.Env.SSL_POLICY) "Mozilla-Intermediate") }} +{{- $_ := set $config "enable_debug_endpoint" ($globals.Env.DEBUG_ENDPOINT | default "false") }} {{- $_ := set $globals "config" $config }} {{- $_ := set $globals "vhosts" (dict) }} @@ -348,6 +350,42 @@ upstream {{ $vpath.upstream }} { } {{- end }} +{{- /* debug "endpoint" response template */}} +{{- define "debug_response" }} + {{- $debug_paths := dict }} + {{- range $path, $vpath := .VHost.paths }} + {{- $tmp_port := dict }} + {{- range $port, $containers := $vpath.ports }} + {{- $tmp_containers := list }} + {{- range $container := $containers }} + {{- $tmp_containers = dict "Name" $container.Name | append $tmp_containers }} + {{- end }} + {{- $_ := dict $port $tmp_containers | set $tmp_port "ports" }} + {{- $tmp_port = deepCopy $vpath | merge $tmp_port }} + {{- end }} + {{- $_ := set $debug_paths $path $tmp_port }} + {{- end }} + + {{- $debug_vhost := deepCopy .VHost }} + {{- $_ := set $debug_vhost "paths" $debug_paths }} + + {{- $debug_response := dict + "global" .GlobalConfig + "hostname" .Hostname + "request" (dict + "host" "$host" + "https" "$https" + "http2" "$http2" + "http3" "$http3" + "ssl_cipher" "$ssl_cipher" + "ssl_protocol" "$ssl_protocol" + ) + "vhost" $debug_vhost + }} + + {{- toJson $debug_response }} +{{- end }} + # If we receive X-Forwarded-Proto, pass it through; otherwise, pass along the # scheme used to connect to this server map $http_x_forwarded_proto $proxy_x_forwarded_proto { @@ -614,6 +652,7 @@ proxy_set_header Proxy ""; {{- $cert := or $certName $vhostCert }} {{- $cert_ok := and (ne $cert "") (exists (printf "/etc/nginx/certs/%s.crt" $cert)) (exists (printf "/etc/nginx/certs/%s.key" $cert)) }} + {{- $enable_debug_endpoint := coalesce (groupByLabel $vhost_containers "com.github.nginx-proxy.nginx-proxy.debug-endpoint" | keys | first) $globals.config.enable_debug_endpoint | parseBool }} {{- $default := eq $globals.Env.DEFAULT_HOST $hostname }} {{- $https_method := or (first (groupByKeys $vhost_containers "Env.HTTPS_METHOD")) $globals.Env.HTTPS_METHOD "redirect" }} {{- $enable_http_on_missing_cert := parseBool (or (first (groupByKeys $vhost_containers "Env.ENABLE_HTTP_ON_MISSING_CERT")) $globals.Env.ENABLE_HTTP_ON_MISSING_CERT "true") }} @@ -645,6 +684,7 @@ proxy_set_header Proxy ""; {{- $vhost_data = merge $vhost_data (dict "cert" $cert "cert_ok" $cert_ok + "enable_debug_endpoint" $enable_debug_endpoint "default" $default "hsts" $hsts "https_method" $https_method @@ -780,6 +820,13 @@ server { break; } {{- end }} + + {{- if $vhost.enable_debug_endpoint }} + location /nginx-proxy-debug { + default_type application/json; + return 200 '{{- template "debug_response" (dict "GlobalConfig" $globals.config "Hostname" $hostname "VHost" $vhost) }}'; + } + {{- end }} location / { {{- if eq $globals.config.external_https_port "443" }} @@ -897,6 +944,13 @@ server { include /etc/nginx/vhost.d/default; {{- end }} + {{- if $vhost.enable_debug_endpoint }} + location /nginx-proxy-debug { + default_type application/json; + return 200 '{{- template "debug_response" (dict "GlobalConfig" $globals.config "Hostname" $hostname "VHost" $vhost) }}'; + } + {{- end }} + {{- range $path, $vpath := $vhost.paths }} {{- template "location" (dict "Path" $path From fe52878940813cebbfaab019e54c7131e8807d29 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Wed, 16 Oct 2024 22:41:32 +0200 Subject: [PATCH 07/27] refactor: expose clearly access log status in debug endpoint --- nginx.tmpl | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/nginx.tmpl b/nginx.tmpl index 2202a85eb..c7b5b2d4c 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -20,7 +20,7 @@ {{- $_ := set $config "sha1_upstream_name" (parseBool (coalesce $globals.Env.SHA1_UPSTREAM_NAME "false")) }} {{- $_ := set $config "default_root_response" (coalesce $globals.Env.DEFAULT_ROOT "404") }} {{- $_ := set $config "trust_downstream_proxy" (parseBool (coalesce $globals.Env.TRUST_DOWNSTREAM_PROXY "true")) }} -{{- $_ := set $config "access_log" (or (and (not $globals.Env.DISABLE_ACCESS_LOGS) "access_log /var/log/nginx/access.log vhost;") "") }} +{{- $_ := set $config "enable_access_log" ($globals.Env.DISABLE_ACCESS_LOGS | default "false" | parseBool | not) }} {{- $_ := set $config "enable_ipv6" (parseBool (coalesce $globals.Env.ENABLE_IPV6 "false")) }} {{- $_ := set $config "ssl_policy" (or ($globals.Env.SSL_POLICY) "Mozilla-Intermediate") }} {{- $_ := set $config "enable_debug_endpoint" ($globals.Env.DEBUG_ENDPOINT | default "false") }} @@ -386,6 +386,10 @@ upstream {{ $vpath.upstream }} { {{- toJson $debug_response }} {{- end }} +{{- define "access_log" }} + {{- when .Enable "access_log /var/log/nginx/access.log vhost;" "" }} +{{- end }} + # If we receive X-Forwarded-Proto, pass it through; otherwise, pass along the # scheme used to connect to this server map $http_x_forwarded_proto $proxy_x_forwarded_proto { @@ -744,7 +748,7 @@ proxy_set_header Proxy ""; server { server_name _; # This is just an invalid value which will never trigger on a real hostname. server_tokens off; - {{ $globals.config.access_log }} + {{ template "access_log" (dict "Enable" $globals.config.enable_access_log) }} http2 on; {{- if $fallback_http }} listen {{ $globals.config.external_http_port }}; {{- /* Do not add `default_server` (see comment above). */}} @@ -803,7 +807,7 @@ server { {{- if $vhost.server_tokens }} server_tokens {{ $vhost.server_tokens }}; {{- end }} - {{ $globals.config.access_log }} + {{ template "access_log" (dict "Enable" $globals.config.enable_access_log) }} listen {{ $globals.config.external_http_port }} {{ $default_server }}; {{- if $globals.config.enable_ipv6 }} listen [::]:{{ $globals.config.external_http_port }} {{ $default_server }}; @@ -860,7 +864,7 @@ server { {{- if $vhost.server_tokens }} server_tokens {{ $vhost.server_tokens }}; {{- end }} - {{ $globals.config.access_log }} + {{ template "access_log" (dict "Enable" $globals.config.enable_access_log) }} {{- if $vhost.http2_enabled }} http2 on; {{- end }} From dce7663b691f88cac3e44da185aaec333377f0c7 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Wed, 16 Oct 2024 23:16:48 +0200 Subject: [PATCH 08/27] refactor: remove duplicate code --- nginx.tmpl | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/nginx.tmpl b/nginx.tmpl index c7b5b2d4c..6b2a99ef5 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -350,8 +350,8 @@ upstream {{ $vpath.upstream }} { } {{- end }} -{{- /* debug "endpoint" response template */}} -{{- define "debug_response" }} +{{- /* debug "endpoint" location template */}} +{{- define "debug_location" }} {{- $debug_paths := dict }} {{- range $path, $vpath := .VHost.paths }} {{- $tmp_port := dict }} @@ -382,8 +382,11 @@ upstream {{ $vpath.upstream }} { ) "vhost" $debug_vhost }} - - {{- toJson $debug_response }} + + location /nginx-proxy-debug { + default_type application/json; + return 200 '{{ toJson $debug_response }}'; + } {{- end }} {{- define "access_log" }} @@ -826,10 +829,7 @@ server { {{- end }} {{- if $vhost.enable_debug_endpoint }} - location /nginx-proxy-debug { - default_type application/json; - return 200 '{{- template "debug_response" (dict "GlobalConfig" $globals.config "Hostname" $hostname "VHost" $vhost) }}'; - } + {{ template "debug_location" (dict "GlobalConfig" $globals.config "Hostname" $hostname "VHost" $vhost) }} {{- end }} location / { @@ -949,10 +949,7 @@ server { {{- end }} {{- if $vhost.enable_debug_endpoint }} - location /nginx-proxy-debug { - default_type application/json; - return 200 '{{- template "debug_response" (dict "GlobalConfig" $globals.config "Hostname" $hostname "VHost" $vhost) }}'; - } + {{ template "debug_location" (dict "GlobalConfig" $globals.config "Hostname" $hostname "VHost" $vhost) }} {{- end }} {{- range $path, $vpath := $vhost.paths }} From 7dafac8b8737bbb7809ba76ccb1474b0af9816f7 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Thu, 17 Oct 2024 08:13:11 +0200 Subject: [PATCH 09/27] docs: documentation for debug endpoint --- docs/README.md | 97 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 96 insertions(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index 3990a7a4d..fbfe1e227 100644 --- a/docs/README.md +++ b/docs/README.md @@ -982,7 +982,7 @@ docker exec nginx -T Pay attention to the `upstream` definition blocks, which should look like this: -```Nginx +```nginx # foo.example.com upstream foo.example.com { ## Can be connected with "my_network" network @@ -1002,6 +1002,101 @@ The effective `Port` is retrieved by order of precedence: 1. From the container's exposed port if there is only one 1. From the default port 80 when none of the above methods apply +### Debug endpoint + +The debug endpoint can be enabled: +- globally by setting the `DEBUG_ENDPOINT` environment variable to `true` on the nginx-proxy container. +- per container by setting the `com.github.nginx-proxy.nginx-proxy.debug-endpoint` label to `true` on a proxied container. + +Enabling it will expose the endpoint at `/nginx-proxy-debug`. + +Querying the debug endpoint will show the global config, along with the virtual host and per path configs in JSON format. + +```yaml +services: + nginx-proxy: + image: nginxproxy/nginx-proxy + ports: + - "80:80" + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro + environment: + DEBUG_ENDPOINT: "true" + + test: + image: nginx + environment: + VIRTUAL_HOST: test.nginx-proxy.tld +``` + +(on the CLI, using [`jq`](https://jqlang.github.io/jq/) to format the output of `curl` is recommended) + +```console +curl -s -H "Host: test.nginx-proxy.tld" localhost/nginx-proxy-debug | jq +``` + +```json +{ + "global": { + "default_cert_ok": false, + "default_root_response": "404", + "enable_access_log": true, + "enable_debug_endpoint": "true", + "enable_ipv6": false, + "external_http_port": "80", + "external_https_port": "443", + "nginx_proxy_version": "local", + "sha1_upstream_name": false, + "ssl_policy": "Mozilla-Intermediate", + "trust_downstream_proxy": true + }, + "hostname": "test.nginx-proxy.tld", + "request": { + "host": "test.nginx-proxy.tld", + "http2": "", + "http3": "", + "https": "", + "ssl_cipher": "", + "ssl_protocol": "" + }, + "vhost": { + "acme_http_challenge_enabled": true, + "acme_http_challenge_legacy": false, + "cert": "", + "cert_ok": false, + "default": false, + "enable_debug_endpoint": true, + "hsts": "max-age=31536000", + "http2_enabled": true, + "http3_enabled": false, + "https_method": "noredirect", + "paths": { + "/": { + "dest": "", + "keepalive": "disabled", + "network_tag": "external", + "ports": { + "legacy": [ + { + "Name": "wip-test-1" + } + ] + }, + "proto": "http", + "upstream": "test.nginx-proxy.tld" + } + }, + "server_tokens": "", + "ssl_policy": "", + "upstream_name": "test.nginx-proxy.tld", + "vhost_root": "/var/www/public" + } +} +``` + +:warning: please be aware that the debug endpoint work by rendering the response straight to the nginx configuration, which might result in an unparseable configuration if it exceeds nginx line character limit. Only activate it when needed. + + ⬆️ [back to table of contents](#table-of-contents) ## Contributing From 32ad9b7102cb9a953da7927ec54e56e03494e078 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Thu, 17 Oct 2024 09:08:27 +0200 Subject: [PATCH 10/27] feat: protection against too long debug response --- docs/README.md | 2 +- nginx.tmpl | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index fbfe1e227..06e6b2352 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1094,7 +1094,7 @@ curl -s -H "Host: test.nginx-proxy.tld" localhost/nginx-proxy-debug | jq } ``` -:warning: please be aware that the debug endpoint work by rendering the response straight to the nginx configuration, which might result in an unparseable configuration if it exceeds nginx line character limit. Only activate it when needed. +:warning: please be aware that the debug endpoint work by rendering the JSON response straight to the nginx configuration in plaintext. nginx has an upper limit on the size of the configuration files it can parse, so only activate it when needed, and preferably on a per container basis if your setup has a large number of virtual hosts. ⬆️ [back to table of contents](#table-of-contents) diff --git a/nginx.tmpl b/nginx.tmpl index 6b2a99ef5..2021e7bb6 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -383,6 +383,16 @@ upstream {{ $vpath.upstream }} { "vhost" $debug_vhost }} + {{- /* + * The maximum line length in an nginx config is 4096 characters. + * If we're nearing this limit (with headroom for the rest + * of the directive), strip vhost.paths from the response. + */}} + {{- if gt (toJson $debug_response | len) 4000 }} + {{- $_ := unset $debug_vhost "paths" }} + {{- $_ := set $debug_response "warning" "Virtual paths configuration for this hostname is too large and has been stripped from response." }} + {{- end }} + location /nginx-proxy-debug { default_type application/json; return 200 '{{ toJson $debug_response }}'; From 190030745c608e6d48a0b937cf05cf04314b61e0 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Sat, 2 Nov 2024 16:48:55 +0100 Subject: [PATCH 11/27] test: nginx-proxy debug endpoint --- test/test_debug_endpoint/test_global.py | 24 ++++++++++++++ test/test_debug_endpoint/test_global.yml | 33 +++++++++++++++++++ .../test_debug_endpoint/test_per_container.py | 24 ++++++++++++++ .../test_per_container.yml | 32 ++++++++++++++++++ 4 files changed, 113 insertions(+) create mode 100644 test/test_debug_endpoint/test_global.py create mode 100644 test/test_debug_endpoint/test_global.yml create mode 100644 test/test_debug_endpoint/test_per_container.py create mode 100644 test/test_debug_endpoint/test_per_container.yml diff --git a/test/test_debug_endpoint/test_global.py b/test/test_debug_endpoint/test_global.py new file mode 100644 index 000000000..635aaabb0 --- /dev/null +++ b/test/test_debug_endpoint/test_global.py @@ -0,0 +1,24 @@ +import json +import pytest + +def test_debug_endpoint_is_enabled_globally(docker_compose, nginxproxy): + r = nginxproxy.get("http://enabled1.debug.nginx-proxy.example/nginx-proxy-debug") + assert r.status_code == 200 + r = nginxproxy.get("http://enabled2.debug.nginx-proxy.example/nginx-proxy-debug") + assert r.status_code == 200 + + +def test_debug_endpoint_response_contains_expected_values(docker_compose, nginxproxy): + r = nginxproxy.get("http://enabled1.debug.nginx-proxy.example/nginx-proxy-debug") + assert r.status_code == 200 + try: + jsonResponse = json.loads(r.text) + except ValueError as err: + pytest.fail("Failed to parse JSON response: %s" % err, pytrace=False) + assert jsonResponse["global"]["enable_debug_endpoint"] == "true" + assert jsonResponse["vhost"]["enable_debug_endpoint"] == True + + +def test_debug_endpoint_is_disabled_per_container(docker_compose, nginxproxy): + r = nginxproxy.get("http://disabled.debug.nginx-proxy.example/nginx-proxy-debug") + assert r.status_code == 404 diff --git a/test/test_debug_endpoint/test_global.yml b/test/test_debug_endpoint/test_global.yml new file mode 100644 index 000000000..812ffedc2 --- /dev/null +++ b/test/test_debug_endpoint/test_global.yml @@ -0,0 +1,33 @@ +services: + nginx-proxy: + image: nginxproxy/nginx-proxy:test + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro + environment: + DEBUG_ENDPOINT: "true" + + debug_enabled1: + image: web + expose: + - "81" + environment: + WEB_PORTS: 81 + VIRTUAL_HOST: enabled1.debug.nginx-proxy.example + + debug_enabled2: + image: web + expose: + - "82" + environment: + WEB_PORTS: 82 + VIRTUAL_HOST: enabled2.debug.nginx-proxy.example + + debug_disabled: + image: web + expose: + - "83" + environment: + WEB_PORTS: 83 + VIRTUAL_HOST: disabled.debug.nginx-proxy.example + labels: + com.github.nginx-proxy.nginx-proxy.debug-endpoint: "false" diff --git a/test/test_debug_endpoint/test_per_container.py b/test/test_debug_endpoint/test_per_container.py new file mode 100644 index 000000000..8901f8b3b --- /dev/null +++ b/test/test_debug_endpoint/test_per_container.py @@ -0,0 +1,24 @@ +import json +import pytest + +def test_debug_endpoint_is_disabled_globally(docker_compose, nginxproxy): + r = nginxproxy.get("http://disabled1.debug.nginx-proxy.example/nginx-proxy-debug") + assert r.status_code == 404 + r = nginxproxy.get("http://disabled2.debug.nginx-proxy.example/nginx-proxy-debug") + assert r.status_code == 404 + + +def test_debug_endpoint_is_enabled_per_container(docker_compose, nginxproxy): + r = nginxproxy.get("http://enabled.debug.nginx-proxy.example/nginx-proxy-debug") + assert r.status_code == 200 + + +def test_debug_endpoint_response_contains_expected_values(docker_compose, nginxproxy): + r = nginxproxy.get("http://enabled.debug.nginx-proxy.example/nginx-proxy-debug") + assert r.status_code == 200 + try: + jsonResponse = json.loads(r.text) + except ValueError as err: + pytest.fail("Failed to parse JSON response: %s" % err, pytrace=False) + assert jsonResponse["global"]["enable_debug_endpoint"] == "false" + assert jsonResponse["vhost"]["enable_debug_endpoint"] == True diff --git a/test/test_debug_endpoint/test_per_container.yml b/test/test_debug_endpoint/test_per_container.yml new file mode 100644 index 000000000..56c975cfe --- /dev/null +++ b/test/test_debug_endpoint/test_per_container.yml @@ -0,0 +1,32 @@ +services: + nginx-proxy: + image: nginxproxy/nginx-proxy:test + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro + + debug_disabled1: + image: web + expose: + - "81" + environment: + WEB_PORTS: 81 + VIRTUAL_HOST: disabled1.debug.nginx-proxy.example + + debug_disabled2: + image: web + expose: + - "82" + environment: + WEB_PORTS: 82 + VIRTUAL_HOST: disabled2.debug.nginx-proxy.example + + + debug_enabled: + image: web + expose: + - "83" + environment: + WEB_PORTS: 83 + VIRTUAL_HOST: enabled.debug.nginx-proxy.example + labels: + com.github.nginx-proxy.nginx-proxy.debug-endpoint: "true" From 9114b8047d643e99a7ec000128a731b2fbe97c24 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Sat, 2 Nov 2024 17:14:34 +0100 Subject: [PATCH 12/27] test: paths are stripped from debug endpoint response if too long --- test/test_debug_endpoint/test_global.py | 20 ++++++++++--- test/test_debug_endpoint/test_global.yml | 29 ++++++++++++++++--- .../test_debug_endpoint/test_per_container.py | 2 +- 3 files changed, 42 insertions(+), 9 deletions(-) diff --git a/test/test_debug_endpoint/test_global.py b/test/test_debug_endpoint/test_global.py index 635aaabb0..b151b6941 100644 --- a/test/test_debug_endpoint/test_global.py +++ b/test/test_debug_endpoint/test_global.py @@ -2,23 +2,35 @@ import pytest def test_debug_endpoint_is_enabled_globally(docker_compose, nginxproxy): - r = nginxproxy.get("http://enabled1.debug.nginx-proxy.example/nginx-proxy-debug") + r = nginxproxy.get("http://enabled.debug.nginx-proxy.example/nginx-proxy-debug") assert r.status_code == 200 - r = nginxproxy.get("http://enabled2.debug.nginx-proxy.example/nginx-proxy-debug") + r = nginxproxy.get("http://stripped.debug.nginx-proxy.example/nginx-proxy-debug") assert r.status_code == 200 def test_debug_endpoint_response_contains_expected_values(docker_compose, nginxproxy): - r = nginxproxy.get("http://enabled1.debug.nginx-proxy.example/nginx-proxy-debug") + r = nginxproxy.get("http://enabled.debug.nginx-proxy.example/nginx-proxy-debug") assert r.status_code == 200 try: jsonResponse = json.loads(r.text) except ValueError as err: - pytest.fail("Failed to parse JSON response: %s" % err, pytrace=False) + pytest.fail("Failed to parse debug endpoint response as JSON: %s" % err, pytrace=False) assert jsonResponse["global"]["enable_debug_endpoint"] == "true" assert jsonResponse["vhost"]["enable_debug_endpoint"] == True +def test_debug_endpoint_pahts_stripped_if_response_too_long(docker_compose, nginxproxy): + r = nginxproxy.get("http://stripped.debug.nginx-proxy.example/nginx-proxy-debug") + assert r.status_code == 200 + try: + jsonResponse = json.loads(r.text) + except ValueError as err: + pytest.fail("Failed to parse debug endpoint response as JSON: %s" % err, pytrace=False) + if "paths" in jsonResponse["vhost"]: + pytest.fail("Expected paths to be stripped from debug endpoint response", pytrace=False) + assert jsonResponse["warning"] == "Virtual paths configuration for this hostname is too large and has been stripped from response." + + def test_debug_endpoint_is_disabled_per_container(docker_compose, nginxproxy): r = nginxproxy.get("http://disabled.debug.nginx-proxy.example/nginx-proxy-debug") assert r.status_code == 404 diff --git a/test/test_debug_endpoint/test_global.yml b/test/test_debug_endpoint/test_global.yml index 812ffedc2..7ec99efb2 100644 --- a/test/test_debug_endpoint/test_global.yml +++ b/test/test_debug_endpoint/test_global.yml @@ -6,21 +6,42 @@ services: environment: DEBUG_ENDPOINT: "true" - debug_enabled1: + debug_enabled: image: web expose: - "81" environment: WEB_PORTS: 81 - VIRTUAL_HOST: enabled1.debug.nginx-proxy.example + VIRTUAL_HOST: enabled.debug.nginx-proxy.example - debug_enabled2: + debug_stripped: image: web expose: - "82" environment: WEB_PORTS: 82 - VIRTUAL_HOST: enabled2.debug.nginx-proxy.example + VIRTUAL_HOST_MULTIPORTS: |- + stripped.debug.nginx-proxy.example: + "/1": + "/2": + "/3": + "/4": + "/5": + "/6": + "/7": + "/8": + "/9": + "/10": + "/11": + "/12": + "/13": + "/14": + "/15": + "/16": + "/17": + "/18": + "/19": + "/20": debug_disabled: image: web diff --git a/test/test_debug_endpoint/test_per_container.py b/test/test_debug_endpoint/test_per_container.py index 8901f8b3b..16c680c33 100644 --- a/test/test_debug_endpoint/test_per_container.py +++ b/test/test_debug_endpoint/test_per_container.py @@ -19,6 +19,6 @@ def test_debug_endpoint_response_contains_expected_values(docker_compose, nginxp try: jsonResponse = json.loads(r.text) except ValueError as err: - pytest.fail("Failed to parse JSON response: %s" % err, pytrace=False) + pytest.fail("Failed to parse debug endpoint response as JSON:: %s" % err, pytrace=False) assert jsonResponse["global"]["enable_debug_endpoint"] == "false" assert jsonResponse["vhost"]["enable_debug_endpoint"] == True From 52100c40af5dc17a07c183c06aba94842a7fb60d Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Sat, 2 Nov 2024 18:50:30 +0100 Subject: [PATCH 13/27] refactor: move global hsts to $globals.config --- nginx.tmpl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/nginx.tmpl b/nginx.tmpl index 2021e7bb6..7ed9e6f47 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -24,6 +24,7 @@ {{- $_ := set $config "enable_ipv6" (parseBool (coalesce $globals.Env.ENABLE_IPV6 "false")) }} {{- $_ := set $config "ssl_policy" (or ($globals.Env.SSL_POLICY) "Mozilla-Intermediate") }} {{- $_ := set $config "enable_debug_endpoint" ($globals.Env.DEBUG_ENDPOINT | default "false") }} +{{- $_ := set $config "hsts" ($globals.Env.HSTS | default "max-age=31536000") }} {{- $_ := set $globals "config" $config }} {{- $_ := set $globals "vhosts" (dict) }} @@ -693,7 +694,7 @@ proxy_set_header Proxy ""; {{- $ssl_policy := or (first (groupByKeys $vhost_containers "Env.SSL_POLICY")) "" }} {{- /* Get the HSTS defined by containers w/ the same vhost, falling back to "max-age=31536000". */}} - {{- $hsts := or (first (groupByKeys $vhost_containers "Env.HSTS")) (or $globals.Env.HSTS "max-age=31536000") }} + {{- $hsts := groupByKeys $vhost_containers "Env.HSTS" | first | default $globals.config.hsts }} {{- /* Get the VIRTUAL_ROOT By containers w/ use fastcgi root */}} {{- $vhost_root := or (first (groupByKeys $vhost_containers "Env.VIRTUAL_ROOT")) "/var/www/public" }} From 07aef2bd838ae42c5c331ec2db2615f987e5b2cc Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Sat, 2 Nov 2024 18:59:21 +0100 Subject: [PATCH 14/27] refactor: move global acme challenge location to $globals.config --- nginx.tmpl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/nginx.tmpl b/nginx.tmpl index 7ed9e6f47..513587c5b 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -25,6 +25,7 @@ {{- $_ := set $config "ssl_policy" (or ($globals.Env.SSL_POLICY) "Mozilla-Intermediate") }} {{- $_ := 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 $globals "config" $config }} {{- $_ := set $globals "vhosts" (dict) }} @@ -680,7 +681,7 @@ proxy_set_header Proxy ""; {{- end }} {{- $http2_enabled := parseBool (or (first (keys (groupByLabel $vhost_containers "com.github.nginx-proxy.nginx-proxy.http2.enable"))) $globals.Env.ENABLE_HTTP2 "true")}} {{- $http3_enabled := parseBool (or (first (keys (groupByLabel $vhost_containers "com.github.nginx-proxy.nginx-proxy.http3.enable"))) $globals.Env.ENABLE_HTTP3 "false")}} - {{- $acme_http_challenge := or (first (groupByKeys $vhost_containers "Env.ACME_HTTP_CHALLENGE_LOCATION")) $globals.Env.ACME_HTTP_CHALLENGE_LOCATION "true" }} + {{- $acme_http_challenge := groupByKeys $vhost_containers "Env.ACME_HTTP_CHALLENGE_LOCATION" | first | default $globals.config.acme_http_challenge }} {{- $acme_http_challenge_legacy := eq $acme_http_challenge "legacy" }} {{- $acme_http_challenge_enabled := false }} {{- if (not $acme_http_challenge_legacy) }} From dcbb695a4b5c06e81977c85ca88227274c37578f Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Sat, 2 Nov 2024 19:05:57 +0100 Subject: [PATCH 15/27] refactor: move global http2/http3 to $globals.config --- nginx.tmpl | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/nginx.tmpl b/nginx.tmpl index 513587c5b..2c3686c14 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -26,6 +26,8 @@ {{- $_ := 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 "enable_http2" ($globals.Env.ENABLE_HTTP2 | default "true") }} +{{- $_ := set $config "enable_http3" ($globals.Env.ENABLE_HTTP3 | default "false") }} {{- $_ := set $globals "config" $config }} {{- $_ := set $globals "vhosts" (dict) }} @@ -679,8 +681,8 @@ proxy_set_header Proxy ""; {{- if (and $enable_http_on_missing_cert (not $cert_ok) (or (eq $https_method "nohttp") (eq $https_method "redirect"))) }} {{- $https_method = "noredirect" }} {{- end }} - {{- $http2_enabled := parseBool (or (first (keys (groupByLabel $vhost_containers "com.github.nginx-proxy.nginx-proxy.http2.enable"))) $globals.Env.ENABLE_HTTP2 "true")}} - {{- $http3_enabled := parseBool (or (first (keys (groupByLabel $vhost_containers "com.github.nginx-proxy.nginx-proxy.http3.enable"))) $globals.Env.ENABLE_HTTP3 "false")}} + {{- $http2_enabled := groupByLabel $vhost_containers "com.github.nginx-proxy.nginx-proxy.http2.enable" | keys | first | default $globals.config.enable_http2 | parseBool }} + {{- $http3_enabled := groupByLabel $vhost_containers "com.github.nginx-proxy.nginx-proxy.http3.enable" | keys | first | default $globals.config.enable_http3 | parseBool }} {{- $acme_http_challenge := groupByKeys $vhost_containers "Env.ACME_HTTP_CHALLENGE_LOCATION" | first | default $globals.config.acme_http_challenge }} {{- $acme_http_challenge_legacy := eq $acme_http_challenge "legacy" }} {{- $acme_http_challenge_enabled := false }} From 30b909de8eacaee7e282ca4abe71c720e993a05b Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Sat, 2 Nov 2024 19:09:54 +0100 Subject: [PATCH 16/27] refactor: move https enforcing to $globals.config --- nginx.tmpl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/nginx.tmpl b/nginx.tmpl index 2c3686c14..83aa46028 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -28,6 +28,7 @@ {{- $_ := set $config "acme_http_challenge" ($globals.Env.ACME_HTTP_CHALLENGE_LOCATION | default "true") }} {{- $_ := 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") }} {{- $_ := set $globals "config" $config }} {{- $_ := set $globals "vhosts" (dict) }} @@ -676,7 +677,7 @@ proxy_set_header Proxy ""; {{- $enable_debug_endpoint := coalesce (groupByLabel $vhost_containers "com.github.nginx-proxy.nginx-proxy.debug-endpoint" | keys | first) $globals.config.enable_debug_endpoint | parseBool }} {{- $default := eq $globals.Env.DEFAULT_HOST $hostname }} {{- $https_method := or (first (groupByKeys $vhost_containers "Env.HTTPS_METHOD")) $globals.Env.HTTPS_METHOD "redirect" }} - {{- $enable_http_on_missing_cert := parseBool (or (first (groupByKeys $vhost_containers "Env.ENABLE_HTTP_ON_MISSING_CERT")) $globals.Env.ENABLE_HTTP_ON_MISSING_CERT "true") }} + {{- $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"))) }} {{- $https_method = "noredirect" }} From db0421eb4ad43c90e66917a28d8d18c166955ce7 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Sat, 2 Nov 2024 19:12:08 +0100 Subject: [PATCH 17/27] refactor: move https method to $globals.config --- nginx.tmpl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/nginx.tmpl b/nginx.tmpl index 83aa46028..fb0efcc1e 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -29,6 +29,7 @@ {{- $_ := 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") }} +{{- $_ := set $config "https_method" ($globals.Env.HTTPS_METHOD | default "redirect") }} {{- $_ := set $globals "config" $config }} {{- $_ := set $globals "vhosts" (dict) }} @@ -676,7 +677,7 @@ proxy_set_header Proxy ""; {{- $enable_debug_endpoint := coalesce (groupByLabel $vhost_containers "com.github.nginx-proxy.nginx-proxy.debug-endpoint" | keys | first) $globals.config.enable_debug_endpoint | parseBool }} {{- $default := eq $globals.Env.DEFAULT_HOST $hostname }} - {{- $https_method := or (first (groupByKeys $vhost_containers "Env.HTTPS_METHOD")) $globals.Env.HTTPS_METHOD "redirect" }} + {{- $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"))) }} From 946485e0b8104e462b58ca08be27c25dbed77f58 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Sat, 2 Nov 2024 19:14:38 +0100 Subject: [PATCH 18/27] refactor: move default host to $globals.config --- nginx.tmpl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/nginx.tmpl b/nginx.tmpl index fb0efcc1e..ffa147561 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -30,6 +30,7 @@ {{- $_ := 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") }} {{- $_ := set $config "https_method" ($globals.Env.HTTPS_METHOD | default "redirect") }} +{{- $_ := set $config "default_host" $globals.Env.DEFAULT_HOST }} {{- $_ := set $globals "config" $config }} {{- $_ := set $globals "vhosts" (dict) }} @@ -676,7 +677,7 @@ proxy_set_header Proxy ""; {{- $cert_ok := and (ne $cert "") (exists (printf "/etc/nginx/certs/%s.crt" $cert)) (exists (printf "/etc/nginx/certs/%s.key" $cert)) }} {{- $enable_debug_endpoint := coalesce (groupByLabel $vhost_containers "com.github.nginx-proxy.nginx-proxy.debug-endpoint" | keys | first) $globals.config.enable_debug_endpoint | parseBool }} - {{- $default := eq $globals.Env.DEFAULT_HOST $hostname }} + {{- $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' */}} From a06cd1ae9a2a2302b38bd720db418d91c92115ba Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Sat, 2 Nov 2024 19:16:09 +0100 Subject: [PATCH 19/27] refactor: move resolvers to $globals.config --- nginx.tmpl | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/nginx.tmpl b/nginx.tmpl index ffa147561..81200e3db 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -31,6 +31,7 @@ {{- $_ := set $config "enable_http_on_missing_cert" ($globals.Env.ENABLE_HTTP_ON_MISSING_CERT | default "true") }} {{- $_ := set $config "https_method" ($globals.Env.HTTPS_METHOD | default "redirect") }} {{- $_ := set $config "default_host" $globals.Env.DEFAULT_HOST }} +{{- $_ := set $config "resolvers" $globals.Env.RESOLVERS }} {{- $_ := set $globals "config" $config }} {{- $_ := set $globals "vhosts" (dict) }} @@ -519,8 +520,8 @@ access_log off; {{- template "ssl_policy" (dict "ssl_policy" $httpContextSslPolicy) }} error_log /dev/stderr; -{{- if $globals.Env.RESOLVERS }} -resolver {{ $globals.Env.RESOLVERS }}; +{{- if $globals.config.resolvers }} +resolver {{ $globals.config.resolvers }}; {{- end }} {{- if (exists "/etc/nginx/proxy.conf") }} From cab2a2d151f498d576ad5b4b417d7bd77f0257c0 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Sat, 2 Nov 2024 19:41:34 +0100 Subject: [PATCH 20/27] refactor: move log configs to $globals.config --- nginx.tmpl | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/nginx.tmpl b/nginx.tmpl index 81200e3db..2df219996 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -32,6 +32,11 @@ {{- $_ := set $config "https_method" ($globals.Env.HTTPS_METHOD | default "redirect") }} {{- $_ := set $config "default_host" $globals.Env.DEFAULT_HOST }} {{- $_ := set $config "resolvers" $globals.Env.RESOLVERS }} +{{- /* LOG_JSON is a shorthand that sets logging defaults to JSON format */}} +{{- $_ := set $config "enable_json_logs" ($globals.Env.LOG_JSON | default "false" | parseBool) }} +{{- $_ := set $config "log_format" $globals.Env.LOG_FORMAT }} +{{- $_ := set $config "log_format_escape" $globals.Env.LOG_FORMAT_ESCAPE }} + {{- $_ := set $globals "config" $config }} {{- $_ := set $globals "vhosts" (dict) }} @@ -487,19 +492,16 @@ gzip_types text/plain text/css application/javascript application/json applicati * LOG_FORMAT_ESCAPE sets the escape part of the log format * LOG_FORMAT sets the log format */}} -{{- $logEscape := printf "escape=%s" (or $globals.Env.LOG_FORMAT_ESCAPE "default") }} -{{- $logFormat := or $globals.Env.LOG_FORMAT `$host $remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" "$upstream_addr"` }} +{{- $logEscape := $globals.config.log_format_escape | default "default" | printf "escape=%s" }} +{{- $logFormat := $globals.config.log_format | default `$host $remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" "$upstream_addr"` }} -{{- if parseBool (or $globals.Env.LOG_JSON "false") }} - {{- /* LOG_JSON is a shorthand - * that sets logging defaults to JSON format - */}} +{{- if $globals.config.enable_json_logs }} # JSON Logging enabled (via LOG_JSON env variable) - {{- $logEscape = printf "escape=%s" (or $globals.Env.LOG_FORMAT_ESCAPE "json") }} - {{- $logFormat = or $globals.Env.LOG_FORMAT `{"time_local":"$time_iso8601","client_ip":"$http_x_forwarded_for","remote_addr":"$remote_addr","request":"$request","status":"$status","body_bytes_sent":"$body_bytes_sent","request_time":"$request_time","upstream_response_time":"$upstream_response_time","upstream_addr":"$upstream_addr","http_referrer":"$http_referer","http_user_agent":"$http_user_agent","request_id":"$request_id"}` }} + {{- $logEscape = $globals.config.log_format_escape | default "json" | printf "escape=%s" }} + {{- $logFormat = $globals.config.log_format | default `{"time_local":"$time_iso8601","client_ip":"$http_x_forwarded_for","remote_addr":"$remote_addr","request":"$request","status":"$status","body_bytes_sent":"$body_bytes_sent","request_time":"$request_time","upstream_response_time":"$upstream_response_time","upstream_addr":"$upstream_addr","http_referrer":"$http_referer","http_user_agent":"$http_user_agent","request_id":"$request_id"}` }} {{- end }} -log_format vhost {{ $logEscape }} '{{ or $globals.Env.LOG_FORMAT $logFormat }}'; +log_format vhost {{ $logEscape }} '{{ $logFormat }}'; access_log off; From 01d14f09423889489d71e4cc540d92f085f5b91b Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Sat, 2 Nov 2024 19:58:39 +0100 Subject: [PATCH 21/27] refactor: align global config template syntax --- nginx.tmpl | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/nginx.tmpl b/nginx.tmpl index 2df219996..8e6d57637 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -15,14 +15,14 @@ {{- $config := dict }} {{- $_ := set $config "nginx_proxy_version" $.Env.NGINX_PROXY_VERSION }} {{- $_ := set $config "default_cert_ok" (and (exists "/etc/nginx/certs/default.crt") (exists "/etc/nginx/certs/default.key")) }} -{{- $_ := set $config "external_http_port" (coalesce $globals.Env.HTTP_PORT "80") }} -{{- $_ := set $config "external_https_port" (coalesce $globals.Env.HTTPS_PORT "443") }} -{{- $_ := set $config "sha1_upstream_name" (parseBool (coalesce $globals.Env.SHA1_UPSTREAM_NAME "false")) }} -{{- $_ := set $config "default_root_response" (coalesce $globals.Env.DEFAULT_ROOT "404") }} -{{- $_ := set $config "trust_downstream_proxy" (parseBool (coalesce $globals.Env.TRUST_DOWNSTREAM_PROXY "true")) }} +{{- $_ := set $config "external_http_port" ($globals.Env.HTTP_PORT | default "80") }} +{{- $_ := set $config "external_https_port" ($globals.Env.HTTPS_PORT | default "443") }} +{{- $_ := set $config "sha1_upstream_name" ($globals.Env.SHA1_UPSTREAM_NAME | default "false" | parseBool) }} +{{- $_ := set $config "default_root_response" ($globals.Env.DEFAULT_ROOT | default "404") }} +{{- $_ := set $config "trust_downstream_proxy" ($globals.Env.TRUST_DOWNSTREAM_PROXY | default "true" | parseBool) }} {{- $_ := set $config "enable_access_log" ($globals.Env.DISABLE_ACCESS_LOGS | default "false" | parseBool | not) }} -{{- $_ := set $config "enable_ipv6" (parseBool (coalesce $globals.Env.ENABLE_IPV6 "false")) }} -{{- $_ := set $config "ssl_policy" (or ($globals.Env.SSL_POLICY) "Mozilla-Intermediate") }} +{{- $_ := set $config "enable_ipv6" ($globals.Env.ENABLE_IPV6 | default "false" | parseBool) }} +{{- $_ := set $config "ssl_policy" ($globals.Env.SSL_POLICY | default "Mozilla-Intermediate") }} {{- $_ := 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") }} From 72bb8a66d87de744f230d68695a6af6acab50664 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Sat, 2 Nov 2024 23:45:31 +0100 Subject: [PATCH 22/27] refactor: further align template syntax --- nginx.tmpl | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/nginx.tmpl b/nginx.tmpl index 8e6d57637..9c76c1655 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -562,7 +562,7 @@ proxy_set_header Proxy ""; {{- range $hostname, $vhost := $parsedVhosts }} {{- $vhost_data := when (hasKey $globals.vhosts $hostname) (get $globals.vhosts $hostname) (dict) }} - {{- $paths := coalesce $vhost_data.paths (dict) }} + {{- $paths := $vhost_data.paths | default (dict) }} {{- if (empty $vhost) }} {{ $vhost = dict "/" (dict) }} @@ -572,7 +572,7 @@ proxy_set_header Proxy ""; {{- if (empty $vpath) }} {{- $vpath = dict "dest" "" "port" "default" }} {{- end }} - {{- $dest := coalesce $vpath.dest "" }} + {{- $dest := $vpath.dest | default "" }} {{- $port := when (hasKey $vpath "port") (toString $vpath.port) "default" }} {{- $path_data := when (hasKey $paths $path) (get $paths $path) (dict) }} {{- $path_ports := when (hasKey $path_data "ports") (get $path_data "ports") (dict) }} @@ -613,12 +613,12 @@ proxy_set_header Proxy ""; {{- end }} {{- $vhost_data := when (hasKey $globals.vhosts $hostname) (get $globals.vhosts $hostname) (dict) }} - {{- $paths := coalesce $vhost_data.paths (dict) }} + {{- $paths := $vhost_data.paths | default (dict) }} {{- $tmp_paths := groupByWithDefault $containers "Env.VIRTUAL_PATH" "/" }} {{- range $path, $containers := $tmp_paths }} - {{- $dest := or (first (groupByKeys $containers "Env.VIRTUAL_DEST")) "" }} + {{- $dest := groupByKeys $containers "Env.VIRTUAL_DEST" | first | default "" }} {{- $port := "legacy" }} {{- $path_data := when (hasKey $paths $path) (get $paths $path) (dict) }} {{- $path_ports := when (hasKey $path_data "ports") (get $path_data "ports") (dict) }} @@ -649,12 +649,12 @@ proxy_set_header Proxy ""; {{- end }} {{- /* Get the VIRTUAL_PROTO defined by containers w/ the same vhost-vpath, falling back to "http". */}} - {{- $proto := trim (or (first (groupByKeys $vpath_containers "Env.VIRTUAL_PROTO")) "http") }} + {{- $proto := groupByKeys $vpath_containers "Env.VIRTUAL_PROTO" | first | default "http" | trim }} {{- /* Get the NETWORK_ACCESS defined by containers w/ the same vhost, falling back to "external". */}} - {{- $network_tag := or (first (groupByKeys $vpath_containers "Env.NETWORK_ACCESS")) "external" }} + {{- $network_tag := groupByKeys $vpath_containers "Env.NETWORK_ACCESS" | first | default "external" }} - {{- $loadbalance := first (keys (groupByLabel $vpath_containers "com.github.nginx-proxy.nginx-proxy.loadbalance")) }} - {{- $keepalive := coalesce (first (keys (groupByLabel $vpath_containers "com.github.nginx-proxy.nginx-proxy.keepalive"))) "disabled" }} + {{- $loadbalance := groupByLabel $vpath_containers "com.github.nginx-proxy.nginx-proxy.loadbalance" | keys | first }} + {{- $keepalive := groupByLabel $vpath_containers "com.github.nginx-proxy.nginx-proxy.keepalive" | keys | first | default "disabled" }} {{- $upstream := $vhost_data.upstream_name }} {{- if (not (eq $path "/")) }} @@ -672,14 +672,14 @@ proxy_set_header Proxy ""; {{ $vhost_containers = concat $vhost_containers $vpath_containers }} {{- end }} - {{- $certName := first (groupByKeys $vhost_containers "Env.CERT_NAME") }} + {{- $certName := groupByKeys $vhost_containers "Env.CERT_NAME" | first }} {{- $vhostCert := closest (dir "/etc/nginx/certs") (printf "%s.crt" $hostname) }} {{- $vhostCert = trimSuffix ".crt" $vhostCert }} {{- $vhostCert = trimSuffix ".key" $vhostCert }} {{- $cert := or $certName $vhostCert }} {{- $cert_ok := and (ne $cert "") (exists (printf "/etc/nginx/certs/%s.crt" $cert)) (exists (printf "/etc/nginx/certs/%s.key" $cert)) }} - {{- $enable_debug_endpoint := coalesce (groupByLabel $vhost_containers "com.github.nginx-proxy.nginx-proxy.debug-endpoint" | keys | first) $globals.config.enable_debug_endpoint | parseBool }} + {{- $enable_debug_endpoint := groupByLabel $vhost_containers "com.github.nginx-proxy.nginx-proxy.debug-endpoint" | keys | first | default $globals.config.enable_debug_endpoint | parseBool }} {{- $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 }} @@ -697,16 +697,16 @@ proxy_set_header Proxy ""; {{- end }} {{- /* Get the SERVER_TOKENS defined by containers w/ the same vhost, falling back to "". */}} - {{- $server_tokens := trim (or (first (groupByKeys $vhost_containers "Env.SERVER_TOKENS")) "") }} + {{- $server_tokens := groupByKeys $vhost_containers "Env.SERVER_TOKENS" | first | default "" | trim }} {{- /* Get the SSL_POLICY defined by containers w/ the same vhost, falling back to empty string (use default). */}} - {{- $ssl_policy := or (first (groupByKeys $vhost_containers "Env.SSL_POLICY")) "" }} + {{- $ssl_policy := groupByKeys $vhost_containers "Env.SSL_POLICY" | first | default "" }} {{- /* Get the HSTS defined by containers w/ the same vhost, falling back to "max-age=31536000". */}} {{- $hsts := groupByKeys $vhost_containers "Env.HSTS" | first | default $globals.config.hsts }} {{- /* Get the VIRTUAL_ROOT By containers w/ use fastcgi root */}} - {{- $vhost_root := or (first (groupByKeys $vhost_containers "Env.VIRTUAL_ROOT")) "/var/www/public" }} + {{- $vhost_root := groupByKeys $vhost_containers "Env.VIRTUAL_ROOT" | first | default "/var/www/public" }} {{- $vhost_data = merge $vhost_data (dict "cert" $cert From 7d909782f9ae747d7580c9e810433d9f16e3e989 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Sun, 3 Nov 2024 11:28:39 +0100 Subject: [PATCH 23/27] refactor: move debug's hostname into vhost --- nginx.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nginx.tmpl b/nginx.tmpl index 9c76c1655..bdb23e0e7 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -380,11 +380,11 @@ upstream {{ $vpath.upstream }} { {{- end }} {{- $debug_vhost := deepCopy .VHost }} + {{- $_ := set $debug_vhost "hostname" .Hostname }} {{- $_ := set $debug_vhost "paths" $debug_paths }} {{- $debug_response := dict "global" .GlobalConfig - "hostname" .Hostname "request" (dict "host" "$host" "https" "$https" From fbf3e2f4580a9faeac9115e10528bdbfc262839f Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Sun, 3 Nov 2024 11:43:16 +0100 Subject: [PATCH 24/27] docs: complete debug endpoint docs --- docs/README.md | 16 ++++++++++++++-- nginx.tmpl | 6 +++--- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/docs/README.md b/docs/README.md index 06e6b2352..ecbd724a5 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1038,19 +1038,29 @@ curl -s -H "Host: test.nginx-proxy.tld" localhost/nginx-proxy-debug | jq ```json { "global": { + "acme_http_challenge": "true", "default_cert_ok": false, + "default_host": null, "default_root_response": "404", "enable_access_log": true, "enable_debug_endpoint": "true", + "enable_http2": "true", + "enable_http3": "false", + "enable_http_on_missing_cert": "true", "enable_ipv6": false, + "enable_json_logs": false, "external_http_port": "80", "external_https_port": "443", - "nginx_proxy_version": "local", + "hsts": "max-age=31536000", + "https_method": "redirect", + "log_format": null, + "log_format_escape": null, + "nginx_proxy_version": "1.6.3", + "resolvers": "127.0.0.11", "sha1_upstream_name": false, "ssl_policy": "Mozilla-Intermediate", "trust_downstream_proxy": true }, - "hostname": "test.nginx-proxy.tld", "request": { "host": "test.nginx-proxy.tld", "http2": "", @@ -1066,10 +1076,12 @@ curl -s -H "Host: test.nginx-proxy.tld" localhost/nginx-proxy-debug | jq "cert_ok": false, "default": false, "enable_debug_endpoint": true, + "hostname": "test.nginx-proxy.tld", "hsts": "max-age=31536000", "http2_enabled": true, "http3_enabled": false, "https_method": "noredirect", + "is_regexp": false, "paths": { "/": { "dest": "", diff --git a/nginx.tmpl b/nginx.tmpl index bdb23e0e7..ba91048bc 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -1,10 +1,10 @@ # nginx-proxy{{ if $.Env.NGINX_PROXY_VERSION }} version : {{ $.Env.NGINX_PROXY_VERSION }}{{ end }} {{- /* - * Global values. Values are stored in this map rather than in individual + * Global values. Values are stored in this map rather than in individual * global variables so that the values can be easily passed to embedded - * templates. (Go templates cannot access variables outside of their own - * scope.) + * templates (Go templates cannot access variables outside of their own + * scope) and displayed in the debug endpoint output. */}} {{- $globals := dict }} {{- $_ := set $globals "containers" $ }} From 523112d205ba4117d423cacc0b99765539b94504 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Nov 2024 04:17:03 +0000 Subject: [PATCH 25/27] build: bump nginxproxy/docker-gen from 0.14.2-debian to 0.14.3-debian Bumps nginxproxy/docker-gen from 0.14.2-debian to 0.14.3-debian. --- updated-dependencies: - dependency-name: nginxproxy/docker-gen dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Dockerfile.alpine | 2 +- Dockerfile.debian | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile.alpine b/Dockerfile.alpine index 9ead8e069..c602cdfc5 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -1,4 +1,4 @@ -FROM docker.io/nginxproxy/docker-gen:0.14.2 AS docker-gen +FROM docker.io/nginxproxy/docker-gen:0.14.3 AS docker-gen FROM docker.io/nginxproxy/forego:0.18.2 AS forego diff --git a/Dockerfile.debian b/Dockerfile.debian index 99cff868e..ec63da850 100644 --- a/Dockerfile.debian +++ b/Dockerfile.debian @@ -1,4 +1,4 @@ -FROM docker.io/nginxproxy/docker-gen:0.14.2-debian AS docker-gen +FROM docker.io/nginxproxy/docker-gen:0.14.3-debian AS docker-gen FROM docker.io/nginxproxy/forego:0.18.2-debian AS forego From fdb7310cda59736cdaee9ea517dd963abf279e33 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Mon, 4 Nov 2024 23:03:01 +0100 Subject: [PATCH 26/27] fix: do not render regexp hostname in debug endpoint response --- nginx.tmpl | 3 ++- test/test_debug_endpoint/test_global.py | 12 +++++++++++- test/test_debug_endpoint/test_global.yml | 8 ++++++++ 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/nginx.tmpl b/nginx.tmpl index ba91048bc..3d416c3c5 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -380,7 +380,8 @@ upstream {{ $vpath.upstream }} { {{- end }} {{- $debug_vhost := deepCopy .VHost }} - {{- $_ := set $debug_vhost "hostname" .Hostname }} + {{- /* If it's a regexp, do not render the Hostname to the response to avoid rendering config breaking characters */}} + {{- $_ := set $debug_vhost "hostname" (.VHost.is_regexp | ternary "Hostname is a regexp and unsafe to include in the debug response." .Hostname) }} {{- $_ := set $debug_vhost "paths" $debug_paths }} {{- $debug_response := dict diff --git a/test/test_debug_endpoint/test_global.py b/test/test_debug_endpoint/test_global.py index b151b6941..aaa7b1fc0 100644 --- a/test/test_debug_endpoint/test_global.py +++ b/test/test_debug_endpoint/test_global.py @@ -19,7 +19,7 @@ def test_debug_endpoint_response_contains_expected_values(docker_compose, nginxp assert jsonResponse["vhost"]["enable_debug_endpoint"] == True -def test_debug_endpoint_pahts_stripped_if_response_too_long(docker_compose, nginxproxy): +def test_debug_endpoint_paths_stripped_if_response_too_long(docker_compose, nginxproxy): r = nginxproxy.get("http://stripped.debug.nginx-proxy.example/nginx-proxy-debug") assert r.status_code == 200 try: @@ -31,6 +31,16 @@ def test_debug_endpoint_pahts_stripped_if_response_too_long(docker_compose, ngin assert jsonResponse["warning"] == "Virtual paths configuration for this hostname is too large and has been stripped from response." +def test_debug_endpoint_hostname_replaced_by_warning_if_regexp(docker_compose, nginxproxy): + r = nginxproxy.get("http://regexp.foo.debug.nginx-proxy.example/nginx-proxy-debug") + assert r.status_code == 200 + try: + jsonResponse = json.loads(r.text) + except ValueError as err: + pytest.fail("Failed to parse debug endpoint response as JSON: %s" % err, pytrace=False) + assert jsonResponse["vhost"]["hostname"] == "Hostname is a regexp and unsafe to include in the debug response." + + def test_debug_endpoint_is_disabled_per_container(docker_compose, nginxproxy): r = nginxproxy.get("http://disabled.debug.nginx-proxy.example/nginx-proxy-debug") assert r.status_code == 404 diff --git a/test/test_debug_endpoint/test_global.yml b/test/test_debug_endpoint/test_global.yml index 7ec99efb2..179703899 100644 --- a/test/test_debug_endpoint/test_global.yml +++ b/test/test_debug_endpoint/test_global.yml @@ -42,6 +42,14 @@ services: "/18": "/19": "/20": + + debug_regexp: + image: web + expose: + - "84" + environment: + WEB_PORTS: 84 + VIRTUAL_HOST: ~^regexp.*\.debug.nginx-proxy.example debug_disabled: image: web From d4d6567bd3c04c1634616eb30832a9c0c9d3daa9 Mon Sep 17 00:00:00 2001 From: Niek <100143256+SchoNie@users.noreply.github.com> Date: Tue, 5 Nov 2024 14:05:53 +0100 Subject: [PATCH 27/27] Test for DISABLE_ACCESS_LOGS --- test/test_logs/test_log_disabled.py | 11 +++++++++++ test/test_logs/test_log_disabled.yml | 18 ++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 test/test_logs/test_log_disabled.py create mode 100644 test/test_logs/test_log_disabled.yml diff --git a/test/test_logs/test_log_disabled.py b/test/test_logs/test_log_disabled.py new file mode 100644 index 000000000..2870b9057 --- /dev/null +++ b/test/test_logs/test_log_disabled.py @@ -0,0 +1,11 @@ +import pytest + +def test_log_disabled(docker_compose, nginxproxy): + r = nginxproxy.get("http://nginx-proxy.test/port") + assert r.status_code == 200 + assert r.text == "answer from port 81\n" + sut_container = docker_compose.containers.get("sut") + docker_logs = sut_container.logs(stdout=True, stderr=True, stream=False, follow=False) + docker_logs = docker_logs.decode("utf-8").splitlines() + docker_logs = [line for line in docker_logs if "GET /port" in line] + assert len(docker_logs) == 0 diff --git a/test/test_logs/test_log_disabled.yml b/test/test_logs/test_log_disabled.yml new file mode 100644 index 000000000..2d8a59c91 --- /dev/null +++ b/test/test_logs/test_log_disabled.yml @@ -0,0 +1,18 @@ +version: "2" + +services: + web1: + image: web + expose: + - "81" + environment: + WEB_PORTS: 81 + VIRTUAL_HOST: nginx-proxy.test + + sut: + container_name: sut + image: nginxproxy/nginx-proxy:test + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro + environment: + DISABLE_ACCESS_LOGS: true