From 0780e636f94a7eee9ba76249c05ccbe07257a9f5 Mon Sep 17 00:00:00 2001 From: Unchun Yang Date: Sat, 23 Oct 2021 00:08:32 +0900 Subject: [PATCH 001/300] Remove unnecessary tabs --- nginx.tmpl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nginx.tmpl b/nginx.tmpl index e79f790..2e1415e 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -266,7 +266,7 @@ server { listen [::]:{{ $external_http_port }} {{ $default_server }}; {{ end }} {{ $access_log }} - + # Do not HTTPS redirect Let'sEncrypt ACME challenge location ^~ /.well-known/acme-challenge/ { auth_basic off; @@ -276,7 +276,7 @@ server { try_files $uri =404; break; } - + location / { {{ if eq $external_https_port "443" }} return 301 https://$host$request_uri; From 8c909e7d11087a1a80bbd220e5c016dbea9c82d4 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Wed, 15 Dec 2021 11:53:37 +0100 Subject: [PATCH 002/300] build: nginx 1.21.3 -> 1.21.4 --- Dockerfile | 2 +- Dockerfile.alpine | 2 +- README.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index 52deb3f..8005b95 100644 --- a/Dockerfile +++ b/Dockerfile @@ -36,7 +36,7 @@ RUN git clone https://github.com/nginx-proxy/forego/ \ && rm -rf /go/forego # Build the final image -FROM nginx:1.21.3 +FROM nginx:1.21.4 LABEL maintainer="Nicolas Duchon (@buchdag)" # Install wget and install/updates certificates diff --git a/Dockerfile.alpine b/Dockerfile.alpine index cf64cb7..75250f6 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -37,7 +37,7 @@ RUN git clone https://github.com/nginx-proxy/forego/ \ && rm -rf /go/forego # Build the final image -FROM nginx:1.21.3-alpine +FROM nginx:1.21.4-alpine LABEL maintainer="Nicolas Duchon (@buchdag)" # Install wget and install/updates certificates diff --git a/README.md b/README.md index d387b73..45b0f6c 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ [![Test](https://github.com/nginx-proxy/nginx-proxy/actions/workflows/test.yml/badge.svg)](https://github.com/nginx-proxy/nginx-proxy/actions/workflows/test.yml) [![GitHub release](https://img.shields.io/github/v/release/nginx-proxy/nginx-proxy)](https://github.com/nginx-proxy/nginx-proxy/releases) -![nginx 1.21.1](https://img.shields.io/badge/nginx-1.21.1-brightgreen.svg) +![nginx 1.21.4](https://img.shields.io/badge/nginx-1.21.4-brightgreen.svg) [![Docker Image Size](https://img.shields.io/docker/image-size/nginxproxy/nginx-proxy?sort=semver)](https://hub.docker.com/r/nginxproxy/nginx-proxy "Click to view the image on Docker Hub") [![Docker stars](https://img.shields.io/docker/stars/nginxproxy/nginx-proxy.svg)](https://hub.docker.com/r/nginxproxy/nginx-proxy 'DockerHub') [![Docker pulls](https://img.shields.io/docker/pulls/nginxproxy/nginx-proxy.svg)](https://hub.docker.com/r/nginxproxy/nginx-proxy 'DockerHub') From 496e0f5f27974f21c444910477b4e18444f73b58 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Wed, 15 Dec 2021 13:01:38 +0100 Subject: [PATCH 003/300] tests: mark test_deleted_cert as xfail test_delete_cert_and_restart_reverseproxy still fails intermitently --- .../test_deleted_cert/test_restart_while_missing_cert.py | 1 + 1 file changed, 1 insertion(+) diff --git a/test/stress_tests/test_deleted_cert/test_restart_while_missing_cert.py b/test/stress_tests/test_deleted_cert/test_restart_while_missing_cert.py index 0c5565b..d7e4cbb 100644 --- a/test/stress_tests/test_deleted_cert/test_restart_while_missing_cert.py +++ b/test/stress_tests/test_deleted_cert/test_restart_while_missing_cert.py @@ -9,6 +9,7 @@ from requests import ConnectionError script_dir = os.path.dirname(__file__) +pytestmark = pytest.mark.xfail() # TODO delete this marker once those issues are fixed @pytest.fixture(scope="module", autouse=True) def certs(): From 75528bdfcbde2f341824787fa075e7599032fcb4 Mon Sep 17 00:00:00 2001 From: polarathene <5098581+polarathene@users.noreply.github.com> Date: Tue, 21 Dec 2021 18:36:21 +1300 Subject: [PATCH 004/300] chore: Refactor checksum comparisons - Use a DRY method instead. - ENV test changed from 2048-bit to 3072-bit to avoid confusion in a future test that should not be mixed up accidentally with 2048-bit elsewhere. - Custom DH file test comparison changed to match other comparisons for equality against the expected DH param content. - Related comments revised, additional comment for context added by the test definition. - Minor white-space adjustments. --- test/test_ssl/test_dhparam.py | 40 ++++++++++++++++++++++++---------- test/test_ssl/test_dhparam.yml | 6 ++--- 2 files changed, 31 insertions(+), 15 deletions(-) diff --git a/test/test_ssl/test_dhparam.py b/test/test_ssl/test_dhparam.py index 6de92b2..64b26ae 100644 --- a/test/test_ssl/test_dhparam.py +++ b/test/test_ssl/test_dhparam.py @@ -101,6 +101,13 @@ def cannot_negotiate_dhe_ciphersuite(sut_container): assert "X25519" in r3 +def should_be_equivalent_content(sut_container, expected, actual): + expected_checksum = sut_container.exec_run(f"md5sum {expected}").output.split()[0] + actual_checksum = sut_container.exec_run(f"md5sum {actual}").output.split()[0] + + assert expected_checksum == actual_checksum + + # Parse array of container ENV, splitting at the `=` and returning the value, otherwise `None` def get_env(sut_container, var): env = sut_container.attrs['Config']['Env'] @@ -125,14 +132,17 @@ def test_default_dhparam_is_ffdhe4096(docker_compose): assert_log_contains("Setting up DH Parameters..", container_name) - # Make sure the dhparam file used is the default ffdhe4096.pem: - default_checksum = sut_container.exec_run("md5sum /app/dhparam/ffdhe4096.pem").output.split() - current_checksum = sut_container.exec_run("md5sum /etc/nginx/dhparam/dhparam.pem").output.split() - assert default_checksum[0] == current_checksum[0] + # `dhparam.pem` contents should match the default (ffdhe4096.pem): + should_be_equivalent_content( + sut_container, + "/app/dhparam/ffdhe4096.pem", + "/etc/nginx/dhparam/dhparam.pem" + ) can_negotiate_dhe_ciphersuite(sut_container) +# Overrides default DH group via ENV `DHPARAM_BITS=3072`: def test_can_change_dhparam_group(docker_compose): container_name="dh-env" sut_container = docker_client.containers.get(container_name) @@ -140,10 +150,12 @@ def test_can_change_dhparam_group(docker_compose): assert_log_contains("Setting up DH Parameters..", container_name) - # Make sure the dhparam file used is ffdhe2048.pem, not the default (ffdhe4096.pem): - default_checksum = sut_container.exec_run("md5sum /app/dhparam/ffdhe2048.pem").output.split() - current_checksum = sut_container.exec_run("md5sum /etc/nginx/dhparam/dhparam.pem").output.split() - assert default_checksum[0] == current_checksum[0] + # `dhparam.pem` contents should not match the default (ffdhe4096.pem): + should_be_equivalent_content( + sut_container, + "/app/dhparam/ffdhe3072.pem", + "/etc/nginx/dhparam/dhparam.pem" + ) can_negotiate_dhe_ciphersuite(sut_container) @@ -162,6 +174,7 @@ def test_fail_if_dhparam_group_not_supported(docker_compose): ) +# Overrides default DH group by providing a custom `/etc/nginx/dhparam/dhparam.pem`: def test_custom_dhparam_is_supported(docker_compose): container_name="dh-file" sut_container = docker_client.containers.get(container_name) @@ -172,10 +185,12 @@ def test_custom_dhparam_is_supported(docker_compose): container_name ) - # Make sure the dhparam file used is not the default (ffdhe4096.pem): - default_checksum = sut_container.exec_run("md5sum /app/dhparam/ffdhe4096.pem").output.split() - current_checksum = sut_container.exec_run("md5sum /etc/nginx/dhparam/dhparam.pem").output.split() - assert default_checksum[0] != current_checksum[0] + # `dhparam.pem` contents should not match the default (ffdhe4096.pem): + should_be_equivalent_content( + sut_container, + "/app/dhparam/ffdhe3072.pem", + "/etc/nginx/dhparam/dhparam.pem" + ) can_negotiate_dhe_ciphersuite(sut_container) @@ -189,6 +204,7 @@ def test_can_skip_dhparam(docker_compose): cannot_negotiate_dhe_ciphersuite(sut_container) + def test_can_skip_dhparam_backward_compatibility(docker_compose): container_name="dh-skip-backward" sut_container = docker_client.containers.get(container_name) diff --git a/test/test_ssl/test_dhparam.yml b/test/test_ssl/test_dhparam.yml index d49afc9..c8b0a85 100644 --- a/test/test_ssl/test_dhparam.yml +++ b/test/test_ssl/test_dhparam.yml @@ -19,7 +19,7 @@ with_default_group: with_alternative_group: container_name: dh-env environment: - - DHPARAM_BITS=2048 + - DHPARAM_BITS=3072 image: *img-nginxproxy volumes: *vols-common @@ -33,7 +33,7 @@ with_invalid_group: with_custom_file: container_name: dh-file image: *img-nginxproxy - volumes: + volumes: - *docker-sock - *nginx-certs - ../../dhparam/ffdhe3072.pem:/etc/nginx/dhparam/dhparam.pem:ro @@ -50,4 +50,4 @@ with_skip_backward: environment: - DHPARAM_GENERATION=false image: *img-nginxproxy - volumes: *vols-common \ No newline at end of file + volumes: *vols-common From 0f15130476412664c0ce41bbad2456d6dbae25f3 Mon Sep 17 00:00:00 2001 From: polarathene <5098581+polarathene@users.noreply.github.com> Date: Tue, 21 Dec 2021 17:38:38 +1300 Subject: [PATCH 005/300] tests: Verify correct DH group size when negotiating Additionally allows for adding extra openssl params when needed. --- test/test_ssl/test_dhparam.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/test/test_ssl/test_dhparam.py b/test/test_ssl/test_dhparam.py index 64b26ae..ee83214 100644 --- a/test/test_ssl/test_dhparam.py +++ b/test/test_ssl/test_dhparam.py @@ -80,12 +80,17 @@ def negotiate_cipher(sut_container, additional_params='', grep='Cipher is'): raise Exception("Failed to process CLI request:\n" + e.stderr) from None -def can_negotiate_dhe_ciphersuite(sut_container): - r = negotiate_cipher(sut_container, "-cipher 'EDH'") +# The default `dh_bits` can vary due to configuration. +# `additional_params` allows for adjusting the request to a specific `VIRTUAL_HOST`, +# where DH size can differ from the configured global default DH size. +def can_negotiate_dhe_ciphersuite(sut_container, dh_bits=4096, additional_params=''): + openssl_params = f"-cipher 'EDH' {additional_params}" + + r = negotiate_cipher(sut_container, openssl_params) assert "New, TLSv1.2, Cipher is DHE-RSA-AES256-GCM-SHA384\n" == r - r2 = negotiate_cipher(sut_container, "-cipher 'EDH'", "Server Temp Key") - assert "DH" in r2 + r2 = negotiate_cipher(sut_container, openssl_params, "Server Temp Key") + assert f"Server Temp Key: DH, {dh_bits} bits" in r2 def cannot_negotiate_dhe_ciphersuite(sut_container): @@ -139,7 +144,7 @@ def test_default_dhparam_is_ffdhe4096(docker_compose): "/etc/nginx/dhparam/dhparam.pem" ) - can_negotiate_dhe_ciphersuite(sut_container) + can_negotiate_dhe_ciphersuite(sut_container, 4096) # Overrides default DH group via ENV `DHPARAM_BITS=3072`: @@ -157,7 +162,7 @@ def test_can_change_dhparam_group(docker_compose): "/etc/nginx/dhparam/dhparam.pem" ) - can_negotiate_dhe_ciphersuite(sut_container) + can_negotiate_dhe_ciphersuite(sut_container, 3072) def test_fail_if_dhparam_group_not_supported(docker_compose): @@ -192,7 +197,7 @@ def test_custom_dhparam_is_supported(docker_compose): "/etc/nginx/dhparam/dhparam.pem" ) - can_negotiate_dhe_ciphersuite(sut_container) + can_negotiate_dhe_ciphersuite(sut_container, 3072) def test_can_skip_dhparam(docker_compose): From 9dc9d90d34b4d47b4b2ca975235f12a6b7a220b2 Mon Sep 17 00:00:00 2001 From: polarathene <5098581+polarathene@users.noreply.github.com> Date: Tue, 21 Dec 2021 17:50:58 +1300 Subject: [PATCH 006/300] tests: Verify site-specific DH params feature works correctly This addition requires usage of `DEFAULT_HOST` on containers tested to ensure they don't accidentally use `web2` as their default fallback (due to no SNI / `-servername` requested in openssl queries), otherwise they would be testing against the incorrect DH params response. They could alternatively request an FQDN explicitly as well, instead of relying on implicit fallback/default server selection behaviour. --- `web2.nginx-proxy.tld.dhparam.pem` is a copy of `ffdhe2048.pem`. --- .../certs/web2.nginx-proxy.tld.dhparam.pem | 8 +++++++ test/test_ssl/test_dhparam.py | 24 +++++++++++++++++++ test/test_ssl/test_dhparam.yml | 20 ++++++++++++++++ 3 files changed, 52 insertions(+) create mode 100644 test/test_ssl/certs/web2.nginx-proxy.tld.dhparam.pem diff --git a/test/test_ssl/certs/web2.nginx-proxy.tld.dhparam.pem b/test/test_ssl/certs/web2.nginx-proxy.tld.dhparam.pem new file mode 100644 index 0000000..088f967 --- /dev/null +++ b/test/test_ssl/certs/web2.nginx-proxy.tld.dhparam.pem @@ -0,0 +1,8 @@ +-----BEGIN DH PARAMETERS----- +MIIBCAKCAQEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz ++8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a +87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7 +YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi +7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD +ssbzSibBsu/6iGtCOGEoXJf//////////wIBAg== +-----END DH PARAMETERS----- \ No newline at end of file diff --git a/test/test_ssl/test_dhparam.py b/test/test_ssl/test_dhparam.py index ee83214..c95af6e 100644 --- a/test/test_ssl/test_dhparam.py +++ b/test/test_ssl/test_dhparam.py @@ -200,6 +200,30 @@ def test_custom_dhparam_is_supported(docker_compose): can_negotiate_dhe_ciphersuite(sut_container, 3072) +# Only `web2` has a site-specific DH param file (which overrides all other DH config) +# Other tests here use `web5` explicitly, or implicitly (via ENV `DEFAULT_HOST`, otherwise first HTTPS server) +def test_custom_dhparam_is_supported_per_site(docker_compose): + container_name="dh-file" + sut_container = docker_client.containers.get(container_name) + assert sut_container.status == "running" + + # A site specific `dhparam.pem` with DH group size of 2048-bit. + # DH group size should not match the: + # - 4096-bit default. + # - 3072-bit default, overriden by file. + should_be_equivalent_content( + sut_container, + "/app/dhparam/ffdhe2048.pem", + "/etc/nginx/certs/web2.nginx-proxy.tld.dhparam.pem" + ) + + # `-servername` required for nginx-proxy to respond with site-specific DH params used: + can_negotiate_dhe_ciphersuite(sut_container, 2048, '-servername web2.nginx-proxy.tld') + + +# NOTE: These two tests will fail without the ENV `DEFAULT_HOST` to prevent +# accidentally falling back to `web2` as the default server, which has explicit DH params configured. +# Only copying DH params is skipped, not explicit usage via user providing custom files. def test_can_skip_dhparam(docker_compose): container_name="dh-skip" sut_container = docker_client.containers.get(container_name) diff --git a/test/test_ssl/test_dhparam.yml b/test/test_ssl/test_dhparam.yml index c8b0a85..fa4fe1e 100644 --- a/test/test_ssl/test_dhparam.yml +++ b/test/test_ssl/test_dhparam.yml @@ -6,12 +6,27 @@ web5: WEB_PORTS: "85" VIRTUAL_HOST: "web5.nginx-proxy.tld" +# Intended for testing with `dh-file` container. +# VIRTUAL_HOST is paired with site-specific DH param file. +# DEFAULT_HOST is required to avoid defaulting to web2, +# if not specifying FQDN (`-servername`) in openssl queries. +web2: + image: web + expose: + - "85" + environment: + WEB_PORTS: "85" + VIRTUAL_HOST: "web2.nginx-proxy.tld" + + # sut - System Under Test # `docker.sock` required for functionality # `certs` required to enable HTTPS via template with_default_group: container_name: dh-default image: &img-nginxproxy nginxproxy/nginx-proxy:test + environment: &env-common + - &default-host DEFAULT_HOST=web5.nginx-proxy.tld volumes: &vols-common - &docker-sock /var/run/docker.sock:/tmp/docker.sock:ro - &nginx-certs ./certs:/etc/nginx/certs:ro @@ -20,6 +35,7 @@ with_alternative_group: container_name: dh-env environment: - DHPARAM_BITS=3072 + - *default-host image: *img-nginxproxy volumes: *vols-common @@ -27,12 +43,14 @@ with_invalid_group: container_name: invalid-group-1024 environment: - DHPARAM_BITS=1024 + - *default-host image: *img-nginxproxy volumes: *vols-common with_custom_file: container_name: dh-file image: *img-nginxproxy + environment: *env-common volumes: - *docker-sock - *nginx-certs @@ -42,6 +60,7 @@ with_skip: container_name: dh-skip environment: - DHPARAM_SKIP=true + - *default-host image: *img-nginxproxy volumes: *vols-common @@ -49,5 +68,6 @@ with_skip_backward: container_name: dh-skip-backward environment: - DHPARAM_GENERATION=false + - *default-host image: *img-nginxproxy volumes: *vols-common From c5166f580e61442668bd1223a1867ecd0882e809 Mon Sep 17 00:00:00 2001 From: polarathene <5098581+polarathene@users.noreply.github.com> Date: Tue, 21 Dec 2021 18:00:39 +1300 Subject: [PATCH 007/300] tests: Add utility method to verify TLS chain of trust --- test/test_ssl/test_dhparam.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/test/test_ssl/test_dhparam.py b/test/test_ssl/test_dhparam.py index c95af6e..2f69ad3 100644 --- a/test/test_ssl/test_dhparam.py +++ b/test/test_ssl/test_dhparam.py @@ -1,5 +1,6 @@ import re import subprocess +import os import backoff import docker @@ -106,6 +107,22 @@ def cannot_negotiate_dhe_ciphersuite(sut_container): assert "X25519" in r3 +# To verify self-signed certificates, the file path to their CA cert must be provided. +# Use the `fqdn` arg to specify the `VIRTUAL_HOST` to request for verification for that cert. +# +# Resolves the following stderr warnings regarding self-signed cert verification and missing SNI: +# `Can't use SSL_get_servername` +# `verify error:num=20:unable to get local issuer certificate` +# `verify error:num=21:unable to verify the first certificate` +# +# The stderr output is hidden due to running the openssl command with `stderr=subprocess.PIPE`. +def can_verify_chain_of_trust(sut_container, ca_cert, fqdn): + openssl_params = f"-CAfile '{ca_cert}' -servername '{fqdn}'" + + r = negotiate_cipher(sut_container, openssl_params, "Verify return code") + assert "Verify return code: 0 (ok)" in r + + def should_be_equivalent_content(sut_container, expected, actual): expected_checksum = sut_container.exec_run(f"md5sum {expected}").output.split()[0] actual_checksum = sut_container.exec_run(f"md5sum {actual}").output.split()[0] @@ -220,6 +237,15 @@ def test_custom_dhparam_is_supported_per_site(docker_compose): # `-servername` required for nginx-proxy to respond with site-specific DH params used: can_negotiate_dhe_ciphersuite(sut_container, 2048, '-servername web2.nginx-proxy.tld') + # --Unrelated to DH support-- + # - `web5` is missing a certificate, but falls back to available `/etc/nginx/certs/nginx-proxy.tld.crt` via `nginx.tmpl` "closest" result. + # - `web2` has it's own cert provisioned at `/etc/nginx/certs/web2.nginx-proxy.tld.crt`. + can_verify_chain_of_trust( + sut_container, + ca_cert = f"{os.getcwd()}/certs/ca-root.crt", + fqdn = 'web2.nginx-proxy.tld' + ) + # NOTE: These two tests will fail without the ENV `DEFAULT_HOST` to prevent # accidentally falling back to `web2` as the default server, which has explicit DH params configured. From 0493e799f4b30536594ee7d9f603769e2ce81d2c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 30 Dec 2021 04:08:35 +0000 Subject: [PATCH 008/300] chore(deps): bump nginx from 1.21.4 to 1.21.5 Bumps nginx from 1.21.4 to 1.21.5. --- updated-dependencies: - dependency-name: nginx dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Dockerfile | 2 +- Dockerfile.alpine | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 8005b95..95db046 100644 --- a/Dockerfile +++ b/Dockerfile @@ -36,7 +36,7 @@ RUN git clone https://github.com/nginx-proxy/forego/ \ && rm -rf /go/forego # Build the final image -FROM nginx:1.21.4 +FROM nginx:1.21.5 LABEL maintainer="Nicolas Duchon (@buchdag)" # Install wget and install/updates certificates diff --git a/Dockerfile.alpine b/Dockerfile.alpine index 75250f6..81fd9d3 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -37,7 +37,7 @@ RUN git clone https://github.com/nginx-proxy/forego/ \ && rm -rf /go/forego # Build the final image -FROM nginx:1.21.4-alpine +FROM nginx:1.21.5-alpine LABEL maintainer="Nicolas Duchon (@buchdag)" # Install wget and install/updates certificates From 93c04dce8df3025f77912c5d93d99e619172266c Mon Sep 17 00:00:00 2001 From: polarathene <5098581+polarathene@users.noreply.github.com> Date: Fri, 31 Dec 2021 20:43:02 +1300 Subject: [PATCH 009/300] fix: Properly detect pytest running via container The original `/.dockerenv` approach is no longer valid, and context wise we're only using this for the test suite, so using an ENV in that container is a better solution. --- test/conftest.py | 10 +++++----- test/requirements/Dockerfile-nginx-proxy-tester | 2 ++ 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/test/conftest.py b/test/conftest.py index 3e0f3af..438210e 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -23,7 +23,7 @@ logging.getLogger('DNS').setLevel(logging.DEBUG) logging.getLogger('requests.packages.urllib3.connectionpool').setLevel(logging.WARN) CA_ROOT_CERTIFICATE = os.path.join(os.path.dirname(__file__), 'certs/ca-root.crt') -I_AM_RUNNING_INSIDE_A_DOCKER_CONTAINER = os.path.isfile("/.dockerenv") +PYTEST_RUNNING_IN_CONTAINER = os.environ.get('PYTEST_RUNNING_IN_CONTAINER') == "1" FORCE_CONTAINER_IPV6 = False # ugly global state to consider containers' IPv6 address instead of IPv4 @@ -259,7 +259,7 @@ def restore_urllib_dns_resolver(getaddrinfo_func): def remove_all_containers(): for container in docker_client.containers.list(all=True): - if I_AM_RUNNING_INSIDE_A_DOCKER_CONTAINER and container.id.startswith(socket.gethostname()): + if PYTEST_RUNNING_IN_CONTAINER and container.id.startswith(socket.gethostname()): continue # pytest is running within a Docker container, so we do not want to remove that particular container logging.info(f"removing container {container.name}") container.remove(v=True, force=True) @@ -349,7 +349,7 @@ def connect_to_network(network): :return: the name of the network we were connected to, or None """ - if I_AM_RUNNING_INSIDE_A_DOCKER_CONTAINER: + if PYTEST_RUNNING_IN_CONTAINER: try: my_container = docker_client.containers.get(socket.gethostname()) except docker.errors.NotFound: @@ -372,7 +372,7 @@ def disconnect_from_network(network=None): :param network: name of a docker network to disconnect from """ - if I_AM_RUNNING_INSIDE_A_DOCKER_CONTAINER and network is not None: + if PYTEST_RUNNING_IN_CONTAINER and network is not None: try: my_container = docker_client.containers.get(socket.gethostname()) except docker.errors.NotFound: @@ -394,7 +394,7 @@ def connect_to_all_networks(): :return: a list of networks we connected to """ - if not I_AM_RUNNING_INSIDE_A_DOCKER_CONTAINER: + if not PYTEST_RUNNING_IN_CONTAINER: return [] else: # find the list of docker networks diff --git a/test/requirements/Dockerfile-nginx-proxy-tester b/test/requirements/Dockerfile-nginx-proxy-tester index 3c25c0c..36984fe 100644 --- a/test/requirements/Dockerfile-nginx-proxy-tester +++ b/test/requirements/Dockerfile-nginx-proxy-tester @@ -1,5 +1,7 @@ FROM python:3.9 +ENV PYTEST_RUNNING_IN_CONTAINER=1 + COPY python-requirements.txt /requirements.txt RUN pip install -r /requirements.txt From e748d53a1f614b5210143e00202daf6c1219e127 Mon Sep 17 00:00:00 2001 From: polarathene <5098581+polarathene@users.noreply.github.com> Date: Fri, 31 Dec 2021 21:51:40 +1300 Subject: [PATCH 010/300] chore: Extract hostname access to a var DRY and clearer that we're referring to the pytest container. --- test/conftest.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/test/conftest.py b/test/conftest.py index 438210e..2212ba4 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -28,6 +28,7 @@ FORCE_CONTAINER_IPV6 = False # ugly global state to consider containers' IPv6 a docker_client = docker.from_env() +test_container = socket.gethostname() ############################################################################### @@ -259,7 +260,7 @@ def restore_urllib_dns_resolver(getaddrinfo_func): def remove_all_containers(): for container in docker_client.containers.list(all=True): - if PYTEST_RUNNING_IN_CONTAINER and container.id.startswith(socket.gethostname()): + if PYTEST_RUNNING_IN_CONTAINER and container.id.startswith(test_container): continue # pytest is running within a Docker container, so we do not want to remove that particular container logging.info(f"removing container {container.name}") container.remove(v=True, force=True) @@ -351,9 +352,9 @@ def connect_to_network(network): """ if PYTEST_RUNNING_IN_CONTAINER: try: - my_container = docker_client.containers.get(socket.gethostname()) + my_container = docker_client.containers.get(test_container) except docker.errors.NotFound: - logging.warn(f"container {socket.gethostname()!r} not found") + logging.warn(f"container {test_container} not found") return # figure out our container networks @@ -374,9 +375,9 @@ def disconnect_from_network(network=None): """ if PYTEST_RUNNING_IN_CONTAINER and network is not None: try: - my_container = docker_client.containers.get(socket.gethostname()) + my_container = docker_client.containers.get(test_container) except docker.errors.NotFound: - logging.warn(f"container {socket.gethostname()!r} not found") + logging.warn(f"container {test_container} not found") return # figure out our container networks From b2b4c7199730baa86996fececaedeb70d4618198 Mon Sep 17 00:00:00 2001 From: polarathene <5098581+polarathene@users.noreply.github.com> Date: Fri, 31 Dec 2021 22:12:25 +1300 Subject: [PATCH 011/300] fix: Don't remove pytest container when running with host network mode When the container runs with host networking instead of the default bridge, the `$HOSTNAME` / `/etc/hostname` reflects that of the host instead of the container ID , which causes the pytest container to get removed accidentally. Using a container name instead we can more reliably target the container to avoid removing it, should we need to run with host networking instead. --- test/conftest.py | 6 ++++-- test/pytest.sh | 10 +++++----- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/test/conftest.py b/test/conftest.py index 2212ba4..b8db538 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -28,7 +28,9 @@ FORCE_CONTAINER_IPV6 = False # ugly global state to consider containers' IPv6 a docker_client = docker.from_env() -test_container = socket.gethostname() + +# Name of pytest container to reference if it's being used for running tests +test_container = 'nginx-proxy-pytest' ############################################################################### @@ -260,7 +262,7 @@ def restore_urllib_dns_resolver(getaddrinfo_func): def remove_all_containers(): for container in docker_client.containers.list(all=True): - if PYTEST_RUNNING_IN_CONTAINER and container.id.startswith(test_container): + if PYTEST_RUNNING_IN_CONTAINER and container.name == test_container: continue # pytest is running within a Docker container, so we do not want to remove that particular container logging.info(f"removing container {container.name}") container.remove(v=True, force=True) diff --git a/test/pytest.sh b/test/pytest.sh index 99c054c..28275e5 100755 --- a/test/pytest.sh +++ b/test/pytest.sh @@ -18,8 +18,8 @@ docker build -t nginx-proxy-tester -f "${DIR}/requirements/Dockerfile-nginx-prox # run the nginx-proxy-tester container setting the correct value for the working dir in order for # docker-compose to work properly when run from within that container. -exec docker run --rm -it \ ---volume /var/run/docker.sock:/var/run/docker.sock \ ---volume "${DIR}:${DIR}" \ ---workdir "${DIR}" \ -nginx-proxy-tester "${ARGS[@]}" \ No newline at end of file +exec docker run --rm -it --name "nginx-proxy-pytest" \ + --volume "/var/run/docker.sock:/var/run/docker.sock" \ + --volume "${DIR}:${DIR}" \ + --workdir "${DIR}" \ + nginx-proxy-tester "${ARGS[@]}" \ No newline at end of file From 0e5d97a268a7dac6151631ce664cadf201b84fa9 Mon Sep 17 00:00:00 2001 From: polarathene <5098581+polarathene@users.noreply.github.com> Date: Fri, 31 Dec 2021 22:14:26 +1300 Subject: [PATCH 012/300] fix: Don't connect pytest container to networks when using host network This is not compatible or required, since host networking is no longer isolated to container networks only. --- test/conftest.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/conftest.py b/test/conftest.py index b8db538..3f5f04c 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -362,6 +362,10 @@ def connect_to_network(network): # figure out our container networks my_networks = list(my_container.attrs["NetworkSettings"]["Networks"].keys()) + # If the pytest container is using host networking, it cannot connect to container networks (not required with host network) + if 'host' in my_networks: + return None + # make sure our container is connected to the nginx-proxy's network if network not in my_networks: logging.info(f"Connecting to docker network: {network.name}") From 04b0181980c0ec51accede0618a53788959e3d95 Mon Sep 17 00:00:00 2001 From: polarathene <5098581+polarathene@users.noreply.github.com> Date: Fri, 31 Dec 2021 22:30:49 +1300 Subject: [PATCH 013/300] fix: Ensure networks are actually connected to pytest container The `network` object would never be in a list of network names (strings), and without `greedy=True` arg as the `docker-py` API docs note, the containers will not be part of the results, thus always returning an empty list which was not intended.. Now the network will properly match the current networks for pytest container, avoiding duplicate connect attempts, and the network list result will actually have containers to count when filtering by length. --- test/conftest.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/conftest.py b/test/conftest.py index 3f5f04c..fce4cde 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -367,7 +367,7 @@ def connect_to_network(network): return None # make sure our container is connected to the nginx-proxy's network - if network not in my_networks: + if network.name not in my_networks: logging.info(f"Connecting to docker network: {network.name}") network.connect(my_container) return network @@ -405,7 +405,7 @@ def connect_to_all_networks(): return [] else: # find the list of docker networks - networks = [network for network in docker_client.networks.list() if len(network.containers) > 0 and network.name != 'bridge'] + networks = [network for network in docker_client.networks.list(greedy=True) if len(network.containers) > 0 and network.name != 'bridge'] return [connect_to_network(network) for network in networks] From 115461744b931f81f175b5f2ed3b17e74179e1f8 Mon Sep 17 00:00:00 2001 From: polarathene <5098581+polarathene@users.noreply.github.com> Date: Sat, 1 Jan 2022 01:38:13 +1300 Subject: [PATCH 014/300] fix: Skip IPv6 when forced but not available + avoid `none` network A test on raw IP addresses doesn't reach the existing IPv6 skip logic, added that to avoid a test failing when only IPv4 is available (eg: standard docker container networks). Additionally some other tests set the `none` network and connecting to this fails as it's not allowed? Preventing that from happening resolves the final failing tests within containerized pytest. --- test/conftest.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/test/conftest.py b/test/conftest.py index fce4cde..dda8379 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -239,6 +239,11 @@ def monkey_patch_urllib_dns_resolver(): logging.getLogger('DNS').debug(f"resolving domain name {repr(args)}") _args = list(args) + # Fail early when querying IP directly and it is forced ipv6 when not supported, + # Otherwise a pytest container not using the host network fails to pass `test_raw-ip-vhost`. + if FORCE_CONTAINER_IPV6 and not HAS_IPV6: + pytest.skip("This system does not support IPv6") + # custom DNS resolvers ip = nginx_proxy_dns_resolver(args[0]) if ip is None: @@ -366,8 +371,9 @@ def connect_to_network(network): if 'host' in my_networks: return None - # make sure our container is connected to the nginx-proxy's network - if network.name not in my_networks: + # Make sure our container is connected to the nginx-proxy's network, + # but avoid connecting to `none` network (not valid) with `test_server-down` tests + if network.name not in my_networks and network.name != 'none': logging.info(f"Connecting to docker network: {network.name}") network.connect(my_container) return network From 6b3ee66783889599f96c43807792e15c2b01bb0d Mon Sep 17 00:00:00 2001 From: polarathene <5098581+polarathene@users.noreply.github.com> Date: Sat, 1 Jan 2022 01:39:51 +1300 Subject: [PATCH 015/300] chore: white-space housekeeping Noticed some trailing white-space. Removed for consistency with the rest of the file. --- test/conftest.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/test/conftest.py b/test/conftest.py index dda8379..cf26b30 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -34,9 +34,9 @@ test_container = 'nginx-proxy-pytest' ############################################################################### -# +# # utilities -# +# ############################################################################### @contextlib.contextmanager @@ -60,7 +60,7 @@ def ipv6(force_ipv6=True): class requests_for_docker(object): """ - Proxy for calling methods of the requests module. + Proxy for calling methods of the requests module. When a HTTP response failed due to HTTP Error 404 or 502, retry a few times. Provides method `get_conf` to extract the nginx-proxy configuration content. """ @@ -224,7 +224,7 @@ def docker_container_dns_resolver(domain_name): ip = container_ip(container) log.info(f"resolving domain name {domain_name!r} as IP address {ip} of container {container.name}") - return ip + return ip def monkey_patch_urllib_dns_resolver(): @@ -306,7 +306,7 @@ def docker_compose_down(compose_file='docker-compose.yml'): def wait_for_nginxproxy_to_be_ready(): """ - If one (and only one) container started from image nginxproxy/nginx-proxy:test is found, + If one (and only one) container started from image nginxproxy/nginx-proxy:test is found, wait for its log to contain substring "Watching docker events" """ containers = docker_client.containers.list(filters={"ancestor": "nginxproxy/nginx-proxy:test"}) @@ -416,18 +416,18 @@ def connect_to_all_networks(): ############################################################################### -# +# # Py.test fixtures -# +# ############################################################################### @pytest.fixture(scope="module") def docker_compose(request): """ pytest fixture providing containers described in a docker compose file. After the tests, remove the created containers - + A custom docker compose file name can be defined in a variable named `docker_compose_file`. - + Also, in the case where pytest is running from a docker container, this fixture makes sure our container will be attached to all the docker networks. """ @@ -463,9 +463,9 @@ def nginxproxy(): ############################################################################### -# +# # Py.test hooks -# +# ############################################################################### # pytest hook to display additionnal stuff in test report @@ -492,9 +492,9 @@ def pytest_runtest_setup(item): pytest.xfail(f"previous test failed ({previousfailed.name})") ############################################################################### -# +# # Check requirements -# +# ############################################################################### try: From b9ac4b936e15b482b1a9b4712a265ebf934b625d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 6 Jan 2022 04:21:32 +0000 Subject: [PATCH 016/300] chore(deps): bump requests from 2.26.0 to 2.27.1 in /test/requirements Bumps [requests](https://github.com/psf/requests) from 2.26.0 to 2.27.1. - [Release notes](https://github.com/psf/requests/releases) - [Changelog](https://github.com/psf/requests/blob/main/HISTORY.md) - [Commits](https://github.com/psf/requests/compare/v2.26.0...v2.27.1) --- updated-dependencies: - dependency-name: requests dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- test/requirements/python-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/requirements/python-requirements.txt b/test/requirements/python-requirements.txt index 1a2ad1e..1e53b31 100644 --- a/test/requirements/python-requirements.txt +++ b/test/requirements/python-requirements.txt @@ -2,4 +2,4 @@ backoff==1.11.1 docker-compose==1.29.2 docker==5.0.3 pytest==6.2.5 -requests==2.26.0 +requests==2.27.1 From 53ef90a2f6e02b295c8e176c7cd08a139d958d54 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Thu, 6 Jan 2022 17:12:36 +0100 Subject: [PATCH 017/300] docs: nginx badge 1.21.4 -> 1.21.5 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 45b0f6c..c5f153f 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ [![Test](https://github.com/nginx-proxy/nginx-proxy/actions/workflows/test.yml/badge.svg)](https://github.com/nginx-proxy/nginx-proxy/actions/workflows/test.yml) [![GitHub release](https://img.shields.io/github/v/release/nginx-proxy/nginx-proxy)](https://github.com/nginx-proxy/nginx-proxy/releases) -![nginx 1.21.4](https://img.shields.io/badge/nginx-1.21.4-brightgreen.svg) +![nginx 1.21.5](https://img.shields.io/badge/nginx-1.21.5-brightgreen.svg) [![Docker Image Size](https://img.shields.io/docker/image-size/nginxproxy/nginx-proxy?sort=semver)](https://hub.docker.com/r/nginxproxy/nginx-proxy "Click to view the image on Docker Hub") [![Docker stars](https://img.shields.io/docker/stars/nginxproxy/nginx-proxy.svg)](https://hub.docker.com/r/nginxproxy/nginx-proxy 'DockerHub') [![Docker pulls](https://img.shields.io/docker/pulls/nginxproxy/nginx-proxy.svg)](https://hub.docker.com/r/nginxproxy/nginx-proxy 'DockerHub') From 679c971a19d7d159f551e95aae654280934009bc Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Tue, 11 Jan 2022 19:46:42 +0100 Subject: [PATCH 018/300] docs: update maintainers list on license --- LICENSE | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index fc926a8..ce7d86c 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,7 @@ The MIT License (MIT) -Copyright (c) 2014 Jason Wilder +Copyright (c) 2014-2020 Jason Wilder +Copyright (c) 2021-2022 Nicolas Duchon Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From fde0e809e4758d255be61f7207c8d538b82232bc Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Tue, 11 Jan 2022 19:55:29 +0100 Subject: [PATCH 019/300] chore: jwilder/docker-gen > nginx-proxy/docker-gen --- Dockerfile | 2 +- Dockerfile.alpine | 2 +- README.md | 6 +++--- docker-compose-separate-containers.yml | 5 +++-- test/test_dockergen/test_dockergen_v2.yml | 2 +- test/test_dockergen/test_dockergen_v3.yml | 2 +- 6 files changed, 10 insertions(+), 9 deletions(-) diff --git a/Dockerfile b/Dockerfile index 95db046..22f910d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,7 +10,7 @@ FROM gobuilder as dockergen ARG DOCKER_GEN_VERSION -RUN git clone https://github.com/jwilder/docker-gen \ +RUN git clone https://github.com/nginx-proxy/docker-gen \ && cd /go/docker-gen \ && git -c advice.detachedHead=false checkout $DOCKER_GEN_VERSION \ && go mod download \ diff --git a/Dockerfile.alpine b/Dockerfile.alpine index 81fd9d3..94a122e 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -11,7 +11,7 @@ FROM gobuilder as dockergen ARG DOCKER_GEN_VERSION -RUN git clone https://github.com/jwilder/docker-gen \ +RUN git clone https://github.com/nginx-proxy/docker-gen \ && cd /go/docker-gen \ && git -c advice.detachedHead=false checkout $DOCKER_GEN_VERSION \ && go mod download \ diff --git a/README.md b/README.md index c5f153f..18e5dcf 100644 --- a/README.md +++ b/README.md @@ -193,7 +193,7 @@ docker run -d -e VIRTUAL_HOST=foo.bar.com nginx ### Separate Containers -nginx-proxy can also be run as two separate containers using the [jwilder/docker-gen](https://hub.docker.com/r/jwilder/docker-gen) image and the official [nginx](https://registry.hub.docker.com/_/nginx/) image. +nginx-proxy can also be run as two separate containers using the [nginxproxy/docker-gen](https://hub.docker.com/r/nginxproxy/docker-gen) image and the official [nginx](https://registry.hub.docker.com/_/nginx/) image. You may want to do this to prevent having the docker socket bound to a publicly exposed container service. @@ -224,7 +224,7 @@ Then start the docker-gen container with the shared volume and template: docker run --volumes-from nginx \ -v /var/run/docker.sock:/tmp/docker.sock:ro \ -v $(pwd):/etc/docker-gen/templates \ - -t jwilder/docker-gen -notify-sighup nginx -watch /etc/docker-gen/templates/nginx.tmpl /etc/nginx/conf.d/default.conf + -t nginxproxy/docker-gen -notify-sighup nginx -watch /etc/docker-gen/templates/nginx.tmpl /etc/nginx/conf.d/default.conf ``` Finally, start your containers with `VIRTUAL_HOST` environment variables. @@ -259,7 +259,7 @@ To use custom `dhparam.pem` files per-virtual-host, the files should be named af > COMPATIBILITY WARNING: The default generated `dhparam.pem` key is 4096 bits for A+ security. Some older clients (like Java 6 and 7) do not support DH keys with over 1024 bits. In order to support these clients, you must provide your own `dhparam.pem`. -In the separate container setup, no pre-generated key will be available and neither the [jwilder/docker-gen](https://hub.docker.com/r/jwilder/docker-gen) image, nor the offical [nginx](https://registry.hub.docker.com/_/nginx/) image will provide one. If you still want A+ security in a separate container setup, you should mount an RFC7919 DH key file to the nginx container at `/etc/nginx/dhparam/dhparam.pem`. +In the separate container setup, no pre-generated key will be available and neither the [nginxproxy/docker-gen](https://hub.docker.com/r/nginxproxy/docker-gen) image, nor the offical [nginx](https://registry.hub.docker.com/_/nginx/) image will provide one. If you still want A+ security in a separate container setup, you should mount an RFC7919 DH key file to the nginx container at `/etc/nginx/dhparam/dhparam.pem`. Set `DHPARAM_SKIP` environment variable to `true` to disable using default Diffie-Hellman parameters. The default value is `false`. diff --git a/docker-compose-separate-containers.yml b/docker-compose-separate-containers.yml index a4edb94..254b742 100644 --- a/docker-compose-separate-containers.yml +++ b/docker-compose-separate-containers.yml @@ -9,8 +9,9 @@ services: - /etc/nginx/conf.d dockergen: - image: jwilder/docker-gen - command: -notify-sighup nginx -watch /etc/docker-gen/templates/nginx.tmpl /etc/nginx/conf.d/default.conf + image: nginxproxy/docker-gen + command: -notify-sighup nginx -watch /etc/docker-gen/templates/nginx.tmpl + /etc/nginx/conf.d/default.conf volumes_from: - nginx volumes: diff --git a/test/test_dockergen/test_dockergen_v2.yml b/test/test_dockergen/test_dockergen_v2.yml index 919461d..b1f443c 100644 --- a/test/test_dockergen/test_dockergen_v2.yml +++ b/test/test_dockergen/test_dockergen_v2.yml @@ -8,7 +8,7 @@ services: - /etc/nginx/conf.d dockergen: - image: jwilder/docker-gen + image: nginxproxy/docker-gen command: -notify-sighup nginx -watch /etc/docker-gen/templates/nginx.tmpl /etc/nginx/conf.d/default.conf volumes_from: - nginx diff --git a/test/test_dockergen/test_dockergen_v3.yml b/test/test_dockergen/test_dockergen_v3.yml index 5bc4bff..8339273 100644 --- a/test/test_dockergen/test_dockergen_v3.yml +++ b/test/test_dockergen/test_dockergen_v3.yml @@ -7,7 +7,7 @@ services: - nginx_conf:/etc/nginx/conf.d dockergen: - image: jwilder/docker-gen + image: nginxproxy/docker-gen command: -notify-sighup nginx -watch /etc/docker-gen/templates/nginx.tmpl /etc/nginx/conf.d/default.conf volumes: - /var/run/docker.sock:/tmp/docker.sock:ro From fbf37456d02523bf9beeac9f498384de283b6258 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Tue, 11 Jan 2022 22:38:30 +0100 Subject: [PATCH 020/300] feat: display container version --- Dockerfile | 15 ++++++++------- Dockerfile.alpine | 15 ++++++++------- docker-entrypoint.sh | 8 ++++++++ nginx.tmpl | 5 +++++ 4 files changed, 29 insertions(+), 14 deletions(-) diff --git a/Dockerfile b/Dockerfile index 22f910d..232098e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -39,6 +39,14 @@ RUN git clone https://github.com/nginx-proxy/forego/ \ FROM nginx:1.21.5 LABEL maintainer="Nicolas Duchon (@buchdag)" +ARG NGINX_PROXY_VERSION +# Add DOCKER_GEN_VERSION environment variable +# Because some external projects rely on it +ARG DOCKER_GEN_VERSION +ENV NGINX_PROXY_VERSION=${NGINX_PROXY_VERSION} \ + DOCKER_GEN_VERSION=${DOCKER_GEN_VERSION} \ + DOCKER_HOST=unix:///tmp/docker.sock + # Install wget and install/updates certificates RUN apt-get update \ && apt-get install -y -q --no-install-recommends \ @@ -58,17 +66,10 @@ RUN echo "daemon off;" >> /etc/nginx/nginx.conf \ COPY --from=forego /usr/local/bin/forego /usr/local/bin/forego COPY --from=dockergen /usr/local/bin/docker-gen /usr/local/bin/docker-gen -# Add DOCKER_GEN_VERSION environment variable -# Because some external projects rely on it -ARG DOCKER_GEN_VERSION -ENV DOCKER_GEN_VERSION=${DOCKER_GEN_VERSION} - COPY network_internal.conf /etc/nginx/ COPY . /app/ WORKDIR /app/ -ENV DOCKER_HOST unix:///tmp/docker.sock - ENTRYPOINT ["/app/docker-entrypoint.sh"] CMD ["forego", "start", "-r"] diff --git a/Dockerfile.alpine b/Dockerfile.alpine index 94a122e..6852b5a 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -40,6 +40,14 @@ RUN git clone https://github.com/nginx-proxy/forego/ \ FROM nginx:1.21.5-alpine LABEL maintainer="Nicolas Duchon (@buchdag)" +ARG NGINX_PROXY_VERSION +# Add DOCKER_GEN_VERSION environment variable +# Because some external projects rely on it +ARG DOCKER_GEN_VERSION +ENV NGINX_PROXY_VERSION=${NGINX_PROXY_VERSION} \ + DOCKER_GEN_VERSION=${DOCKER_GEN_VERSION} \ + DOCKER_HOST=unix:///tmp/docker.sock + # Install wget and install/updates certificates RUN apk add --no-cache --virtual .run-deps \ ca-certificates bash wget openssl \ @@ -55,17 +63,10 @@ RUN echo "daemon off;" >> /etc/nginx/nginx.conf \ COPY --from=forego /usr/local/bin/forego /usr/local/bin/forego COPY --from=dockergen /usr/local/bin/docker-gen /usr/local/bin/docker-gen -# Add DOCKER_GEN_VERSION environment variable -# Because some external projects rely on it -ARG DOCKER_GEN_VERSION -ENV DOCKER_GEN_VERSION=${DOCKER_GEN_VERSION} - COPY network_internal.conf /etc/nginx/ COPY . /app/ WORKDIR /app/ -ENV DOCKER_HOST unix:///tmp/docker.sock - ENTRYPOINT ["/app/docker-entrypoint.sh"] CMD ["forego", "start", "-r"] diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh index 45d6cd2..8f4ed7a 100755 --- a/docker-entrypoint.sh +++ b/docker-entrypoint.sh @@ -29,6 +29,12 @@ function _parse_false() { esac } +function _print_version { + if [[ -n "${NGINX_PROXY_VERSION:-}" ]]; then + echo "Info: running nginx-proxy version ${NGINX_PROXY_VERSION}" + fi +} + function _check_unix_socket() { # Warn if the DOCKER_HOST socket does not exist if [[ ${DOCKER_HOST} == unix://* ]]; then @@ -96,6 +102,8 @@ function _setup_dhparam() { # Run the init logic if the default CMD was provided if [[ $* == 'forego start -r' ]]; then + _print_version + _check_unix_socket _resolvers diff --git a/nginx.tmpl b/nginx.tmpl index 2e1415e..2414633 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -1,5 +1,6 @@ {{ $CurrentContainer := where $ "ID" .Docker.CurrentContainerID | first }} +{{ $nginx_proxy_version := coalesce $.Env.NGINX_PROXY_VERSION "" }} {{ $external_http_port := coalesce $.Env.HTTP_PORT "80" }} {{ $external_https_port := coalesce $.Env.HTTPS_PORT "443" }} {{ $debug_all := $.Env.DEBUG }} @@ -48,6 +49,10 @@ {{ end }} {{ end }} +{{ if ne $nginx_proxy_version "" }} +# nginx-proxy version : {{ $nginx_proxy_version }} +{{ 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 { From e22ae4a6fdfa6760651b9864a3fb042ba896a9ff Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Tue, 11 Jan 2022 22:53:39 +0100 Subject: [PATCH 021/300] tests: display container version --- Makefile | 4 ++-- test/test_nominal.py | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 18fcd33..ab44880 100644 --- a/Makefile +++ b/Makefile @@ -6,10 +6,10 @@ build-webserver: docker build -t web test/requirements/web build-nginx-proxy-test-debian: - docker build -t nginxproxy/nginx-proxy:test . + docker build --build-arg NGINX_PROXY_VERSION="test" -t nginxproxy/nginx-proxy:test . build-nginx-proxy-test-alpine: - docker build -f Dockerfile.alpine -t nginxproxy/nginx-proxy:test . + docker build --build-arg NGINX_PROXY_VERSION="test" -f Dockerfile.alpine -t nginxproxy/nginx-proxy:test . test-debian: build-webserver build-nginx-proxy-test-debian test/pytest.sh diff --git a/test/test_nominal.py b/test/test_nominal.py index cce7c94..a3f9c87 100644 --- a/test/test_nominal.py +++ b/test/test_nominal.py @@ -22,3 +22,8 @@ def test_forwards_to_web2(docker_compose, nginxproxy): def test_ipv6_is_disabled_by_default(docker_compose, nginxproxy): with pytest.raises(ConnectionError): nginxproxy.get("http://nginx-proxy/port", ipv6=True) + + +def test_container_version_is_displayed(docker_compose, nginxproxy): + conf = nginxproxy.get_conf().decode('ASCII') + assert "# nginx-proxy version : test" in conf From dbca945a8f1f1dbd35f0f8308413a1859882660a Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Wed, 12 Jan 2022 11:26:20 +0100 Subject: [PATCH 022/300] ci: add nginx-proxy version to image on build --- .github/workflows/dockerhub.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/dockerhub.yml b/.github/workflows/dockerhub.yml index 5d4cfba..3dea999 100644 --- a/.github/workflows/dockerhub.yml +++ b/.github/workflows/dockerhub.yml @@ -53,12 +53,16 @@ jobs: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} + - name: Retrieve version + run: echo "GIT_DESCRIBE=$(git describe --tags)" >> $GITHUB_ENV + - name: Build and push the Debian based image id: docker_build_debian uses: docker/build-push-action@v2 with: context: . file: Dockerfile + build-args: NGINX_PROXY_VERSION=${{ env.GIT_DESCRIBE }} platforms: linux/amd64,linux/arm64,linux/arm/v7 push: true tags: ${{ steps.docker_meta_debian.outputs.tags }} @@ -101,12 +105,16 @@ jobs: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} + - name: Retrieve version + run: echo "GIT_DESCRIBE=$(git describe --tags)" >> $GITHUB_ENV + - name: Build and push the Alpine based image id: docker_build_alpine uses: docker/build-push-action@v2 with: context: . file: Dockerfile.alpine + build-args: NGINX_PROXY_VERSION=${{ env.GIT_DESCRIBE }} platforms: linux/amd64,linux/arm64,linux/arm/v7 push: true tags: ${{ steps.docker_meta_alpine.outputs.tags }} From b411a84a59d138e5dd1ce87ca85203c082f98461 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Fri, 14 Jan 2022 13:38:23 +0100 Subject: [PATCH 023/300] docs: update issue template --- .github/ISSUE_TEMPLATE.md | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 99d688b..9824d63 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -1,16 +1,35 @@ -# !!!PLEASE READ!!! +# ⚠️ PLEASE READ ⚠️ -## Questions +## Questions or Features -If you have a question, DO NOT SUBMIT a new issue. +If you have a question or want to request a feature, please **DO NOT SUBMIT** a new issue. -Please ask the question on the Discussions section: https://github.com/nginx-proxy/nginx-proxy/discussions +Instead please use the relevant Discussions section's category: +- 🙏 [Ask a question](https://github.com/nginx-proxy/nginx-proxy/discussions/categories/q-a) +- 💡 [Request a feature](https://github.com/nginx-proxy/nginx-proxy/discussions/categories/ideas) -## Bugs or Features +## Bugs -If you are logging a bug or feature request, please search the current open issues to see if there is already a bug or feature opened. +If you are logging a bug, please search the current open issues first to see if there is already a bug opened. -For bugs, the easier you make it to reproduce the issue you see, the easier and faster it can get fixed. If you can provide a script or docker-compose file that reproduces the problems, that is very helpful. +For bugs, the easier you make it to reproduce the issue you see and the more initial information you provide, the easier and faster the bug can be identified and can get fixed. + +Please at least provide: +- the exact nginx-proxy version you're using (if using `latest` please make sure it is up to date and provide the version number printed at container startup). +- complete configuration (compose file, command line, etc) of both your nginx-proxy container(s) and proxied containers. You should redact sensitive info if needed but please provide **full** configurations. +- generated nginx configuration obtained with `docker exec nameofyournginxproxycontainer nginx -T` + +If you can provide a script or docker-compose file that reproduces the problems, that is very helpful. + +## General advice about `latest` + +Do not use the `latest` tag for production setups. + +`latest` is nothing more than a convenient default used by Docker if no specific tag is provided, there isn't any strict convention on what goes into this tag over different projects, and it does not carry any promise of stability. + +Using `latest` will most certainly put you at risk of experiencing uncontrolled updates to non backward compatible versions (or versions with breaking changes) and makes it harder for maintainers to track which exact version of the container you are experiencing an issue with. + +This recommendation stands for pretty much every Docker image in existence, not just nginx-proxy's ones. Thanks, -Jason +Nicolas From 2daa09ff21be7970631ad3b709ab823b47d68337 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Fri, 14 Jan 2022 14:17:21 +0100 Subject: [PATCH 024/300] ci: upgrade to docker/metadata-action@v3 --- .github/workflows/dockerhub.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/dockerhub.yml b/.github/workflows/dockerhub.yml index 3dea999..c39d457 100644 --- a/.github/workflows/dockerhub.yml +++ b/.github/workflows/dockerhub.yml @@ -31,7 +31,7 @@ jobs: - name: Get Docker tags for Debian based image id: docker_meta_debian - uses: crazy-max/ghaction-docker-meta@v2 + uses: docker/metadata-action@v3 with: images: | nginxproxy/nginx-proxy @@ -82,7 +82,7 @@ jobs: - name: Get Docker tags for Alpine based image id: docker_meta_alpine - uses: crazy-max/ghaction-docker-meta@v2 + uses: docker/metadata-action@v3 with: images: | nginxproxy/nginx-proxy From 0ff39b804cc2f98816a78ee95ab5e5229ed2894d Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Fri, 14 Jan 2022 14:29:03 +0100 Subject: [PATCH 025/300] ci: use git describe for OCI image version label --- .github/workflows/dockerhub.yml | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/.github/workflows/dockerhub.yml b/.github/workflows/dockerhub.yml index c39d457..757e8ac 100644 --- a/.github/workflows/dockerhub.yml +++ b/.github/workflows/dockerhub.yml @@ -28,6 +28,9 @@ jobs: uses: actions/checkout@v2 with: fetch-depth: 0 + + - name: Retrieve version + run: echo "GIT_DESCRIBE=$(git describe --tags)" >> $GITHUB_ENV - name: Get Docker tags for Debian based image id: docker_meta_debian @@ -40,6 +43,8 @@ jobs: type=semver,pattern={{version}} type=semver,pattern={{major}}.{{minor}} type=raw,value=latest,enable=${{ endsWith(github.ref, github.event.repository.default_branch) }} + labels: | + org.opencontainers.image.version=${{ env.GIT_DESCRIBE }} - name: Set up QEMU uses: docker/setup-qemu-action@v1 @@ -53,9 +58,6 @@ jobs: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - - name: Retrieve version - run: echo "GIT_DESCRIBE=$(git describe --tags)" >> $GITHUB_ENV - - name: Build and push the Debian based image id: docker_build_debian uses: docker/build-push-action@v2 @@ -79,6 +81,9 @@ jobs: uses: actions/checkout@v2 with: fetch-depth: 0 + + - name: Retrieve version + run: echo "GIT_DESCRIBE=$(git describe --tags)" >> $GITHUB_ENV - name: Get Docker tags for Alpine based image id: docker_meta_alpine @@ -91,6 +96,8 @@ jobs: type=semver,suffix=-alpine,pattern={{version}} type=semver,suffix=-alpine,pattern={{major}}.{{minor}} type=raw,value=alpine,enable=${{ endsWith(github.ref, github.event.repository.default_branch) }} + labels: | + org.opencontainers.image.version=${{ env.GIT_DESCRIBE }} flavor: latest=false - name: Set up QEMU @@ -105,9 +112,6 @@ jobs: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - - name: Retrieve version - run: echo "GIT_DESCRIBE=$(git describe --tags)" >> $GITHUB_ENV - - name: Build and push the Alpine based image id: docker_build_alpine uses: docker/build-push-action@v2 From 42c8b0c4c9e31889d6c1f66397ac004d1965e095 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Fri, 14 Jan 2022 14:39:33 +0100 Subject: [PATCH 026/300] CI: replace maintainer label w/ OCI authors label --- .github/workflows/dockerhub.yml | 2 ++ Dockerfile | 1 - Dockerfile.alpine | 1 - 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/dockerhub.yml b/.github/workflows/dockerhub.yml index 757e8ac..cb3635e 100644 --- a/.github/workflows/dockerhub.yml +++ b/.github/workflows/dockerhub.yml @@ -44,6 +44,7 @@ jobs: type=semver,pattern={{major}}.{{minor}} type=raw,value=latest,enable=${{ endsWith(github.ref, github.event.repository.default_branch) }} labels: | + org.opencontainers.image.authors=Nicolas Duchon (@buchdag), Jason Wilder org.opencontainers.image.version=${{ env.GIT_DESCRIBE }} - name: Set up QEMU @@ -97,6 +98,7 @@ jobs: type=semver,suffix=-alpine,pattern={{major}}.{{minor}} type=raw,value=alpine,enable=${{ endsWith(github.ref, github.event.repository.default_branch) }} labels: | + org.opencontainers.image.authors=Nicolas Duchon (@buchdag), Jason Wilder org.opencontainers.image.version=${{ env.GIT_DESCRIBE }} flavor: latest=false diff --git a/Dockerfile b/Dockerfile index 232098e..4574b27 100644 --- a/Dockerfile +++ b/Dockerfile @@ -37,7 +37,6 @@ RUN git clone https://github.com/nginx-proxy/forego/ \ # Build the final image FROM nginx:1.21.5 -LABEL maintainer="Nicolas Duchon (@buchdag)" ARG NGINX_PROXY_VERSION # Add DOCKER_GEN_VERSION environment variable diff --git a/Dockerfile.alpine b/Dockerfile.alpine index 6852b5a..c7f2472 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -38,7 +38,6 @@ RUN git clone https://github.com/nginx-proxy/forego/ \ # Build the final image FROM nginx:1.21.5-alpine -LABEL maintainer="Nicolas Duchon (@buchdag)" ARG NGINX_PROXY_VERSION # Add DOCKER_GEN_VERSION environment variable From 2671ef4aef0b28355ca555ca02096819fb69864c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 26 Jan 2022 04:07:38 +0000 Subject: [PATCH 027/300] chore(deps): bump nginx from 1.21.5 to 1.21.6 Bumps nginx from 1.21.5 to 1.21.6. --- updated-dependencies: - dependency-name: nginx dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Dockerfile | 2 +- Dockerfile.alpine | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 4574b27..d5c71bc 100644 --- a/Dockerfile +++ b/Dockerfile @@ -36,7 +36,7 @@ RUN git clone https://github.com/nginx-proxy/forego/ \ && rm -rf /go/forego # Build the final image -FROM nginx:1.21.5 +FROM nginx:1.21.6 ARG NGINX_PROXY_VERSION # Add DOCKER_GEN_VERSION environment variable diff --git a/Dockerfile.alpine b/Dockerfile.alpine index c7f2472..2552615 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -37,7 +37,7 @@ RUN git clone https://github.com/nginx-proxy/forego/ \ && rm -rf /go/forego # Build the final image -FROM nginx:1.21.5-alpine +FROM nginx:1.21.6-alpine ARG NGINX_PROXY_VERSION # Add DOCKER_GEN_VERSION environment variable From dc8094daf57ad1fe313c18d1adaca0ad855c9984 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 7 Feb 2022 04:23:26 +0000 Subject: [PATCH 028/300] chore(deps): bump pytest from 6.2.5 to 7.0.0 in /test/requirements Bumps [pytest](https://github.com/pytest-dev/pytest) from 6.2.5 to 7.0.0. - [Release notes](https://github.com/pytest-dev/pytest/releases) - [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst) - [Commits](https://github.com/pytest-dev/pytest/compare/6.2.5...7.0.0) --- updated-dependencies: - dependency-name: pytest dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- test/requirements/python-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/requirements/python-requirements.txt b/test/requirements/python-requirements.txt index 1e53b31..be4665e 100644 --- a/test/requirements/python-requirements.txt +++ b/test/requirements/python-requirements.txt @@ -1,5 +1,5 @@ backoff==1.11.1 docker-compose==1.29.2 docker==5.0.3 -pytest==6.2.5 +pytest==7.0.0 requests==2.27.1 From 42535c01d97a3d8d255c9e8f90b9b2d78e6d596f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Feb 2022 04:20:00 +0000 Subject: [PATCH 029/300] chore(deps): bump pytest from 7.0.0 to 7.0.1 in /test/requirements Bumps [pytest](https://github.com/pytest-dev/pytest) from 7.0.0 to 7.0.1. - [Release notes](https://github.com/pytest-dev/pytest/releases) - [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst) - [Commits](https://github.com/pytest-dev/pytest/compare/7.0.0...7.0.1) --- updated-dependencies: - dependency-name: pytest dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- test/requirements/python-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/requirements/python-requirements.txt b/test/requirements/python-requirements.txt index be4665e..3747455 100644 --- a/test/requirements/python-requirements.txt +++ b/test/requirements/python-requirements.txt @@ -1,5 +1,5 @@ backoff==1.11.1 docker-compose==1.29.2 docker==5.0.3 -pytest==7.0.0 +pytest==7.0.1 requests==2.27.1 From 098e551c3522c5493b663feb26c33dd83248a453 Mon Sep 17 00:00:00 2001 From: Nathan Weeks <1800812+nathanweeks@users.noreply.github.com> Date: Mon, 14 Feb 2022 07:42:46 -0500 Subject: [PATCH 030/300] Fix path to default.conf in README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 18e5dcf..e996eed 100644 --- a/README.md +++ b/README.md @@ -423,10 +423,10 @@ Please note that using regular expressions in `VIRTUAL_HOST` will always result ### Troubleshooting -In case you can't access your VIRTUAL_HOST, set `DEBUG=true` in the client container's environment and have a look at the generated nginx configuration file `/etc/nginx/conf.d/default`: +In case you can't access your VIRTUAL_HOST, set `DEBUG=true` in the client container's environment and have a look at the generated nginx configuration file `/etc/nginx/conf.d/default.conf`: ```console -docker exec cat /etc/nginx/conf.d/default +docker exec cat /etc/nginx/conf.d/default.conf ``` Especially at `upstream` definition blocks which should look like: From 15e33a3de57f59cef8c883120b24d7dde695fca8 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Mon, 14 Feb 2022 16:18:25 +0100 Subject: [PATCH 031/300] docs: suggest alternatives to xip.io Fixes #1887 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 18e5dcf..d955a33 100644 --- a/README.md +++ b/README.md @@ -115,7 +115,7 @@ For each host defined into `VIRTUAL_HOST`, the associated virtual port is retrie ### Wildcard Hosts -You can also use wildcards at the beginning and the end of host name, like `*.bar.com` or `foo.bar.*`. Or even a regular expression, which can be very useful in conjunction with a wildcard DNS service like [xip.io](http://xip.io), using `~^foo\.bar\..*\.xip\.io` will match `foo.bar.127.0.0.1.xip.io`, `foo.bar.10.0.2.2.xip.io` and all other given IPs. More information about this topic can be found in the nginx documentation about [`server_names`](http://nginx.org/en/docs/http/server_names.html). +You can also use wildcards at the beginning and the end of host name, like `*.bar.com` or `foo.bar.*`. Or even a regular expression, which can be very useful in conjunction with a wildcard DNS service like [nip.io](https://nip.io) or [sslip.io](https://sslip.io), using `~^foo\.bar\..*\.xip\.io` will match `foo.bar.127.0.0.1.xip.io`, `foo.bar.10.0.2.2.xip.io` and all other given IPs. More information about this topic can be found in the nginx documentation about [`server_names`](http://nginx.org/en/docs/http/server_names.html). ### Multiple Networks From 3670d39b71e8fe7dcc0b317accdf1d9ba6f18840 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Tue, 15 Feb 2022 11:12:52 +0100 Subject: [PATCH 032/300] docs: xip.io -> nip.io --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c175ad2..556cf5c 100644 --- a/README.md +++ b/README.md @@ -115,7 +115,7 @@ For each host defined into `VIRTUAL_HOST`, the associated virtual port is retrie ### Wildcard Hosts -You can also use wildcards at the beginning and the end of host name, like `*.bar.com` or `foo.bar.*`. Or even a regular expression, which can be very useful in conjunction with a wildcard DNS service like [nip.io](https://nip.io) or [sslip.io](https://sslip.io), using `~^foo\.bar\..*\.xip\.io` will match `foo.bar.127.0.0.1.xip.io`, `foo.bar.10.0.2.2.xip.io` and all other given IPs. More information about this topic can be found in the nginx documentation about [`server_names`](http://nginx.org/en/docs/http/server_names.html). +You can also use wildcards at the beginning and the end of host name, like `*.bar.com` or `foo.bar.*`. Or even a regular expression, which can be very useful in conjunction with a wildcard DNS service like [nip.io](https://nip.io) or [sslip.io](https://sslip.io), using `~^foo\.bar\..*\.nip\.io` will match `foo.bar.127.0.0.1.nip.io`, `foo.bar.10.0.2.2.nip.io` and all other given IPs. More information about this topic can be found in the nginx documentation about [`server_names`](http://nginx.org/en/docs/http/server_names.html). ### Multiple Networks From 18027fa71b0c28312b2c290f99a74fbbac03ad76 Mon Sep 17 00:00:00 2001 From: Robin Windey Date: Sun, 20 Feb 2022 15:10:05 +0100 Subject: [PATCH 033/300] Add container logs in case testcontainer exited unexpectedly --- test/conftest.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/conftest.py b/test/conftest.py index cf26b30..1121e96 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -192,6 +192,10 @@ def nginx_proxy_dns_resolver(domain_name): nginxproxy_containers = docker_client.containers.list(filters={"status": "running", "ancestor": "nginxproxy/nginx-proxy:test"}) if len(nginxproxy_containers) == 0: log.warn(f"no container found from image nginxproxy/nginx-proxy:test while resolving {domain_name!r}") + exited_nginxproxy_containers = docker_client.containers.list(filters={"status": "exited", "ancestor": "nginxproxy/nginx-proxy:test"}) + if len(exited_nginxproxy_containers) > 0: + exited_nginxproxy_container_logs = exited_nginxproxy_containers[0].logs() + log.warn(f"nginxproxy/nginx-proxy:test container might have exited unexpectedly. Container logs: " + "\n" + exited_nginxproxy_container_logs.decode()) return nginxproxy_container = nginxproxy_containers[0] ip = container_ip(nginxproxy_container) From b6e9cdc065a19ce7e7cb0dcf2c11cd7c9fe1d063 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Tue, 4 May 2021 11:03:27 +0200 Subject: [PATCH 034/300] ci: use docker-gen main on dev branch tests --- .github/workflows/test.yml | 20 ++++++++++++++++---- Makefile | 6 ++++++ 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 6be93bd..8c4a173 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -3,13 +3,16 @@ name: Tests on: workflow_dispatch: push: + branches: + - main + - dev paths-ignore: - - 'LICENSE' - - '**.md' + - 'LICENSE' + - '**.md' pull_request: paths-ignore: - - 'LICENSE' - - '**.md' + - 'LICENSE' + - '**.md' jobs: unit: @@ -39,6 +42,15 @@ jobs: - name: Build Docker nginx proxy test image run: make build-nginx-proxy-test-${{ matrix.base_docker_image }} + if: | + ( github.event_name == 'push' && github.ref != 'refs/heads/dev' ) || + ( github.event_name == 'pull_request' && github.base_ref != 'dev' ) + + - name: Build Docker nginx proxy dev test image + run: make build-nginx-proxy-test-${{ matrix.base_docker_image }}-dev + if: | + ( github.event_name == 'push' && github.ref == 'refs/heads/dev' ) || + ( github.event_name == 'pull_request' && github.base_ref == 'dev' ) - name: Run tests run: pytest diff --git a/Makefile b/Makefile index ab44880..60406b6 100644 --- a/Makefile +++ b/Makefile @@ -11,6 +11,12 @@ build-nginx-proxy-test-debian: build-nginx-proxy-test-alpine: docker build --build-arg NGINX_PROXY_VERSION="test" -f Dockerfile.alpine -t nginxproxy/nginx-proxy:test . +build-nginx-proxy-test-debian-dev: + docker build --build-arg DOCKER_GEN_VERSION=main -t nginxproxy/nginx-proxy:test . + +build-nginx-proxy-test-alpine-dev: + docker build -f Dockerfile.alpine --build-arg DOCKER_GEN_VERSION=main -t nginxproxy/nginx-proxy:test . + test-debian: build-webserver build-nginx-proxy-test-debian test/pytest.sh From 2901b917a0cee641b58e66338d8855366b60d1c2 Mon Sep 17 00:00:00 2001 From: Greg Symons Date: Sun, 23 May 2021 22:52:57 +0200 Subject: [PATCH 035/300] feat: support for path-based routing Co-authored-by: Josh Trow Co-authored-by: Adrian Co-authored-by: Rodrigo Aguilera Co-authored-by: Alexander Lieret --- nginx.tmpl | 212 +++++++++++++++++++++++++++++------------------------ 1 file changed, 115 insertions(+), 97 deletions(-) diff --git a/nginx.tmpl b/nginx.tmpl index 2414633..fc6f540 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -49,6 +49,92 @@ {{ end }} {{ end }} +{{ define "location" }} +location {{ .Path }} { + {{ if eq .Proto "uwsgi" }} + include uwsgi_params; + uwsgi_pass {{ trim .Proto }}://{{ trim .Upstream }}; + {{ else if eq .Proto "fastcgi" }} + root {{ trim .Vhostroot }}; + include fastcgi.conf; + fastcgi_pass {{ trim .Upstream }}; + {{ else if eq .Proto "grpc" }} + grpc_pass {{ trim .Proto }}://{{ trim .Upstream }}; + {{ else }} + proxy_pass {{ trim .Proto }}://{{ trim .Upstream }}/; + {{ end }} + + {{ if (exists (printf "/etc/nginx/htpasswd/%s" .Host)) }} + auth_basic "Restricted {{ .Host }}"; + auth_basic_user_file {{ (printf "/etc/nginx/htpasswd/%s" .Host) }}; + {{ end }} + + {{ if (exists (printf "/etc/nginx/vhost.d/%s_location" .Host)) }} + include {{ printf "/etc/nginx/vhost.d/%s_location" .Host}}; + {{ else if (exists "/etc/nginx/vhost.d/default_location") }} + include /etc/nginx/vhost.d/default_location; + {{ end }} +} +{{ end }} + +{{ define "upstream-definition" }} + {{ $networks := .Networks }} + {{ $debug_all := .Debug }} + upstream {{ .Upstream }} { + {{ $server_found := "false" }} + {{ range $container := .Containers }} + {{ $debug := (eq (coalesce $container.Env.DEBUG $debug_all "false") "true") }} + {{/* If only 1 port exposed, use that as a default, else 80 */}} + {{ $defaultPort := (when (eq (len $container.Addresses) 1) (first $container.Addresses) (dict "Port" "80")).Port }} + {{ $port := (coalesce $container.Env.VIRTUAL_PORT $defaultPort) }} + {{ $address := where $container.Addresses "Port" $port | first }} + {{ if $debug }} + # Exposed ports: {{ $container.Addresses }} + # Default virtual port: {{ $defaultPort }} + # VIRTUAL_PORT: {{ $container.Env.VIRTUAL_PORT }} + {{ if not $address }} + # /!\ Virtual port not exposed + {{ end }} + {{ end }} + {{ range $knownNetwork := $networks }} + {{ range $containerNetwork := $container.Networks }} + {{ if (and (ne $containerNetwork.Name "ingress") (or (eq $knownNetwork.Name $containerNetwork.Name) (eq $knownNetwork.Name "host"))) }} + ## Can be connected with "{{ $containerNetwork.Name }}" network + {{ if $address }} + {{/* If we got the containers from swarm and this container's port is published to host, use host IP:PORT */}} + {{ if and $container.Node.ID $address.HostPort }} + {{ $server_found = "true" }} + # {{ $container.Node.Name }}/{{ $container.Name }} + server {{ $container.Node.Address.IP }}:{{ $address.HostPort }}; + {{/* If there is no swarm node or the port is not published on host, use container's IP:PORT */}} + {{ else if $containerNetwork }} + {{ $server_found = "true" }} + # {{ $container.Name }} + server {{ $containerNetwork.IP }}:{{ $address.Port }}; + {{ end }} + {{ else if $containerNetwork }} + # {{ $container.Name }} + {{ if $containerNetwork.IP }} + {{ $server_found = "true" }} + server {{ $containerNetwork.IP }}:{{ $port }}; + {{ else }} + # /!\ No IP for this network! + {{ end }} + {{ end }} + {{ else }} + # Cannot connect to network '{{ $containerNetwork.Name }}' of this container + {{ end }} + {{ end }} + {{ end }} + {{ end }} + {{/* nginx-proxy/nginx-proxy#1105 */}} + {{ if (eq $server_found "false") }} + # Fallback entry + server 127.0.0.1 down; + {{ end }} + } +{{ end }} + {{ if ne $nginx_proxy_version "" }} # nginx-proxy version : {{ $nginx_proxy_version }} {{ end }} @@ -100,6 +186,7 @@ access_log off; {{/* Get the SSL_POLICY defined by this container, falling back to "Mozilla-Intermediate" */}} {{ $ssl_policy := or ($.Env.SSL_POLICY) "Mozilla-Intermediate" }} {{ template "ssl_policy" (dict "ssl_policy" $ssl_policy) }} +error_log /dev/stderr; {{ if $.Env.RESOLVERS }} resolver {{ $.Env.RESOLVERS }}; @@ -119,6 +206,7 @@ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto; proxy_set_header X-Forwarded-Ssl $proxy_x_forwarded_ssl; proxy_set_header X-Forwarded-Port $proxy_x_forwarded_port; +proxy_set_header X-Original-URI $request_uri; # Mitigate httpoxy attack (see README for details) proxy_set_header Proxy ""; @@ -162,61 +250,20 @@ server { {{ $is_regexp := hasPrefix "~" $host }} {{ $upstream_name := when (or $is_regexp $sha1_upstream_name) (sha1 $host) $host }} -# {{ $host }} -upstream {{ $upstream_name }} { +{{ $paths := groupBy $containers "Env.VIRTUAL_PATH" }} +{{ $nPaths := len $paths }} -{{ $server_found := "false" }} -{{ range $container := $containers }} - {{ $debug := (eq (coalesce $container.Env.DEBUG $debug_all "false") "true") }} - {{/* If only 1 port exposed, use that as a default, else 80 */}} - {{ $defaultPort := (when (eq (len $container.Addresses) 1) (first $container.Addresses) (dict "Port" "80")).Port }} - {{ $port := (coalesce $container.Env.VIRTUAL_PORT $defaultPort) }} - {{ $address := where $container.Addresses "Port" $port | first }} - {{ if $debug }} - # Exposed ports: {{ $container.Addresses }} - # Default virtual port: {{ $defaultPort }} - # VIRTUAL_PORT: {{ $container.Env.VIRTUAL_PORT }} - {{ if not $address }} - # /!\ Virtual port not exposed - {{ end }} - {{ end }} - {{ range $knownNetwork := $CurrentContainer.Networks }} - {{ range $containerNetwork := $container.Networks }} - {{ if (and (ne $containerNetwork.Name "ingress") (or (eq $knownNetwork.Name $containerNetwork.Name) (eq $knownNetwork.Name "host"))) }} - ## Can be connected with "{{ $containerNetwork.Name }}" network - {{ if $address }} - {{/* If we got the containers from swarm and this container's port is published to host, use host IP:PORT */}} - {{ if and $container.Node.ID $address.HostPort }} - {{ $server_found = "true" }} - # {{ $container.Node.Name }}/{{ $container.Name }} - server {{ $container.Node.Address.IP }}:{{ $address.HostPort }}; - {{/* If there is no swarm node or the port is not published on host, use container's IP:PORT */}} - {{ else if $containerNetwork }} - {{ $server_found = "true" }} - # {{ $container.Name }} - server {{ $containerNetwork.IP }}:{{ $address.Port }}; - {{ end }} - {{ else if $containerNetwork }} - # {{ $container.Name }} - {{ if $containerNetwork.IP }} - {{ $server_found = "true" }} - server {{ $containerNetwork.IP }}:{{ $port }}; - {{ else }} - # /!\ No IP for this network! - {{ end }} - {{ end }} - {{ else }} - # Cannot connect to network '{{ $containerNetwork.Name }}' of this container - {{ end }} - {{ end }} +{{ if eq $nPaths 0 }} + # {{ $host }} + {{ template "upstream-definition" (dict "Upstream" $upstream_name "Containers" $containers "Networks" $CurrentContainer.Networks "Debug" $debug_all) }} +{{ else }} + {{ range $path, $containers := $paths }} + {{ $sum := sha1 $path }} + {{ $upstream := printf "%s-%s" $upstream_name $sum }} + # {{ $host }}{{ $path }} + {{ template "upstream-definition" (dict "Upstream" $upstream "Containers" $containers "Networks" $CurrentContainer.Networks "Debug" $debug_all) }} {{ end }} {{ end }} -{{/* nginx-proxy/nginx-proxy#1105 */}} -{{ if (eq $server_found "false") }} - # Fallback entry - server 127.0.0.1 down; -{{ end }} -} {{ $default_host := or ($.Env.DEFAULT_HOST) "" }} {{ $default_server := index (dict $host "" $default_host "default_server") $host }} @@ -337,30 +384,15 @@ server { include /etc/nginx/vhost.d/default; {{ end }} - location / { - {{ if eq $proto "uwsgi" }} - include uwsgi_params; - uwsgi_pass {{ trim $proto }}://{{ trim $upstream_name }}; - {{ else if eq $proto "fastcgi" }} - root {{ trim $vhost_root }}; - include fastcgi_params; - fastcgi_pass {{ trim $upstream_name }}; - {{ else if eq $proto "grpc" }} - grpc_pass {{ trim $proto }}://{{ trim $upstream_name }}; - {{ else }} - proxy_pass {{ trim $proto }}://{{ trim $upstream_name }}; + {{ if eq $nPaths 0 }} + {{ template "location" (dict "Path" "/" "Proto" $proto "Upstream" $upstream_name "Host" $host "Vhostroot" $vhost_root) }} + {{ else }} + {{ range $path, $container := $paths }} + {{ $sum := sha1 $path }} + {{ $upstream := printf "%s-%s" $host $sum }} + {{ template "location" (dict "Path" $path "Proto" $proto "Upstream" $upstream "Host" $host "Vhostroot" $vhost_root) }} {{ end }} - - {{ if (exists (printf "/etc/nginx/htpasswd/%s" $host)) }} - auth_basic "Restricted {{ $host }}"; - auth_basic_user_file {{ (printf "/etc/nginx/htpasswd/%s" $host) }}; - {{ end }} - {{ if (exists (printf "/etc/nginx/vhost.d/%s_location" $host)) }} - include {{ printf "/etc/nginx/vhost.d/%s_location" $host}}; - {{ else if (exists "/etc/nginx/vhost.d/default_location") }} - include /etc/nginx/vhost.d/default_location; - {{ end }} - } + {{ end }} } {{ end }} @@ -389,29 +421,15 @@ server { include /etc/nginx/vhost.d/default; {{ end }} - location / { - {{ if eq $proto "uwsgi" }} - include uwsgi_params; - uwsgi_pass {{ trim $proto }}://{{ trim $upstream_name }}; - {{ else if eq $proto "fastcgi" }} - root {{ trim $vhost_root }}; - include fastcgi_params; - fastcgi_pass {{ trim $upstream_name }}; - {{ else if eq $proto "grpc" }} - grpc_pass {{ trim $proto }}://{{ trim $upstream_name }}; - {{ else }} - proxy_pass {{ trim $proto }}://{{ trim $upstream_name }}; + {{ if eq $nPaths 0 }} + {{ template "location" (dict "Path" "/" "Proto" $proto "Upstream" $upstream_name "Host" $host "Vhostroot" $vhost_root) }} + {{ else }} + {{ range $path, $container := $paths }} + {{ $sum := sha1 $path }} + {{ $upstream := printf "%s-%s" $upstream_name $sum }} + {{ template "location" (dict "Path" $path "Proto" $proto "Upstream" $upstream "Host" $host "Vhostroot" $vhost_root) }} {{ end }} - {{ if (exists (printf "/etc/nginx/htpasswd/%s" $host)) }} - auth_basic "Restricted {{ $host }}"; - auth_basic_user_file {{ (printf "/etc/nginx/htpasswd/%s" $host) }}; - {{ end }} - {{ if (exists (printf "/etc/nginx/vhost.d/%s_location" $host)) }} - include {{ printf "/etc/nginx/vhost.d/%s_location" $host}}; - {{ else if (exists "/etc/nginx/vhost.d/default_location") }} - include /etc/nginx/vhost.d/default_location; - {{ end }} - } + {{ end }} } {{ if (and (not $is_https) (exists "/etc/nginx/certs/default.crt") (exists "/etc/nginx/certs/default.key")) }} From fc4c4e17cab24f84f6b2b9691a43cd4bb90d688b Mon Sep 17 00:00:00 2001 From: Alexander Lieret Date: Tue, 6 Jul 2021 14:40:21 +0200 Subject: [PATCH 036/300] ci: Add tests for the virtual-path routing @gregsymons test cases were too outdated to be ported easily. The new tests should include the coverage of the old ones. --- test/test_events.py | 38 +++++++++++- test/test_virtual-path/test_virtual_paths.py | 59 +++++++++++++++++++ test/test_virtual-path/test_virtual_paths.yml | 42 +++++++++++++ 3 files changed, 138 insertions(+), 1 deletion(-) create mode 100644 test/test_virtual-path/test_virtual_paths.py create mode 100644 test/test_virtual-path/test_virtual_paths.yml diff --git a/test/test_events.py b/test/test_events.py index 201917f..b5da3dd 100644 --- a/test/test_events.py +++ b/test/test_events.py @@ -29,13 +29,36 @@ def web1(docker_compose): except NotFound: pass +@pytest.fixture() +def web2(docker_compose): + """ + pytest fixture creating a web container with `VIRTUAL_HOST=nginx-proxy`, `VIRTUAL_PATH=/web2/` and `VIRTUAL_DEST=/` listening on port 82. + """ + container = docker_compose.containers.run( + name="web2", + image="web", + detach=True, + environment={ + "WEB_PORTS": "82", + "VIRTUAL_HOST": "nginx-proxy", + "VIRTUAL_PATH": "/web2/", + "VIRTUAL_DEST": "/", + }, + ports={"82/tcp": None} + ) + sleep(2) # give it some time to initialize and for docker-gen to detect it + yield container + try: + docker_compose.containers.get("web2").remove(force=True) + except NotFound: + pass def test_nginx_proxy_behavior_when_alone(docker_compose, nginxproxy): r = nginxproxy.get("http://nginx-proxy/") assert r.status_code == 503 -def test_new_container_is_detected(web1, nginxproxy): +def test_new_container_is_detected_vhost(web1, nginxproxy): r = nginxproxy.get("http://web1.nginx-proxy/port") assert r.status_code == 200 assert "answer from port 81\n" == r.text @@ -44,3 +67,16 @@ def test_new_container_is_detected(web1, nginxproxy): sleep(2) r = nginxproxy.get("http://web1.nginx-proxy/port") assert r.status_code == 503 + +def test_new_container_is_detected_vpath(web2, nginxproxy): + r = nginxproxy.get("http://nginx-proxy/web2/port") + assert r.status_code == 200 + assert "answer from port 82\n" == r.text + r = nginxproxy.get("http://nginx-proxy/port") + assert r.status_code in [404, 503] + + web2.remove(force=True) + sleep(2) + r = nginxproxy.get("http://nginx-proxy/web2/port") + assert r.status_code == 503 + diff --git a/test/test_virtual-path/test_virtual_paths.py b/test/test_virtual-path/test_virtual_paths.py new file mode 100644 index 0000000..115d47f --- /dev/null +++ b/test/test_virtual-path/test_virtual_paths.py @@ -0,0 +1,59 @@ +from time import sleep + +import pytest +from docker.errors import NotFound + +@pytest.mark.parametrize("stub,expected_port", [ + ("nginx-proxy.test/web1", 81), + ("nginx-proxy.test/web2", 82), + ("nginx-proxy.test", 83), + ("foo.nginx-proxy.test", 42), +]) +def test_valid_path(docker_compose, nginxproxy, stub, expected_port): + r = nginxproxy.get(f"http://{stub}/port") + assert r.status_code == 200 + assert r.text == f"answer from port {expected_port}\n" + +@pytest.mark.parametrize("stub", [ + "nginx-proxy.test/foo", + "bar.nginx-proxy.test", +]) +def test_invalid_path(docker_compose, nginxproxy, stub): + r = nginxproxy.get(f"http://{stub}/port") + assert r.status_code in [404, 503] + +@pytest.fixture() +def web4(docker_compose): + """ + pytest fixture creating a web container with `VIRTUAL_HOST=nginx-proxy.test`, `VIRTUAL_PATH=/web4/` and `VIRTUAL_DEST=/` listening on port 84. + """ + container = docker_compose.containers.run( + name="web4", + image="web", + detach=True, + environment={ + "WEB_PORTS": "84", + "VIRTUAL_HOST": "nginx-proxy.test", + "VIRTUAL_PATH": "/web4/", + "VIRTUAL_DEST": "/", + }, + ports={"84/tcp": None} + ) + sleep(2) # give it some time to initialize and for docker-gen to detect it + yield container + try: + docker_compose.containers.get("web4").remove(force=True) + except NotFound: + pass + +""" +Test if we can add and remove a single virtual_path from multiple ones on the same subdomain. +""" +def test_container_hotplug(web4, nginxproxy): + r = nginxproxy.get(f"http://nginx-proxy.test/web4/port") + assert r.status_code == 200 + assert r.text == f"answer from port 84\n" + web4.remove(force=True) + sleep(2) + r = nginxproxy.get(f"http://nginx-proxy.test/web4/port") + assert r.status_code == 404 diff --git a/test/test_virtual-path/test_virtual_paths.yml b/test/test_virtual-path/test_virtual_paths.yml new file mode 100644 index 0000000..ca688eb --- /dev/null +++ b/test/test_virtual-path/test_virtual_paths.yml @@ -0,0 +1,42 @@ + +foo: + image: web + expose: + - "42" + environment: + WEB_PORTS: "42" + VIRTUAL_HOST: "foo.nginx-proxy.test" + +web1: + image: web + expose: + - "81" + environment: + WEB_PORTS: "81" + VIRTUAL_HOST: "nginx-proxy.test" + VIRTUAL_PATH: "/web1/" + +web2: + image: web + expose: + - "82" + environment: + WEB_PORTS: "82" + VIRTUAL_HOST: "nginx-proxy.test" + VIRTUAL_PATH: "/web2/" + +web3: + image: web + expose: + - "83" + environment: + WEB_PORTS: "83" + VIRTUAL_HOST: "nginx-proxy.test" + VIRTUAL_PATH: "/" + +sut: + image: nginxproxy/nginx-proxy:test + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro + - ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro + From e0e1732842b7c4f90847a4a9f7ca1747a8e17558 Mon Sep 17 00:00:00 2001 From: Greg Symons Date: Tue, 6 Jul 2021 15:02:09 +0200 Subject: [PATCH 037/300] docs: Add documentation for path-based routing Co-authored-by: Josh Trow Co-authored-by: Adrian Co-authored-by: Rodrigo Aguilera Co-authored-by: Alexander Lieret --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index 556cf5c..9e248fa 100644 --- a/README.md +++ b/README.md @@ -117,6 +117,12 @@ For each host defined into `VIRTUAL_HOST`, the associated virtual port is retrie You can also use wildcards at the beginning and the end of host name, like `*.bar.com` or `foo.bar.*`. Or even a regular expression, which can be very useful in conjunction with a wildcard DNS service like [nip.io](https://nip.io) or [sslip.io](https://sslip.io), using `~^foo\.bar\..*\.nip\.io` will match `foo.bar.127.0.0.1.nip.io`, `foo.bar.10.0.2.2.nip.io` and all other given IPs. More information about this topic can be found in the nginx documentation about [`server_names`](http://nginx.org/en/docs/http/server_names.html). +### Path-based Routing + +You can have multiple containers proxied by the same `VIRTUAL_HOST` by adding a `VIRTUAL_PATH` environment variable containing the absolute path to where the container should be mounted. For example with `VIRTUAL_HOST=foo.example.com` and `VIRTUAL_PATH=/api/v2/service`, then requests to http://foo.example.com/api/v2/service will be routed to the container. If you wish to have a container serve the root while other containers serve other paths, make give the root container a `VIRTUAL_PATH` of `/`. Unmatched paths will be served by the container at `/` or will return the default nginx error page if no container has been assigned `/`. + +The full request URI will be forwarded to the serving container in the `X-Forwarded-Path` header. + ### Multiple Networks With the addition of [overlay networking](https://docs.docker.com/engine/userguide/networking/get-started-overlay/) in Docker 1.9, your `nginx-proxy` container may need to connect to backend containers on multiple networks. By default, if you don't pass the `--net` flag when your `nginx-proxy` container is created, it will only be attached to the default `bridge` network. This means that it will not be able to connect to containers on networks other than `bridge`. @@ -337,6 +343,7 @@ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto; proxy_set_header X-Forwarded-Ssl $proxy_x_forwarded_ssl; proxy_set_header X-Forwarded-Port $proxy_x_forwarded_port; +proxy_set_header X-Forwarded-Path $request_uri; # Mitigate httpoxy attack (see README for details) proxy_set_header Proxy ""; From 9cd85f61d5165f5307cae1dfad5c165bc9821c75 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Thu, 15 Jul 2021 21:47:03 +0200 Subject: [PATCH 038/300] build: build and push the dev branch to Dockerhub --- .github/workflows/dockerhub.yml | 43 +++++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/.github/workflows/dockerhub.yml b/.github/workflows/dockerhub.yml index cb3635e..74283b7 100644 --- a/.github/workflows/dockerhub.yml +++ b/.github/workflows/dockerhub.yml @@ -7,6 +7,7 @@ on: push: branches: - main + - dev tags: - '*.*.*' paths-ignore: @@ -42,7 +43,8 @@ jobs: tags: | type=semver,pattern={{version}} type=semver,pattern={{major}}.{{minor}} - type=raw,value=latest,enable=${{ endsWith(github.ref, github.event.repository.default_branch) }} + type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' }} + type=raw,value=dev,enable=${{ github.ref == 'refs/heads/dev' }} labels: | org.opencontainers.image.authors=Nicolas Duchon (@buchdag), Jason Wilder org.opencontainers.image.version=${{ env.GIT_DESCRIBE }} @@ -60,6 +62,7 @@ jobs: password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Build and push the Debian based image + if: github.ref == 'refs/heads/main' id: docker_build_debian uses: docker/build-push-action@v2 with: @@ -72,8 +75,25 @@ jobs: labels: ${{ steps.docker_meta_debian.outputs.labels }} - name: Images digests + if: github.ref == 'refs/heads/main' run: echo ${{ steps.docker_build_debian.outputs.digest }} + - name: Build and push the Debian based dev image + if: github.ref == 'refs/heads/dev' + id: docker_build_debian_dev + uses: docker/build-push-action@v2 + with: + file: Dockerfile + build-args: DOCKER_GEN_VERSION=main + platforms: linux/amd64,linux/arm64,linux/arm/v7 + push: true + tags: ${{ steps.docker_meta_debian.outputs.tags }} + labels: ${{ steps.docker_meta_debian.outputs.labels }} + + - name: Images digests + if: github.ref == 'refs/heads/dev' + run: echo ${{ steps.docker_build_debian_dev.outputs.digest }} + multiarch-build-alpine: runs-on: ubuntu-latest steps: @@ -96,7 +116,8 @@ jobs: tags: | type=semver,suffix=-alpine,pattern={{version}} type=semver,suffix=-alpine,pattern={{major}}.{{minor}} - type=raw,value=alpine,enable=${{ endsWith(github.ref, github.event.repository.default_branch) }} + type=raw,value=alpine,enable=${{ github.ref == 'refs/heads/main' }} + type=raw,value=dev-alpine,enable=${{ github.ref == 'refs/heads/dev' }} labels: | org.opencontainers.image.authors=Nicolas Duchon (@buchdag), Jason Wilder org.opencontainers.image.version=${{ env.GIT_DESCRIBE }} @@ -115,6 +136,7 @@ jobs: password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Build and push the Alpine based image + if: github.ref == 'refs/heads/main' id: docker_build_alpine uses: docker/build-push-action@v2 with: @@ -127,4 +149,21 @@ jobs: labels: ${{ steps.docker_meta_alpine.outputs.labels }} - name: Images digests + if: github.ref == 'refs/heads/main' run: echo ${{ steps.docker_build_alpine.outputs.digest }} + + - name: Build and push the Alpine based dev image + if: github.ref == 'refs/heads/dev' + id: docker_build_alpine_dev + uses: docker/build-push-action@v2 + with: + file: Dockerfile.alpine + build-args: DOCKER_GEN_VERSION=main + platforms: linux/amd64,linux/arm64,linux/arm/v7 + push: true + tags: ${{ steps.docker_meta_alpine.outputs.tags }} + labels: ${{ steps.docker_meta_alpine.outputs.labels }} + + - name: Images digests + if: github.ref == 'refs/heads/dev' + run: echo ${{ steps.docker_build_alpine_dev.outputs.digest }} From dad4a2d7bfcf71d517b35a4fe1f7f46c74b4fea8 Mon Sep 17 00:00:00 2001 From: Rafael Kraut Date: Tue, 20 Jul 2021 10:28:39 +0200 Subject: [PATCH 039/300] docs: remove unnecessary word --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9e248fa..262147c 100644 --- a/README.md +++ b/README.md @@ -119,7 +119,7 @@ You can also use wildcards at the beginning and the end of host name, like `*.ba ### Path-based Routing -You can have multiple containers proxied by the same `VIRTUAL_HOST` by adding a `VIRTUAL_PATH` environment variable containing the absolute path to where the container should be mounted. For example with `VIRTUAL_HOST=foo.example.com` and `VIRTUAL_PATH=/api/v2/service`, then requests to http://foo.example.com/api/v2/service will be routed to the container. If you wish to have a container serve the root while other containers serve other paths, make give the root container a `VIRTUAL_PATH` of `/`. Unmatched paths will be served by the container at `/` or will return the default nginx error page if no container has been assigned `/`. +You can have multiple containers proxied by the same `VIRTUAL_HOST` by adding a `VIRTUAL_PATH` environment variable containing the absolute path to where the container should be mounted. For example with `VIRTUAL_HOST=foo.example.com` and `VIRTUAL_PATH=/api/v2/service`, then requests to http://foo.example.com/api/v2/service will be routed to the container. If you wish to have a container serve the root while other containers serve other paths, give the root container a `VIRTUAL_PATH` of `/`. Unmatched paths will be served by the container at `/` or will return the default nginx error page if no container has been assigned `/`. The full request URI will be forwarded to the serving container in the `X-Forwarded-Path` header. From 28c73e5b52d281964812e411c0a411dabf1a387e Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Wed, 11 Aug 2021 18:04:53 +0200 Subject: [PATCH 040/300] fix: non working https with virtual path --- nginx.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nginx.tmpl b/nginx.tmpl index fc6f540..73fba26 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -389,7 +389,7 @@ server { {{ else }} {{ range $path, $container := $paths }} {{ $sum := sha1 $path }} - {{ $upstream := printf "%s-%s" $host $sum }} + {{ $upstream := printf "%s-%s" $upstream_name $sum }} {{ template "location" (dict "Path" $path "Proto" $proto "Upstream" $upstream "Host" $host "Vhostroot" $vhost_root) }} {{ end }} {{ end }} From 9df330e51ebb405966c942a4f5241faec16a462e Mon Sep 17 00:00:00 2001 From: Alexander Lieret Date: Tue, 6 Jul 2021 15:26:02 +0200 Subject: [PATCH 041/300] feat: Add user customizable default root response --- Dockerfile | 2 +- Dockerfile.alpine | 2 +- README.md | 10 +++++++++ nginx.tmpl | 11 ++++++++++ test/test_virtual-path/test_custom_conf.py | 6 ++++++ test/test_virtual-path/test_custom_conf.yml | 24 +++++++++++++++++++++ 6 files changed, 53 insertions(+), 2 deletions(-) create mode 100644 test/test_virtual-path/test_custom_conf.py create mode 100644 test/test_virtual-path/test_custom_conf.yml diff --git a/Dockerfile b/Dockerfile index d5c71bc..bc4093d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # setup build arguments for version of dependencies to use -ARG DOCKER_GEN_VERSION=0.7.7 +ARG DOCKER_GEN_VERSION=main ARG FOREGO_VERSION=v0.17.0 # Use a specific version of golang to build both binaries diff --git a/Dockerfile.alpine b/Dockerfile.alpine index 2552615..98e9bc5 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -1,5 +1,5 @@ # setup build arguments for version of dependencies to use -ARG DOCKER_GEN_VERSION=0.7.7 +ARG DOCKER_GEN_VERSION=main ARG FOREGO_VERSION=v0.17.0 # Use a specific version of golang to build both binaries diff --git a/README.md b/README.md index 262147c..aa1b79b 100644 --- a/README.md +++ b/README.md @@ -123,6 +123,16 @@ You can have multiple containers proxied by the same `VIRTUAL_HOST` by adding a The full request URI will be forwarded to the serving container in the `X-Forwarded-Path` header. +**NOTE**: Your application needs to be able to generate links starting with `VIRTUAL_PATH`. This can be achieved by it being natively on this path or havin an option to prepend this path. The application does not need to expect this path in the request. + +#### DEFAULT_ROOT + +This environment variable of the nginx proxy container can be used to customize the return error page if no matching path is found. Furthermore it is possible to use anything which is compatible with the `return` statement of nginx. + +For example `DEFAUL_ROOT=418` will return a 418 error page instead of the normal 404 one. +Another example is `DEFAULT_ROOT="301 https://github.com/nginx-proxy/nginx-proxy/blob/main/README.md"` which would redirect an invalid request to this documentation. + + ### Multiple Networks With the addition of [overlay networking](https://docs.docker.com/engine/userguide/networking/get-started-overlay/) in Docker 1.9, your `nginx-proxy` container may need to connect to backend containers on multiple networks. By default, if you don't pass the `--net` flag when your `nginx-proxy` container is created, it will only be attached to the default `bridge` network. This means that it will not be able to connect to containers on networks other than `bridge`. diff --git a/nginx.tmpl b/nginx.tmpl index 73fba26..85ccbda 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -5,6 +5,7 @@ {{ $external_https_port := coalesce $.Env.HTTPS_PORT "443" }} {{ $debug_all := $.Env.DEBUG }} {{ $sha1_upstream_name := parseBool (coalesce $.Env.SHA1_UPSTREAM_NAME "false") }} +{{ $default_root_response := coalesce $.Env.DEFAULT_ROOT "404" }} {{ define "ssl_policy" }} {{ if eq .ssl_policy "Mozilla-Modern" }} @@ -392,6 +393,11 @@ server { {{ $upstream := printf "%s-%s" $upstream_name $sum }} {{ template "location" (dict "Path" $path "Proto" $proto "Upstream" $upstream "Host" $host "Vhostroot" $vhost_root) }} {{ end }} + {{ if (not (contains $paths "/")) }} + location / { + return {{ $default_root_response }}; + } + {{ end }} {{ end }} } @@ -429,6 +435,11 @@ server { {{ $upstream := printf "%s-%s" $upstream_name $sum }} {{ template "location" (dict "Path" $path "Proto" $proto "Upstream" $upstream "Host" $host "Vhostroot" $vhost_root) }} {{ end }} + {{ if (not (contains $paths "/")) }} + location / { + return {{ $default_root_response }}; + } + {{ end }} {{ end }} } diff --git a/test/test_virtual-path/test_custom_conf.py b/test/test_virtual-path/test_custom_conf.py new file mode 100644 index 0000000..68ecd3a --- /dev/null +++ b/test/test_virtual-path/test_custom_conf.py @@ -0,0 +1,6 @@ +import pytest + +def test_default_root_response(docker_compose, nginxproxy): + r = nginxproxy.get("http://nginx-proxy.test/") + assert r.status_code == 418 + diff --git a/test/test_virtual-path/test_custom_conf.yml b/test/test_virtual-path/test_custom_conf.yml new file mode 100644 index 0000000..2fffd65 --- /dev/null +++ b/test/test_virtual-path/test_custom_conf.yml @@ -0,0 +1,24 @@ +web1: + image: web + expose: + - "81" + environment: + WEB_PORTS: "81" + VIRTUAL_HOST: "nginx-proxy.test" + VIRTUAL_PATH: "/web1/" + +web2: + image: web + expose: + - "82" + environment: + WEB_PORTS: "82" + VIRTUAL_HOST: "nginx-proxy.test" + VIRTUAL_PATH: "/web2/" +sut: + image: nginxproxy/nginx-proxy:test + environment: + DEFAULT_ROOT: 418 + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro + - ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro From 4b85e9582450ff07dcf205ad8ab5f5b1131599ef Mon Sep 17 00:00:00 2001 From: Alexander Lieret Date: Tue, 6 Jul 2021 15:36:06 +0200 Subject: [PATCH 042/300] feat: Replace path stripping with variable This commit removes the automatic path stripping and replaces it with a user configurable environment variable. This can be set individually for each container. --- README.md | 14 ++++++++++++++ nginx.tmpl | 12 +++++++----- test/test_virtual-path/test_custom_conf.yml | 3 +++ test/test_virtual-path/test_virtual_paths.yml | 2 ++ 4 files changed, 26 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index aa1b79b..33ec073 100644 --- a/README.md +++ b/README.md @@ -125,6 +125,20 @@ The full request URI will be forwarded to the serving container in the `X-Forwar **NOTE**: Your application needs to be able to generate links starting with `VIRTUAL_PATH`. This can be achieved by it being natively on this path or havin an option to prepend this path. The application does not need to expect this path in the request. +#### VIRTUAL_DEST + +This environment variable can be used to rewrite the `VIRTUAL_PATH` part of the requested URL to proxied application. The default value is empty (off). +Make sure that your settings won't result in the slash missing or being doubled. Both these versions can cause troubles. + +If the application runs natively on this sub-path or has a setting to do so, `VIRTUAL_DEST` should not be set or empty. +If the requests are expected to not contain a sub-path and the generated links contain the sub-path, `VIRTUAL_DEST=/` should be used. + +```console +$ docker run -d -e VIRTUAL_HOST=example.tld -e VIRTUAL_PATH=/app1/ -e VIRTUAL_DEST=/ --name app1 app +``` + +In this example, the incoming request `http://example.tld/app1/foo` will be proxied as `http://app1/foo` instead of `http://app1/app1/foo`. + #### DEFAULT_ROOT This environment variable of the nginx proxy container can be used to customize the return error page if no matching path is found. Furthermore it is possible to use anything which is compatible with the `return` statement of nginx. diff --git a/nginx.tmpl b/nginx.tmpl index 85ccbda..b1e6249 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -62,7 +62,7 @@ location {{ .Path }} { {{ else if eq .Proto "grpc" }} grpc_pass {{ trim .Proto }}://{{ trim .Upstream }}; {{ else }} - proxy_pass {{ trim .Proto }}://{{ trim .Upstream }}/; + proxy_pass {{ trim .Proto }}://{{ trim .Upstream }}{{ trim .Dest }}; {{ end }} {{ if (exists (printf "/etc/nginx/htpasswd/%s" .Host)) }} @@ -386,12 +386,13 @@ server { {{ end }} {{ if eq $nPaths 0 }} - {{ template "location" (dict "Path" "/" "Proto" $proto "Upstream" $upstream_name "Host" $host "Vhostroot" $vhost_root) }} + {{ template "location" (dict "Path" "/" "Proto" $proto "Upstream" $upstream_name "Host" $host "Vhostroot" $vhost_root "Dest" "") }} {{ else }} {{ range $path, $container := $paths }} {{ $sum := sha1 $path }} {{ $upstream := printf "%s-%s" $upstream_name $sum }} - {{ template "location" (dict "Path" $path "Proto" $proto "Upstream" $upstream "Host" $host "Vhostroot" $vhost_root) }} + {{ $dest := (or (first (groupByKeys $container "Env.VIRTUAL_DEST")) "") }} + {{ template "location" (dict "Path" $path "Proto" $proto "Upstream" $upstream "Host" $host "Vhostroot" $vhost_root "Dest" $dest) }} {{ end }} {{ if (not (contains $paths "/")) }} location / { @@ -428,12 +429,13 @@ server { {{ end }} {{ if eq $nPaths 0 }} - {{ template "location" (dict "Path" "/" "Proto" $proto "Upstream" $upstream_name "Host" $host "Vhostroot" $vhost_root) }} + {{ template "location" (dict "Path" "/" "Proto" $proto "Upstream" $upstream_name "Host" $host "Vhostroot" $vhost_root "Dest" "") }} {{ else }} {{ range $path, $container := $paths }} {{ $sum := sha1 $path }} {{ $upstream := printf "%s-%s" $upstream_name $sum }} - {{ template "location" (dict "Path" $path "Proto" $proto "Upstream" $upstream "Host" $host "Vhostroot" $vhost_root) }} + {{ $dest := (or (first (groupByKeys $container "Env.VIRTUAL_DEST")) "") }} + {{ template "location" (dict "Path" $path "Proto" $proto "Upstream" $upstream "Host" $host "Vhostroot" $vhost_root "Dest" $dest) }} {{ end }} {{ if (not (contains $paths "/")) }} location / { diff --git a/test/test_virtual-path/test_custom_conf.yml b/test/test_virtual-path/test_custom_conf.yml index 2fffd65..2369bac 100644 --- a/test/test_virtual-path/test_custom_conf.yml +++ b/test/test_virtual-path/test_custom_conf.yml @@ -6,6 +6,7 @@ web1: WEB_PORTS: "81" VIRTUAL_HOST: "nginx-proxy.test" VIRTUAL_PATH: "/web1/" + VIRTUAL_DEST: "/" web2: image: web @@ -15,6 +16,8 @@ web2: WEB_PORTS: "82" VIRTUAL_HOST: "nginx-proxy.test" VIRTUAL_PATH: "/web2/" + VIRTUAL_DEST: "/" + sut: image: nginxproxy/nginx-proxy:test environment: diff --git a/test/test_virtual-path/test_virtual_paths.yml b/test/test_virtual-path/test_virtual_paths.yml index ca688eb..b335c3f 100644 --- a/test/test_virtual-path/test_virtual_paths.yml +++ b/test/test_virtual-path/test_virtual_paths.yml @@ -15,6 +15,7 @@ web1: WEB_PORTS: "81" VIRTUAL_HOST: "nginx-proxy.test" VIRTUAL_PATH: "/web1/" + VIRTUAL_DEST: "/" web2: image: web @@ -24,6 +25,7 @@ web2: WEB_PORTS: "82" VIRTUAL_HOST: "nginx-proxy.test" VIRTUAL_PATH: "/web2/" + VIRTUAL_DEST: "/" web3: image: web From 33eab70d321b727b245f5d59056b8a990048eb68 Mon Sep 17 00:00:00 2001 From: Alexander Lieret Date: Tue, 6 Jul 2021 15:41:14 +0200 Subject: [PATCH 043/300] feat: Add custom location block to virtual paths This features allows the custom location blocks to be added to the virtual path based routing. The custom config can be specified for each container individually. --- README.md | 9 ++++++ nginx.tmpl | 2 ++ test/test_virtual-path/alternate.conf | 1 + test/test_virtual-path/bar.conf | 1 + test/test_virtual-path/foo.conf | 1 + test/test_virtual-path/test_custom_conf.py | 32 +++++++++++++++++++++ test/test_virtual-path/test_custom_conf.yml | 22 ++++++++++++++ 7 files changed, 68 insertions(+) create mode 100644 test/test_virtual-path/alternate.conf create mode 100644 test/test_virtual-path/bar.conf create mode 100644 test/test_virtual-path/foo.conf diff --git a/README.md b/README.md index 33ec073..2f00d1c 100644 --- a/README.md +++ b/README.md @@ -120,6 +120,7 @@ You can also use wildcards at the beginning and the end of host name, like `*.ba ### Path-based Routing You can have multiple containers proxied by the same `VIRTUAL_HOST` by adding a `VIRTUAL_PATH` environment variable containing the absolute path to where the container should be mounted. For example with `VIRTUAL_HOST=foo.example.com` and `VIRTUAL_PATH=/api/v2/service`, then requests to http://foo.example.com/api/v2/service will be routed to the container. If you wish to have a container serve the root while other containers serve other paths, give the root container a `VIRTUAL_PATH` of `/`. Unmatched paths will be served by the container at `/` or will return the default nginx error page if no container has been assigned `/`. +It is also possible to specify multiple paths with regex locations like `VIRTUAL_PATH=~^/(app1|alternative1)/`. For further details see the nginx documentation on location blocks. This is not compatible with `VIRTUAL_DEST`. The full request URI will be forwarded to the serving container in the `X-Forwarded-Path` header. @@ -139,6 +140,14 @@ $ docker run -d -e VIRTUAL_HOST=example.tld -e VIRTUAL_PATH=/app1/ -e VIRTUAL_DE In this example, the incoming request `http://example.tld/app1/foo` will be proxied as `http://app1/foo` instead of `http://app1/app1/foo`. +#### 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 filename of the previous example would be `example.tld_8610f6c344b4096614eab6e09d58885349f42faf_location`. + #### DEFAULT_ROOT This environment variable of the nginx proxy container can be used to customize the return error page if no matching path is found. Furthermore it is possible to use anything which is compatible with the `return` statement of nginx. diff --git a/nginx.tmpl b/nginx.tmpl index b1e6249..dd48d4b 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -72,6 +72,8 @@ location {{ .Path }} { {{ if (exists (printf "/etc/nginx/vhost.d/%s_location" .Host)) }} include {{ printf "/etc/nginx/vhost.d/%s_location" .Host}}; + {{ else if (exists (printf "/etc/nginx/vhost.d/%s_%s_location" .Host (sha1 .Path) )) }} + include {{ printf "/etc/nginx/vhost.d/%s_%s_location" .Host (sha1 .Path) }}; {{ else if (exists "/etc/nginx/vhost.d/default_location") }} include /etc/nginx/vhost.d/default_location; {{ end }} diff --git a/test/test_virtual-path/alternate.conf b/test/test_virtual-path/alternate.conf new file mode 100644 index 0000000..541332e --- /dev/null +++ b/test/test_virtual-path/alternate.conf @@ -0,0 +1 @@ +rewrite ^/(web3|alt)/(.*) /$2 break; diff --git a/test/test_virtual-path/bar.conf b/test/test_virtual-path/bar.conf new file mode 100644 index 0000000..e8b0827 --- /dev/null +++ b/test/test_virtual-path/bar.conf @@ -0,0 +1 @@ +add_header X-test bar; diff --git a/test/test_virtual-path/foo.conf b/test/test_virtual-path/foo.conf new file mode 100644 index 0000000..8d8502d --- /dev/null +++ b/test/test_virtual-path/foo.conf @@ -0,0 +1 @@ +add_header X-test f00; \ No newline at end of file diff --git a/test/test_virtual-path/test_custom_conf.py b/test/test_virtual-path/test_custom_conf.py index 68ecd3a..eec149f 100644 --- a/test/test_virtual-path/test_custom_conf.py +++ b/test/test_virtual-path/test_custom_conf.py @@ -4,3 +4,35 @@ def test_default_root_response(docker_compose, nginxproxy): r = nginxproxy.get("http://nginx-proxy.test/") assert r.status_code == 418 +@pytest.mark.parametrize("stub,header", [ + ("nginx-proxy.test/web1", "bar"), + ("foo.nginx-proxy.test", "f00"), +]) +def test_custom_applies(docker_compose, nginxproxy, stub, header): + r = nginxproxy.get(f"http://{stub}/port") + assert r.status_code == 200 + assert "X-test" in r.headers + assert header == r.headers["X-test"] + +@pytest.mark.parametrize("stub,code", [ + ("nginx-proxy.test/foo", 418), + ("nginx-proxy.test/web2", 200), + ("nginx-proxy.test/web3", 200), + ("bar.nginx-proxy.test", 503), +]) +def test_custom_does_not_apply(docker_compose, nginxproxy, stub, code): + r = nginxproxy.get(f"http://{stub}/port") + assert r.status_code == code + assert "X-test" not in r.headers + +@pytest.mark.parametrize("stub,port", [ + ("nginx-proxy.test/web1", 81), + ("nginx-proxy.test/web2", 82), + ("nginx-proxy.test/web3", 83), + ("nginx-proxy.test/alt", 83), +]) +def test_alternate(docker_compose, nginxproxy, stub, port): + r = nginxproxy.get(f"http://{stub}/port") + assert r.status_code == 200 + assert r.text == f"answer from port {port}\n" + diff --git a/test/test_virtual-path/test_custom_conf.yml b/test/test_virtual-path/test_custom_conf.yml index 2369bac..abd9d0c 100644 --- a/test/test_virtual-path/test_custom_conf.yml +++ b/test/test_virtual-path/test_custom_conf.yml @@ -1,3 +1,12 @@ + +foo: + image: web + expose: + - "42" + environment: + WEB_PORTS: "42" + VIRTUAL_HOST: "foo.nginx-proxy.test" + web1: image: web expose: @@ -18,6 +27,15 @@ web2: VIRTUAL_PATH: "/web2/" VIRTUAL_DEST: "/" +web3: + image: web + expose: + - "83" + environment: + WEB_PORTS: "83" + VIRTUAL_HOST: "nginx-proxy.test" + VIRTUAL_PATH: "~ ^/(web3|alt)/" + sut: image: nginxproxy/nginx-proxy:test environment: @@ -25,3 +43,7 @@ sut: volumes: - /var/run/docker.sock:/tmp/docker.sock:ro - ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro + - ./foo.conf:/etc/nginx/vhost.d/foo.nginx-proxy.test:ro + - ./bar.conf:/etc/nginx/vhost.d/nginx-proxy.test_918d687a929083edd0c7224ee2293e0e7c062ab4_location:ro + - ./alternate.conf:/etc/nginx/vhost.d/nginx-proxy.test_7fb22b74bbdf907425dbbad18e4462565cada230_location:ro + From c75622db87abf0aee6eb97affa95474ea0b2573b Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Fri, 13 Aug 2021 10:54:12 +0200 Subject: [PATCH 044/300] docs: fix typo in README.md Co-authored-by: Jonathan Underwood --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2f00d1c..9a69d1c 100644 --- a/README.md +++ b/README.md @@ -124,7 +124,7 @@ It is also possible to specify multiple paths with regex locations like `VIRTUAL The full request URI will be forwarded to the serving container in the `X-Forwarded-Path` header. -**NOTE**: Your application needs to be able to generate links starting with `VIRTUAL_PATH`. This can be achieved by it being natively on this path or havin an option to prepend this path. The application does not need to expect this path in the request. +**NOTE**: Your application needs to be able to generate links starting with `VIRTUAL_PATH`. This can be achieved by it being natively on this path or having an option to prepend this path. The application does not need to expect this path in the request. #### VIRTUAL_DEST From efb250da0120854e4f399d58e4a4c2e2db82333e Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Sat, 14 Aug 2021 21:38:13 +0200 Subject: [PATCH 045/300] fix: use most specific custom location config first Co-authored-by: Jonathan Underwood --- nginx.tmpl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/nginx.tmpl b/nginx.tmpl index dd48d4b..c0f6db5 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -70,10 +70,10 @@ location {{ .Path }} { auth_basic_user_file {{ (printf "/etc/nginx/htpasswd/%s" .Host) }}; {{ end }} - {{ if (exists (printf "/etc/nginx/vhost.d/%s_location" .Host)) }} - include {{ printf "/etc/nginx/vhost.d/%s_location" .Host}}; - {{ else if (exists (printf "/etc/nginx/vhost.d/%s_%s_location" .Host (sha1 .Path) )) }} + {{ if (exists (printf "/etc/nginx/vhost.d/%s_%s_location" .Host (sha1 .Path) )) }} include {{ printf "/etc/nginx/vhost.d/%s_%s_location" .Host (sha1 .Path) }}; + {{ else if (exists (printf "/etc/nginx/vhost.d/%s_location" .Host)) }} + include {{ printf "/etc/nginx/vhost.d/%s_location" .Host}}; {{ else if (exists "/etc/nginx/vhost.d/default_location") }} include /etc/nginx/vhost.d/default_location; {{ end }} From 12887a977b3570e27775f19c13563d68ded4314e Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Sat, 14 Aug 2021 21:40:25 +0200 Subject: [PATCH 046/300] docs: update DEFAULT_ROOT documentation Co-authored-by: Jonathan Underwood --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 9a69d1c..880d0e8 100644 --- a/README.md +++ b/README.md @@ -154,6 +154,11 @@ This environment variable of the nginx proxy container can be used to customize For example `DEFAUL_ROOT=418` will return a 418 error page instead of the normal 404 one. Another example is `DEFAULT_ROOT="301 https://github.com/nginx-proxy/nginx-proxy/blob/main/README.md"` which would redirect an invalid request to this documentation. +Nginx variables such as $scheme, $host, and $request_uri can be used. However, care must be taken to make sure the $ signs are escaped properly. +If you want to use `301 $scheme://$host/myapp1$request_uri` you should use: + +* Bash: `DEFAULT_ROOT='301 $scheme://$host/myapp1$request_uri'` +* Docker Compose yaml: `- DEFAULT_ROOT: 301 $$scheme://$$host/myapp1$$request_uri` ### Multiple Networks From e08b3487c95b38cd3f094e86f9638a39c12bbf84 Mon Sep 17 00:00:00 2001 From: Alexander Lieret Date: Tue, 17 Aug 2021 10:51:32 +0200 Subject: [PATCH 047/300] test: Add test to cover SSL of path-based routing --- test/test_ssl/test_virtual_path.py | 15 +++++++++++++++ test/test_ssl/test_virtual_path.yml | 27 +++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 test/test_ssl/test_virtual_path.py create mode 100644 test/test_ssl/test_virtual_path.yml diff --git a/test/test_ssl/test_virtual_path.py b/test/test_ssl/test_virtual_path.py new file mode 100644 index 0000000..508653f --- /dev/null +++ b/test/test_ssl/test_virtual_path.py @@ -0,0 +1,15 @@ +import pytest + +@pytest.mark.parametrize("path", ["web1", "web2"]) +def test_web1_http_redirects_to_https(docker_compose, nginxproxy, path): + r = nginxproxy.get("http://www.nginx-proxy.tld/%s/port" % path, allow_redirects=False) + assert r.status_code == 301 + assert "Location" in r.headers + assert "https://www.nginx-proxy.tld/%s/port" % path == r.headers['Location'] + +@pytest.mark.parametrize("path,port", [("web1", 81), ("web2", 82)]) +def test_web1_https_is_forwarded(docker_compose, nginxproxy, path, port): + r = nginxproxy.get("https://www.nginx-proxy.tld/%s/port" % path, allow_redirects=False) + assert r.status_code == 200 + assert "answer from port %d\n" % port in r.text + diff --git a/test/test_ssl/test_virtual_path.yml b/test/test_ssl/test_virtual_path.yml new file mode 100644 index 0000000..07175ac --- /dev/null +++ b/test/test_ssl/test_virtual_path.yml @@ -0,0 +1,27 @@ +web1: + image: web + expose: + - "81" + environment: + WEB_PORTS: "81" + VIRTUAL_HOST: "www.nginx-proxy.tld" + VIRTUAL_PATH: "/web1/" + VIRTUAL_DEST: "/" + +web2: + image: web + expose: + - "82" + environment: + WEB_PORTS: "82" + VIRTUAL_HOST: "www.nginx-proxy.tld" + VIRTUAL_PATH: "/web2/" + VIRTUAL_DEST: "/" + +sut: + image: nginxproxy/nginx-proxy:test + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro + - ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro + - ./certs:/etc/nginx/certs:ro + From 4099fcd61872fe4093323771090ccad570a80e77 Mon Sep 17 00:00:00 2001 From: Alexander Lieret Date: Tue, 17 Aug 2021 11:08:56 +0200 Subject: [PATCH 048/300] test: Add test case for default app redirect Co-authored-by: Jonathan Underwood --- test/test_virtual-path/test_forwarding.py | 18 ++++++++++++++++++ test/test_virtual-path/test_forwarding.yml | 18 ++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 test/test_virtual-path/test_forwarding.py create mode 100644 test/test_virtual-path/test_forwarding.yml diff --git a/test/test_virtual-path/test_forwarding.py b/test/test_virtual-path/test_forwarding.py new file mode 100644 index 0000000..062dd6c --- /dev/null +++ b/test/test_virtual-path/test_forwarding.py @@ -0,0 +1,18 @@ +import pytest + +def test_root_redirects_to_web1(docker_compose, nginxproxy): + r = nginxproxy.get("http://www.nginx-proxy.tld/port", allow_redirects=False) + assert r.status_code == 301 + assert "Location" in r.headers + assert "http://www.nginx-proxy.tld/web1/port" == r.headers['Location'] + +def test_direct_access(docker_compose, nginxproxy): + r = nginxproxy.get("http://www.nginx-proxy.tld/web1/port", allow_redirects=False) + assert r.status_code == 200 + assert "answer from port 81\n" in r.text + +def test_root_is_forwarded(docker_compose, nginxproxy): + r = nginxproxy.get("http://www.nginx-proxy.tld/port", allow_redirects=True) + assert r.status_code == 200 + assert "answer from port 81\n" in r.text + diff --git a/test/test_virtual-path/test_forwarding.yml b/test/test_virtual-path/test_forwarding.yml new file mode 100644 index 0000000..78662d8 --- /dev/null +++ b/test/test_virtual-path/test_forwarding.yml @@ -0,0 +1,18 @@ +web1: + image: web + expose: + - "81" + environment: + WEB_PORTS: "81" + VIRTUAL_HOST: "www.nginx-proxy.tld" + VIRTUAL_PATH: "/web1/" + VIRTUAL_DEST: "/" + +sut: + image: nginxproxy/nginx-proxy:test + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro + - ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro + - ./certs:/etc/nginx/certs:ro + environment: + - DEFAULT_ROOT=301 http://$$host/web1$$request_uri From 6a580ad66435b7d2b81a3df0cfb857636db46ef3 Mon Sep 17 00:00:00 2001 From: Alexander Lieret Date: Wed, 18 Aug 2021 15:34:30 +0200 Subject: [PATCH 049/300] test: Add test case for location config priority --- test/test_virtual-path/default.conf | 1 + test/test_virtual-path/host.conf | 1 + test/test_virtual-path/path.conf | 1 + .../test_location_precedence.py | 32 ++++++++++++++++ .../test_location_precedence.yml | 38 +++++++++++++++++++ 5 files changed, 73 insertions(+) create mode 100644 test/test_virtual-path/default.conf create mode 100644 test/test_virtual-path/host.conf create mode 100644 test/test_virtual-path/path.conf create mode 100644 test/test_virtual-path/test_location_precedence.py create mode 100644 test/test_virtual-path/test_location_precedence.yml diff --git a/test/test_virtual-path/default.conf b/test/test_virtual-path/default.conf new file mode 100644 index 0000000..087e66c --- /dev/null +++ b/test/test_virtual-path/default.conf @@ -0,0 +1 @@ +add_header X-test-default true; diff --git a/test/test_virtual-path/host.conf b/test/test_virtual-path/host.conf new file mode 100644 index 0000000..fe05265 --- /dev/null +++ b/test/test_virtual-path/host.conf @@ -0,0 +1 @@ +add_header X-test-host true; diff --git a/test/test_virtual-path/path.conf b/test/test_virtual-path/path.conf new file mode 100644 index 0000000..6c23b9a --- /dev/null +++ b/test/test_virtual-path/path.conf @@ -0,0 +1 @@ +add_header X-test-path true; diff --git a/test/test_virtual-path/test_location_precedence.py b/test/test_virtual-path/test_location_precedence.py new file mode 100644 index 0000000..415c6c1 --- /dev/null +++ b/test/test_virtual-path/test_location_precedence.py @@ -0,0 +1,32 @@ +import pytest + +def test_location_precedence_case1(docker_compose, nginxproxy): + r = nginxproxy.get(f"http://foo.nginx-proxy.test/web1/port") + assert r.status_code == 200 + + assert "X-test-default" in r.headers + assert "X-test-host" not in r.headers + assert "X-test-path" not in r.headers + + assert r.headers["X-test-default"] == "true" + +def test_location_precedence_case2(docker_compose, nginxproxy): + r = nginxproxy.get(f"http://bar.nginx-proxy.test/web2/port") + assert r.status_code == 200 + + assert "X-test-default" not in r.headers + assert "X-test-host" in r.headers + assert "X-test-path" not in r.headers + + assert r.headers["X-test-host"] == "true" + +def test_location_precedence_case3(docker_compose, nginxproxy): + r = nginxproxy.get(f"http://bar.nginx-proxy.test/web3/port") + assert r.status_code == 200 + + assert "X-test-default" not in r.headers + assert "X-test-host" not in r.headers + assert "X-test-path" in r.headers + + assert r.headers["X-test-path"] == "true" + diff --git a/test/test_virtual-path/test_location_precedence.yml b/test/test_virtual-path/test_location_precedence.yml new file mode 100644 index 0000000..be93b58 --- /dev/null +++ b/test/test_virtual-path/test_location_precedence.yml @@ -0,0 +1,38 @@ +web1: + image: web + expose: + - "81" + environment: + WEB_PORTS: "81" + VIRTUAL_HOST: "foo.nginx-proxy.test" + VIRTUAL_PATH: "/web1/" + VIRTUAL_DEST: "/" + +web2: + image: web + expose: + - "82" + environment: + WEB_PORTS: "82" + VIRTUAL_HOST: "bar.nginx-proxy.test" + VIRTUAL_PATH: "/web2/" + VIRTUAL_DEST: "/" + +web3: + image: web + expose: + - "83" + environment: + WEB_PORTS: "83" + VIRTUAL_HOST: "bar.nginx-proxy.test" + VIRTUAL_PATH: "/web3/" + VIRTUAL_DEST: "/" + +sut: + image: nginxproxy/nginx-proxy:test + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro + - ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro + - ./default.conf:/etc/nginx/vhost.d/default_location:ro + - ./host.conf:/etc/nginx/vhost.d/bar.nginx-proxy.test_location:ro + - ./path.conf:/etc/nginx/vhost.d/bar.nginx-proxy.test_99f2db0ed8aa95dbb5b87fca79c7eff2ff6bb8bd_location:ro From 28c74e8daeb0eb7f5bcace7db4c5b570af6b5436 Mon Sep 17 00:00:00 2001 From: Alexander Lieret Date: Tue, 24 Aug 2021 15:51:39 +0200 Subject: [PATCH 050/300] fix: Move NETWORK_ACCESS to location block --- network_internal.conf | 1 + nginx.tmpl | 33 +++++++++++++++++---------------- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/network_internal.conf b/network_internal.conf index cdf3c9c..bacceb1 100644 --- a/network_internal.conf +++ b/network_internal.conf @@ -3,4 +3,5 @@ allow 127.0.0.0/8; allow 10.0.0.0/8; allow 192.168.0.0/16; allow 172.16.0.0/12; +allow fc00::/7; # IPv6 local address range deny all; diff --git a/nginx.tmpl b/nginx.tmpl index c0f6db5..13ca7a4 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -52,6 +52,11 @@ {{ define "location" }} location {{ .Path }} { + {{ if eq .NetworkTag "internal" }} + # Only allow traffic from internal clients + include /etc/nginx/network_internal.conf; + {{ end }} + {{ if eq .Proto "uwsgi" }} include uwsgi_params; uwsgi_pass {{ trim .Proto }}://{{ trim .Upstream }}; @@ -277,8 +282,6 @@ server { {{/* Get the SERVER_TOKENS defined by containers w/ the same vhost, falling back to "" */}} {{ $server_tokens := trim (or (first (groupByKeys $containers "Env.SERVER_TOKENS")) "") }} -{{/* Get the NETWORK_ACCESS defined by containers w/ the same vhost, falling back to "external" */}} -{{ $network_tag := or (first (groupByKeys $containers "Env.NETWORK_ACCESS")) "external" }} {{/* Get the HTTPS_METHOD defined by containers w/ the same vhost, falling back to "redirect" */}} {{ $https_method := or (first (groupByKeys $containers "Env.HTTPS_METHOD")) (or $.Env.HTTPS_METHOD "redirect") }} @@ -353,11 +356,6 @@ server { {{ end }} {{ $access_log }} - {{ if eq $network_tag "internal" }} - # Only allow traffic from internal clients - include /etc/nginx/network_internal.conf; - {{ end }} - {{ template "ssl_policy" (dict "ssl_policy" $ssl_policy) }} ssl_session_timeout 5m; @@ -388,13 +386,17 @@ server { {{ end }} {{ if eq $nPaths 0 }} - {{ template "location" (dict "Path" "/" "Proto" $proto "Upstream" $upstream_name "Host" $host "Vhostroot" $vhost_root "Dest" "") }} + {{/* Get the NETWORK_ACCESS defined by containers w/ the same vhost, falling back to "external" */}} + {{ $network_tag := or (first (groupByKeys $containers "Env.NETWORK_ACCESS")) "external" }} + {{ template "location" (dict "Path" "/" "Proto" $proto "Upstream" $upstream_name "Host" $host "Vhostroot" $vhost_root "Dest" "" "NetworkTag" $network_tag) }} {{ else }} {{ range $path, $container := $paths }} + {{/* Get the NETWORK_ACCESS defined by containers w/ the same vhost, falling back to "external" */}} + {{ $network_tag := or (first (groupByKeys $container "Env.NETWORK_ACCESS")) "external" }} {{ $sum := sha1 $path }} {{ $upstream := printf "%s-%s" $upstream_name $sum }} {{ $dest := (or (first (groupByKeys $container "Env.VIRTUAL_DEST")) "") }} - {{ template "location" (dict "Path" $path "Proto" $proto "Upstream" $upstream "Host" $host "Vhostroot" $vhost_root "Dest" $dest) }} + {{ template "location" (dict "Path" $path "Proto" $proto "Upstream" $upstream "Host" $host "Vhostroot" $vhost_root "Dest" $dest "NetworkTag" $network_tag) }} {{ end }} {{ if (not (contains $paths "/")) }} location / { @@ -419,11 +421,6 @@ server { {{ end }} {{ $access_log }} - {{ if eq $network_tag "internal" }} - # Only allow traffic from internal clients - include /etc/nginx/network_internal.conf; - {{ end }} - {{ if (exists (printf "/etc/nginx/vhost.d/%s" $host)) }} include {{ printf "/etc/nginx/vhost.d/%s" $host }}; {{ else if (exists "/etc/nginx/vhost.d/default") }} @@ -431,13 +428,17 @@ server { {{ end }} {{ if eq $nPaths 0 }} - {{ template "location" (dict "Path" "/" "Proto" $proto "Upstream" $upstream_name "Host" $host "Vhostroot" $vhost_root "Dest" "") }} + {{/* Get the NETWORK_ACCESS defined by containers w/ the same vhost, falling back to "external" */}} + {{ $network_tag := or (first (groupByKeys $containers "Env.NETWORK_ACCESS")) "external" }} + {{ template "location" (dict "Path" "/" "Proto" $proto "Upstream" $upstream_name "Host" $host "Vhostroot" $vhost_root "Dest" "" "NetworkTag" $network_tag) }} {{ else }} {{ range $path, $container := $paths }} + {{/* Get the NETWORK_ACCESS defined by containers w/ the same vhost, falling back to "external" */}} + {{ $network_tag := or (first (groupByKeys $container "Env.NETWORK_ACCESS")) "external" }} {{ $sum := sha1 $path }} {{ $upstream := printf "%s-%s" $upstream_name $sum }} {{ $dest := (or (first (groupByKeys $container "Env.VIRTUAL_DEST")) "") }} - {{ template "location" (dict "Path" $path "Proto" $proto "Upstream" $upstream "Host" $host "Vhostroot" $vhost_root "Dest" $dest) }} + {{ template "location" (dict "Path" $path "Proto" $proto "Upstream" $upstream "Host" $host "Vhostroot" $vhost_root "Dest" $dest "NetworkTag" $network_tag) }} {{ end }} {{ if (not (contains $paths "/")) }} location / { From 2509fc1076d50832e124955a829c7a94634be98e Mon Sep 17 00:00:00 2001 From: Alexander Lieret Date: Mon, 30 Aug 2021 12:19:10 +0200 Subject: [PATCH 051/300] test: Add test cases for NETWORK_ACCESS=internal --- test/test_internal/network_internal.conf | 11 ++++++++++ test/test_internal/test_per-vhost.py | 14 ++++++++++++ test/test_internal/test_per-vhost.yml | 24 ++++++++++++++++++++ test/test_internal/test_per-vpath.py | 14 ++++++++++++ test/test_internal/test_per-vpath.yml | 28 ++++++++++++++++++++++++ 5 files changed, 91 insertions(+) create mode 100644 test/test_internal/network_internal.conf create mode 100644 test/test_internal/test_per-vhost.py create mode 100644 test/test_internal/test_per-vhost.yml create mode 100644 test/test_internal/test_per-vpath.py create mode 100644 test/test_internal/test_per-vpath.yml diff --git a/test/test_internal/network_internal.conf b/test/test_internal/network_internal.conf new file mode 100644 index 0000000..496e569 --- /dev/null +++ b/test/test_internal/network_internal.conf @@ -0,0 +1,11 @@ +# Only allow traffic from internal clients +allow 127.0.0.0/8; +allow 10.0.0.0/8; +allow 192.168.0.0/16; +allow 172.16.0.0/12; +allow fc00::/7; # IPv6 local address range +deny all; + +# Dummy header for testing +add_header X-network internal; + diff --git a/test/test_internal/test_per-vhost.py b/test/test_internal/test_per-vhost.py new file mode 100644 index 0000000..4586cc0 --- /dev/null +++ b/test/test_internal/test_per-vhost.py @@ -0,0 +1,14 @@ +import pytest + +def test_network_web1(docker_compose, nginxproxy): + r = nginxproxy.get("http://web1.nginx-proxy.local/port") + assert r.status_code == 200 + assert r.text == "answer from port 81\n" + assert "X-network" in r.headers + assert "internal" == r.headers["X-network"] + +def test_network_web2(docker_compose, nginxproxy): + r = nginxproxy.get("http://web2.nginx-proxy.local/port") + assert r.status_code == 200 + assert r.text == "answer from port 82\n" + assert "X-network" not in r.headers diff --git a/test/test_internal/test_per-vhost.yml b/test/test_internal/test_per-vhost.yml new file mode 100644 index 0000000..a935e53 --- /dev/null +++ b/test/test_internal/test_per-vhost.yml @@ -0,0 +1,24 @@ +web1: + image: web + expose: + - "81" + environment: + WEB_PORTS: 81 + VIRTUAL_HOST: web1.nginx-proxy.local + NETWORK_ACCESS: internal + +web2: + image: web + expose: + - "82" + environment: + WEB_PORTS: 82 + VIRTUAL_HOST: web2.nginx-proxy.local + +sut: + image: nginxproxy/nginx-proxy:test + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro + - ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro + - ./network_internal.conf:/etc/nginx/network_internal.conf:ro + diff --git a/test/test_internal/test_per-vpath.py b/test/test_internal/test_per-vpath.py new file mode 100644 index 0000000..e95fe00 --- /dev/null +++ b/test/test_internal/test_per-vpath.py @@ -0,0 +1,14 @@ +import pytest + +def test_network_web1(docker_compose, nginxproxy): + r = nginxproxy.get("http://nginx-proxy.local/web1/port") + assert r.status_code == 200 + assert r.text == "answer from port 81\n" + assert "X-network" in r.headers + assert "internal" == r.headers["X-network"] + +def test_network_web2(docker_compose, nginxproxy): + r = nginxproxy.get("http://nginx-proxy.local/web2/port") + assert r.status_code == 200 + assert r.text == "answer from port 82\n" + assert "X-network" not in r.headers diff --git a/test/test_internal/test_per-vpath.yml b/test/test_internal/test_per-vpath.yml new file mode 100644 index 0000000..1ea470f --- /dev/null +++ b/test/test_internal/test_per-vpath.yml @@ -0,0 +1,28 @@ +web1: + image: web + expose: + - "81" + environment: + WEB_PORTS: 81 + VIRTUAL_HOST: nginx-proxy.local + VIRTUAL_PATH: /web1/ + VIRTUAL_DEST: / + NETWORK_ACCESS: internal + +web2: + image: web + expose: + - "82" + environment: + WEB_PORTS: 82 + VIRTUAL_HOST: nginx-proxy.local + VIRTUAL_PATH: /web2/ + VIRTUAL_DEST: / + +sut: + image: nginxproxy/nginx-proxy:test + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro + - ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro + - ./network_internal.conf:/etc/nginx/network_internal.conf:ro + From 7ede0fa4b97840c02aeac5498c43d616c74b6221 Mon Sep 17 00:00:00 2001 From: Alexander Lieret Date: Mon, 30 Aug 2021 14:37:28 +0200 Subject: [PATCH 052/300] test: fix: Rename new test files --- .../{test_per-vhost.py => test_internal-per-vhost.py} | 0 .../{test_per-vhost.yml => test_internal-per-vhost.yml} | 0 .../{test_per-vpath.py => test_internal-per-vpath.py} | 0 .../{test_per-vpath.yml => test_internal-per-vpath.yml} | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename test/test_internal/{test_per-vhost.py => test_internal-per-vhost.py} (100%) rename test/test_internal/{test_per-vhost.yml => test_internal-per-vhost.yml} (100%) rename test/test_internal/{test_per-vpath.py => test_internal-per-vpath.py} (100%) rename test/test_internal/{test_per-vpath.yml => test_internal-per-vpath.yml} (100%) diff --git a/test/test_internal/test_per-vhost.py b/test/test_internal/test_internal-per-vhost.py similarity index 100% rename from test/test_internal/test_per-vhost.py rename to test/test_internal/test_internal-per-vhost.py diff --git a/test/test_internal/test_per-vhost.yml b/test/test_internal/test_internal-per-vhost.yml similarity index 100% rename from test/test_internal/test_per-vhost.yml rename to test/test_internal/test_internal-per-vhost.yml diff --git a/test/test_internal/test_per-vpath.py b/test/test_internal/test_internal-per-vpath.py similarity index 100% rename from test/test_internal/test_per-vpath.py rename to test/test_internal/test_internal-per-vpath.py diff --git a/test/test_internal/test_per-vpath.yml b/test/test_internal/test_internal-per-vpath.yml similarity index 100% rename from test/test_internal/test_per-vpath.yml rename to test/test_internal/test_internal-per-vpath.yml From 08c9586346703dfa7035404ca7ab724afd3a0e54 Mon Sep 17 00:00:00 2001 From: Alexander Lieret Date: Tue, 21 Sep 2021 14:07:41 +0200 Subject: [PATCH 053/300] fix: Handle VIRTUAL_PROTO on virtual path basis --- nginx.tmpl | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/nginx.tmpl b/nginx.tmpl index 13ca7a4..0eeeac9 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -276,9 +276,6 @@ server { {{ $default_host := or ($.Env.DEFAULT_HOST) "" }} {{ $default_server := index (dict $host "" $default_host "default_server") $host }} -{{/* Get the VIRTUAL_PROTO defined by containers w/ the same vhost, falling back to "http" */}} -{{ $proto := trim (or (first (groupByKeys $containers "Env.VIRTUAL_PROTO")) "http") }} - {{/* Get the SERVER_TOKENS defined by containers w/ the same vhost, falling back to "" */}} {{ $server_tokens := trim (or (first (groupByKeys $containers "Env.SERVER_TOKENS")) "") }} @@ -386,11 +383,17 @@ server { {{ end }} {{ if eq $nPaths 0 }} + {{/* Get the VIRTUAL_PROTO defined by containers w/ the same vhost, falling back to "http" */}} + {{ $proto := trim (or (first (groupByKeys $containers "Env.VIRTUAL_PROTO")) "http") }} + {{/* Get the NETWORK_ACCESS defined by containers w/ the same vhost, falling back to "external" */}} {{ $network_tag := or (first (groupByKeys $containers "Env.NETWORK_ACCESS")) "external" }} {{ template "location" (dict "Path" "/" "Proto" $proto "Upstream" $upstream_name "Host" $host "Vhostroot" $vhost_root "Dest" "" "NetworkTag" $network_tag) }} {{ else }} {{ range $path, $container := $paths }} + {{/* Get the VIRTUAL_PROTO defined by containers w/ the same vhost-vpath, falling back to "http" */}} + {{ $proto := trim (or (first (groupByKeys $container "Env.VIRTUAL_PROTO")) "http") }} + {{/* Get the NETWORK_ACCESS defined by containers w/ the same vhost, falling back to "external" */}} {{ $network_tag := or (first (groupByKeys $container "Env.NETWORK_ACCESS")) "external" }} {{ $sum := sha1 $path }} @@ -428,11 +431,17 @@ server { {{ end }} {{ if eq $nPaths 0 }} + {{/* Get the VIRTUAL_PROTO defined by containers w/ the same vhost, falling back to "http" */}} + {{ $proto := trim (or (first (groupByKeys $containers "Env.VIRTUAL_PROTO")) "http") }} + {{/* Get the NETWORK_ACCESS defined by containers w/ the same vhost, falling back to "external" */}} {{ $network_tag := or (first (groupByKeys $containers "Env.NETWORK_ACCESS")) "external" }} {{ template "location" (dict "Path" "/" "Proto" $proto "Upstream" $upstream_name "Host" $host "Vhostroot" $vhost_root "Dest" "" "NetworkTag" $network_tag) }} {{ else }} {{ range $path, $container := $paths }} + {{/* Get the VIRTUAL_PROTO defined by containers w/ the same vhost-vpath, falling back to "http" */}} + {{ $proto := trim (or (first (groupByKeys $container "Env.VIRTUAL_PROTO")) "http") }} + {{/* Get the NETWORK_ACCESS defined by containers w/ the same vhost, falling back to "external" */}} {{ $network_tag := or (first (groupByKeys $container "Env.NETWORK_ACCESS")) "external" }} {{ $sum := sha1 $path }} From 01446472dddb3c7ebbe7f69c7269b3461daa9aec Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Thu, 24 Feb 2022 15:08:45 +0100 Subject: [PATCH 054/300] Revert "ci: use docker-gen main on dev branch tests" This reverts commit b6e9cdc065a19ce7e7cb0dcf2c11cd7c9fe1d063. --- .github/workflows/test.yml | 20 ++++---------------- Makefile | 6 ------ 2 files changed, 4 insertions(+), 22 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8c4a173..6be93bd 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -3,16 +3,13 @@ name: Tests on: workflow_dispatch: push: - branches: - - main - - dev paths-ignore: - - 'LICENSE' - - '**.md' + - 'LICENSE' + - '**.md' pull_request: paths-ignore: - - 'LICENSE' - - '**.md' + - 'LICENSE' + - '**.md' jobs: unit: @@ -42,15 +39,6 @@ jobs: - name: Build Docker nginx proxy test image run: make build-nginx-proxy-test-${{ matrix.base_docker_image }} - if: | - ( github.event_name == 'push' && github.ref != 'refs/heads/dev' ) || - ( github.event_name == 'pull_request' && github.base_ref != 'dev' ) - - - name: Build Docker nginx proxy dev test image - run: make build-nginx-proxy-test-${{ matrix.base_docker_image }}-dev - if: | - ( github.event_name == 'push' && github.ref == 'refs/heads/dev' ) || - ( github.event_name == 'pull_request' && github.base_ref == 'dev' ) - name: Run tests run: pytest diff --git a/Makefile b/Makefile index 60406b6..ab44880 100644 --- a/Makefile +++ b/Makefile @@ -11,12 +11,6 @@ build-nginx-proxy-test-debian: build-nginx-proxy-test-alpine: docker build --build-arg NGINX_PROXY_VERSION="test" -f Dockerfile.alpine -t nginxproxy/nginx-proxy:test . -build-nginx-proxy-test-debian-dev: - docker build --build-arg DOCKER_GEN_VERSION=main -t nginxproxy/nginx-proxy:test . - -build-nginx-proxy-test-alpine-dev: - docker build -f Dockerfile.alpine --build-arg DOCKER_GEN_VERSION=main -t nginxproxy/nginx-proxy:test . - test-debian: build-webserver build-nginx-proxy-test-debian test/pytest.sh From b6b7133a2eba412749a6e90856b98292ce09c3af Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Thu, 24 Feb 2022 15:17:47 +0100 Subject: [PATCH 055/300] fix: minor fixes on nginx template --- nginx.tmpl | 70 +++++++++++++++++++++++++++--------------------------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/nginx.tmpl b/nginx.tmpl index 0eeeac9..351cf88 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -61,8 +61,8 @@ location {{ .Path }} { include uwsgi_params; uwsgi_pass {{ trim .Proto }}://{{ trim .Upstream }}; {{ else if eq .Proto "fastcgi" }} - root {{ trim .Vhostroot }}; - include fastcgi.conf; + root {{ trim .VhostRoot }}; + include fastcgi_params; fastcgi_pass {{ trim .Upstream }}; {{ else if eq .Proto "grpc" }} grpc_pass {{ trim .Proto }}://{{ trim .Upstream }}; @@ -85,12 +85,12 @@ location {{ .Path }} { } {{ end }} -{{ define "upstream-definition" }} +{{ define "upstream" }} {{ $networks := .Networks }} {{ $debug_all := .Debug }} upstream {{ .Upstream }} { - {{ $server_found := "false" }} - {{ range $container := .Containers }} + {{ $server_found := "false" }} + {{ range $container := .Containers }} {{ $debug := (eq (coalesce $container.Env.DEBUG $debug_all "false") "true") }} {{/* If only 1 port exposed, use that as a default, else 80 */}} {{ $defaultPort := (when (eq (len $container.Addresses) 1) (first $container.Addresses) (dict "Port" "80")).Port }} @@ -100,46 +100,46 @@ location {{ .Path }} { # Exposed ports: {{ $container.Addresses }} # Default virtual port: {{ $defaultPort }} # VIRTUAL_PORT: {{ $container.Env.VIRTUAL_PORT }} - {{ if not $address }} + {{ if not $address }} # /!\ Virtual port not exposed - {{ end }} + {{ end }} {{ end }} - {{ range $knownNetwork := $networks }} - {{ range $containerNetwork := $container.Networks }} - {{ if (and (ne $containerNetwork.Name "ingress") (or (eq $knownNetwork.Name $containerNetwork.Name) (eq $knownNetwork.Name "host"))) }} + {{ range $knownNetwork := $networks }} + {{ range $containerNetwork := $container.Networks }} + {{ if (and (ne $containerNetwork.Name "ingress") (or (eq $knownNetwork.Name $containerNetwork.Name) (eq $knownNetwork.Name "host"))) }} ## Can be connected with "{{ $containerNetwork.Name }}" network - {{ if $address }} - {{/* If we got the containers from swarm and this container's port is published to host, use host IP:PORT */}} - {{ if and $container.Node.ID $address.HostPort }} - {{ $server_found = "true" }} + {{ if $address }} + {{/* If we got the containers from swarm and this container's port is published to host, use host IP:PORT */}} + {{ if and $container.Node.ID $address.HostPort }} + {{ $server_found = "true" }} # {{ $container.Node.Name }}/{{ $container.Name }} server {{ $container.Node.Address.IP }}:{{ $address.HostPort }}; - {{/* If there is no swarm node or the port is not published on host, use container's IP:PORT */}} - {{ else if $containerNetwork }} - {{ $server_found = "true" }} + {{/* If there is no swarm node or the port is not published on host, use container's IP:PORT */}} + {{ else if $containerNetwork }} + {{ $server_found = "true" }} # {{ $container.Name }} server {{ $containerNetwork.IP }}:{{ $address.Port }}; - {{ end }} - {{ else if $containerNetwork }} + {{ end }} + {{ else if $containerNetwork }} # {{ $container.Name }} - {{ if $containerNetwork.IP }} - {{ $server_found = "true" }} + {{ if $containerNetwork.IP }} + {{ $server_found = "true" }} server {{ $containerNetwork.IP }}:{{ $port }}; - {{ else }} + {{ else }} # /!\ No IP for this network! - {{ end }} - {{ end }} - {{ else }} - # Cannot connect to network '{{ $containerNetwork.Name }}' of this container + {{ end }} {{ end }} + {{ else }} + # Cannot connect to network '{{ $containerNetwork.Name }}' of this container {{ end }} {{ end }} {{ end }} - {{/* nginx-proxy/nginx-proxy#1105 */}} - {{ if (eq $server_found "false") }} + {{ end }} + {{/* nginx-proxy/nginx-proxy#1105 */}} + {{ if (eq $server_found "false") }} # Fallback entry server 127.0.0.1 down; - {{ end }} + {{ end }} } {{ end }} @@ -263,13 +263,13 @@ server { {{ if eq $nPaths 0 }} # {{ $host }} - {{ template "upstream-definition" (dict "Upstream" $upstream_name "Containers" $containers "Networks" $CurrentContainer.Networks "Debug" $debug_all) }} + {{ template "upstream" (dict "Upstream" $upstream_name "Containers" $containers "Networks" $CurrentContainer.Networks "Debug" $debug_all) }} {{ else }} {{ range $path, $containers := $paths }} {{ $sum := sha1 $path }} {{ $upstream := printf "%s-%s" $upstream_name $sum }} # {{ $host }}{{ $path }} - {{ template "upstream-definition" (dict "Upstream" $upstream "Containers" $containers "Networks" $CurrentContainer.Networks "Debug" $debug_all) }} + {{ template "upstream" (dict "Upstream" $upstream "Containers" $containers "Networks" $CurrentContainer.Networks "Debug" $debug_all) }} {{ end }} {{ end }} @@ -388,7 +388,7 @@ server { {{/* Get the NETWORK_ACCESS defined by containers w/ the same vhost, falling back to "external" */}} {{ $network_tag := or (first (groupByKeys $containers "Env.NETWORK_ACCESS")) "external" }} - {{ template "location" (dict "Path" "/" "Proto" $proto "Upstream" $upstream_name "Host" $host "Vhostroot" $vhost_root "Dest" "" "NetworkTag" $network_tag) }} + {{ template "location" (dict "Path" "/" "Proto" $proto "Upstream" $upstream_name "Host" $host "VhostRoot" $vhost_root "Dest" "" "NetworkTag" $network_tag) }} {{ else }} {{ range $path, $container := $paths }} {{/* Get the VIRTUAL_PROTO defined by containers w/ the same vhost-vpath, falling back to "http" */}} @@ -399,7 +399,7 @@ server { {{ $sum := sha1 $path }} {{ $upstream := printf "%s-%s" $upstream_name $sum }} {{ $dest := (or (first (groupByKeys $container "Env.VIRTUAL_DEST")) "") }} - {{ template "location" (dict "Path" $path "Proto" $proto "Upstream" $upstream "Host" $host "Vhostroot" $vhost_root "Dest" $dest "NetworkTag" $network_tag) }} + {{ template "location" (dict "Path" $path "Proto" $proto "Upstream" $upstream "Host" $host "VhostRoot" $vhost_root "Dest" $dest "NetworkTag" $network_tag) }} {{ end }} {{ if (not (contains $paths "/")) }} location / { @@ -436,7 +436,7 @@ server { {{/* Get the NETWORK_ACCESS defined by containers w/ the same vhost, falling back to "external" */}} {{ $network_tag := or (first (groupByKeys $containers "Env.NETWORK_ACCESS")) "external" }} - {{ template "location" (dict "Path" "/" "Proto" $proto "Upstream" $upstream_name "Host" $host "Vhostroot" $vhost_root "Dest" "" "NetworkTag" $network_tag) }} + {{ template "location" (dict "Path" "/" "Proto" $proto "Upstream" $upstream_name "Host" $host "VhostRoot" $vhost_root "Dest" "" "NetworkTag" $network_tag) }} {{ else }} {{ range $path, $container := $paths }} {{/* Get the VIRTUAL_PROTO defined by containers w/ the same vhost-vpath, falling back to "http" */}} @@ -447,7 +447,7 @@ server { {{ $sum := sha1 $path }} {{ $upstream := printf "%s-%s" $upstream_name $sum }} {{ $dest := (or (first (groupByKeys $container "Env.VIRTUAL_DEST")) "") }} - {{ template "location" (dict "Path" $path "Proto" $proto "Upstream" $upstream "Host" $host "Vhostroot" $vhost_root "Dest" $dest "NetworkTag" $network_tag) }} + {{ template "location" (dict "Path" $path "Proto" $proto "Upstream" $upstream "Host" $host "VhostRoot" $vhost_root "Dest" $dest "NetworkTag" $network_tag) }} {{ end }} {{ if (not (contains $paths "/")) }} location / { From 0185a2971c6538afa72021acefd9bfdc1552034d Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Thu, 24 Feb 2022 15:21:14 +0100 Subject: [PATCH 056/300] tests: fix virtual path tests for new dhparam --- test/test_internal/test_internal-per-vhost.yml | 1 - test/test_internal/test_internal-per-vpath.yml | 1 - test/test_ssl/test_virtual_path.yml | 1 - test/test_virtual-path/test_custom_conf.yml | 1 - test/test_virtual-path/test_forwarding.yml | 1 - test/test_virtual-path/test_location_precedence.yml | 1 - test/test_virtual-path/test_virtual_paths.yml | 2 -- 7 files changed, 8 deletions(-) diff --git a/test/test_internal/test_internal-per-vhost.yml b/test/test_internal/test_internal-per-vhost.yml index a935e53..5c732ee 100644 --- a/test/test_internal/test_internal-per-vhost.yml +++ b/test/test_internal/test_internal-per-vhost.yml @@ -19,6 +19,5 @@ sut: image: nginxproxy/nginx-proxy:test volumes: - /var/run/docker.sock:/tmp/docker.sock:ro - - ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro - ./network_internal.conf:/etc/nginx/network_internal.conf:ro diff --git a/test/test_internal/test_internal-per-vpath.yml b/test/test_internal/test_internal-per-vpath.yml index 1ea470f..f5bac55 100644 --- a/test/test_internal/test_internal-per-vpath.yml +++ b/test/test_internal/test_internal-per-vpath.yml @@ -23,6 +23,5 @@ sut: image: nginxproxy/nginx-proxy:test volumes: - /var/run/docker.sock:/tmp/docker.sock:ro - - ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro - ./network_internal.conf:/etc/nginx/network_internal.conf:ro diff --git a/test/test_ssl/test_virtual_path.yml b/test/test_ssl/test_virtual_path.yml index 07175ac..2260321 100644 --- a/test/test_ssl/test_virtual_path.yml +++ b/test/test_ssl/test_virtual_path.yml @@ -22,6 +22,5 @@ sut: image: nginxproxy/nginx-proxy:test volumes: - /var/run/docker.sock:/tmp/docker.sock:ro - - ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro - ./certs:/etc/nginx/certs:ro diff --git a/test/test_virtual-path/test_custom_conf.yml b/test/test_virtual-path/test_custom_conf.yml index abd9d0c..40ab512 100644 --- a/test/test_virtual-path/test_custom_conf.yml +++ b/test/test_virtual-path/test_custom_conf.yml @@ -42,7 +42,6 @@ sut: DEFAULT_ROOT: 418 volumes: - /var/run/docker.sock:/tmp/docker.sock:ro - - ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro - ./foo.conf:/etc/nginx/vhost.d/foo.nginx-proxy.test:ro - ./bar.conf:/etc/nginx/vhost.d/nginx-proxy.test_918d687a929083edd0c7224ee2293e0e7c062ab4_location:ro - ./alternate.conf:/etc/nginx/vhost.d/nginx-proxy.test_7fb22b74bbdf907425dbbad18e4462565cada230_location:ro diff --git a/test/test_virtual-path/test_forwarding.yml b/test/test_virtual-path/test_forwarding.yml index 78662d8..ee87e8d 100644 --- a/test/test_virtual-path/test_forwarding.yml +++ b/test/test_virtual-path/test_forwarding.yml @@ -12,7 +12,6 @@ sut: image: nginxproxy/nginx-proxy:test volumes: - /var/run/docker.sock:/tmp/docker.sock:ro - - ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro - ./certs:/etc/nginx/certs:ro environment: - DEFAULT_ROOT=301 http://$$host/web1$$request_uri diff --git a/test/test_virtual-path/test_location_precedence.yml b/test/test_virtual-path/test_location_precedence.yml index be93b58..be3248c 100644 --- a/test/test_virtual-path/test_location_precedence.yml +++ b/test/test_virtual-path/test_location_precedence.yml @@ -32,7 +32,6 @@ sut: image: nginxproxy/nginx-proxy:test volumes: - /var/run/docker.sock:/tmp/docker.sock:ro - - ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro - ./default.conf:/etc/nginx/vhost.d/default_location:ro - ./host.conf:/etc/nginx/vhost.d/bar.nginx-proxy.test_location:ro - ./path.conf:/etc/nginx/vhost.d/bar.nginx-proxy.test_99f2db0ed8aa95dbb5b87fca79c7eff2ff6bb8bd_location:ro diff --git a/test/test_virtual-path/test_virtual_paths.yml b/test/test_virtual-path/test_virtual_paths.yml index b335c3f..9f6a54f 100644 --- a/test/test_virtual-path/test_virtual_paths.yml +++ b/test/test_virtual-path/test_virtual_paths.yml @@ -40,5 +40,3 @@ sut: image: nginxproxy/nginx-proxy:test volumes: - /var/run/docker.sock:/tmp/docker.sock:ro - - ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro - From 621e703fad4c6ab58fc1248211fe2a674b688e5f Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Thu, 24 Feb 2022 16:21:10 +0100 Subject: [PATCH 057/300] build: docker-gen main -> 0.8.2 --- Dockerfile | 2 +- Dockerfile.alpine | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index bc4093d..9857927 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # setup build arguments for version of dependencies to use -ARG DOCKER_GEN_VERSION=main +ARG DOCKER_GEN_VERSION=0.8.2 ARG FOREGO_VERSION=v0.17.0 # Use a specific version of golang to build both binaries diff --git a/Dockerfile.alpine b/Dockerfile.alpine index 98e9bc5..f8e5b56 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -1,5 +1,5 @@ # setup build arguments for version of dependencies to use -ARG DOCKER_GEN_VERSION=main +ARG DOCKER_GEN_VERSION=0.8.2 ARG FOREGO_VERSION=v0.17.0 # Use a specific version of golang to build both binaries From 061d129b1b38af335aad70ef7cd613254927adb9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 24 Feb 2022 15:39:59 +0000 Subject: [PATCH 058/300] chore(deps): bump golang from 1.16.7 to 1.17.7 Bumps golang from 1.16.7 to 1.17.7. --- updated-dependencies: - dependency-name: golang dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- Dockerfile | 2 +- Dockerfile.alpine | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 9857927..7aa1a77 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,7 +3,7 @@ ARG DOCKER_GEN_VERSION=0.8.2 ARG FOREGO_VERSION=v0.17.0 # Use a specific version of golang to build both binaries -FROM golang:1.16.7 as gobuilder +FROM golang:1.17.7 as gobuilder # Build docker-gen from scratch FROM gobuilder as dockergen diff --git a/Dockerfile.alpine b/Dockerfile.alpine index f8e5b56..ec330a8 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -3,7 +3,7 @@ ARG DOCKER_GEN_VERSION=0.8.2 ARG FOREGO_VERSION=v0.17.0 # Use a specific version of golang to build both binaries -FROM golang:1.16.7-alpine as gobuilder +FROM golang:1.17.7-alpine as gobuilder RUN apk add --no-cache git musl-dev # Build docker-gen from scratch From fee27ea712eec20e0642043fad6fddf8edad1159 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Thu, 24 Feb 2022 16:43:45 +0100 Subject: [PATCH 059/300] docs: nginx badge 1.21.5 -> 1.21.6 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 880d0e8..dc8414b 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ [![Test](https://github.com/nginx-proxy/nginx-proxy/actions/workflows/test.yml/badge.svg)](https://github.com/nginx-proxy/nginx-proxy/actions/workflows/test.yml) [![GitHub release](https://img.shields.io/github/v/release/nginx-proxy/nginx-proxy)](https://github.com/nginx-proxy/nginx-proxy/releases) -![nginx 1.21.5](https://img.shields.io/badge/nginx-1.21.5-brightgreen.svg) +![nginx 1.21.6](https://img.shields.io/badge/nginx-1.21.6-brightgreen.svg) [![Docker Image Size](https://img.shields.io/docker/image-size/nginxproxy/nginx-proxy?sort=semver)](https://hub.docker.com/r/nginxproxy/nginx-proxy "Click to view the image on Docker Hub") [![Docker stars](https://img.shields.io/docker/stars/nginxproxy/nginx-proxy.svg)](https://hub.docker.com/r/nginxproxy/nginx-proxy 'DockerHub') [![Docker pulls](https://img.shields.io/docker/pulls/nginxproxy/nginx-proxy.svg)](https://hub.docker.com/r/nginxproxy/nginx-proxy 'DockerHub') From 5ab320d82aa4338e702b6f7dfa635cbe990b6503 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Fri, 4 Mar 2022 10:59:50 +0100 Subject: [PATCH 060/300] ci: publish Docker images to ghcr.io --- .github/workflows/dockerhub.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/dockerhub.yml b/.github/workflows/dockerhub.yml index 74283b7..1630f8a 100644 --- a/.github/workflows/dockerhub.yml +++ b/.github/workflows/dockerhub.yml @@ -38,6 +38,7 @@ jobs: uses: docker/metadata-action@v3 with: images: | + ghcr.io/nginx-proxy/nginx-proxy nginxproxy/nginx-proxy jwilder/nginx-proxy tags: | @@ -60,6 +61,13 @@ jobs: with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Log in to GitHub Container Registry + uses: docker/login-action@v1 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} - name: Build and push the Debian based image if: github.ref == 'refs/heads/main' From 993e5f82824d016366615ec7fc6235ddd620da09 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Fri, 4 Mar 2022 11:10:14 +0100 Subject: [PATCH 061/300] ci: publish the alpine image to ghcr.io too --- .github/workflows/dockerhub.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/dockerhub.yml b/.github/workflows/dockerhub.yml index 1630f8a..dfb4286 100644 --- a/.github/workflows/dockerhub.yml +++ b/.github/workflows/dockerhub.yml @@ -119,6 +119,7 @@ jobs: uses: docker/metadata-action@v3 with: images: | + ghcr.io/nginx-proxy/nginx-proxy nginxproxy/nginx-proxy jwilder/nginx-proxy tags: | @@ -142,6 +143,13 @@ jobs: with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Log in to GitHub Container Registry + uses: docker/login-action@v1 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} - name: Build and push the Alpine based image if: github.ref == 'refs/heads/main' From 0ea8a087612807971ebd21ae05a06868120ca5fb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 7 Mar 2022 04:11:51 +0000 Subject: [PATCH 062/300] chore(deps): bump golang from 1.17.7 to 1.17.8 Bumps golang from 1.17.7 to 1.17.8. --- updated-dependencies: - dependency-name: golang dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Dockerfile | 2 +- Dockerfile.alpine | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 7aa1a77..16de38c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,7 +3,7 @@ ARG DOCKER_GEN_VERSION=0.8.2 ARG FOREGO_VERSION=v0.17.0 # Use a specific version of golang to build both binaries -FROM golang:1.17.7 as gobuilder +FROM golang:1.17.8 as gobuilder # Build docker-gen from scratch FROM gobuilder as dockergen diff --git a/Dockerfile.alpine b/Dockerfile.alpine index ec330a8..0208de6 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -3,7 +3,7 @@ ARG DOCKER_GEN_VERSION=0.8.2 ARG FOREGO_VERSION=v0.17.0 # Use a specific version of golang to build both binaries -FROM golang:1.17.7-alpine as gobuilder +FROM golang:1.17.8-alpine as gobuilder RUN apk add --no-cache git musl-dev # Build docker-gen from scratch From 5ee6db5e3e798588edd9433495f16617d688d148 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Mon, 7 Mar 2022 14:12:26 +0100 Subject: [PATCH 063/300] ci: remove dev branch build, fix build on tags --- .github/workflows/dockerhub.yml | 40 --------------------------------- 1 file changed, 40 deletions(-) diff --git a/.github/workflows/dockerhub.yml b/.github/workflows/dockerhub.yml index dfb4286..706d298 100644 --- a/.github/workflows/dockerhub.yml +++ b/.github/workflows/dockerhub.yml @@ -7,13 +7,11 @@ on: push: branches: - main - - dev tags: - '*.*.*' paths-ignore: - 'test/*' - '.gitignore' - - '.travis.yml' - 'docker-compose-separate-containers.yml' - 'docker-compose.yml' - 'LICENSE' @@ -45,7 +43,6 @@ jobs: type=semver,pattern={{version}} type=semver,pattern={{major}}.{{minor}} type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' }} - type=raw,value=dev,enable=${{ github.ref == 'refs/heads/dev' }} labels: | org.opencontainers.image.authors=Nicolas Duchon (@buchdag), Jason Wilder org.opencontainers.image.version=${{ env.GIT_DESCRIBE }} @@ -70,7 +67,6 @@ jobs: password: ${{ secrets.GITHUB_TOKEN }} - name: Build and push the Debian based image - if: github.ref == 'refs/heads/main' id: docker_build_debian uses: docker/build-push-action@v2 with: @@ -83,25 +79,8 @@ jobs: labels: ${{ steps.docker_meta_debian.outputs.labels }} - name: Images digests - if: github.ref == 'refs/heads/main' run: echo ${{ steps.docker_build_debian.outputs.digest }} - - name: Build and push the Debian based dev image - if: github.ref == 'refs/heads/dev' - id: docker_build_debian_dev - uses: docker/build-push-action@v2 - with: - file: Dockerfile - build-args: DOCKER_GEN_VERSION=main - platforms: linux/amd64,linux/arm64,linux/arm/v7 - push: true - tags: ${{ steps.docker_meta_debian.outputs.tags }} - labels: ${{ steps.docker_meta_debian.outputs.labels }} - - - name: Images digests - if: github.ref == 'refs/heads/dev' - run: echo ${{ steps.docker_build_debian_dev.outputs.digest }} - multiarch-build-alpine: runs-on: ubuntu-latest steps: @@ -126,7 +105,6 @@ jobs: type=semver,suffix=-alpine,pattern={{version}} type=semver,suffix=-alpine,pattern={{major}}.{{minor}} type=raw,value=alpine,enable=${{ github.ref == 'refs/heads/main' }} - type=raw,value=dev-alpine,enable=${{ github.ref == 'refs/heads/dev' }} labels: | org.opencontainers.image.authors=Nicolas Duchon (@buchdag), Jason Wilder org.opencontainers.image.version=${{ env.GIT_DESCRIBE }} @@ -152,7 +130,6 @@ jobs: password: ${{ secrets.GITHUB_TOKEN }} - name: Build and push the Alpine based image - if: github.ref == 'refs/heads/main' id: docker_build_alpine uses: docker/build-push-action@v2 with: @@ -165,21 +142,4 @@ jobs: labels: ${{ steps.docker_meta_alpine.outputs.labels }} - name: Images digests - if: github.ref == 'refs/heads/main' run: echo ${{ steps.docker_build_alpine.outputs.digest }} - - - name: Build and push the Alpine based dev image - if: github.ref == 'refs/heads/dev' - id: docker_build_alpine_dev - uses: docker/build-push-action@v2 - with: - file: Dockerfile.alpine - build-args: DOCKER_GEN_VERSION=main - platforms: linux/amd64,linux/arm64,linux/arm/v7 - push: true - tags: ${{ steps.docker_meta_alpine.outputs.tags }} - labels: ${{ steps.docker_meta_alpine.outputs.labels }} - - - name: Images digests - if: github.ref == 'refs/heads/dev' - run: echo ${{ steps.docker_build_alpine_dev.outputs.digest }} From 3257177d80cfcc27d3ae556471a9b87a7af5f92a Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Mon, 7 Mar 2022 14:14:16 +0100 Subject: [PATCH 064/300] fix: remove outdated comment from Dockerfiles --- Dockerfile | 2 +- Dockerfile.alpine | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 16de38c..851baa1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -55,7 +55,7 @@ RUN apt-get update \ && rm -r /var/lib/apt/lists/* -# Configure Nginx and apply fix for very long server names +# Configure Nginx RUN echo "daemon off;" >> /etc/nginx/nginx.conf \ && sed -i 's/worker_processes 1/worker_processes auto/' /etc/nginx/nginx.conf \ && sed -i 's/worker_connections 1024/worker_connections 10240/' /etc/nginx/nginx.conf \ diff --git a/Dockerfile.alpine b/Dockerfile.alpine index 0208de6..7779572 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -52,7 +52,7 @@ RUN apk add --no-cache --virtual .run-deps \ ca-certificates bash wget openssl \ && update-ca-certificates -# Configure Nginx and apply fix for very long server names +# Configure Nginx RUN echo "daemon off;" >> /etc/nginx/nginx.conf \ && sed -i 's/worker_processes 1/worker_processes auto/' /etc/nginx/nginx.conf \ && sed -i 's/worker_connections 1024/worker_connections 10240/' /etc/nginx/nginx.conf \ From 5aba125fb7b359c44b419a746c052a3806d08d09 Mon Sep 17 00:00:00 2001 From: Gilles Filippini Date: Mon, 1 Jun 2020 07:15:00 +0000 Subject: [PATCH 065/300] chore: do not copy useless files into the image Move required files but 'nginx.tmpl' into a local 'app' folder and copy the folder content into the image. 'nginx.tmpl' should be moved as well, but this is a breaking change for configuration with a separate 'docker-gen' container. --- Dockerfile | 2 +- Dockerfile.alpine | 2 +- Procfile => app/Procfile | 0 {dhparam => app/dhparam}/ffdhe2048.pem | 0 {dhparam => app/dhparam}/ffdhe3072.pem | 0 {dhparam => app/dhparam}/ffdhe4096.pem | 0 docker-entrypoint.sh => app/docker-entrypoint.sh | 0 test/test_ssl/test_dhparam.yml | 2 +- 8 files changed, 3 insertions(+), 3 deletions(-) rename Procfile => app/Procfile (100%) rename {dhparam => app/dhparam}/ffdhe2048.pem (100%) rename {dhparam => app/dhparam}/ffdhe3072.pem (100%) rename {dhparam => app/dhparam}/ffdhe4096.pem (100%) rename docker-entrypoint.sh => app/docker-entrypoint.sh (100%) diff --git a/Dockerfile b/Dockerfile index 851baa1..35a2dbb 100644 --- a/Dockerfile +++ b/Dockerfile @@ -67,7 +67,7 @@ COPY --from=dockergen /usr/local/bin/docker-gen /usr/local/bin/docker-gen COPY network_internal.conf /etc/nginx/ -COPY . /app/ +COPY app nginx.tmpl /app/ WORKDIR /app/ ENTRYPOINT ["/app/docker-entrypoint.sh"] diff --git a/Dockerfile.alpine b/Dockerfile.alpine index 7779572..602c5f9 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -64,7 +64,7 @@ COPY --from=dockergen /usr/local/bin/docker-gen /usr/local/bin/docker-gen COPY network_internal.conf /etc/nginx/ -COPY . /app/ +COPY app nginx.tmpl /app/ WORKDIR /app/ ENTRYPOINT ["/app/docker-entrypoint.sh"] diff --git a/Procfile b/app/Procfile similarity index 100% rename from Procfile rename to app/Procfile diff --git a/dhparam/ffdhe2048.pem b/app/dhparam/ffdhe2048.pem similarity index 100% rename from dhparam/ffdhe2048.pem rename to app/dhparam/ffdhe2048.pem diff --git a/dhparam/ffdhe3072.pem b/app/dhparam/ffdhe3072.pem similarity index 100% rename from dhparam/ffdhe3072.pem rename to app/dhparam/ffdhe3072.pem diff --git a/dhparam/ffdhe4096.pem b/app/dhparam/ffdhe4096.pem similarity index 100% rename from dhparam/ffdhe4096.pem rename to app/dhparam/ffdhe4096.pem diff --git a/docker-entrypoint.sh b/app/docker-entrypoint.sh similarity index 100% rename from docker-entrypoint.sh rename to app/docker-entrypoint.sh diff --git a/test/test_ssl/test_dhparam.yml b/test/test_ssl/test_dhparam.yml index fa4fe1e..505ac4c 100644 --- a/test/test_ssl/test_dhparam.yml +++ b/test/test_ssl/test_dhparam.yml @@ -54,7 +54,7 @@ with_custom_file: volumes: - *docker-sock - *nginx-certs - - ../../dhparam/ffdhe3072.pem:/etc/nginx/dhparam/dhparam.pem:ro + - ../../app/dhparam/ffdhe3072.pem:/etc/nginx/dhparam/dhparam.pem:ro with_skip: container_name: dh-skip From fea6cc7537ae3e60d94903be2e0928c0c8941008 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Mon, 7 Mar 2022 15:35:49 +0100 Subject: [PATCH 066/300] chore: update .dockerignore --- .dockerignore | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.dockerignore b/.dockerignore index 8fafbb0..6849862 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,6 +1,10 @@ .git +.github +test .dockerignore -circle.yml +.gitignore +*.yml +Dockerfile* +LICENSE Makefile README.md -test From 4ea3437dfab423b6710b32b2aa9d50f9f750bed9 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Wed, 9 Mar 2022 12:05:56 +0100 Subject: [PATCH 067/300] chore: include license into the Docker images --- .dockerignore | 1 - Dockerfile | 2 +- Dockerfile.alpine | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/.dockerignore b/.dockerignore index 6849862..aad7a31 100644 --- a/.dockerignore +++ b/.dockerignore @@ -5,6 +5,5 @@ test .gitignore *.yml Dockerfile* -LICENSE Makefile README.md diff --git a/Dockerfile b/Dockerfile index 35a2dbb..8a46d97 100644 --- a/Dockerfile +++ b/Dockerfile @@ -67,7 +67,7 @@ COPY --from=dockergen /usr/local/bin/docker-gen /usr/local/bin/docker-gen COPY network_internal.conf /etc/nginx/ -COPY app nginx.tmpl /app/ +COPY app nginx.tmpl LICENSE /app/ WORKDIR /app/ ENTRYPOINT ["/app/docker-entrypoint.sh"] diff --git a/Dockerfile.alpine b/Dockerfile.alpine index 602c5f9..cc1247e 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -64,7 +64,7 @@ COPY --from=dockergen /usr/local/bin/docker-gen /usr/local/bin/docker-gen COPY network_internal.conf /etc/nginx/ -COPY app nginx.tmpl /app/ +COPY app nginx.tmpl LICENSE /app/ WORKDIR /app/ ENTRYPOINT ["/app/docker-entrypoint.sh"] From 1cc3bbf5cea53a78dd9a830d7948f3e9ebd5b3e1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 18 Mar 2022 04:16:58 +0000 Subject: [PATCH 068/300] chore(deps): bump pytest from 7.0.1 to 7.1.1 in /test/requirements Bumps [pytest](https://github.com/pytest-dev/pytest) from 7.0.1 to 7.1.1. - [Release notes](https://github.com/pytest-dev/pytest/releases) - [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst) - [Commits](https://github.com/pytest-dev/pytest/compare/7.0.1...7.1.1) --- updated-dependencies: - dependency-name: pytest dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- test/requirements/python-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/requirements/python-requirements.txt b/test/requirements/python-requirements.txt index 3747455..865bb27 100644 --- a/test/requirements/python-requirements.txt +++ b/test/requirements/python-requirements.txt @@ -1,5 +1,5 @@ backoff==1.11.1 docker-compose==1.29.2 docker==5.0.3 -pytest==7.0.1 +pytest==7.1.1 requests==2.27.1 From 55d913255d82f78f62a41c490d82b00454701b40 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Sun, 20 Mar 2022 18:54:07 -0400 Subject: [PATCH 069/300] Fix IPv6 HTTP listen port --- nginx.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nginx.tmpl b/nginx.tmpl index 351cf88..610edf1 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -420,7 +420,7 @@ server { {{ end }} listen {{ $external_http_port }} {{ $default_server }}; {{ if $enable_ipv6 }} - listen [::]:80 {{ $default_server }}; + listen [::]:{{ $external_http_port }} {{ $default_server }}; {{ end }} {{ $access_log }} From 6a0a1f67825dfb5beb7fe58aaaa611773a212a30 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Fri, 25 Mar 2022 11:05:17 +0100 Subject: [PATCH 070/300] build: bump docker-gen from 0.8.2 to 0.8.4 --- Dockerfile | 2 +- Dockerfile.alpine | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 8a46d97..46524b8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # setup build arguments for version of dependencies to use -ARG DOCKER_GEN_VERSION=0.8.2 +ARG DOCKER_GEN_VERSION=0.8.4 ARG FOREGO_VERSION=v0.17.0 # Use a specific version of golang to build both binaries diff --git a/Dockerfile.alpine b/Dockerfile.alpine index cc1247e..14f558e 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -1,5 +1,5 @@ # setup build arguments for version of dependencies to use -ARG DOCKER_GEN_VERSION=0.8.2 +ARG DOCKER_GEN_VERSION=0.8.4 ARG FOREGO_VERSION=v0.17.0 # Use a specific version of golang to build both binaries From 2e1da37f9af3dbd4a70a8095fab1d55bb972ef9b Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Sun, 10 Apr 2022 13:15:02 +0200 Subject: [PATCH 071/300] build: bump docker-gen from 0.8.4 to 0.9.0 --- Dockerfile | 4 ++-- Dockerfile.alpine | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Dockerfile b/Dockerfile index 46524b8..168858b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,9 +1,9 @@ # setup build arguments for version of dependencies to use -ARG DOCKER_GEN_VERSION=0.8.4 +ARG DOCKER_GEN_VERSION=0.9.0 ARG FOREGO_VERSION=v0.17.0 # Use a specific version of golang to build both binaries -FROM golang:1.17.8 as gobuilder +FROM golang:1.18.0 as gobuilder # Build docker-gen from scratch FROM gobuilder as dockergen diff --git a/Dockerfile.alpine b/Dockerfile.alpine index 14f558e..f98c4b8 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -1,9 +1,9 @@ # setup build arguments for version of dependencies to use -ARG DOCKER_GEN_VERSION=0.8.4 +ARG DOCKER_GEN_VERSION=0.9.0 ARG FOREGO_VERSION=v0.17.0 # Use a specific version of golang to build both binaries -FROM golang:1.17.8-alpine as gobuilder +FROM golang:1.18.0-alpine as gobuilder RUN apk add --no-cache git musl-dev # Build docker-gen from scratch From ae0faa43cd3b452bc576a4f440fff22b19589301 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 14 Apr 2022 04:10:10 +0000 Subject: [PATCH 072/300] chore(deps): bump golang from 1.18.0 to 1.18.1 Bumps golang from 1.18.0 to 1.18.1. --- updated-dependencies: - dependency-name: golang dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Dockerfile | 2 +- Dockerfile.alpine | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 168858b..dcd0285 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,7 +3,7 @@ ARG DOCKER_GEN_VERSION=0.9.0 ARG FOREGO_VERSION=v0.17.0 # Use a specific version of golang to build both binaries -FROM golang:1.18.0 as gobuilder +FROM golang:1.18.1 as gobuilder # Build docker-gen from scratch FROM gobuilder as dockergen diff --git a/Dockerfile.alpine b/Dockerfile.alpine index f98c4b8..51cafd9 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -3,7 +3,7 @@ ARG DOCKER_GEN_VERSION=0.9.0 ARG FOREGO_VERSION=v0.17.0 # Use a specific version of golang to build both binaries -FROM golang:1.18.0-alpine as gobuilder +FROM golang:1.18.1-alpine as gobuilder RUN apk add --no-cache git musl-dev # Build docker-gen from scratch From 998d56c473079901b788c6ddc297307016362419 Mon Sep 17 00:00:00 2001 From: Nitin Jain Date: Wed, 6 Apr 2022 16:24:27 +0530 Subject: [PATCH 073/300] chore: indent location, upstream in template --- nginx.tmpl | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/nginx.tmpl b/nginx.tmpl index 610edf1..e8a555d 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -51,10 +51,10 @@ {{ end }} {{ define "location" }} -location {{ .Path }} { + location {{ .Path }} { {{ if eq .NetworkTag "internal" }} - # Only allow traffic from internal clients - include /etc/nginx/network_internal.conf; + # Only allow traffic from internal clients + include /etc/nginx/network_internal.conf; {{ end }} {{ if eq .Proto "uwsgi" }} @@ -88,7 +88,7 @@ location {{ .Path }} { {{ define "upstream" }} {{ $networks := .Networks }} {{ $debug_all := .Debug }} - upstream {{ .Upstream }} { +upstream {{ .Upstream }} { {{ $server_found := "false" }} {{ range $container := .Containers }} {{ $debug := (eq (coalesce $container.Env.DEBUG $debug_all "false") "true") }} @@ -140,7 +140,7 @@ location {{ .Path }} { # Fallback entry server 127.0.0.1 down; {{ end }} - } +} {{ end }} {{ if ne $nginx_proxy_version "" }} From 20e76ac7a68f89060bb234c58dfb99f3d3d3fb9f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 25 Apr 2022 04:22:00 +0000 Subject: [PATCH 074/300] chore(deps): bump pytest from 7.1.1 to 7.1.2 in /test/requirements Bumps [pytest](https://github.com/pytest-dev/pytest) from 7.1.1 to 7.1.2. - [Release notes](https://github.com/pytest-dev/pytest/releases) - [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst) - [Commits](https://github.com/pytest-dev/pytest/compare/7.1.1...7.1.2) --- updated-dependencies: - dependency-name: pytest dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- test/requirements/python-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/requirements/python-requirements.txt b/test/requirements/python-requirements.txt index 865bb27..7aa8731 100644 --- a/test/requirements/python-requirements.txt +++ b/test/requirements/python-requirements.txt @@ -1,5 +1,5 @@ backoff==1.11.1 docker-compose==1.29.2 docker==5.0.3 -pytest==7.1.1 +pytest==7.1.2 requests==2.27.1 From 510d376f00f3c747c3ccd3221656499c6b390ebe Mon Sep 17 00:00:00 2001 From: SilverFire - Dmitry Naumenko Date: Wed, 11 May 2022 12:54:51 +0000 Subject: [PATCH 075/300] Make sure networks order is the same --- nginx.tmpl | 2 +- test/test_vhost-in-multiple-networks.py | 29 ++++++++++++++++++++++++ test/test_vhost-in-multiple-networks.yml | 26 +++++++++++++++++++++ 3 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 test/test_vhost-in-multiple-networks.py create mode 100644 test/test_vhost-in-multiple-networks.yml diff --git a/nginx.tmpl b/nginx.tmpl index e8a555d..e96f0e2 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -105,7 +105,7 @@ upstream {{ .Upstream }} { {{ end }} {{ end }} {{ range $knownNetwork := $networks }} - {{ range $containerNetwork := $container.Networks }} + {{ range $containerNetwork := sortObjectsByKeysAsc $container.Networks "Name" }} {{ if (and (ne $containerNetwork.Name "ingress") (or (eq $knownNetwork.Name $containerNetwork.Name) (eq $knownNetwork.Name "host"))) }} ## Can be connected with "{{ $containerNetwork.Name }}" network {{ if $address }} diff --git a/test/test_vhost-in-multiple-networks.py b/test/test_vhost-in-multiple-networks.py new file mode 100644 index 0000000..97a48fc --- /dev/null +++ b/test/test_vhost-in-multiple-networks.py @@ -0,0 +1,29 @@ +import pytest +import logging +import time + +def test_forwards_to_web1(docker_compose, nginxproxy): + r = nginxproxy.get("http://web1.nginx-proxy.local/port") + assert r.status_code == 200 + assert r.text == "answer from port 81\n" + +def test_nginx_config_remains_the_same_after_restart(docker_compose, nginxproxy): + """ + Restarts the Web container and returns nginx-proxy config after restart + """ + def get_conf_after_web_container_restart(): + web_containers = docker_compose.containers.list(filters={"ancestor": "web:latest"}) + assert len(web_containers) == 1 + web_containers[0].restart() + time.sleep(3) + + return nginxproxy.get_conf() + + config_before_restart = nginxproxy.get_conf() + + for i in range(1, 8): + logging.info(f"Checking for the {i}-st time that config is the same") + config_after_restart = get_conf_after_web_container_restart() + if config_before_restart != config_after_restart: + logging.debug(f"{config_before_restart!r} \n\n {config_after_restart!r}") + pytest.fail("nginx-proxy config before and after restart of a web container does not match", pytrace=False) diff --git a/test/test_vhost-in-multiple-networks.yml b/test/test_vhost-in-multiple-networks.yml new file mode 100644 index 0000000..bd01b7e --- /dev/null +++ b/test/test_vhost-in-multiple-networks.yml @@ -0,0 +1,26 @@ +version: '2' + +networks: + net1: {} + net2: {} + net3: {} + +services: + nginx-proxy: + image: nginxproxy/nginx-proxy:test + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro + networks: + - net1 + + web: + image: web + expose: + - "81" + environment: + WEB_PORTS: 81 + VIRTUAL_HOST: web1.nginx-proxy.local + networks: + - net1 + - net2 + - net3 From 9218caef710e47ebb1cfc21177528b5ad57ca258 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Val=C3=A8re=20BRON?= Date: Tue, 23 Aug 2022 12:45:45 +0200 Subject: [PATCH 076/300] Simple mistake in DEFAULT_ROOT variable name `DEFAUL_ROOT` should be `DEFAULT_ROOT` --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index dc8414b..fe1dc40 100644 --- a/README.md +++ b/README.md @@ -152,7 +152,7 @@ The filename of the previous example would be `example.tld_8610f6c344b4096614eab This environment variable of the nginx proxy container can be used to customize the return error page if no matching path is found. Furthermore it is possible to use anything which is compatible with the `return` statement of nginx. -For example `DEFAUL_ROOT=418` will return a 418 error page instead of the normal 404 one. +For example `DEFAULT_ROOT=418` will return a 418 error page instead of the normal 404 one. Another example is `DEFAULT_ROOT="301 https://github.com/nginx-proxy/nginx-proxy/blob/main/README.md"` which would redirect an invalid request to this documentation. Nginx variables such as $scheme, $host, and $request_uri can be used. However, care must be taken to make sure the $ signs are escaped properly. If you want to use `301 $scheme://$host/myapp1$request_uri` you should use: From 0fbd71362b7e4be0cffa9308c184428df975af50 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 20 Oct 2022 04:07:57 +0000 Subject: [PATCH 077/300] chore(deps): bump nginx from 1.21.6 to 1.23.2 Bumps nginx from 1.21.6 to 1.23.2. --- updated-dependencies: - dependency-name: nginx dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- Dockerfile | 2 +- Dockerfile.alpine | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index dcd0285..eaf4f8d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -36,7 +36,7 @@ RUN git clone https://github.com/nginx-proxy/forego/ \ && rm -rf /go/forego # Build the final image -FROM nginx:1.21.6 +FROM nginx:1.23.2 ARG NGINX_PROXY_VERSION # Add DOCKER_GEN_VERSION environment variable diff --git a/Dockerfile.alpine b/Dockerfile.alpine index 51cafd9..55a7c6c 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -37,7 +37,7 @@ RUN git clone https://github.com/nginx-proxy/forego/ \ && rm -rf /go/forego # Build the final image -FROM nginx:1.21.6-alpine +FROM nginx:1.23.2-alpine ARG NGINX_PROXY_VERSION # Add DOCKER_GEN_VERSION environment variable From d23a746833f155be1e00f0a02d272182a594b46d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 26 Oct 2022 04:21:21 +0000 Subject: [PATCH 078/300] chore(deps): bump pytest from 7.1.2 to 7.2.0 in /test/requirements Bumps [pytest](https://github.com/pytest-dev/pytest) from 7.1.2 to 7.2.0. - [Release notes](https://github.com/pytest-dev/pytest/releases) - [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst) - [Commits](https://github.com/pytest-dev/pytest/compare/7.1.2...7.2.0) --- updated-dependencies: - dependency-name: pytest dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- test/requirements/python-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/requirements/python-requirements.txt b/test/requirements/python-requirements.txt index 7aa8731..5597fd2 100644 --- a/test/requirements/python-requirements.txt +++ b/test/requirements/python-requirements.txt @@ -1,5 +1,5 @@ backoff==1.11.1 docker-compose==1.29.2 docker==5.0.3 -pytest==7.1.2 +pytest==7.2.0 requests==2.27.1 From 302ecfff518bbb6cd8924e96618a1d9d92b6f3c2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Dec 2022 12:00:48 +0000 Subject: [PATCH 079/300] chore(deps): bump requests from 2.27.1 to 2.28.1 in /test/requirements Bumps [requests](https://github.com/psf/requests) from 2.27.1 to 2.28.1. - [Release notes](https://github.com/psf/requests/releases) - [Changelog](https://github.com/psf/requests/blob/main/HISTORY.md) - [Commits](https://github.com/psf/requests/compare/v2.27.1...v2.28.1) --- updated-dependencies: - dependency-name: requests dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- test/requirements/python-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/requirements/python-requirements.txt b/test/requirements/python-requirements.txt index 5597fd2..ec5c918 100644 --- a/test/requirements/python-requirements.txt +++ b/test/requirements/python-requirements.txt @@ -2,4 +2,4 @@ backoff==1.11.1 docker-compose==1.29.2 docker==5.0.3 pytest==7.2.0 -requests==2.27.1 +requests==2.28.1 From b53e09373a5b0a7529b3db1194a462bc86d7460f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Dec 2022 13:02:13 +0000 Subject: [PATCH 080/300] chore(deps): bump backoff from 1.11.1 to 2.2.1 in /test/requirements Bumps [backoff](https://github.com/litl/backoff) from 1.11.1 to 2.2.1. - [Release notes](https://github.com/litl/backoff/releases) - [Changelog](https://github.com/litl/backoff/blob/master/CHANGELOG.md) - [Commits](https://github.com/litl/backoff/compare/v1.11.1...v2.2.1) --- updated-dependencies: - dependency-name: backoff dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- test/requirements/python-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/requirements/python-requirements.txt b/test/requirements/python-requirements.txt index ec5c918..b9b5a8e 100644 --- a/test/requirements/python-requirements.txt +++ b/test/requirements/python-requirements.txt @@ -1,4 +1,4 @@ -backoff==1.11.1 +backoff==2.2.1 docker-compose==1.29.2 docker==5.0.3 pytest==7.2.0 From e5b340cb6f4b3f7dc259e008d0e770346422ad08 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Dec 2022 14:30:16 +0000 Subject: [PATCH 081/300] chore(deps): bump docker from 5.0.3 to 6.0.1 in /test/requirements Bumps [docker](https://github.com/docker/docker-py) from 5.0.3 to 6.0.1. - [Release notes](https://github.com/docker/docker-py/releases) - [Commits](https://github.com/docker/docker-py/compare/5.0.3...6.0.1) --- updated-dependencies: - dependency-name: docker dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- test/requirements/python-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/requirements/python-requirements.txt b/test/requirements/python-requirements.txt index b9b5a8e..c75a674 100644 --- a/test/requirements/python-requirements.txt +++ b/test/requirements/python-requirements.txt @@ -1,5 +1,5 @@ backoff==2.2.1 docker-compose==1.29.2 -docker==5.0.3 +docker==6.0.1 pytest==7.2.0 requests==2.28.1 From b4dd1a4ba881877260ab7fcc0f1da57eeca5861b Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Thu, 1 Dec 2022 23:22:02 +0100 Subject: [PATCH 082/300] build: dockergen 0.9.0 -> 0.9.1 --- Dockerfile | 2 +- Dockerfile.alpine | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index eaf4f8d..9dff82f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # setup build arguments for version of dependencies to use -ARG DOCKER_GEN_VERSION=0.9.0 +ARG DOCKER_GEN_VERSION=0.9.1 ARG FOREGO_VERSION=v0.17.0 # Use a specific version of golang to build both binaries diff --git a/Dockerfile.alpine b/Dockerfile.alpine index 55a7c6c..9f4c2ae 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -1,5 +1,5 @@ # setup build arguments for version of dependencies to use -ARG DOCKER_GEN_VERSION=0.9.0 +ARG DOCKER_GEN_VERSION=0.9.1 ARG FOREGO_VERSION=v0.17.0 # Use a specific version of golang to build both binaries From 050d9da7bd21881f8584db5485deac27f1786d96 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Thu, 1 Dec 2022 23:24:53 +0100 Subject: [PATCH 083/300] docs: nginx badge 1.21.6 -> 1.23.2 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fe1dc40..239a905 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ [![Test](https://github.com/nginx-proxy/nginx-proxy/actions/workflows/test.yml/badge.svg)](https://github.com/nginx-proxy/nginx-proxy/actions/workflows/test.yml) [![GitHub release](https://img.shields.io/github/v/release/nginx-proxy/nginx-proxy)](https://github.com/nginx-proxy/nginx-proxy/releases) -![nginx 1.21.6](https://img.shields.io/badge/nginx-1.21.6-brightgreen.svg) +![nginx 1.23.2](https://img.shields.io/badge/nginx-1.23.2-brightgreen.svg) [![Docker Image Size](https://img.shields.io/docker/image-size/nginxproxy/nginx-proxy?sort=semver)](https://hub.docker.com/r/nginxproxy/nginx-proxy "Click to view the image on Docker Hub") [![Docker stars](https://img.shields.io/docker/stars/nginxproxy/nginx-proxy.svg)](https://hub.docker.com/r/nginxproxy/nginx-proxy 'DockerHub') [![Docker pulls](https://img.shields.io/docker/pulls/nginxproxy/nginx-proxy.svg)](https://hub.docker.com/r/nginxproxy/nginx-proxy 'DockerHub') From 75c7b1399bfe57707550adcafe1dae1f567aa80d Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Fri, 2 Dec 2022 00:21:56 +0100 Subject: [PATCH 084/300] build: golang 1.18.1 -> 1.18.8 --- Dockerfile | 2 +- Dockerfile.alpine | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 9dff82f..cf33847 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,7 +3,7 @@ ARG DOCKER_GEN_VERSION=0.9.1 ARG FOREGO_VERSION=v0.17.0 # Use a specific version of golang to build both binaries -FROM golang:1.18.1 as gobuilder +FROM golang:1.18.8 as gobuilder # Build docker-gen from scratch FROM gobuilder as dockergen diff --git a/Dockerfile.alpine b/Dockerfile.alpine index 9f4c2ae..43a57fd 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -3,7 +3,7 @@ ARG DOCKER_GEN_VERSION=0.9.1 ARG FOREGO_VERSION=v0.17.0 # Use a specific version of golang to build both binaries -FROM golang:1.18.1-alpine as gobuilder +FROM golang:1.18.8-alpine as gobuilder RUN apk add --no-cache git musl-dev # Build docker-gen from scratch From 02d3a37cfbf55dfce154d35eb9859eb63ef46d21 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Sat, 3 Dec 2022 14:30:40 +0100 Subject: [PATCH 085/300] style: linting on CI yaml files --- .github/dependabot.yml | 1 - .github/workflows/dockerhub.yml | 32 +++++++++++++++----------------- .github/workflows/test.yml | 8 ++++---- 3 files changed, 19 insertions(+), 22 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 9056ae1..81ddf73 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,6 +1,5 @@ version: 2 updates: - # Maintain dependencies for Docker - package-ecosystem: "docker" directory: "/" diff --git a/.github/workflows/dockerhub.yml b/.github/workflows/dockerhub.yml index 706d298..72c769e 100644 --- a/.github/workflows/dockerhub.yml +++ b/.github/workflows/dockerhub.yml @@ -3,31 +3,30 @@ name: DockerHub on: workflow_dispatch: schedule: - - cron: '0 0 * * 1' + - cron: "0 0 * * 1" push: branches: - main tags: - - '*.*.*' + - "*.*.*" paths-ignore: - - 'test/*' - - '.gitignore' - - 'docker-compose-separate-containers.yml' - - 'docker-compose.yml' - - 'LICENSE' - - 'Makefile' - - '*.md' + - "test/*" + - ".gitignore" + - "docker-compose-separate-containers.yml" + - "docker-compose.yml" + - "LICENSE" + - "Makefile" + - "*.md" jobs: multiarch-build-debian: runs-on: ubuntu-latest steps: - - name: Checkout uses: actions/checkout@v2 with: fetch-depth: 0 - + - name: Retrieve version run: echo "GIT_DESCRIBE=$(git describe --tags)" >> $GITHUB_ENV @@ -54,11 +53,11 @@ jobs: uses: docker/setup-buildx-action@v1 - name: Login to DockerHub - uses: docker/login-action@v1 + uses: docker/login-action@v1 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - + - name: Log in to GitHub Container Registry uses: docker/login-action@v1 with: @@ -84,12 +83,11 @@ jobs: multiarch-build-alpine: runs-on: ubuntu-latest steps: - - name: Checkout uses: actions/checkout@v2 with: fetch-depth: 0 - + - name: Retrieve version run: echo "GIT_DESCRIBE=$(git describe --tags)" >> $GITHUB_ENV @@ -117,11 +115,11 @@ jobs: uses: docker/setup-buildx-action@v1 - name: Login to DockerHub - uses: docker/login-action@v1 + uses: docker/login-action@v1 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - + - name: Log in to GitHub Container Registry uses: docker/login-action@v1 with: diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 6be93bd..3f088d9 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -4,12 +4,12 @@ on: workflow_dispatch: push: paths-ignore: - - 'LICENSE' - - '**.md' + - "LICENSE" + - "**.md" pull_request: paths-ignore: - - 'LICENSE' - - '**.md' + - "LICENSE" + - "**.md" jobs: unit: From 9f9e5b8cd41da7b86fba0295e3d98c4f9861df20 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Sat, 3 Dec 2022 14:34:15 +0100 Subject: [PATCH 086/300] ci: update Actions versions --- .github/workflows/dockerhub.yml | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/.github/workflows/dockerhub.yml b/.github/workflows/dockerhub.yml index 72c769e..e628b2f 100644 --- a/.github/workflows/dockerhub.yml +++ b/.github/workflows/dockerhub.yml @@ -32,7 +32,7 @@ jobs: - name: Get Docker tags for Debian based image id: docker_meta_debian - uses: docker/metadata-action@v3 + uses: docker/metadata-action@v4 with: images: | ghcr.io/nginx-proxy/nginx-proxy @@ -41,25 +41,25 @@ jobs: tags: | type=semver,pattern={{version}} type=semver,pattern={{major}}.{{minor}} - type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' }} + type=raw,value=latest,enable={{is_default_branch}} labels: | org.opencontainers.image.authors=Nicolas Duchon (@buchdag), Jason Wilder org.opencontainers.image.version=${{ env.GIT_DESCRIBE }} - name: Set up QEMU - uses: docker/setup-qemu-action@v1 + uses: docker/setup-qemu-action@v2 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1 + uses: docker/setup-buildx-action@v2 - name: Login to DockerHub - uses: docker/login-action@v1 + uses: docker/login-action@v2 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Log in to GitHub Container Registry - uses: docker/login-action@v1 + uses: docker/login-action@v2 with: registry: ghcr.io username: ${{ github.actor }} @@ -67,7 +67,7 @@ jobs: - name: Build and push the Debian based image id: docker_build_debian - uses: docker/build-push-action@v2 + uses: docker/build-push-action@v3 with: context: . file: Dockerfile @@ -93,7 +93,7 @@ jobs: - name: Get Docker tags for Alpine based image id: docker_meta_alpine - uses: docker/metadata-action@v3 + uses: docker/metadata-action@v4 with: images: | ghcr.io/nginx-proxy/nginx-proxy @@ -102,26 +102,26 @@ jobs: tags: | type=semver,suffix=-alpine,pattern={{version}} type=semver,suffix=-alpine,pattern={{major}}.{{minor}} - type=raw,value=alpine,enable=${{ github.ref == 'refs/heads/main' }} + type=raw,value=alpine,enable={{is_default_branch}} labels: | org.opencontainers.image.authors=Nicolas Duchon (@buchdag), Jason Wilder org.opencontainers.image.version=${{ env.GIT_DESCRIBE }} flavor: latest=false - name: Set up QEMU - uses: docker/setup-qemu-action@v1 + uses: docker/setup-qemu-action@v2 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1 + uses: docker/setup-buildx-action@v2 - name: Login to DockerHub - uses: docker/login-action@v1 + uses: docker/login-action@v2 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Log in to GitHub Container Registry - uses: docker/login-action@v1 + uses: docker/login-action@v2 with: registry: ghcr.io username: ${{ github.actor }} @@ -129,7 +129,7 @@ jobs: - name: Build and push the Alpine based image id: docker_build_alpine - uses: docker/build-push-action@v2 + uses: docker/build-push-action@v3 with: context: . file: Dockerfile.alpine From 9c2b2cec38d82e60e6abdd56431d8d435a7b3daa Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Sat, 3 Dec 2022 19:36:31 +0100 Subject: [PATCH 087/300] ci: use actions/checkout@v3 --- .github/workflows/dockerhub.yml | 4 ++-- .github/workflows/test.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/dockerhub.yml b/.github/workflows/dockerhub.yml index e628b2f..8b33fb2 100644 --- a/.github/workflows/dockerhub.yml +++ b/.github/workflows/dockerhub.yml @@ -23,7 +23,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: fetch-depth: 0 @@ -84,7 +84,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: fetch-depth: 0 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 3f088d9..3dd2674 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -21,7 +21,7 @@ jobs: base_docker_image: [alpine, debian] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Set up Python 3.9 uses: actions/setup-python@v2 From f1fb85865dd36f5620b3383c625ab55e4488d6ea Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 7 Dec 2022 04:02:52 +0000 Subject: [PATCH 088/300] chore(deps): bump golang from 1.18.8 to 1.19.4 Bumps golang from 1.18.8 to 1.19.4. --- updated-dependencies: - dependency-name: golang dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- Dockerfile | 2 +- Dockerfile.alpine | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index cf33847..e599c8f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,7 +3,7 @@ ARG DOCKER_GEN_VERSION=0.9.1 ARG FOREGO_VERSION=v0.17.0 # Use a specific version of golang to build both binaries -FROM golang:1.18.8 as gobuilder +FROM golang:1.19.4 as gobuilder # Build docker-gen from scratch FROM gobuilder as dockergen diff --git a/Dockerfile.alpine b/Dockerfile.alpine index 43a57fd..ecdfe2c 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -3,7 +3,7 @@ ARG DOCKER_GEN_VERSION=0.9.1 ARG FOREGO_VERSION=v0.17.0 # Use a specific version of golang to build both binaries -FROM golang:1.18.8-alpine as gobuilder +FROM golang:1.19.4-alpine as gobuilder RUN apk add --no-cache git musl-dev # Build docker-gen from scratch From 1aadd9ba8c691282468a077057404c042bc1d3e4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 14 Dec 2022 04:02:52 +0000 Subject: [PATCH 089/300] chore(deps): bump nginx from 1.23.2 to 1.23.3 Bumps nginx from 1.23.2 to 1.23.3. --- updated-dependencies: - dependency-name: nginx dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Dockerfile | 2 +- Dockerfile.alpine | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index cf33847..9b04e48 100644 --- a/Dockerfile +++ b/Dockerfile @@ -36,7 +36,7 @@ RUN git clone https://github.com/nginx-proxy/forego/ \ && rm -rf /go/forego # Build the final image -FROM nginx:1.23.2 +FROM nginx:1.23.3 ARG NGINX_PROXY_VERSION # Add DOCKER_GEN_VERSION environment variable diff --git a/Dockerfile.alpine b/Dockerfile.alpine index 43a57fd..5aec1d6 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -37,7 +37,7 @@ RUN git clone https://github.com/nginx-proxy/forego/ \ && rm -rf /go/forego # Build the final image -FROM nginx:1.23.2-alpine +FROM nginx:1.23.3-alpine ARG NGINX_PROXY_VERSION # Add DOCKER_GEN_VERSION environment variable From 9cb21132a461461c2a60d4293042edc6b8a54f77 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Wed, 16 Mar 2022 01:10:56 -0400 Subject: [PATCH 090/300] docs: Sync README.md with default proxy.conf settings --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 239a905..1b1b529 100644 --- a/README.md +++ b/README.md @@ -122,7 +122,7 @@ You can also use wildcards at the beginning and the end of host name, like `*.ba You can have multiple containers proxied by the same `VIRTUAL_HOST` by adding a `VIRTUAL_PATH` environment variable containing the absolute path to where the container should be mounted. For example with `VIRTUAL_HOST=foo.example.com` and `VIRTUAL_PATH=/api/v2/service`, then requests to http://foo.example.com/api/v2/service will be routed to the container. If you wish to have a container serve the root while other containers serve other paths, give the root container a `VIRTUAL_PATH` of `/`. Unmatched paths will be served by the container at `/` or will return the default nginx error page if no container has been assigned `/`. It is also possible to specify multiple paths with regex locations like `VIRTUAL_PATH=~^/(app1|alternative1)/`. For further details see the nginx documentation on location blocks. This is not compatible with `VIRTUAL_DEST`. -The full request URI will be forwarded to the serving container in the `X-Forwarded-Path` header. +The full request URI will be forwarded to the serving container in the `X-Original-URI` header. **NOTE**: Your application needs to be able to generate links starting with `VIRTUAL_PATH`. This can be achieved by it being natively on this path or having an option to prepend this path. The application does not need to expect this path in the request. @@ -381,7 +381,7 @@ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto; proxy_set_header X-Forwarded-Ssl $proxy_x_forwarded_ssl; proxy_set_header X-Forwarded-Port $proxy_x_forwarded_port; -proxy_set_header X-Forwarded-Path $request_uri; +proxy_set_header X-Original-URI $request_uri; # Mitigate httpoxy attack (see README for details) proxy_set_header Proxy ""; From 5f15f045564da8d91332a4e9e3cdccce2be171d5 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Sat, 26 Mar 2022 21:10:16 -0400 Subject: [PATCH 091/300] docs: Document the request headers sent to the backend server --- README.md | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 1b1b529..564f72e 100644 --- a/README.md +++ b/README.md @@ -361,6 +361,19 @@ docker run -d -p 80:80 -p 443:443 \ You'll need apache2-utils on the machine where you plan to create the htpasswd file. Follow these [instructions](http://httpd.apache.org/docs/2.2/programs/htpasswd.html) +### Headers + +By default, `nginx-proxy` forwards all incoming request headers from the client to the backend server unmodified, with the following exceptions: + + * `Connection`: Set to `upgrade` if the client sets the `Upgrade` header, otherwise set to `close`. (Keep-alive between `nginx-proxy` and the backend server is not supported.) + * `Proxy`: Always removed if present. This prevents attackers from using the so-called [httpoxy attack](http://httpoxy.org). There is no legitimate reason for a client to send this header, and there are many vulnerable languages / platforms (`CVE-2016-5385`, `CVE-2016-5386`, `CVE-2016-5387`, `CVE-2016-5388`, `CVE-2016-1000109`, `CVE-2016-1000110`, `CERT-VU#797896`). + * `X-Real-IP`: Set to the client's IP address. + * `X-Forwarded-For`: The client's IP address is appended to the value provided by the client. (If the client did not provide this header, it is set to the client's IP address.) + * `X-Forwarded-Proto`: If the client did not provide this header, this is set to `http` for plain HTTP connections and `https` for TLS connections. Otherwise, the header is forwarded to the backend server unmodified. + * `X-Forwarded-Ssl`: Set to `on` if the `X-Forwarded-Proto` header sent to the backend server is `https`, otherwise set to `off`. + * `X-Forwarded-Port`: If the client did not provide this header, this is set to the port of the server that accepted the client's request. Otherwise, the header is forwarded to the backend server unmodified. + * `X-Original-URI`: Set to the original request URI. + ### Custom Nginx Configuration If you need to configure Nginx beyond what is possible using environment variables, you can provide custom configuration files on either a proxy-wide or per-`VIRTUAL_HOST` basis. @@ -389,8 +402,6 @@ proxy_set_header Proxy ""; ***NOTE***: If you provide this file it will replace the defaults; you may want to check the .tmpl file to make sure you have all of the needed options. -***NOTE***: The default configuration blocks the `Proxy` HTTP request header from being sent to downstream servers. This prevents attackers from using the so-called [httpoxy attack](http://httpoxy.org). There is no legitimate reason for a client to send this header, and there are many vulnerable languages / platforms (`CVE-2016-5385`, `CVE-2016-5386`, `CVE-2016-5387`, `CVE-2016-5388`, `CVE-2016-1000109`, `CVE-2016-1000110`, `CERT-VU#797896`). - #### Proxy-wide To add settings on a proxy-wide basis, add your configuration file under `/etc/nginx/conf.d` using a name ending in `.conf`. From 8aa00fcea2588eb39565b030c706068a21f9ee33 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Wed, 16 Mar 2022 00:59:03 -0400 Subject: [PATCH 092/300] feat: Option to not trust `X-Forwarded-*` headers from clients If header values from a malicious client are passed to the backend server unchecked and unchanged, the client may be able to subvert security checks done by the backend server. --- README.md | 13 +++- app/docker-entrypoint.sh | 7 ++ nginx.tmpl | 5 +- .../certs/web.nginx-proxy.tld.crt | 70 +++++++++++++++++++ .../certs/web.nginx-proxy.tld.key | 27 +++++++ .../test_default.py | 20 ++++++ .../test_default.yml | 16 +++++ .../test_disabled.py | 20 ++++++ .../test_disabled.yml | 18 +++++ .../test_enabled.py | 20 ++++++ .../test_enabled.yml | 18 +++++ 11 files changed, 230 insertions(+), 4 deletions(-) create mode 100644 test/test_trust-downstream-proxy/certs/web.nginx-proxy.tld.crt create mode 100644 test/test_trust-downstream-proxy/certs/web.nginx-proxy.tld.key create mode 100644 test/test_trust-downstream-proxy/test_default.py create mode 100644 test/test_trust-downstream-proxy/test_default.yml create mode 100644 test/test_trust-downstream-proxy/test_disabled.py create mode 100644 test/test_trust-downstream-proxy/test_disabled.yml create mode 100644 test/test_trust-downstream-proxy/test_enabled.py create mode 100644 test/test_trust-downstream-proxy/test_enabled.yml diff --git a/README.md b/README.md index 564f72e..367be6b 100644 --- a/README.md +++ b/README.md @@ -369,11 +369,20 @@ By default, `nginx-proxy` forwards all incoming request headers from the client * `Proxy`: Always removed if present. This prevents attackers from using the so-called [httpoxy attack](http://httpoxy.org). There is no legitimate reason for a client to send this header, and there are many vulnerable languages / platforms (`CVE-2016-5385`, `CVE-2016-5386`, `CVE-2016-5387`, `CVE-2016-5388`, `CVE-2016-1000109`, `CVE-2016-1000110`, `CERT-VU#797896`). * `X-Real-IP`: Set to the client's IP address. * `X-Forwarded-For`: The client's IP address is appended to the value provided by the client. (If the client did not provide this header, it is set to the client's IP address.) - * `X-Forwarded-Proto`: If the client did not provide this header, this is set to `http` for plain HTTP connections and `https` for TLS connections. Otherwise, the header is forwarded to the backend server unmodified. + * `X-Forwarded-Proto`: If the client did not provide this header or if the `TRUST_DOWNSTREAM_PROXY` environment variable is set to `false` (see below), this is set to `http` for plain HTTP connections and `https` for TLS connections. Otherwise, the header is forwarded to the backend server unmodified. * `X-Forwarded-Ssl`: Set to `on` if the `X-Forwarded-Proto` header sent to the backend server is `https`, otherwise set to `off`. - * `X-Forwarded-Port`: If the client did not provide this header, this is set to the port of the server that accepted the client's request. Otherwise, the header is forwarded to the backend server unmodified. + * `X-Forwarded-Port`: If the client did not provide this header or if the `TRUST_DOWNSTREAM_PROXY` environment variable is set to `false` (see below), this is set to the port of the server that accepted the client's request. Otherwise, the header is forwarded to the backend server unmodified. * `X-Original-URI`: Set to the original request URI. +#### Trusting Downstream Proxy Headers + +For legacy compatibility reasons, `nginx-proxy` forwards any client-supplied `X-Forwarded-Proto` (which affects the value of `X-Forwarded-Ssl`) and `X-Forwarded-Port` headers unchecked and unmodified. To prevent malicious clients from spoofing the protocol or port that is perceived by your backend server, you are encouraged to set the `TRUST_DOWNSTREAM_PROXY` value to `false` if: + + * you do not operate a second reverse proxy downstream of `nginx-proxy`, or + * you do operate a second reverse proxy downstream of `nginx-proxy` but that proxy forwards those headers unchecked from untrusted clients. + +The default for `TRUST_DOWNSTREAM_PROXY` may change to `false` in a future version of `nginx-proxy`. If you require it to be enabled, you are encouraged to explicitly set it to `true` to avoid compatibility problems when upgrading. + ### Custom Nginx Configuration If you need to configure Nginx beyond what is possible using environment variables, you can provide custom configuration files on either a proxy-wide or per-`VIRTUAL_HOST` basis. diff --git a/app/docker-entrypoint.sh b/app/docker-entrypoint.sh index 8f4ed7a..0477dd2 100755 --- a/app/docker-entrypoint.sh +++ b/app/docker-entrypoint.sh @@ -109,6 +109,13 @@ if [[ $* == 'forego start -r' ]]; then _resolvers _setup_dhparam + + if [ -z "${TRUST_DOWNSTREAM_PROXY}" ]; then + cat >&2 <<-EOT + Warning: TRUST_DOWNSTREAM_PROXY is not set; defaulting to "true". For security, you should explicitly set TRUST_DOWNSTREAM_PROXY to "false" if there is not a trusted reverse proxy in front of this proxy. + Warning: The default value of TRUST_DOWNSTREAM_PROXY might change to "false" in a future version of nginx-proxy. If you require TRUST_DOWNSTREAM_PROXY to be enabled, explicitly set it to "true". + EOT + fi fi exec "$@" diff --git a/nginx.tmpl b/nginx.tmpl index e8a555d..295af0c 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -6,6 +6,7 @@ {{ $debug_all := $.Env.DEBUG }} {{ $sha1_upstream_name := parseBool (coalesce $.Env.SHA1_UPSTREAM_NAME "false") }} {{ $default_root_response := coalesce $.Env.DEFAULT_ROOT "404" }} +{{ $trust_downstream_proxy := parseBool (coalesce $.Env.TRUST_DOWNSTREAM_PROXY "true") }} {{ define "ssl_policy" }} {{ if eq .ssl_policy "Mozilla-Modern" }} @@ -150,14 +151,14 @@ upstream {{ .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 $http_x_forwarded_proto; + default {{ if $trust_downstream_proxy }}$http_x_forwarded_proto{{ else }}$scheme{{ end }}; '' $scheme; } # 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 $http_x_forwarded_port; + default {{ if $trust_downstream_proxy }}$http_x_forwarded_port{{ else }}$server_port{{ end }}; '' $server_port; } diff --git a/test/test_trust-downstream-proxy/certs/web.nginx-proxy.tld.crt b/test/test_trust-downstream-proxy/certs/web.nginx-proxy.tld.crt new file mode 100644 index 0000000..aed9349 --- /dev/null +++ b/test/test_trust-downstream-proxy/certs/web.nginx-proxy.tld.crt @@ -0,0 +1,70 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 4096 (0x1000) + Signature Algorithm: sha256WithRSAEncryption + Issuer: O=nginx-proxy test suite, CN=www.nginx-proxy.tld + Validity + Not Before: Jan 13 03:06:39 2017 GMT + Not After : May 31 03:06:39 2044 GMT + Subject: CN=web.nginx-proxy.tld + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:95:56:c7:0d:48:a5:2b:3c:65:49:3f:26:e1:38: + 2b:61:30:56:e4:92:d7:63:e0:eb:ad:ac:f9:33:9b: + b2:31:f1:39:13:0b:e5:43:7b:c5:bd:8a:85:c8:d9: + 3d:d8:ac:71:ba:16:e7:81:96:b2:ab:ae:c6:c0:bd: + be:a7:d1:96:8f:b2:9b:df:ba:f9:4d:a1:3b:7e:21: + 4a:cd:b6:45:f9:6d:79:50:bf:24:8f:c1:6b:c1:09: + 19:5b:62:cb:96:e8:04:14:20:e8:d4:16:62:6a:f2: + 37:c1:96:e2:9d:53:05:0b:52:1d:e7:68:92:db:8b: + 36:68:cd:8d:5b:02:ff:12:f0:ac:5d:0c:c4:e0:7a: + 55:a2:49:60:9f:ff:47:1f:52:73:55:4d:d4:f2:d1: + 62:a2:f4:50:9d:c9:f6:f1:43:b3:dc:57:e1:31:76: + b4:e0:a4:69:7e:f2:6d:34:ae:b9:8d:74:26:7b:d9: + f6:07:00:ef:4b:36:61:b3:ef:7a:a1:36:3a:b6:d0: + 9e:f8:b8:a9:0d:4c:30:a2:ed:eb:ab:6b:eb:2e:e2: + 0b:28:be:f7:04:b1:e9:e0:84:d6:5d:31:77:7c:dc: + d2:1f:d4:1d:71:6f:6f:6c:6d:1b:bf:31:e2:5b:c3: + 52:d0:14:fc:8b:fb:45:ea:41:ec:ca:c7:3b:67:12: + c4:df + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Alternative Name: + DNS:web.nginx-proxy.tld + Signature Algorithm: sha256WithRSAEncryption + 4e:48:7d:81:66:ba:2f:50:3d:24:42:61:3f:1f:de:cf:ec:1b: + 1b:bd:0a:67:b6:62:c8:79:9d:31:a0:fd:a9:61:ce:ff:69:bf: + 0e:f4:f7:e6:15:2b:b0:f0:e4:f2:f4:d2:8f:74:02:b1:1e:4a: + a8:6f:26:0a:77:32:29:cf:dc:b5:61:82:3e:58:47:61:92:f0: + 0c:20:25:f8:41:4d:34:09:44:bc:39:9e:aa:82:06:83:13:8b: + 1e:2c:3d:cf:cd:1a:f7:77:39:38:e0:a3:a7:f3:09:da:02:8d: + 73:75:38:b4:dd:24:a7:f9:03:db:98:c6:88:54:87:dc:e0:65: + 4c:95:c5:39:9c:00:30:dc:f0:d3:2c:19:ca:f1:f4:6c:c6:d9: + b5:c4:4a:c7:bc:a1:2e:88:7b:b5:33:d0:ff:fb:48:5e:3e:29: + fa:58:e5:03:de:d8:17:de:ed:96:fc:7e:1f:fe:98:f6:be:99: + 38:87:51:c0:d3:b7:9a:0f:26:92:e5:53:1b:d6:25:4c:ac:48: + f3:29:fc:74:64:9d:07:6a:25:57:24:aa:a7:70:fa:8f:6c:a7: + 2b:b7:9d:81:46:10:32:93:b9:45:6d:0f:16:18:b2:21:1f:f3: + 30:24:62:3f:e1:6c:07:1d:71:28:cb:4c:bb:f5:39:05:f9:b2: + 5b:a0:05:1b +-----BEGIN CERTIFICATE----- +MIIC+zCCAeOgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwPzEfMB0GA1UECgwWbmdp +bngtcHJveHkgdGVzdCBzdWl0ZTEcMBoGA1UEAwwTd3d3Lm5naW54LXByb3h5LnRs +ZDAeFw0xNzAxMTMwMzA2MzlaFw00NDA1MzEwMzA2MzlaMB4xHDAaBgNVBAMME3dl +Yi5uZ2lueC1wcm94eS50bGQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB +AQCVVscNSKUrPGVJPybhOCthMFbkktdj4OutrPkzm7Ix8TkTC+VDe8W9ioXI2T3Y +rHG6FueBlrKrrsbAvb6n0ZaPspvfuvlNoTt+IUrNtkX5bXlQvySPwWvBCRlbYsuW +6AQUIOjUFmJq8jfBluKdUwULUh3naJLbizZozY1bAv8S8KxdDMTgelWiSWCf/0cf +UnNVTdTy0WKi9FCdyfbxQ7PcV+ExdrTgpGl+8m00rrmNdCZ72fYHAO9LNmGz73qh +Njq20J74uKkNTDCi7eura+su4gsovvcEsenghNZdMXd83NIf1B1xb29sbRu/MeJb +w1LQFPyL+0XqQezKxztnEsTfAgMBAAGjIjAgMB4GA1UdEQQXMBWCE3dlYi5uZ2lu +eC1wcm94eS50bGQwDQYJKoZIhvcNAQELBQADggEBAE5IfYFmui9QPSRCYT8f3s/s +Gxu9Cme2Ysh5nTGg/alhzv9pvw709+YVK7Dw5PL00o90ArEeSqhvJgp3MinP3LVh +gj5YR2GS8AwgJfhBTTQJRLw5nqqCBoMTix4sPc/NGvd3OTjgo6fzCdoCjXN1OLTd +JKf5A9uYxohUh9zgZUyVxTmcADDc8NMsGcrx9GzG2bXESse8oS6Ie7Uz0P/7SF4+ +KfpY5QPe2Bfe7Zb8fh/+mPa+mTiHUcDTt5oPJpLlUxvWJUysSPMp/HRknQdqJVck +qqdw+o9spyu3nYFGEDKTuUVtDxYYsiEf8zAkYj/hbAcdcSjLTLv1OQX5slugBRs= +-----END CERTIFICATE----- diff --git a/test/test_trust-downstream-proxy/certs/web.nginx-proxy.tld.key b/test/test_trust-downstream-proxy/certs/web.nginx-proxy.tld.key new file mode 100644 index 0000000..8365ecf --- /dev/null +++ b/test/test_trust-downstream-proxy/certs/web.nginx-proxy.tld.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEogIBAAKCAQEAlVbHDUilKzxlST8m4TgrYTBW5JLXY+Drraz5M5uyMfE5Ewvl +Q3vFvYqFyNk92KxxuhbngZayq67GwL2+p9GWj7Kb37r5TaE7fiFKzbZF+W15UL8k +j8FrwQkZW2LLlugEFCDo1BZiavI3wZbinVMFC1Id52iS24s2aM2NWwL/EvCsXQzE +4HpVoklgn/9HH1JzVU3U8tFiovRQncn28UOz3FfhMXa04KRpfvJtNK65jXQme9n2 +BwDvSzZhs+96oTY6ttCe+LipDUwwou3rq2vrLuILKL73BLHp4ITWXTF3fNzSH9Qd +cW9vbG0bvzHiW8NS0BT8i/tF6kHsysc7ZxLE3wIDAQABAoIBAEmK7IecKMq7+V0y +3mC3GpXICmKR9cRX9XgX4LkLiZuSoXrBtuuevmhzGSMp6I0VjwQHV4a3wdFORs6Q +Ip3eVvj5Ck4Jc9BJAFVC6+WWR6tnwACFwOmSZRAw/O3GH2B3bdrDwiT/yQPFuLN7 +LKoxQiCrFdLp6rh3PBosb9pMBXU7k/HUazIdgmSKg6/JIoo/4Gwyid04TF/4MI2l +RscxtP5/ANtS8VgwBEqhgdafRJ4KnLEpgvswgIQvUKmduVhZQlzd0LMY8FbhKVqz +Utg8gsXaTyH6df/nmgUIInxLMz/MKPnMkv99fS6Sp/hvYlGpLZFWBJ6unMq3lKEr +LMbHfIECgYEAxB+5QWdVqG2r9loJlf8eeuNeMPml4P8Jmi5RKyJC7Cww6DMlMxOS +78ZJfl4b3ZrWuyvhjOfX/aTq7kQaF1BI9o3KJBH8k6EtO4gI8KeNmDONyQk9zsrn +ru8Zwr7hVbAo8fCXxCnmPzhDLsYg6f3BVOsQWoX2SFYKZ1GvkPfIReECgYEAwu6G +qtgFb57Vim10ecfWGM6vrPxvyfqP+zlH/p4nR+aQ+2sFbt27D0B1byWBRZe4KQyw +Vq6XiQ09Fk6MJr8E8iAr9GXPPHcqlYI6bbNc6YOP3jVSKut0tQdTUOHll4kYIY+h +RS3VA3+BA//ADpWpywu+7RZRbaIECA+U2a224r8CgYB5PCMIixgoRaNHZeEHF+1/ +iY1wOOKRcxY8eOU0BLnZxHd3EiasrCzoi2pi80nGczDKAxYqRCcAZDHVl8OJJdf0 +kTGjmnrHx5pucmkUWn7s1vGOlGfgrQ0K1kLWX6hrj7m/1Tn7yOrLqbvd7hvqiTI5 +jBVP3/+eN5G2zIf61TC4AQKBgCX2Q92jojNhsF58AHHy+/vqzIWYx8CC/mVDe4TX +kfjLqzJ7XhyAK/zFZdlWaX1/FYtRAEpxR+uV226rr1mgW7s3jrfS1/ADmRRyvyQ8 +CP0k9PCmW7EmF51lptEanRbMyRlIGnUZfuFmhF6eAO4WMXHsgKs1bHg4VCapuihG +T1aLAoGACRGn1UxFuBGqtsh2zhhsBZE7GvXKJSk/eP7QJeEXUNpNjCpgm8kIZM5K +GorpL7PSB8mwVlDl18TpMm3P7nz6YkJYte+HdjO7pg59H39Uvtg3tZnIrFxNxVNb +YF62/yHfk2AyTgjQZQUSmDS84jq1zUK4oS90lxr+u8qwELTniMs= +-----END RSA PRIVATE KEY----- diff --git a/test/test_trust-downstream-proxy/test_default.py b/test/test_trust-downstream-proxy/test_default.py new file mode 100644 index 0000000..456d07a --- /dev/null +++ b/test/test_trust-downstream-proxy/test_default.py @@ -0,0 +1,20 @@ +import pytest +import re + + +@pytest.mark.parametrize('url,header,input,want', [ + ('http://web.nginx-proxy.tld/headers', 'X-Forwarded-Proto', None, 'http'), + ('http://web.nginx-proxy.tld/headers', 'X-Forwarded-Proto', 'f00', 'f00'), + ('https://web.nginx-proxy.tld/headers', 'X-Forwarded-Proto', None, 'https'), + ('https://web.nginx-proxy.tld/headers', 'X-Forwarded-Proto', 'f00', 'f00'), + + ('http://web.nginx-proxy.tld/headers', 'X-Forwarded-Port', None, '80'), + ('http://web.nginx-proxy.tld/headers', 'X-Forwarded-Port', '1234', '1234'), + ('https://web.nginx-proxy.tld/headers', 'X-Forwarded-Port', None, '443'), + ('https://web.nginx-proxy.tld/headers', 'X-Forwarded-Port', '1234', '1234'), +]) +def test_downstream_proxy_header(docker_compose, nginxproxy, url, header, input, want): + kwargs = {} if input is None else {'headers': {header: input}} + r = nginxproxy.get(url, **kwargs) + assert r.status_code == 200 + assert re.search(fr'(?m)^(?i:{re.escape(header)}): {re.escape(want)}$', r.text) diff --git a/test/test_trust-downstream-proxy/test_default.yml b/test/test_trust-downstream-proxy/test_default.yml new file mode 100644 index 0000000..c420d80 --- /dev/null +++ b/test/test_trust-downstream-proxy/test_default.yml @@ -0,0 +1,16 @@ +web: + image: web + expose: + - "80" + environment: + WEB_PORTS: 80 + VIRTUAL_HOST: web.nginx-proxy.tld + HTTPS_METHOD: noredirect + + +sut: + image: nginxproxy/nginx-proxy:test + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro + - ./certs/web.nginx-proxy.tld.crt:/etc/nginx/certs/web.nginx-proxy.tld.crt:ro + - ./certs/web.nginx-proxy.tld.key:/etc/nginx/certs/web.nginx-proxy.tld.key:ro diff --git a/test/test_trust-downstream-proxy/test_disabled.py b/test/test_trust-downstream-proxy/test_disabled.py new file mode 100644 index 0000000..bc9684f --- /dev/null +++ b/test/test_trust-downstream-proxy/test_disabled.py @@ -0,0 +1,20 @@ +import pytest +import re + + +@pytest.mark.parametrize('url,header,input,want', [ + ('http://web.nginx-proxy.tld/headers', 'X-Forwarded-Proto', None, 'http'), + ('http://web.nginx-proxy.tld/headers', 'X-Forwarded-Proto', 'f00', 'http'), + ('https://web.nginx-proxy.tld/headers', 'X-Forwarded-Proto', None, 'https'), + ('https://web.nginx-proxy.tld/headers', 'X-Forwarded-Proto', 'f00', 'https'), + + ('http://web.nginx-proxy.tld/headers', 'X-Forwarded-Port', None, '80'), + ('http://web.nginx-proxy.tld/headers', 'X-Forwarded-Port', '1234', '80'), + ('https://web.nginx-proxy.tld/headers', 'X-Forwarded-Port', None, '443'), + ('https://web.nginx-proxy.tld/headers', 'X-Forwarded-Port', '1234', '443'), +]) +def test_downstream_proxy_header(docker_compose, nginxproxy, url, header, input, want): + kwargs = {} if input is None else {'headers': {header: input}} + r = nginxproxy.get(url, **kwargs) + assert r.status_code == 200 + assert re.search(fr'(?m)^(?i:{re.escape(header)}): {re.escape(want)}$', r.text) diff --git a/test/test_trust-downstream-proxy/test_disabled.yml b/test/test_trust-downstream-proxy/test_disabled.yml new file mode 100644 index 0000000..860e5f9 --- /dev/null +++ b/test/test_trust-downstream-proxy/test_disabled.yml @@ -0,0 +1,18 @@ +web: + image: web + expose: + - "80" + environment: + WEB_PORTS: 80 + VIRTUAL_HOST: web.nginx-proxy.tld + HTTPS_METHOD: noredirect + + +sut: + image: nginxproxy/nginx-proxy:test + environment: + TRUST_DOWNSTREAM_PROXY: "false" + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro + - ./certs/web.nginx-proxy.tld.crt:/etc/nginx/certs/web.nginx-proxy.tld.crt:ro + - ./certs/web.nginx-proxy.tld.key:/etc/nginx/certs/web.nginx-proxy.tld.key:ro diff --git a/test/test_trust-downstream-proxy/test_enabled.py b/test/test_trust-downstream-proxy/test_enabled.py new file mode 100644 index 0000000..456d07a --- /dev/null +++ b/test/test_trust-downstream-proxy/test_enabled.py @@ -0,0 +1,20 @@ +import pytest +import re + + +@pytest.mark.parametrize('url,header,input,want', [ + ('http://web.nginx-proxy.tld/headers', 'X-Forwarded-Proto', None, 'http'), + ('http://web.nginx-proxy.tld/headers', 'X-Forwarded-Proto', 'f00', 'f00'), + ('https://web.nginx-proxy.tld/headers', 'X-Forwarded-Proto', None, 'https'), + ('https://web.nginx-proxy.tld/headers', 'X-Forwarded-Proto', 'f00', 'f00'), + + ('http://web.nginx-proxy.tld/headers', 'X-Forwarded-Port', None, '80'), + ('http://web.nginx-proxy.tld/headers', 'X-Forwarded-Port', '1234', '1234'), + ('https://web.nginx-proxy.tld/headers', 'X-Forwarded-Port', None, '443'), + ('https://web.nginx-proxy.tld/headers', 'X-Forwarded-Port', '1234', '1234'), +]) +def test_downstream_proxy_header(docker_compose, nginxproxy, url, header, input, want): + kwargs = {} if input is None else {'headers': {header: input}} + r = nginxproxy.get(url, **kwargs) + assert r.status_code == 200 + assert re.search(fr'(?m)^(?i:{re.escape(header)}): {re.escape(want)}$', r.text) diff --git a/test/test_trust-downstream-proxy/test_enabled.yml b/test/test_trust-downstream-proxy/test_enabled.yml new file mode 100644 index 0000000..7b2a8de --- /dev/null +++ b/test/test_trust-downstream-proxy/test_enabled.yml @@ -0,0 +1,18 @@ +web: + image: web + expose: + - "80" + environment: + WEB_PORTS: 80 + VIRTUAL_HOST: web.nginx-proxy.tld + HTTPS_METHOD: noredirect + + +sut: + image: nginxproxy/nginx-proxy:test + environment: + TRUST_DOWNSTREAM_PROXY: "true" + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro + - ./certs/web.nginx-proxy.tld.crt:/etc/nginx/certs/web.nginx-proxy.tld.crt:ro + - ./certs/web.nginx-proxy.tld.key:/etc/nginx/certs/web.nginx-proxy.tld.key:ro From ee0d68c34e8817ce31da7315505fd885d5e47354 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Fri, 23 Dec 2022 19:42:48 +0100 Subject: [PATCH 093/300] docs: nginx badge 1.23.2 -> 1.23.3 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 239a905..e79331d 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ [![Test](https://github.com/nginx-proxy/nginx-proxy/actions/workflows/test.yml/badge.svg)](https://github.com/nginx-proxy/nginx-proxy/actions/workflows/test.yml) [![GitHub release](https://img.shields.io/github/v/release/nginx-proxy/nginx-proxy)](https://github.com/nginx-proxy/nginx-proxy/releases) -![nginx 1.23.2](https://img.shields.io/badge/nginx-1.23.2-brightgreen.svg) +![nginx 1.23.3](https://img.shields.io/badge/nginx-1.23.3-brightgreen.svg) [![Docker Image Size](https://img.shields.io/docker/image-size/nginxproxy/nginx-proxy?sort=semver)](https://hub.docker.com/r/nginxproxy/nginx-proxy "Click to view the image on Docker Hub") [![Docker stars](https://img.shields.io/docker/stars/nginxproxy/nginx-proxy.svg)](https://hub.docker.com/r/nginxproxy/nginx-proxy 'DockerHub') [![Docker pulls](https://img.shields.io/docker/pulls/nginxproxy/nginx-proxy.svg)](https://hub.docker.com/r/nginxproxy/nginx-proxy 'DockerHub') From ba8f5a4eb84904251617d77b8d618b1513756fdc Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Fri, 23 Dec 2022 19:45:04 +0100 Subject: [PATCH 094/300] build: dockergen 0.9.1 -> 0.9.2 --- Dockerfile | 2 +- Dockerfile.alpine | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index a2332ce..1319579 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # setup build arguments for version of dependencies to use -ARG DOCKER_GEN_VERSION=0.9.1 +ARG DOCKER_GEN_VERSION=0.9.2 ARG FOREGO_VERSION=v0.17.0 # Use a specific version of golang to build both binaries diff --git a/Dockerfile.alpine b/Dockerfile.alpine index cb8597a..4e70c11 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -1,5 +1,5 @@ # setup build arguments for version of dependencies to use -ARG DOCKER_GEN_VERSION=0.9.1 +ARG DOCKER_GEN_VERSION=0.9.2 ARG FOREGO_VERSION=v0.17.0 # Use a specific version of golang to build both binaries From af877cf784829ab22eb43aa9f77083baba3eb755 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B5=8A=E9=85=92?= Date: Fri, 10 Dec 2021 13:08:18 +0800 Subject: [PATCH 095/300] feat: Add proxy header `X-Forwarded-Host` Co-authored-by: Richard Hansen --- README.md | 4 +++- nginx.tmpl | 6 ++++++ test/test_headers/test_http.py | 13 +++++++++++++ test/test_headers/test_https.py | 13 +++++++++++++ test/test_trust-downstream-proxy/test_default.py | 5 +++++ test/test_trust-downstream-proxy/test_disabled.py | 5 +++++ test/test_trust-downstream-proxy/test_enabled.py | 5 +++++ 7 files changed, 50 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 0b6229e..0ca08d7 100644 --- a/README.md +++ b/README.md @@ -369,6 +369,7 @@ By default, `nginx-proxy` forwards all incoming request headers from the client * `Proxy`: Always removed if present. This prevents attackers from using the so-called [httpoxy attack](http://httpoxy.org). There is no legitimate reason for a client to send this header, and there are many vulnerable languages / platforms (`CVE-2016-5385`, `CVE-2016-5386`, `CVE-2016-5387`, `CVE-2016-5388`, `CVE-2016-1000109`, `CVE-2016-1000110`, `CERT-VU#797896`). * `X-Real-IP`: Set to the client's IP address. * `X-Forwarded-For`: The client's IP address is appended to the value provided by the client. (If the client did not provide this header, it is set to the client's IP address.) + * `X-Forwarded-Host`: If the client did not provide this header or if the `TRUST_DOWNSTREAM_PROXY` environment variable is set to `false` (see below), this is set to the value of the `Host` header provided by the client. Otherwise, the header is forwarded to the backend server unmodified. * `X-Forwarded-Proto`: If the client did not provide this header or if the `TRUST_DOWNSTREAM_PROXY` environment variable is set to `false` (see below), this is set to `http` for plain HTTP connections and `https` for TLS connections. Otherwise, the header is forwarded to the backend server unmodified. * `X-Forwarded-Ssl`: Set to `on` if the `X-Forwarded-Proto` header sent to the backend server is `https`, otherwise set to `off`. * `X-Forwarded-Port`: If the client did not provide this header or if the `TRUST_DOWNSTREAM_PROXY` environment variable is set to `false` (see below), this is set to the port of the server that accepted the client's request. Otherwise, the header is forwarded to the backend server unmodified. @@ -376,7 +377,7 @@ By default, `nginx-proxy` forwards all incoming request headers from the client #### Trusting Downstream Proxy Headers -For legacy compatibility reasons, `nginx-proxy` forwards any client-supplied `X-Forwarded-Proto` (which affects the value of `X-Forwarded-Ssl`) and `X-Forwarded-Port` headers unchecked and unmodified. To prevent malicious clients from spoofing the protocol or port that is perceived by your backend server, you are encouraged to set the `TRUST_DOWNSTREAM_PROXY` value to `false` if: +For legacy compatibility reasons, `nginx-proxy` forwards any client-supplied `X-Forwarded-Proto` (which affects the value of `X-Forwarded-Ssl`), `X-Forwarded-Host`, and `X-Forwarded-Port` headers unchecked and unmodified. To prevent malicious clients from spoofing the protocol, hostname, or port that is perceived by your backend server, you are encouraged to set the `TRUST_DOWNSTREAM_PROXY` value to `false` if: * you do not operate a second reverse proxy downstream of `nginx-proxy`, or * you do operate a second reverse proxy downstream of `nginx-proxy` but that proxy forwards those headers unchecked from untrusted clients. @@ -400,6 +401,7 @@ proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $proxy_connection; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; +proxy_set_header X-Forwarded-Host $proxy_x_forwarded_host; proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto; proxy_set_header X-Forwarded-Ssl $proxy_x_forwarded_ssl; proxy_set_header X-Forwarded-Port $proxy_x_forwarded_port; diff --git a/nginx.tmpl b/nginx.tmpl index eaf4121..e7d77c9 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -155,6 +155,11 @@ map $http_x_forwarded_proto $proxy_x_forwarded_proto { '' $scheme; } +map $http_x_forwarded_host $proxy_x_forwarded_host { + default {{ if $trust_downstream_proxy }}$http_x_forwarded_host{{ else }}$http_host{{ end }}; + '' $http_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 { @@ -212,6 +217,7 @@ proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $proxy_connection; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; +proxy_set_header X-Forwarded-Host $proxy_x_forwarded_host; proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto; proxy_set_header X-Forwarded-Ssl $proxy_x_forwarded_ssl; proxy_set_header X-Forwarded-Port $proxy_x_forwarded_port; diff --git a/test/test_headers/test_http.py b/test/test_headers/test_http.py index 5983a10..739b455 100644 --- a/test/test_headers/test_http.py +++ b/test/test_headers/test_http.py @@ -30,6 +30,19 @@ def test_X_Forwarded_Proto_is_passed_on(docker_compose, nginxproxy): assert "X-Forwarded-Proto: f00\n" in r.text +##### Testing the handling of X-Forwarded-Host ##### + +def test_X_Forwarded_Host_is_generated(docker_compose, nginxproxy): + r = nginxproxy.get("http://web.nginx-proxy.tld/headers") + assert r.status_code == 200 + assert "X-Forwarded-Host: web.nginx-proxy.tld\n" in r.text + +def test_X_Forwarded_Host_is_passed_on(docker_compose, nginxproxy): + r = nginxproxy.get("http://web.nginx-proxy.tld/headers", headers={'X-Forwarded-Host': 'example.com'}) + assert r.status_code == 200 + assert "X-Forwarded-Host: example.com\n" in r.text + + ##### Testing the handling of X-Forwarded-Port ##### def test_X_Forwarded_Port_is_generated(docker_compose, nginxproxy): diff --git a/test/test_headers/test_https.py b/test/test_headers/test_https.py index c5457c4..7a428ae 100644 --- a/test/test_headers/test_https.py +++ b/test/test_headers/test_https.py @@ -33,6 +33,19 @@ def test_X_Forwarded_Proto_is_passed_on(docker_compose, nginxproxy): assert "X-Forwarded-Proto: f00\n" in r.text +##### Testing the handling of X-Forwarded-Host ##### + +def test_X_Forwarded_Host_is_generated(docker_compose, nginxproxy): + r = nginxproxy.get("https://web.nginx-proxy.tld/headers") + assert r.status_code == 200 + assert "X-Forwarded-Host: web.nginx-proxy.tld\n" in r.text + +def test_X_Forwarded_Host_is_passed_on(docker_compose, nginxproxy): + r = nginxproxy.get("https://web.nginx-proxy.tld/headers", headers={'X-Forwarded-Host': 'example.com'}) + assert r.status_code == 200 + assert "X-Forwarded-Host: example.com\n" in r.text + + ##### Testing the handling of X-Forwarded-Port ##### def test_X_Forwarded_Port_is_generated(docker_compose, nginxproxy): diff --git a/test/test_trust-downstream-proxy/test_default.py b/test/test_trust-downstream-proxy/test_default.py index 456d07a..f56c406 100644 --- a/test/test_trust-downstream-proxy/test_default.py +++ b/test/test_trust-downstream-proxy/test_default.py @@ -8,6 +8,11 @@ import re ('https://web.nginx-proxy.tld/headers', 'X-Forwarded-Proto', None, 'https'), ('https://web.nginx-proxy.tld/headers', 'X-Forwarded-Proto', 'f00', 'f00'), + ('http://web.nginx-proxy.tld/headers', 'X-Forwarded-Host', None, 'web.nginx-proxy.tld'), + ('http://web.nginx-proxy.tld/headers', 'X-Forwarded-Host', 'example.com', 'example.com'), + ('https://web.nginx-proxy.tld/headers', 'X-Forwarded-Host', None, 'web.nginx-proxy.tld'), + ('https://web.nginx-proxy.tld/headers', 'X-Forwarded-Host', 'example.com', 'example.com'), + ('http://web.nginx-proxy.tld/headers', 'X-Forwarded-Port', None, '80'), ('http://web.nginx-proxy.tld/headers', 'X-Forwarded-Port', '1234', '1234'), ('https://web.nginx-proxy.tld/headers', 'X-Forwarded-Port', None, '443'), diff --git a/test/test_trust-downstream-proxy/test_disabled.py b/test/test_trust-downstream-proxy/test_disabled.py index bc9684f..88c8054 100644 --- a/test/test_trust-downstream-proxy/test_disabled.py +++ b/test/test_trust-downstream-proxy/test_disabled.py @@ -8,6 +8,11 @@ import re ('https://web.nginx-proxy.tld/headers', 'X-Forwarded-Proto', None, 'https'), ('https://web.nginx-proxy.tld/headers', 'X-Forwarded-Proto', 'f00', 'https'), + ('http://web.nginx-proxy.tld/headers', 'X-Forwarded-Host', None, 'web.nginx-proxy.tld'), + ('http://web.nginx-proxy.tld/headers', 'X-Forwarded-Host', 'example.com', 'web.nginx-proxy.tld'), + ('https://web.nginx-proxy.tld/headers', 'X-Forwarded-Host', None, 'web.nginx-proxy.tld'), + ('https://web.nginx-proxy.tld/headers', 'X-Forwarded-Host', 'example.com', 'web.nginx-proxy.tld'), + ('http://web.nginx-proxy.tld/headers', 'X-Forwarded-Port', None, '80'), ('http://web.nginx-proxy.tld/headers', 'X-Forwarded-Port', '1234', '80'), ('https://web.nginx-proxy.tld/headers', 'X-Forwarded-Port', None, '443'), diff --git a/test/test_trust-downstream-proxy/test_enabled.py b/test/test_trust-downstream-proxy/test_enabled.py index 456d07a..f56c406 100644 --- a/test/test_trust-downstream-proxy/test_enabled.py +++ b/test/test_trust-downstream-proxy/test_enabled.py @@ -8,6 +8,11 @@ import re ('https://web.nginx-proxy.tld/headers', 'X-Forwarded-Proto', None, 'https'), ('https://web.nginx-proxy.tld/headers', 'X-Forwarded-Proto', 'f00', 'f00'), + ('http://web.nginx-proxy.tld/headers', 'X-Forwarded-Host', None, 'web.nginx-proxy.tld'), + ('http://web.nginx-proxy.tld/headers', 'X-Forwarded-Host', 'example.com', 'example.com'), + ('https://web.nginx-proxy.tld/headers', 'X-Forwarded-Host', None, 'web.nginx-proxy.tld'), + ('https://web.nginx-proxy.tld/headers', 'X-Forwarded-Host', 'example.com', 'example.com'), + ('http://web.nginx-proxy.tld/headers', 'X-Forwarded-Port', None, '80'), ('http://web.nginx-proxy.tld/headers', 'X-Forwarded-Port', '1234', '1234'), ('https://web.nginx-proxy.tld/headers', 'X-Forwarded-Port', None, '443'), From 146b7933a955811bd15597195397c58f0a47f4f9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 11 Jan 2023 04:03:07 +0000 Subject: [PATCH 096/300] chore(deps): bump golang from 1.19.4 to 1.19.5 Bumps golang from 1.19.4 to 1.19.5. --- updated-dependencies: - dependency-name: golang dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Dockerfile | 2 +- Dockerfile.alpine | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 1319579..fa227cf 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,7 +3,7 @@ ARG DOCKER_GEN_VERSION=0.9.2 ARG FOREGO_VERSION=v0.17.0 # Use a specific version of golang to build both binaries -FROM golang:1.19.4 as gobuilder +FROM golang:1.19.5 as gobuilder # Build docker-gen from scratch FROM gobuilder as dockergen diff --git a/Dockerfile.alpine b/Dockerfile.alpine index 4e70c11..5473e53 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -3,7 +3,7 @@ ARG DOCKER_GEN_VERSION=0.9.2 ARG FOREGO_VERSION=v0.17.0 # Use a specific version of golang to build both binaries -FROM golang:1.19.4-alpine as gobuilder +FROM golang:1.19.5-alpine as gobuilder RUN apk add --no-cache git musl-dev # Build docker-gen from scratch From 831615fdd4cf2267257462691882105dde83f759 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 13 Jan 2023 04:04:20 +0000 Subject: [PATCH 097/300] chore(deps): bump requests from 2.28.1 to 2.28.2 in /test/requirements Bumps [requests](https://github.com/psf/requests) from 2.28.1 to 2.28.2. - [Release notes](https://github.com/psf/requests/releases) - [Changelog](https://github.com/psf/requests/blob/main/HISTORY.md) - [Commits](https://github.com/psf/requests/compare/v2.28.1...v2.28.2) --- updated-dependencies: - dependency-name: requests dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- test/requirements/python-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/requirements/python-requirements.txt b/test/requirements/python-requirements.txt index c75a674..995cd1e 100644 --- a/test/requirements/python-requirements.txt +++ b/test/requirements/python-requirements.txt @@ -2,4 +2,4 @@ backoff==2.2.1 docker-compose==1.29.2 docker==6.0.1 pytest==7.2.0 -requests==2.28.1 +requests==2.28.2 From 9c9545bf7f936bb9c96e426baf560b56f8c4db5d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 Jan 2023 04:12:49 +0000 Subject: [PATCH 098/300] chore(deps): bump pytest from 7.2.0 to 7.2.1 in /test/requirements Bumps [pytest](https://github.com/pytest-dev/pytest) from 7.2.0 to 7.2.1. - [Release notes](https://github.com/pytest-dev/pytest/releases) - [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst) - [Commits](https://github.com/pytest-dev/pytest/compare/7.2.0...7.2.1) --- updated-dependencies: - dependency-name: pytest dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- test/requirements/python-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/requirements/python-requirements.txt b/test/requirements/python-requirements.txt index 995cd1e..6d7d495 100644 --- a/test/requirements/python-requirements.txt +++ b/test/requirements/python-requirements.txt @@ -1,5 +1,5 @@ backoff==2.2.1 docker-compose==1.29.2 docker==6.0.1 -pytest==7.2.0 +pytest==7.2.1 requests==2.28.2 From c117ae8fd8cb9b9e2b082ac70ab9d92c63b7b340 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Mon, 28 Mar 2022 01:03:04 -0400 Subject: [PATCH 099/300] chore: Use boolean for `$server_found` variable --- nginx.tmpl | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/nginx.tmpl b/nginx.tmpl index e7d77c9..33df00a 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -90,7 +90,7 @@ {{ $networks := .Networks }} {{ $debug_all := .Debug }} upstream {{ .Upstream }} { - {{ $server_found := "false" }} + {{ $server_found := false }} {{ range $container := .Containers }} {{ $debug := (eq (coalesce $container.Env.DEBUG $debug_all "false") "true") }} {{/* If only 1 port exposed, use that as a default, else 80 */}} @@ -112,19 +112,19 @@ upstream {{ .Upstream }} { {{ if $address }} {{/* If we got the containers from swarm and this container's port is published to host, use host IP:PORT */}} {{ if and $container.Node.ID $address.HostPort }} - {{ $server_found = "true" }} + {{ $server_found = true }} # {{ $container.Node.Name }}/{{ $container.Name }} server {{ $container.Node.Address.IP }}:{{ $address.HostPort }}; {{/* If there is no swarm node or the port is not published on host, use container's IP:PORT */}} {{ else if $containerNetwork }} - {{ $server_found = "true" }} + {{ $server_found = true }} # {{ $container.Name }} server {{ $containerNetwork.IP }}:{{ $address.Port }}; {{ end }} {{ else if $containerNetwork }} # {{ $container.Name }} {{ if $containerNetwork.IP }} - {{ $server_found = "true" }} + {{ $server_found = true }} server {{ $containerNetwork.IP }}:{{ $port }}; {{ else }} # /!\ No IP for this network! @@ -137,7 +137,7 @@ upstream {{ .Upstream }} { {{ end }} {{ end }} {{/* nginx-proxy/nginx-proxy#1105 */}} - {{ if (eq $server_found "false") }} + {{ if not $server_found }} # Fallback entry server 127.0.0.1 down; {{ end }} From 05423c681af6e50e958f46e056dc126941ed6784 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Mon, 28 Mar 2022 01:04:20 -0400 Subject: [PATCH 100/300] fix: Use `parseBool` to parse boolean strings --- nginx.tmpl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nginx.tmpl b/nginx.tmpl index 33df00a..14616d4 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -92,7 +92,7 @@ upstream {{ .Upstream }} { {{ $server_found := false }} {{ range $container := .Containers }} - {{ $debug := (eq (coalesce $container.Env.DEBUG $debug_all "false") "true") }} + {{ $debug := parseBool (coalesce $container.Env.DEBUG $debug_all "false") }} {{/* If only 1 port exposed, use that as a default, else 80 */}} {{ $defaultPort := (when (eq (len $container.Addresses) 1) (first $container.Addresses) (dict "Port" "80")).Port }} {{ $port := (coalesce $container.Env.VIRTUAL_PORT $defaultPort) }} @@ -229,7 +229,7 @@ proxy_set_header Proxy ""; {{ $access_log := (or (and (not $.Env.DISABLE_ACCESS_LOGS) "access_log /var/log/nginx/access.log vhost;") "") }} -{{ $enable_ipv6 := eq (or ($.Env.ENABLE_IPV6) "") "true" }} +{{ $enable_ipv6 := parseBool (coalesce $.Env.ENABLE_IPV6 "false") }} server { server_name _; # This is just an invalid value which will never trigger on a real hostname. server_tokens off; From 14d0f3f222b0d6e627c23bebc80878d79b475d58 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Mon, 28 Mar 2022 02:13:16 -0400 Subject: [PATCH 101/300] chore: Rename `$container` to `$containers` The value is actually a slice/array of containers so it should be pluralized. --- nginx.tmpl | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/nginx.tmpl b/nginx.tmpl index 14616d4..10dd720 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -397,15 +397,15 @@ server { {{ $network_tag := or (first (groupByKeys $containers "Env.NETWORK_ACCESS")) "external" }} {{ template "location" (dict "Path" "/" "Proto" $proto "Upstream" $upstream_name "Host" $host "VhostRoot" $vhost_root "Dest" "" "NetworkTag" $network_tag) }} {{ else }} - {{ range $path, $container := $paths }} + {{ range $path, $containers := $paths }} {{/* Get the VIRTUAL_PROTO defined by containers w/ the same vhost-vpath, falling back to "http" */}} - {{ $proto := trim (or (first (groupByKeys $container "Env.VIRTUAL_PROTO")) "http") }} + {{ $proto := trim (or (first (groupByKeys $containers "Env.VIRTUAL_PROTO")) "http") }} {{/* Get the NETWORK_ACCESS defined by containers w/ the same vhost, falling back to "external" */}} - {{ $network_tag := or (first (groupByKeys $container "Env.NETWORK_ACCESS")) "external" }} + {{ $network_tag := or (first (groupByKeys $containers "Env.NETWORK_ACCESS")) "external" }} {{ $sum := sha1 $path }} {{ $upstream := printf "%s-%s" $upstream_name $sum }} - {{ $dest := (or (first (groupByKeys $container "Env.VIRTUAL_DEST")) "") }} + {{ $dest := (or (first (groupByKeys $containers "Env.VIRTUAL_DEST")) "") }} {{ template "location" (dict "Path" $path "Proto" $proto "Upstream" $upstream "Host" $host "VhostRoot" $vhost_root "Dest" $dest "NetworkTag" $network_tag) }} {{ end }} {{ if (not (contains $paths "/")) }} @@ -445,15 +445,15 @@ server { {{ $network_tag := or (first (groupByKeys $containers "Env.NETWORK_ACCESS")) "external" }} {{ template "location" (dict "Path" "/" "Proto" $proto "Upstream" $upstream_name "Host" $host "VhostRoot" $vhost_root "Dest" "" "NetworkTag" $network_tag) }} {{ else }} - {{ range $path, $container := $paths }} + {{ range $path, $containers := $paths }} {{/* Get the VIRTUAL_PROTO defined by containers w/ the same vhost-vpath, falling back to "http" */}} - {{ $proto := trim (or (first (groupByKeys $container "Env.VIRTUAL_PROTO")) "http") }} + {{ $proto := trim (or (first (groupByKeys $containers "Env.VIRTUAL_PROTO")) "http") }} {{/* Get the NETWORK_ACCESS defined by containers w/ the same vhost, falling back to "external" */}} - {{ $network_tag := or (first (groupByKeys $container "Env.NETWORK_ACCESS")) "external" }} + {{ $network_tag := or (first (groupByKeys $containers "Env.NETWORK_ACCESS")) "external" }} {{ $sum := sha1 $path }} {{ $upstream := printf "%s-%s" $upstream_name $sum }} - {{ $dest := (or (first (groupByKeys $container "Env.VIRTUAL_DEST")) "") }} + {{ $dest := (or (first (groupByKeys $containers "Env.VIRTUAL_DEST")) "") }} {{ template "location" (dict "Path" $path "Proto" $proto "Upstream" $upstream "Host" $host "VhostRoot" $vhost_root "Dest" $dest "NetworkTag" $network_tag) }} {{ end }} {{ if (not (contains $paths "/")) }} From 491642b1e92cb1c058ebd72d6bc0074eec6af387 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Tue, 5 Apr 2022 04:59:54 -0400 Subject: [PATCH 102/300] chore: Factor out duplicate virtual path code --- nginx.tmpl | 52 ++++++++++++++++++++++------------------------------ 1 file changed, 22 insertions(+), 30 deletions(-) diff --git a/nginx.tmpl b/nginx.tmpl index 10dd720..c2409e1 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -269,15 +269,17 @@ server { {{ $nPaths := len $paths }} {{ if eq $nPaths 0 }} - # {{ $host }} - {{ template "upstream" (dict "Upstream" $upstream_name "Containers" $containers "Networks" $CurrentContainer.Networks "Debug" $debug_all) }} -{{ else }} - {{ range $path, $containers := $paths }} + {{ $paths = dict "/" $containers }} +{{ end }} + +{{ range $path, $containers := $paths }} + {{ $upstream := $upstream_name }} + {{ if gt $nPaths 0 }} {{ $sum := sha1 $path }} - {{ $upstream := printf "%s-%s" $upstream_name $sum }} + {{ $upstream = printf "%s-%s" $upstream $sum }} + {{ end }} # {{ $host }}{{ $path }} {{ template "upstream" (dict "Upstream" $upstream "Containers" $containers "Networks" $CurrentContainer.Networks "Debug" $debug_all) }} - {{ end }} {{ end }} {{ $default_host := or ($.Env.DEFAULT_HOST) "" }} @@ -389,23 +391,19 @@ server { include /etc/nginx/vhost.d/default; {{ end }} - {{ if eq $nPaths 0 }} - {{/* Get the VIRTUAL_PROTO defined by containers w/ the same vhost, falling back to "http" */}} - {{ $proto := trim (or (first (groupByKeys $containers "Env.VIRTUAL_PROTO")) "http") }} - - {{/* Get the NETWORK_ACCESS defined by containers w/ the same vhost, falling back to "external" */}} - {{ $network_tag := or (first (groupByKeys $containers "Env.NETWORK_ACCESS")) "external" }} - {{ template "location" (dict "Path" "/" "Proto" $proto "Upstream" $upstream_name "Host" $host "VhostRoot" $vhost_root "Dest" "" "NetworkTag" $network_tag) }} - {{ else }} {{ range $path, $containers := $paths }} {{/* Get the VIRTUAL_PROTO defined by containers w/ the same vhost-vpath, falling back to "http" */}} {{ $proto := trim (or (first (groupByKeys $containers "Env.VIRTUAL_PROTO")) "http") }} {{/* Get the NETWORK_ACCESS defined by containers w/ the same vhost, falling back to "external" */}} {{ $network_tag := or (first (groupByKeys $containers "Env.NETWORK_ACCESS")) "external" }} - {{ $sum := sha1 $path }} - {{ $upstream := printf "%s-%s" $upstream_name $sum }} - {{ $dest := (or (first (groupByKeys $containers "Env.VIRTUAL_DEST")) "") }} + {{ $upstream := $upstream_name }} + {{ $dest := "" }} + {{ if gt $nPaths 0 }} + {{ $sum := sha1 $path }} + {{ $upstream = printf "%s-%s" $upstream $sum }} + {{ $dest = (or (first (groupByKeys $containers "Env.VIRTUAL_DEST")) "") }} + {{ end }} {{ template "location" (dict "Path" $path "Proto" $proto "Upstream" $upstream "Host" $host "VhostRoot" $vhost_root "Dest" $dest "NetworkTag" $network_tag) }} {{ end }} {{ if (not (contains $paths "/")) }} @@ -413,7 +411,6 @@ server { return {{ $default_root_response }}; } {{ end }} - {{ end }} } {{ end }} @@ -437,23 +434,19 @@ server { include /etc/nginx/vhost.d/default; {{ end }} - {{ if eq $nPaths 0 }} - {{/* Get the VIRTUAL_PROTO defined by containers w/ the same vhost, falling back to "http" */}} - {{ $proto := trim (or (first (groupByKeys $containers "Env.VIRTUAL_PROTO")) "http") }} - - {{/* Get the NETWORK_ACCESS defined by containers w/ the same vhost, falling back to "external" */}} - {{ $network_tag := or (first (groupByKeys $containers "Env.NETWORK_ACCESS")) "external" }} - {{ template "location" (dict "Path" "/" "Proto" $proto "Upstream" $upstream_name "Host" $host "VhostRoot" $vhost_root "Dest" "" "NetworkTag" $network_tag) }} - {{ else }} {{ range $path, $containers := $paths }} {{/* Get the VIRTUAL_PROTO defined by containers w/ the same vhost-vpath, falling back to "http" */}} {{ $proto := trim (or (first (groupByKeys $containers "Env.VIRTUAL_PROTO")) "http") }} {{/* Get the NETWORK_ACCESS defined by containers w/ the same vhost, falling back to "external" */}} {{ $network_tag := or (first (groupByKeys $containers "Env.NETWORK_ACCESS")) "external" }} - {{ $sum := sha1 $path }} - {{ $upstream := printf "%s-%s" $upstream_name $sum }} - {{ $dest := (or (first (groupByKeys $containers "Env.VIRTUAL_DEST")) "") }} + {{ $upstream := $upstream_name }} + {{ $dest := "" }} + {{ if gt $nPaths 0 }} + {{ $sum := sha1 $path }} + {{ $upstream = printf "%s-%s" $upstream $sum }} + {{ $dest = (or (first (groupByKeys $containers "Env.VIRTUAL_DEST")) "") }} + {{ end }} {{ template "location" (dict "Path" $path "Proto" $proto "Upstream" $upstream "Host" $host "VhostRoot" $vhost_root "Dest" $dest "NetworkTag" $network_tag) }} {{ end }} {{ if (not (contains $paths "/")) }} @@ -461,7 +454,6 @@ server { return {{ $default_root_response }}; } {{ end }} - {{ end }} } {{ if (and (not $is_https) (exists "/etc/nginx/certs/default.crt") (exists "/etc/nginx/certs/default.key")) }} From 744bd82c5491e46f1ab2bfc7ad803edd1bb37b9b Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Tue, 19 Apr 2022 15:37:53 -0400 Subject: [PATCH 103/300] chore: Combine identical HTTP and HTTPS servers --- nginx.tmpl | 72 ++++++++++++------------------------------------------ 1 file changed, 16 insertions(+), 56 deletions(-) diff --git a/nginx.tmpl b/nginx.tmpl index c2409e1..a262a96 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -239,25 +239,19 @@ server { {{ end }} {{ $access_log }} return 503; -} {{ if (and (exists "/etc/nginx/certs/default.crt") (exists "/etc/nginx/certs/default.key")) }} -server { - server_name _; # This is just an invalid value which will never trigger on a real hostname. - server_tokens off; listen {{ $external_https_port }} ssl http2; {{ if $enable_ipv6 }} listen [::]:{{ $external_https_port }} ssl http2; {{ end }} - {{ $access_log }} - return 503; ssl_session_cache shared:SSL:50m; ssl_session_tickets off; ssl_certificate /etc/nginx/certs/default.crt; ssl_certificate_key /etc/nginx/certs/default.key; -} {{ end }} +} {{ range $host, $containers := groupByMulti $ "Env.VIRTUAL_HOST" "," }} @@ -317,9 +311,7 @@ server { {{ $is_https := (and (ne $https_method "nohttps") (ne $cert "") (exists (printf "/etc/nginx/certs/%s.crt" $cert)) (exists (printf "/etc/nginx/certs/%s.key" $cert))) }} -{{ if $is_https }} - -{{ if eq $https_method "redirect" }} +{{ if and $is_https (eq $https_method "redirect") }} server { server_name {{ $host }}; {{ if $server_tokens }} @@ -356,11 +348,18 @@ server { {{ if $server_tokens }} server_tokens {{ $server_tokens }}; {{ end }} + {{ $access_log }} + {{- if or (not $is_https) (eq $https_method "noredirect") }} + listen {{ $external_http_port }} {{ $default_server }}; + {{ if $enable_ipv6 }} + listen [::]:{{ $external_http_port }} {{ $default_server }}; + {{ end }} + {{- end }} + {{- if $is_https }} listen {{ $external_https_port }} ssl http2 {{ $default_server }}; {{ if $enable_ipv6 }} listen [::]:{{ $external_https_port }} ssl http2 {{ $default_server }}; {{ end }} - {{ $access_log }} {{ template "ssl_policy" (dict "ssl_policy" $ssl_policy) }} @@ -382,51 +381,13 @@ server { {{ end }} {{ if (not (or (eq $https_method "noredirect") (eq $hsts "off"))) }} - add_header Strict-Transport-Security "{{ trim $hsts }}" always; + set $sts_header ""; + if ($https) { + set $sts_header "{{ trim $hsts }}"; + } + add_header Strict-Transport-Security $sts_header always; {{ end }} - - {{ if (exists (printf "/etc/nginx/vhost.d/%s" $host)) }} - include {{ printf "/etc/nginx/vhost.d/%s" $host }}; - {{ else if (exists "/etc/nginx/vhost.d/default") }} - include /etc/nginx/vhost.d/default; - {{ end }} - - {{ range $path, $containers := $paths }} - {{/* Get the VIRTUAL_PROTO defined by containers w/ the same vhost-vpath, falling back to "http" */}} - {{ $proto := trim (or (first (groupByKeys $containers "Env.VIRTUAL_PROTO")) "http") }} - - {{/* Get the NETWORK_ACCESS defined by containers w/ the same vhost, falling back to "external" */}} - {{ $network_tag := or (first (groupByKeys $containers "Env.NETWORK_ACCESS")) "external" }} - {{ $upstream := $upstream_name }} - {{ $dest := "" }} - {{ if gt $nPaths 0 }} - {{ $sum := sha1 $path }} - {{ $upstream = printf "%s-%s" $upstream $sum }} - {{ $dest = (or (first (groupByKeys $containers "Env.VIRTUAL_DEST")) "") }} - {{ end }} - {{ template "location" (dict "Path" $path "Proto" $proto "Upstream" $upstream "Host" $host "VhostRoot" $vhost_root "Dest" $dest "NetworkTag" $network_tag) }} - {{ end }} - {{ if (not (contains $paths "/")) }} - location / { - return {{ $default_root_response }}; - } - {{ end }} -} - -{{ end }} - -{{ if or (not $is_https) (eq $https_method "noredirect") }} - -server { - server_name {{ $host }}; - {{ if $server_tokens }} - server_tokens {{ $server_tokens }}; - {{ end }} - listen {{ $external_http_port }} {{ $default_server }}; - {{ if $enable_ipv6 }} - listen [::]:{{ $external_http_port }} {{ $default_server }}; - {{ end }} - {{ $access_log }} + {{- end }} {{ if (exists (printf "/etc/nginx/vhost.d/%s" $host)) }} include {{ printf "/etc/nginx/vhost.d/%s" $host }}; @@ -475,4 +436,3 @@ server { {{ end }} {{ end }} -{{ end }} From 4651bf411d05b196f75b6af448ef4b33742d0b6e Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Mon, 28 Mar 2022 02:49:58 -0400 Subject: [PATCH 104/300] chore: Fix comment for `$proxy_connection` variable --- nginx.tmpl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nginx.tmpl b/nginx.tmpl index a262a96..68fd3bb 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -167,8 +167,8 @@ map $http_x_forwarded_port $proxy_x_forwarded_port { '' $server_port; } -# If we receive Upgrade, set Connection to "upgrade"; otherwise, delete any -# Connection header that may have been passed to this server +# If we receive Upgrade, set Connection to "upgrade"; otherwise, preserve +# NGINX's default behavior ("Connection: close"). map $http_upgrade $proxy_connection { default upgrade; '' close; From d6d8b2205fcc5e87bf21581cf6a466ce9ba62b1d Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Tue, 17 May 2022 00:47:40 -0400 Subject: [PATCH 105/300] chore: Fix comment terminators --- nginx.tmpl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nginx.tmpl b/nginx.tmpl index 68fd3bb..cf2fd2c 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -11,8 +11,8 @@ {{ define "ssl_policy" }} {{ if eq .ssl_policy "Mozilla-Modern" }} ssl_protocols TLSv1.3; - {{/* nginx currently lacks ability to choose ciphers in TLS 1.3 in configuration, see https://trac.nginx.org/nginx/ticket/1529 /*}} - {{/* a possible workaround can be modify /etc/ssl/openssl.cnf to change it globally (see https://trac.nginx.org/nginx/ticket/1529#comment:12 ) /*}} + {{/* nginx currently lacks ability to choose ciphers in TLS 1.3 in configuration, see https://trac.nginx.org/nginx/ticket/1529 */}} + {{/* a possible workaround can be modify /etc/ssl/openssl.cnf to change it globally (see https://trac.nginx.org/nginx/ticket/1529#comment:12 ) */}} {{/* explicitly set ngnix default value in order to allow single servers to override the global http value */}} ssl_ciphers HIGH:!aNULL:!MD5; ssl_prefer_server_ciphers off; From f20662eeaa877c577bd5712190234ce819dfdef0 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Tue, 17 May 2022 00:56:06 -0400 Subject: [PATCH 106/300] chore: Use `{{-` instead of `{{` to clean up whitespace --- nginx.tmpl | 368 ++++++++++++++++++++++++++--------------------------- 1 file changed, 184 insertions(+), 184 deletions(-) diff --git a/nginx.tmpl b/nginx.tmpl index cf2fd2c..a320def 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -1,152 +1,152 @@ -{{ $CurrentContainer := where $ "ID" .Docker.CurrentContainerID | first }} +{{- $CurrentContainer := where $ "ID" .Docker.CurrentContainerID | first }} -{{ $nginx_proxy_version := coalesce $.Env.NGINX_PROXY_VERSION "" }} -{{ $external_http_port := coalesce $.Env.HTTP_PORT "80" }} -{{ $external_https_port := coalesce $.Env.HTTPS_PORT "443" }} -{{ $debug_all := $.Env.DEBUG }} -{{ $sha1_upstream_name := parseBool (coalesce $.Env.SHA1_UPSTREAM_NAME "false") }} -{{ $default_root_response := coalesce $.Env.DEFAULT_ROOT "404" }} -{{ $trust_downstream_proxy := parseBool (coalesce $.Env.TRUST_DOWNSTREAM_PROXY "true") }} +{{- $nginx_proxy_version := coalesce $.Env.NGINX_PROXY_VERSION "" }} +{{- $external_http_port := coalesce $.Env.HTTP_PORT "80" }} +{{- $external_https_port := coalesce $.Env.HTTPS_PORT "443" }} +{{- $debug_all := $.Env.DEBUG }} +{{- $sha1_upstream_name := parseBool (coalesce $.Env.SHA1_UPSTREAM_NAME "false") }} +{{- $default_root_response := coalesce $.Env.DEFAULT_ROOT "404" }} +{{- $trust_downstream_proxy := parseBool (coalesce $.Env.TRUST_DOWNSTREAM_PROXY "true") }} -{{ define "ssl_policy" }} - {{ if eq .ssl_policy "Mozilla-Modern" }} +{{- define "ssl_policy" }} + {{- if eq .ssl_policy "Mozilla-Modern" }} ssl_protocols TLSv1.3; - {{/* nginx currently lacks ability to choose ciphers in TLS 1.3 in configuration, see https://trac.nginx.org/nginx/ticket/1529 */}} - {{/* a possible workaround can be modify /etc/ssl/openssl.cnf to change it globally (see https://trac.nginx.org/nginx/ticket/1529#comment:12 ) */}} - {{/* explicitly set ngnix default value in order to allow single servers to override the global http value */}} + {{- /* nginx currently lacks ability to choose ciphers in TLS 1.3 in configuration, see https://trac.nginx.org/nginx/ticket/1529 */}} + {{- /* a possible workaround can be modify /etc/ssl/openssl.cnf to change it globally (see https://trac.nginx.org/nginx/ticket/1529#comment:12 ) */}} + {{- /* explicitly set ngnix default value in order to allow single servers to override the global http value */}} ssl_ciphers HIGH:!aNULL:!MD5; ssl_prefer_server_ciphers off; - {{ else if eq .ssl_policy "Mozilla-Intermediate" }} + {{- else if eq .ssl_policy "Mozilla-Intermediate" }} ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384'; ssl_prefer_server_ciphers off; - {{ else if eq .ssl_policy "Mozilla-Old" }} + {{- else if eq .ssl_policy "Mozilla-Old" }} ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA256:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA'; ssl_prefer_server_ciphers on; - {{ else if eq .ssl_policy "AWS-TLS-1-2-2017-01" }} + {{- else if eq .ssl_policy "AWS-TLS-1-2-2017-01" }} ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:AES128-GCM-SHA256:AES128-SHA256:AES256-GCM-SHA384:AES256-SHA256'; ssl_prefer_server_ciphers on; - {{ else if eq .ssl_policy "AWS-TLS-1-1-2017-01" }} + {{- else if eq .ssl_policy "AWS-TLS-1-1-2017-01" }} ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3; ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:AES128-GCM-SHA256:AES128-SHA256:AES128-SHA:AES256-GCM-SHA384:AES256-SHA256:AES256-SHA'; ssl_prefer_server_ciphers on; - {{ else if eq .ssl_policy "AWS-2016-08" }} + {{- else if eq .ssl_policy "AWS-2016-08" }} ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:AES128-GCM-SHA256:AES128-SHA256:AES128-SHA:AES256-GCM-SHA384:AES256-SHA256:AES256-SHA'; ssl_prefer_server_ciphers on; - {{ else if eq .ssl_policy "AWS-2015-05" }} + {{- else if eq .ssl_policy "AWS-2015-05" }} ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:AES128-GCM-SHA256:AES128-SHA256:AES128-SHA:AES256-GCM-SHA384:AES256-SHA256:AES256-SHA:DES-CBC3-SHA'; ssl_prefer_server_ciphers on; - {{ else if eq .ssl_policy "AWS-2015-03" }} + {{- else if eq .ssl_policy "AWS-2015-03" }} ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:AES128-GCM-SHA256:AES128-SHA256:AES128-SHA:AES256-GCM-SHA384:AES256-SHA256:AES256-SHA:DHE-DSS-AES128-SHA:DES-CBC3-SHA'; ssl_prefer_server_ciphers on; - {{ else if eq .ssl_policy "AWS-2015-02" }} + {{- else if eq .ssl_policy "AWS-2015-02" }} ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:AES128-GCM-SHA256:AES128-SHA256:AES128-SHA:AES256-GCM-SHA384:AES256-SHA256:AES256-SHA:DHE-DSS-AES128-SHA'; ssl_prefer_server_ciphers on; - {{ end }} -{{ end }} + {{- end }} +{{- end }} -{{ define "location" }} +{{- define "location" }} location {{ .Path }} { - {{ if eq .NetworkTag "internal" }} + {{- if eq .NetworkTag "internal" }} # Only allow traffic from internal clients include /etc/nginx/network_internal.conf; - {{ end }} + {{- end }} - {{ if eq .Proto "uwsgi" }} + {{- if eq .Proto "uwsgi" }} include uwsgi_params; uwsgi_pass {{ trim .Proto }}://{{ trim .Upstream }}; - {{ else if eq .Proto "fastcgi" }} + {{- else if eq .Proto "fastcgi" }} root {{ trim .VhostRoot }}; include fastcgi_params; fastcgi_pass {{ trim .Upstream }}; - {{ else if eq .Proto "grpc" }} + {{- else if eq .Proto "grpc" }} grpc_pass {{ trim .Proto }}://{{ trim .Upstream }}; - {{ else }} + {{- else }} proxy_pass {{ trim .Proto }}://{{ trim .Upstream }}{{ trim .Dest }}; - {{ end }} + {{- end }} - {{ if (exists (printf "/etc/nginx/htpasswd/%s" .Host)) }} + {{- if (exists (printf "/etc/nginx/htpasswd/%s" .Host)) }} auth_basic "Restricted {{ .Host }}"; auth_basic_user_file {{ (printf "/etc/nginx/htpasswd/%s" .Host) }}; - {{ end }} + {{- end }} - {{ if (exists (printf "/etc/nginx/vhost.d/%s_%s_location" .Host (sha1 .Path) )) }} + {{- if (exists (printf "/etc/nginx/vhost.d/%s_%s_location" .Host (sha1 .Path) )) }} include {{ printf "/etc/nginx/vhost.d/%s_%s_location" .Host (sha1 .Path) }}; - {{ else if (exists (printf "/etc/nginx/vhost.d/%s_location" .Host)) }} + {{- else if (exists (printf "/etc/nginx/vhost.d/%s_location" .Host)) }} include {{ printf "/etc/nginx/vhost.d/%s_location" .Host}}; - {{ else if (exists "/etc/nginx/vhost.d/default_location") }} + {{- else if (exists "/etc/nginx/vhost.d/default_location") }} include /etc/nginx/vhost.d/default_location; - {{ end }} + {{- end }} } -{{ end }} +{{- end }} -{{ define "upstream" }} - {{ $networks := .Networks }} - {{ $debug_all := .Debug }} +{{- define "upstream" }} + {{- $networks := .Networks }} + {{- $debug_all := .Debug }} upstream {{ .Upstream }} { - {{ $server_found := false }} - {{ range $container := .Containers }} - {{ $debug := parseBool (coalesce $container.Env.DEBUG $debug_all "false") }} - {{/* If only 1 port exposed, use that as a default, else 80 */}} - {{ $defaultPort := (when (eq (len $container.Addresses) 1) (first $container.Addresses) (dict "Port" "80")).Port }} - {{ $port := (coalesce $container.Env.VIRTUAL_PORT $defaultPort) }} - {{ $address := where $container.Addresses "Port" $port | first }} - {{ if $debug }} + {{- $server_found := false }} + {{- range $container := .Containers }} + {{- $debug := parseBool (coalesce $container.Env.DEBUG $debug_all "false") }} + {{- /* If only 1 port exposed, use that as a default, else 80 */}} + {{- $defaultPort := (when (eq (len $container.Addresses) 1) (first $container.Addresses) (dict "Port" "80")).Port }} + {{- $port := (coalesce $container.Env.VIRTUAL_PORT $defaultPort) }} + {{- $address := where $container.Addresses "Port" $port | first }} + {{- if $debug }} # Exposed ports: {{ $container.Addresses }} # Default virtual port: {{ $defaultPort }} # VIRTUAL_PORT: {{ $container.Env.VIRTUAL_PORT }} - {{ if not $address }} + {{- if not $address }} # /!\ Virtual port not exposed - {{ end }} - {{ end }} - {{ range $knownNetwork := $networks }} - {{ range $containerNetwork := sortObjectsByKeysAsc $container.Networks "Name" }} - {{ if (and (ne $containerNetwork.Name "ingress") (or (eq $knownNetwork.Name $containerNetwork.Name) (eq $knownNetwork.Name "host"))) }} + {{- end }} + {{- end }} + {{- range $knownNetwork := $networks }} + {{- range $containerNetwork := sortObjectsByKeysAsc $container.Networks "Name" }} + {{- if (and (ne $containerNetwork.Name "ingress") (or (eq $knownNetwork.Name $containerNetwork.Name) (eq $knownNetwork.Name "host"))) }} ## Can be connected with "{{ $containerNetwork.Name }}" network - {{ if $address }} - {{/* If we got the containers from swarm and this container's port is published to host, use host IP:PORT */}} - {{ if and $container.Node.ID $address.HostPort }} - {{ $server_found = true }} + {{- if $address }} + {{- /* If we got the containers from swarm and this container's port is published to host, use host IP:PORT */}} + {{- if and $container.Node.ID $address.HostPort }} + {{- $server_found = true }} # {{ $container.Node.Name }}/{{ $container.Name }} server {{ $container.Node.Address.IP }}:{{ $address.HostPort }}; - {{/* If there is no swarm node or the port is not published on host, use container's IP:PORT */}} - {{ else if $containerNetwork }} - {{ $server_found = true }} + {{- /* If there is no swarm node or the port is not published on host, use container's IP:PORT */}} + {{- else if $containerNetwork }} + {{- $server_found = true }} # {{ $container.Name }} server {{ $containerNetwork.IP }}:{{ $address.Port }}; - {{ end }} - {{ else if $containerNetwork }} + {{- end }} + {{- else if $containerNetwork }} # {{ $container.Name }} - {{ if $containerNetwork.IP }} - {{ $server_found = true }} + {{- if $containerNetwork.IP }} + {{- $server_found = true }} server {{ $containerNetwork.IP }}:{{ $port }}; - {{ else }} + {{- else }} # /!\ No IP for this network! - {{ end }} - {{ end }} - {{ else }} + {{- end }} + {{- end }} + {{- else }} # Cannot connect to network '{{ $containerNetwork.Name }}' of this container - {{ end }} - {{ end }} - {{ end }} - {{ end }} - {{/* nginx-proxy/nginx-proxy#1105 */}} - {{ if not $server_found }} + {{- end }} + {{- end }} + {{- end }} + {{- end }} + {{- /* nginx-proxy/nginx-proxy#1105 */}} + {{- if not $server_found }} # Fallback entry server 127.0.0.1 down; - {{ end }} + {{- end }} } -{{ end }} +{{- end }} -{{ if ne $nginx_proxy_version "" }} +{{- if ne $nginx_proxy_version "" }} # nginx-proxy version : {{ $nginx_proxy_version }} -{{ end }} +{{- end }} # If we receive X-Forwarded-Proto, pass it through; otherwise, pass along the # scheme used to connect to this server @@ -178,9 +178,9 @@ map $http_upgrade $proxy_connection { server_names_hash_bucket_size 128; # Default dhparam -{{ if (exists "/etc/nginx/dhparam/dhparam.pem") }} +{{- if (exists "/etc/nginx/dhparam/dhparam.pem") }} ssl_dhparam /etc/nginx/dhparam/dhparam.pem; -{{ end }} +{{- end }} # Set appropriate X-Forwarded-Ssl header based on $proxy_x_forwarded_proto map $proxy_x_forwarded_proto $proxy_x_forwarded_ssl { @@ -197,18 +197,18 @@ log_format vhost '$host $remote_addr - $remote_user [$time_local] ' access_log off; -{{/* Get the SSL_POLICY defined by this container, falling back to "Mozilla-Intermediate" */}} -{{ $ssl_policy := or ($.Env.SSL_POLICY) "Mozilla-Intermediate" }} -{{ template "ssl_policy" (dict "ssl_policy" $ssl_policy) }} +{{- /* Get the SSL_POLICY defined by this container, falling back to "Mozilla-Intermediate" */}} +{{- $ssl_policy := or ($.Env.SSL_POLICY) "Mozilla-Intermediate" }} +{{- template "ssl_policy" (dict "ssl_policy" $ssl_policy) }} error_log /dev/stderr; -{{ if $.Env.RESOLVERS }} +{{- if $.Env.RESOLVERS }} resolver {{ $.Env.RESOLVERS }}; -{{ end }} +{{- end }} -{{ if (exists "/etc/nginx/proxy.conf") }} +{{- if (exists "/etc/nginx/proxy.conf") }} include /etc/nginx/proxy.conf; -{{ else }} +{{- else }} # HTTP 1.1 support proxy_http_version 1.1; proxy_buffering off; @@ -225,102 +225,102 @@ proxy_set_header X-Original-URI $request_uri; # Mitigate httpoxy attack (see README for details) proxy_set_header Proxy ""; -{{ end }} +{{- end }} -{{ $access_log := (or (and (not $.Env.DISABLE_ACCESS_LOGS) "access_log /var/log/nginx/access.log vhost;") "") }} +{{- $access_log := (or (and (not $.Env.DISABLE_ACCESS_LOGS) "access_log /var/log/nginx/access.log vhost;") "") }} -{{ $enable_ipv6 := parseBool (coalesce $.Env.ENABLE_IPV6 "false") }} +{{- $enable_ipv6 := parseBool (coalesce $.Env.ENABLE_IPV6 "false") }} server { server_name _; # This is just an invalid value which will never trigger on a real hostname. server_tokens off; listen {{ $external_http_port }}; - {{ if $enable_ipv6 }} + {{- if $enable_ipv6 }} listen [::]:{{ $external_http_port }}; - {{ end }} + {{- end }} {{ $access_log }} return 503; -{{ if (and (exists "/etc/nginx/certs/default.crt") (exists "/etc/nginx/certs/default.key")) }} +{{- if (and (exists "/etc/nginx/certs/default.crt") (exists "/etc/nginx/certs/default.key")) }} listen {{ $external_https_port }} ssl http2; - {{ if $enable_ipv6 }} + {{- if $enable_ipv6 }} listen [::]:{{ $external_https_port }} ssl http2; - {{ end }} + {{- end }} ssl_session_cache shared:SSL:50m; ssl_session_tickets off; ssl_certificate /etc/nginx/certs/default.crt; ssl_certificate_key /etc/nginx/certs/default.key; -{{ end }} +{{- end }} } -{{ range $host, $containers := groupByMulti $ "Env.VIRTUAL_HOST" "," }} +{{- range $host, $containers := groupByMulti $ "Env.VIRTUAL_HOST" "," }} -{{ $host := trim $host }} -{{ $is_regexp := hasPrefix "~" $host }} -{{ $upstream_name := when (or $is_regexp $sha1_upstream_name) (sha1 $host) $host }} +{{- $host := trim $host }} +{{- $is_regexp := hasPrefix "~" $host }} +{{- $upstream_name := when (or $is_regexp $sha1_upstream_name) (sha1 $host) $host }} -{{ $paths := groupBy $containers "Env.VIRTUAL_PATH" }} -{{ $nPaths := len $paths }} +{{- $paths := groupBy $containers "Env.VIRTUAL_PATH" }} +{{- $nPaths := len $paths }} -{{ if eq $nPaths 0 }} - {{ $paths = dict "/" $containers }} -{{ end }} +{{- if eq $nPaths 0 }} + {{- $paths = dict "/" $containers }} +{{- end }} -{{ range $path, $containers := $paths }} - {{ $upstream := $upstream_name }} - {{ if gt $nPaths 0 }} - {{ $sum := sha1 $path }} - {{ $upstream = printf "%s-%s" $upstream $sum }} - {{ end }} +{{- range $path, $containers := $paths }} + {{- $upstream := $upstream_name }} + {{- if gt $nPaths 0 }} + {{- $sum := sha1 $path }} + {{- $upstream = printf "%s-%s" $upstream $sum }} + {{- end }} # {{ $host }}{{ $path }} {{ template "upstream" (dict "Upstream" $upstream "Containers" $containers "Networks" $CurrentContainer.Networks "Debug" $debug_all) }} -{{ end }} +{{- end }} -{{ $default_host := or ($.Env.DEFAULT_HOST) "" }} -{{ $default_server := index (dict $host "" $default_host "default_server") $host }} +{{- $default_host := or ($.Env.DEFAULT_HOST) "" }} +{{- $default_server := index (dict $host "" $default_host "default_server") $host }} -{{/* Get the SERVER_TOKENS defined by containers w/ the same vhost, falling back to "" */}} -{{ $server_tokens := trim (or (first (groupByKeys $containers "Env.SERVER_TOKENS")) "") }} +{{- /* Get the SERVER_TOKENS defined by containers w/ the same vhost, falling back to "" */}} +{{- $server_tokens := trim (or (first (groupByKeys $containers "Env.SERVER_TOKENS")) "") }} -{{/* Get the HTTPS_METHOD defined by containers w/ the same vhost, falling back to "redirect" */}} -{{ $https_method := or (first (groupByKeys $containers "Env.HTTPS_METHOD")) (or $.Env.HTTPS_METHOD "redirect") }} +{{- /* Get the HTTPS_METHOD defined by containers w/ the same vhost, falling back to "redirect" */}} +{{- $https_method := or (first (groupByKeys $containers "Env.HTTPS_METHOD")) (or $.Env.HTTPS_METHOD "redirect") }} -{{/* Get the SSL_POLICY defined by containers w/ the same vhost, falling back to empty string (use default) */}} -{{ $ssl_policy := or (first (groupByKeys $containers "Env.SSL_POLICY")) "" }} +{{- /* Get the SSL_POLICY defined by containers w/ the same vhost, falling back to empty string (use default) */}} +{{- $ssl_policy := or (first (groupByKeys $containers "Env.SSL_POLICY")) "" }} -{{/* Get the HSTS defined by containers w/ the same vhost, falling back to "max-age=31536000" */}} -{{ $hsts := or (first (groupByKeys $containers "Env.HSTS")) (or $.Env.HSTS "max-age=31536000") }} +{{- /* Get the HSTS defined by containers w/ the same vhost, falling back to "max-age=31536000" */}} +{{- $hsts := or (first (groupByKeys $containers "Env.HSTS")) (or $.Env.HSTS "max-age=31536000") }} -{{/* Get the VIRTUAL_ROOT By containers w/ use fastcgi root */}} -{{ $vhost_root := or (first (groupByKeys $containers "Env.VIRTUAL_ROOT")) "/var/www/public" }} +{{- /* Get the VIRTUAL_ROOT By containers w/ use fastcgi root */}} +{{- $vhost_root := or (first (groupByKeys $containers "Env.VIRTUAL_ROOT")) "/var/www/public" }} -{{/* Get the first cert name defined by containers w/ the same vhost */}} -{{ $certName := (first (groupByKeys $containers "Env.CERT_NAME")) }} +{{- /* Get the first cert name defined by containers w/ the same vhost */}} +{{- $certName := (first (groupByKeys $containers "Env.CERT_NAME")) }} -{{/* Get the best matching cert by name for the vhost. */}} -{{ $vhostCert := (closest (dir "/etc/nginx/certs") (printf "%s.crt" $host))}} +{{- /* Get the best matching cert by name for the vhost. */}} +{{- $vhostCert := (closest (dir "/etc/nginx/certs") (printf "%s.crt" $host))}} -{{/* vhostCert is actually a filename so remove any suffixes since they are added later */}} -{{ $vhostCert := trimSuffix ".crt" $vhostCert }} -{{ $vhostCert := trimSuffix ".key" $vhostCert }} +{{- /* vhostCert is actually a filename so remove any suffixes since they are added later */}} +{{- $vhostCert := trimSuffix ".crt" $vhostCert }} +{{- $vhostCert := trimSuffix ".key" $vhostCert }} -{{/* Use the cert specified on the container or fallback to the best vhost match */}} -{{ $cert := (coalesce $certName $vhostCert) }} +{{- /* Use the cert specified on the container or fallback to the best vhost match */}} +{{- $cert := (coalesce $certName $vhostCert) }} -{{ $is_https := (and (ne $https_method "nohttps") (ne $cert "") (exists (printf "/etc/nginx/certs/%s.crt" $cert)) (exists (printf "/etc/nginx/certs/%s.key" $cert))) }} +{{- $is_https := (and (ne $https_method "nohttps") (ne $cert "") (exists (printf "/etc/nginx/certs/%s.crt" $cert)) (exists (printf "/etc/nginx/certs/%s.key" $cert))) }} -{{ if and $is_https (eq $https_method "redirect") }} +{{- if and $is_https (eq $https_method "redirect") }} server { server_name {{ $host }}; - {{ if $server_tokens }} + {{- if $server_tokens }} server_tokens {{ $server_tokens }}; - {{ end }} + {{- end }} listen {{ $external_http_port }} {{ $default_server }}; - {{ if $enable_ipv6 }} + {{- if $enable_ipv6 }} listen [::]:{{ $external_http_port }} {{ $default_server }}; - {{ end }} + {{- end }} {{ $access_log }} # Do not HTTPS redirect Let'sEncrypt ACME challenge @@ -334,34 +334,34 @@ server { } location / { - {{ if eq $external_https_port "443" }} + {{- if eq $external_https_port "443" }} return 301 https://$host$request_uri; - {{ else }} + {{- else }} return 301 https://$host:{{ $external_https_port }}$request_uri; - {{ end }} + {{- end }} } } -{{ end }} +{{- end }} server { server_name {{ $host }}; - {{ if $server_tokens }} + {{- if $server_tokens }} server_tokens {{ $server_tokens }}; - {{ end }} + {{- end }} {{ $access_log }} {{- if or (not $is_https) (eq $https_method "noredirect") }} listen {{ $external_http_port }} {{ $default_server }}; - {{ if $enable_ipv6 }} + {{- if $enable_ipv6 }} listen [::]:{{ $external_http_port }} {{ $default_server }}; - {{ end }} + {{- end }} {{- end }} {{- if $is_https }} listen {{ $external_https_port }} ssl http2 {{ $default_server }}; - {{ if $enable_ipv6 }} + {{- if $enable_ipv6 }} listen [::]:{{ $external_https_port }} ssl http2 {{ $default_server }}; - {{ end }} + {{- end }} - {{ template "ssl_policy" (dict "ssl_policy" $ssl_policy) }} + {{- template "ssl_policy" (dict "ssl_policy" $ssl_policy) }} ssl_session_timeout 5m; ssl_session_cache shared:SSL:50m; @@ -370,69 +370,69 @@ server { ssl_certificate /etc/nginx/certs/{{ (printf "%s.crt" $cert) }}; ssl_certificate_key /etc/nginx/certs/{{ (printf "%s.key" $cert) }}; - {{ if (exists (printf "/etc/nginx/certs/%s.dhparam.pem" $cert)) }} + {{- if (exists (printf "/etc/nginx/certs/%s.dhparam.pem" $cert)) }} ssl_dhparam {{ printf "/etc/nginx/certs/%s.dhparam.pem" $cert }}; - {{ end }} + {{- end }} - {{ if (exists (printf "/etc/nginx/certs/%s.chain.pem" $cert)) }} + {{- if (exists (printf "/etc/nginx/certs/%s.chain.pem" $cert)) }} ssl_stapling on; ssl_stapling_verify on; ssl_trusted_certificate {{ printf "/etc/nginx/certs/%s.chain.pem" $cert }}; - {{ end }} + {{- end }} - {{ if (not (or (eq $https_method "noredirect") (eq $hsts "off"))) }} + {{- if (not (or (eq $https_method "noredirect") (eq $hsts "off"))) }} set $sts_header ""; if ($https) { set $sts_header "{{ trim $hsts }}"; } add_header Strict-Transport-Security $sts_header always; - {{ end }} + {{- end }} {{- end }} - {{ if (exists (printf "/etc/nginx/vhost.d/%s" $host)) }} + {{- if (exists (printf "/etc/nginx/vhost.d/%s" $host)) }} include {{ printf "/etc/nginx/vhost.d/%s" $host }}; - {{ else if (exists "/etc/nginx/vhost.d/default") }} + {{- else if (exists "/etc/nginx/vhost.d/default") }} include /etc/nginx/vhost.d/default; - {{ end }} + {{- end }} - {{ range $path, $containers := $paths }} - {{/* Get the VIRTUAL_PROTO defined by containers w/ the same vhost-vpath, falling back to "http" */}} - {{ $proto := trim (or (first (groupByKeys $containers "Env.VIRTUAL_PROTO")) "http") }} + {{- range $path, $containers := $paths }} + {{- /* Get the VIRTUAL_PROTO defined by containers w/ the same vhost-vpath, falling back to "http" */}} + {{- $proto := trim (or (first (groupByKeys $containers "Env.VIRTUAL_PROTO")) "http") }} - {{/* Get the NETWORK_ACCESS defined by containers w/ the same vhost, falling back to "external" */}} - {{ $network_tag := or (first (groupByKeys $containers "Env.NETWORK_ACCESS")) "external" }} - {{ $upstream := $upstream_name }} - {{ $dest := "" }} - {{ if gt $nPaths 0 }} - {{ $sum := sha1 $path }} - {{ $upstream = printf "%s-%s" $upstream $sum }} - {{ $dest = (or (first (groupByKeys $containers "Env.VIRTUAL_DEST")) "") }} - {{ end }} - {{ template "location" (dict "Path" $path "Proto" $proto "Upstream" $upstream "Host" $host "VhostRoot" $vhost_root "Dest" $dest "NetworkTag" $network_tag) }} - {{ end }} - {{ if (not (contains $paths "/")) }} + {{- /* Get the NETWORK_ACCESS defined by containers w/ the same vhost, falling back to "external" */}} + {{- $network_tag := or (first (groupByKeys $containers "Env.NETWORK_ACCESS")) "external" }} + {{- $upstream := $upstream_name }} + {{- $dest := "" }} + {{- if gt $nPaths 0 }} + {{- $sum := sha1 $path }} + {{- $upstream = printf "%s-%s" $upstream $sum }} + {{- $dest = (or (first (groupByKeys $containers "Env.VIRTUAL_DEST")) "") }} + {{- end }} + {{- template "location" (dict "Path" $path "Proto" $proto "Upstream" $upstream "Host" $host "VhostRoot" $vhost_root "Dest" $dest "NetworkTag" $network_tag) }} + {{- end }} + {{- if (not (contains $paths "/")) }} location / { return {{ $default_root_response }}; } - {{ end }} + {{- end }} } -{{ if (and (not $is_https) (exists "/etc/nginx/certs/default.crt") (exists "/etc/nginx/certs/default.key")) }} +{{- if (and (not $is_https) (exists "/etc/nginx/certs/default.crt") (exists "/etc/nginx/certs/default.key")) }} server { server_name {{ $host }}; - {{ if $server_tokens }} + {{- if $server_tokens }} server_tokens {{ $server_tokens }}; - {{ end }} + {{- end }} listen {{ $external_https_port }} ssl http2 {{ $default_server }}; - {{ if $enable_ipv6 }} + {{- if $enable_ipv6 }} listen [::]:{{ $external_https_port }} ssl http2 {{ $default_server }}; - {{ end }} + {{- end }} {{ $access_log }} return 500; ssl_certificate /etc/nginx/certs/default.crt; ssl_certificate_key /etc/nginx/certs/default.key; } -{{ end }} +{{- end }} -{{ end }} +{{- end }} From 0da38122bd17c42d826a714cc05a4160a1a9f63e Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Tue, 17 May 2022 01:19:32 -0400 Subject: [PATCH 107/300] chore: Consistent indentation --- nginx.tmpl | 533 ++++++++++++++++++++++++++--------------------------- 1 file changed, 266 insertions(+), 267 deletions(-) diff --git a/nginx.tmpl b/nginx.tmpl index a320def..2cb0fe4 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -9,138 +9,138 @@ {{- $trust_downstream_proxy := parseBool (coalesce $.Env.TRUST_DOWNSTREAM_PROXY "true") }} {{- define "ssl_policy" }} - {{- if eq .ssl_policy "Mozilla-Modern" }} - ssl_protocols TLSv1.3; - {{- /* nginx currently lacks ability to choose ciphers in TLS 1.3 in configuration, see https://trac.nginx.org/nginx/ticket/1529 */}} - {{- /* a possible workaround can be modify /etc/ssl/openssl.cnf to change it globally (see https://trac.nginx.org/nginx/ticket/1529#comment:12 ) */}} - {{- /* explicitly set ngnix default value in order to allow single servers to override the global http value */}} - ssl_ciphers HIGH:!aNULL:!MD5; - ssl_prefer_server_ciphers off; - {{- else if eq .ssl_policy "Mozilla-Intermediate" }} - ssl_protocols TLSv1.2 TLSv1.3; - ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384'; - ssl_prefer_server_ciphers off; - {{- else if eq .ssl_policy "Mozilla-Old" }} - ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; - ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA256:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA'; - ssl_prefer_server_ciphers on; - {{- else if eq .ssl_policy "AWS-TLS-1-2-2017-01" }} - ssl_protocols TLSv1.2 TLSv1.3; - ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:AES128-GCM-SHA256:AES128-SHA256:AES256-GCM-SHA384:AES256-SHA256'; - ssl_prefer_server_ciphers on; - {{- else if eq .ssl_policy "AWS-TLS-1-1-2017-01" }} - ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3; - ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:AES128-GCM-SHA256:AES128-SHA256:AES128-SHA:AES256-GCM-SHA384:AES256-SHA256:AES256-SHA'; - ssl_prefer_server_ciphers on; - {{- else if eq .ssl_policy "AWS-2016-08" }} - ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; - ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:AES128-GCM-SHA256:AES128-SHA256:AES128-SHA:AES256-GCM-SHA384:AES256-SHA256:AES256-SHA'; - ssl_prefer_server_ciphers on; - {{- else if eq .ssl_policy "AWS-2015-05" }} - ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; - ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:AES128-GCM-SHA256:AES128-SHA256:AES128-SHA:AES256-GCM-SHA384:AES256-SHA256:AES256-SHA:DES-CBC3-SHA'; - ssl_prefer_server_ciphers on; - {{- else if eq .ssl_policy "AWS-2015-03" }} - ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; - ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:AES128-GCM-SHA256:AES128-SHA256:AES128-SHA:AES256-GCM-SHA384:AES256-SHA256:AES256-SHA:DHE-DSS-AES128-SHA:DES-CBC3-SHA'; - ssl_prefer_server_ciphers on; - {{- else if eq .ssl_policy "AWS-2015-02" }} - ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; - ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:AES128-GCM-SHA256:AES128-SHA256:AES128-SHA:AES256-GCM-SHA384:AES256-SHA256:AES256-SHA:DHE-DSS-AES128-SHA'; - ssl_prefer_server_ciphers on; - {{- end }} + {{- if eq .ssl_policy "Mozilla-Modern" }} + ssl_protocols TLSv1.3; + {{- /* nginx currently lacks ability to choose ciphers in TLS 1.3 in configuration, see https://trac.nginx.org/nginx/ticket/1529 */}} + {{- /* a possible workaround can be modify /etc/ssl/openssl.cnf to change it globally (see https://trac.nginx.org/nginx/ticket/1529#comment:12 ) */}} + {{- /* explicitly set ngnix default value in order to allow single servers to override the global http value */}} + ssl_ciphers HIGH:!aNULL:!MD5; + ssl_prefer_server_ciphers off; + {{- else if eq .ssl_policy "Mozilla-Intermediate" }} + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384'; + ssl_prefer_server_ciphers off; + {{- else if eq .ssl_policy "Mozilla-Old" }} + ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; + ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA256:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA'; + ssl_prefer_server_ciphers on; + {{- else if eq .ssl_policy "AWS-TLS-1-2-2017-01" }} + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:AES128-GCM-SHA256:AES128-SHA256:AES256-GCM-SHA384:AES256-SHA256'; + ssl_prefer_server_ciphers on; + {{- else if eq .ssl_policy "AWS-TLS-1-1-2017-01" }} + ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3; + ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:AES128-GCM-SHA256:AES128-SHA256:AES128-SHA:AES256-GCM-SHA384:AES256-SHA256:AES256-SHA'; + ssl_prefer_server_ciphers on; + {{- else if eq .ssl_policy "AWS-2016-08" }} + ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; + ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:AES128-GCM-SHA256:AES128-SHA256:AES128-SHA:AES256-GCM-SHA384:AES256-SHA256:AES256-SHA'; + ssl_prefer_server_ciphers on; + {{- else if eq .ssl_policy "AWS-2015-05" }} + ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; + ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:AES128-GCM-SHA256:AES128-SHA256:AES128-SHA:AES256-GCM-SHA384:AES256-SHA256:AES256-SHA:DES-CBC3-SHA'; + ssl_prefer_server_ciphers on; + {{- else if eq .ssl_policy "AWS-2015-03" }} + ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; + ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:AES128-GCM-SHA256:AES128-SHA256:AES128-SHA:AES256-GCM-SHA384:AES256-SHA256:AES256-SHA:DHE-DSS-AES128-SHA:DES-CBC3-SHA'; + ssl_prefer_server_ciphers on; + {{- else if eq .ssl_policy "AWS-2015-02" }} + ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; + ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:AES128-GCM-SHA256:AES128-SHA256:AES128-SHA:AES256-GCM-SHA384:AES256-SHA256:AES256-SHA:DHE-DSS-AES128-SHA'; + ssl_prefer_server_ciphers on; + {{- end }} {{- end }} {{- define "location" }} - location {{ .Path }} { - {{- if eq .NetworkTag "internal" }} - # Only allow traffic from internal clients - include /etc/nginx/network_internal.conf; - {{- end }} + location {{ .Path }} { + {{- if eq .NetworkTag "internal" }} + # Only allow traffic from internal clients + include /etc/nginx/network_internal.conf; + {{- end }} - {{- if eq .Proto "uwsgi" }} - include uwsgi_params; - uwsgi_pass {{ trim .Proto }}://{{ trim .Upstream }}; - {{- else if eq .Proto "fastcgi" }} - root {{ trim .VhostRoot }}; - include fastcgi_params; - fastcgi_pass {{ trim .Upstream }}; - {{- else if eq .Proto "grpc" }} - grpc_pass {{ trim .Proto }}://{{ trim .Upstream }}; - {{- else }} - proxy_pass {{ trim .Proto }}://{{ trim .Upstream }}{{ trim .Dest }}; - {{- end }} + {{- if eq .Proto "uwsgi" }} + include uwsgi_params; + uwsgi_pass {{ trim .Proto }}://{{ trim .Upstream }}; + {{- else if eq .Proto "fastcgi" }} + root {{ trim .VhostRoot }}; + include fastcgi_params; + fastcgi_pass {{ trim .Upstream }}; + {{- else if eq .Proto "grpc" }} + grpc_pass {{ trim .Proto }}://{{ trim .Upstream }}; + {{- else }} + proxy_pass {{ trim .Proto }}://{{ trim .Upstream }}{{ trim .Dest }}; + {{- end }} - {{- if (exists (printf "/etc/nginx/htpasswd/%s" .Host)) }} - auth_basic "Restricted {{ .Host }}"; - auth_basic_user_file {{ (printf "/etc/nginx/htpasswd/%s" .Host) }}; - {{- end }} + {{- if (exists (printf "/etc/nginx/htpasswd/%s" .Host)) }} + auth_basic "Restricted {{ .Host }}"; + auth_basic_user_file {{ (printf "/etc/nginx/htpasswd/%s" .Host) }}; + {{- end }} - {{- if (exists (printf "/etc/nginx/vhost.d/%s_%s_location" .Host (sha1 .Path) )) }} - include {{ printf "/etc/nginx/vhost.d/%s_%s_location" .Host (sha1 .Path) }}; - {{- else if (exists (printf "/etc/nginx/vhost.d/%s_location" .Host)) }} - include {{ printf "/etc/nginx/vhost.d/%s_location" .Host}}; - {{- else if (exists "/etc/nginx/vhost.d/default_location") }} - include /etc/nginx/vhost.d/default_location; - {{- end }} -} + {{- if (exists (printf "/etc/nginx/vhost.d/%s_%s_location" .Host (sha1 .Path) )) }} + include {{ printf "/etc/nginx/vhost.d/%s_%s_location" .Host (sha1 .Path) }}; + {{- else if (exists (printf "/etc/nginx/vhost.d/%s_location" .Host)) }} + include {{ printf "/etc/nginx/vhost.d/%s_location" .Host}}; + {{- else if (exists "/etc/nginx/vhost.d/default_location") }} + include /etc/nginx/vhost.d/default_location; + {{- end }} + } {{- end }} {{- define "upstream" }} - {{- $networks := .Networks }} - {{- $debug_all := .Debug }} + {{- $networks := .Networks }} + {{- $debug_all := .Debug }} upstream {{ .Upstream }} { - {{- $server_found := false }} - {{- range $container := .Containers }} + {{- $server_found := false }} + {{- range $container := .Containers }} {{- $debug := parseBool (coalesce $container.Env.DEBUG $debug_all "false") }} {{- /* If only 1 port exposed, use that as a default, else 80 */}} {{- $defaultPort := (when (eq (len $container.Addresses) 1) (first $container.Addresses) (dict "Port" "80")).Port }} {{- $port := (coalesce $container.Env.VIRTUAL_PORT $defaultPort) }} {{- $address := where $container.Addresses "Port" $port | first }} {{- if $debug }} - # Exposed ports: {{ $container.Addresses }} - # Default virtual port: {{ $defaultPort }} - # VIRTUAL_PORT: {{ $container.Env.VIRTUAL_PORT }} + # Exposed ports: {{ $container.Addresses }} + # Default virtual port: {{ $defaultPort }} + # VIRTUAL_PORT: {{ $container.Env.VIRTUAL_PORT }} {{- if not $address }} - # /!\ Virtual port not exposed + # /!\ Virtual port not exposed {{- end }} {{- end }} - {{- range $knownNetwork := $networks }} - {{- range $containerNetwork := sortObjectsByKeysAsc $container.Networks "Name" }} - {{- if (and (ne $containerNetwork.Name "ingress") (or (eq $knownNetwork.Name $containerNetwork.Name) (eq $knownNetwork.Name "host"))) }} - ## Can be connected with "{{ $containerNetwork.Name }}" network + {{- range $knownNetwork := $networks }} + {{- range $containerNetwork := sortObjectsByKeysAsc $container.Networks "Name" }} + {{- if (and (ne $containerNetwork.Name "ingress") (or (eq $knownNetwork.Name $containerNetwork.Name) (eq $knownNetwork.Name "host"))) }} + ## Can be connected with "{{ $containerNetwork.Name }}" network {{- if $address }} {{- /* If we got the containers from swarm and this container's port is published to host, use host IP:PORT */}} {{- if and $container.Node.ID $address.HostPort }} {{- $server_found = true }} - # {{ $container.Node.Name }}/{{ $container.Name }} - server {{ $container.Node.Address.IP }}:{{ $address.HostPort }}; - {{- /* If there is no swarm node or the port is not published on host, use container's IP:PORT */}} + # {{ $container.Node.Name }}/{{ $container.Name }} + server {{ $container.Node.Address.IP }}:{{ $address.HostPort }}; + {{- /* If there is no swarm node or the port is not published on host, use container's IP:PORT */}} {{- else if $containerNetwork }} {{- $server_found = true }} - # {{ $container.Name }} - server {{ $containerNetwork.IP }}:{{ $address.Port }}; + # {{ $container.Name }} + server {{ $containerNetwork.IP }}:{{ $address.Port }}; {{- end }} {{- else if $containerNetwork }} - # {{ $container.Name }} + # {{ $container.Name }} {{- if $containerNetwork.IP }} {{- $server_found = true }} - server {{ $containerNetwork.IP }}:{{ $port }}; + server {{ $containerNetwork.IP }}:{{ $port }}; {{- else }} - # /!\ No IP for this network! - {{- end }} - {{- end }} - {{- else }} - # Cannot connect to network '{{ $containerNetwork.Name }}' of this container - {{- end }} - {{- end }} - {{- end }} - {{- end }} - {{- /* nginx-proxy/nginx-proxy#1105 */}} - {{- if not $server_found }} - # Fallback entry - server 127.0.0.1 down; - {{- end }} + # /!\ No IP for this network! + {{- end }} + {{- end }} + {{- else }} + # Cannot connect to network '{{ $containerNetwork.Name }}' of this container + {{- end }} + {{- end }} + {{- end }} + {{- end }} + {{- /* nginx-proxy/nginx-proxy#1105 */}} + {{- if not $server_found }} + # Fallback entry + server 127.0.0.1 down; + {{- end }} } {{- end }} @@ -151,27 +151,27 @@ upstream {{ .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 $trust_downstream_proxy }}$http_x_forwarded_proto{{ else }}$scheme{{ end }}; - '' $scheme; + default {{ if $trust_downstream_proxy }}$http_x_forwarded_proto{{ else }}$scheme{{ end }}; + '' $scheme; } map $http_x_forwarded_host $proxy_x_forwarded_host { - default {{ if $trust_downstream_proxy }}$http_x_forwarded_host{{ else }}$http_host{{ end }}; - '' $http_host; + default {{ if $trust_downstream_proxy }}$http_x_forwarded_host{{ else }}$http_host{{ end }}; + '' $http_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 $trust_downstream_proxy }}$http_x_forwarded_port{{ else }}$server_port{{ end }}; - '' $server_port; + default {{ if $trust_downstream_proxy }}$http_x_forwarded_port{{ else }}$server_port{{ end }}; + '' $server_port; } # If we receive Upgrade, set Connection to "upgrade"; otherwise, preserve # NGINX's default behavior ("Connection: close"). map $http_upgrade $proxy_connection { - default upgrade; - '' close; + default upgrade; + '' close; } # Apply fix for very long server names @@ -184,8 +184,8 @@ ssl_dhparam /etc/nginx/dhparam/dhparam.pem; # Set appropriate X-Forwarded-Ssl header based on $proxy_x_forwarded_proto map $proxy_x_forwarded_proto $proxy_x_forwarded_ssl { - default off; - https on; + default off; + https on; } gzip_types text/plain text/css application/javascript application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript; @@ -231,208 +231,207 @@ proxy_set_header Proxy ""; {{- $enable_ipv6 := parseBool (coalesce $.Env.ENABLE_IPV6 "false") }} server { - server_name _; # This is just an invalid value which will never trigger on a real hostname. - server_tokens off; - listen {{ $external_http_port }}; - {{- if $enable_ipv6 }} - listen [::]:{{ $external_http_port }}; - {{- end }} - {{ $access_log }} - return 503; + server_name _; # This is just an invalid value which will never trigger on a real hostname. + server_tokens off; + listen {{ $external_http_port }}; +{{- if $enable_ipv6 }} + listen [::]:{{ $external_http_port }}; +{{- end }} + {{ $access_log }} + return 503; {{- if (and (exists "/etc/nginx/certs/default.crt") (exists "/etc/nginx/certs/default.key")) }} - listen {{ $external_https_port }} ssl http2; - {{- if $enable_ipv6 }} - listen [::]:{{ $external_https_port }} ssl http2; - {{- end }} + listen {{ $external_https_port }} ssl http2; + {{- if $enable_ipv6 }} + listen [::]:{{ $external_https_port }} ssl http2; + {{- end }} - ssl_session_cache shared:SSL:50m; - ssl_session_tickets off; - ssl_certificate /etc/nginx/certs/default.crt; - ssl_certificate_key /etc/nginx/certs/default.key; + ssl_session_cache shared:SSL:50m; + ssl_session_tickets off; + ssl_certificate /etc/nginx/certs/default.crt; + ssl_certificate_key /etc/nginx/certs/default.key; {{- end }} } {{- range $host, $containers := groupByMulti $ "Env.VIRTUAL_HOST" "," }} -{{- $host := trim $host }} -{{- $is_regexp := hasPrefix "~" $host }} -{{- $upstream_name := when (or $is_regexp $sha1_upstream_name) (sha1 $host) $host }} + {{- $host := trim $host }} + {{- $is_regexp := hasPrefix "~" $host }} + {{- $upstream_name := when (or $is_regexp $sha1_upstream_name) (sha1 $host) $host }} -{{- $paths := groupBy $containers "Env.VIRTUAL_PATH" }} -{{- $nPaths := len $paths }} + {{- $paths := groupBy $containers "Env.VIRTUAL_PATH" }} + {{- $nPaths := len $paths }} + {{- if eq $nPaths 0 }} + {{- $paths = dict "/" $containers }} + {{- end }} -{{- if eq $nPaths 0 }} - {{- $paths = dict "/" $containers }} -{{- end }} + {{- range $path, $containers := $paths }} + {{- $upstream := $upstream_name }} + {{- if gt $nPaths 0 }} + {{- $sum := sha1 $path }} + {{- $upstream = printf "%s-%s" $upstream $sum }} + {{- end }} +# {{ $host }}{{ $path }} +{{ template "upstream" (dict "Upstream" $upstream "Containers" $containers "Networks" $CurrentContainer.Networks "Debug" $debug_all) }} + {{- end }} -{{- range $path, $containers := $paths }} - {{- $upstream := $upstream_name }} - {{- if gt $nPaths 0 }} - {{- $sum := sha1 $path }} - {{- $upstream = printf "%s-%s" $upstream $sum }} - {{- end }} - # {{ $host }}{{ $path }} - {{ template "upstream" (dict "Upstream" $upstream "Containers" $containers "Networks" $CurrentContainer.Networks "Debug" $debug_all) }} -{{- end }} + {{- $default_host := or ($.Env.DEFAULT_HOST) "" }} + {{- $default_server := index (dict $host "" $default_host "default_server") $host }} -{{- $default_host := or ($.Env.DEFAULT_HOST) "" }} -{{- $default_server := index (dict $host "" $default_host "default_server") $host }} - -{{- /* Get the SERVER_TOKENS defined by containers w/ the same vhost, falling back to "" */}} -{{- $server_tokens := trim (or (first (groupByKeys $containers "Env.SERVER_TOKENS")) "") }} + {{- /* Get the SERVER_TOKENS defined by containers w/ the same vhost, falling back to "" */}} + {{- $server_tokens := trim (or (first (groupByKeys $containers "Env.SERVER_TOKENS")) "") }} -{{- /* Get the HTTPS_METHOD defined by containers w/ the same vhost, falling back to "redirect" */}} -{{- $https_method := or (first (groupByKeys $containers "Env.HTTPS_METHOD")) (or $.Env.HTTPS_METHOD "redirect") }} + {{- /* Get the HTTPS_METHOD defined by containers w/ the same vhost, falling back to "redirect" */}} + {{- $https_method := or (first (groupByKeys $containers "Env.HTTPS_METHOD")) (or $.Env.HTTPS_METHOD "redirect") }} -{{- /* Get the SSL_POLICY defined by containers w/ the same vhost, falling back to empty string (use default) */}} -{{- $ssl_policy := or (first (groupByKeys $containers "Env.SSL_POLICY")) "" }} + {{- /* Get the SSL_POLICY defined by containers w/ the same vhost, falling back to empty string (use default) */}} + {{- $ssl_policy := or (first (groupByKeys $containers "Env.SSL_POLICY")) "" }} -{{- /* Get the HSTS defined by containers w/ the same vhost, falling back to "max-age=31536000" */}} -{{- $hsts := or (first (groupByKeys $containers "Env.HSTS")) (or $.Env.HSTS "max-age=31536000") }} + {{- /* Get the HSTS defined by containers w/ the same vhost, falling back to "max-age=31536000" */}} + {{- $hsts := or (first (groupByKeys $containers "Env.HSTS")) (or $.Env.HSTS "max-age=31536000") }} -{{- /* Get the VIRTUAL_ROOT By containers w/ use fastcgi root */}} -{{- $vhost_root := or (first (groupByKeys $containers "Env.VIRTUAL_ROOT")) "/var/www/public" }} + {{- /* Get the VIRTUAL_ROOT By containers w/ use fastcgi root */}} + {{- $vhost_root := or (first (groupByKeys $containers "Env.VIRTUAL_ROOT")) "/var/www/public" }} -{{- /* Get the first cert name defined by containers w/ the same vhost */}} -{{- $certName := (first (groupByKeys $containers "Env.CERT_NAME")) }} + {{- /* Get the first cert name defined by containers w/ the same vhost */}} + {{- $certName := (first (groupByKeys $containers "Env.CERT_NAME")) }} -{{- /* Get the best matching cert by name for the vhost. */}} -{{- $vhostCert := (closest (dir "/etc/nginx/certs") (printf "%s.crt" $host))}} + {{- /* Get the best matching cert by name for the vhost. */}} + {{- $vhostCert := (closest (dir "/etc/nginx/certs") (printf "%s.crt" $host))}} -{{- /* vhostCert is actually a filename so remove any suffixes since they are added later */}} -{{- $vhostCert := trimSuffix ".crt" $vhostCert }} -{{- $vhostCert := trimSuffix ".key" $vhostCert }} + {{- /* vhostCert is actually a filename so remove any suffixes since they are added later */}} + {{- $vhostCert := trimSuffix ".crt" $vhostCert }} + {{- $vhostCert := trimSuffix ".key" $vhostCert }} -{{- /* Use the cert specified on the container or fallback to the best vhost match */}} -{{- $cert := (coalesce $certName $vhostCert) }} + {{- /* Use the cert specified on the container or fallback to the best vhost match */}} + {{- $cert := (coalesce $certName $vhostCert) }} -{{- $is_https := (and (ne $https_method "nohttps") (ne $cert "") (exists (printf "/etc/nginx/certs/%s.crt" $cert)) (exists (printf "/etc/nginx/certs/%s.key" $cert))) }} + {{- $is_https := (and (ne $https_method "nohttps") (ne $cert "") (exists (printf "/etc/nginx/certs/%s.crt" $cert)) (exists (printf "/etc/nginx/certs/%s.key" $cert))) }} -{{- if and $is_https (eq $https_method "redirect") }} + {{- if and $is_https (eq $https_method "redirect") }} server { - server_name {{ $host }}; - {{- if $server_tokens }} - server_tokens {{ $server_tokens }}; - {{- end }} - listen {{ $external_http_port }} {{ $default_server }}; - {{- if $enable_ipv6 }} - listen [::]:{{ $external_http_port }} {{ $default_server }}; - {{- end }} - {{ $access_log }} + server_name {{ $host }}; + {{- if $server_tokens }} + server_tokens {{ $server_tokens }}; + {{- end }} + listen {{ $external_http_port }} {{ $default_server }}; + {{- if $enable_ipv6 }} + listen [::]:{{ $external_http_port }} {{ $default_server }}; + {{- end }} + {{ $access_log }} - # Do not HTTPS redirect Let'sEncrypt ACME challenge - location ^~ /.well-known/acme-challenge/ { - auth_basic off; - auth_request off; - allow all; - root /usr/share/nginx/html; - try_files $uri =404; - break; - } + # Do not HTTPS redirect Let's Encrypt ACME challenge + location ^~ /.well-known/acme-challenge/ { + auth_basic off; + auth_request off; + allow all; + root /usr/share/nginx/html; + try_files $uri =404; + break; + } - location / { - {{- if eq $external_https_port "443" }} - return 301 https://$host$request_uri; - {{- else }} - return 301 https://$host:{{ $external_https_port }}$request_uri; - {{- end }} - } + location / { + {{- if eq $external_https_port "443" }} + return 301 https://$host$request_uri; + {{- else }} + return 301 https://$host:{{ $external_https_port }}$request_uri; + {{- end }} + } } -{{- end }} + {{- end }} server { - server_name {{ $host }}; - {{- if $server_tokens }} - server_tokens {{ $server_tokens }}; - {{- end }} - {{ $access_log }} + server_name {{ $host }}; + {{- if $server_tokens }} + server_tokens {{ $server_tokens }}; + {{- end }} + {{ $access_log }} {{- if or (not $is_https) (eq $https_method "noredirect") }} - listen {{ $external_http_port }} {{ $default_server }}; - {{- if $enable_ipv6 }} - listen [::]:{{ $external_http_port }} {{ $default_server }}; - {{- end }} + listen {{ $external_http_port }} {{ $default_server }}; + {{- if $enable_ipv6 }} + listen [::]:{{ $external_http_port }} {{ $default_server }}; + {{- end }} {{- end }} {{- if $is_https }} - listen {{ $external_https_port }} ssl http2 {{ $default_server }}; - {{- if $enable_ipv6 }} - listen [::]:{{ $external_https_port }} ssl http2 {{ $default_server }}; - {{- end }} + listen {{ $external_https_port }} ssl http2 {{ $default_server }}; + {{- if $enable_ipv6 }} + listen [::]:{{ $external_https_port }} ssl http2 {{ $default_server }}; + {{- end }} - {{- template "ssl_policy" (dict "ssl_policy" $ssl_policy) }} + {{- template "ssl_policy" (dict "ssl_policy" $ssl_policy) }} - ssl_session_timeout 5m; - ssl_session_cache shared:SSL:50m; - ssl_session_tickets off; + ssl_session_timeout 5m; + ssl_session_cache shared:SSL:50m; + ssl_session_tickets off; - ssl_certificate /etc/nginx/certs/{{ (printf "%s.crt" $cert) }}; - ssl_certificate_key /etc/nginx/certs/{{ (printf "%s.key" $cert) }}; + ssl_certificate /etc/nginx/certs/{{ (printf "%s.crt" $cert) }}; + ssl_certificate_key /etc/nginx/certs/{{ (printf "%s.key" $cert) }}; - {{- if (exists (printf "/etc/nginx/certs/%s.dhparam.pem" $cert)) }} - ssl_dhparam {{ printf "/etc/nginx/certs/%s.dhparam.pem" $cert }}; - {{- end }} + {{- if (exists (printf "/etc/nginx/certs/%s.dhparam.pem" $cert)) }} + ssl_dhparam {{ printf "/etc/nginx/certs/%s.dhparam.pem" $cert }}; + {{- end }} - {{- if (exists (printf "/etc/nginx/certs/%s.chain.pem" $cert)) }} - ssl_stapling on; - ssl_stapling_verify on; - ssl_trusted_certificate {{ printf "/etc/nginx/certs/%s.chain.pem" $cert }}; - {{- end }} + {{- if (exists (printf "/etc/nginx/certs/%s.chain.pem" $cert)) }} + ssl_stapling on; + ssl_stapling_verify on; + ssl_trusted_certificate {{ printf "/etc/nginx/certs/%s.chain.pem" $cert }}; + {{- end }} - {{- if (not (or (eq $https_method "noredirect") (eq $hsts "off"))) }} - set $sts_header ""; - if ($https) { - set $sts_header "{{ trim $hsts }}"; - } - add_header Strict-Transport-Security $sts_header always; - {{- end }} + {{- if (not (or (eq $https_method "noredirect") (eq $hsts "off"))) }} + set $sts_header ""; + if ($https) { + set $sts_header "{{ trim $hsts }}"; + } + add_header Strict-Transport-Security $sts_header always; + {{- end }} {{- end }} - {{- if (exists (printf "/etc/nginx/vhost.d/%s" $host)) }} - include {{ printf "/etc/nginx/vhost.d/%s" $host }}; - {{- else if (exists "/etc/nginx/vhost.d/default") }} - include /etc/nginx/vhost.d/default; - {{- end }} + {{- if (exists (printf "/etc/nginx/vhost.d/%s" $host)) }} + include {{ printf "/etc/nginx/vhost.d/%s" $host }}; + {{- else if (exists "/etc/nginx/vhost.d/default") }} + include /etc/nginx/vhost.d/default; + {{- end }} - {{- range $path, $containers := $paths }} - {{- /* Get the VIRTUAL_PROTO defined by containers w/ the same vhost-vpath, falling back to "http" */}} - {{- $proto := trim (or (first (groupByKeys $containers "Env.VIRTUAL_PROTO")) "http") }} + {{- range $path, $containers := $paths }} + {{- /* Get the VIRTUAL_PROTO defined by containers w/ the same vhost-vpath, falling back to "http" */}} + {{- $proto := trim (or (first (groupByKeys $containers "Env.VIRTUAL_PROTO")) "http") }} - {{- /* Get the NETWORK_ACCESS defined by containers w/ the same vhost, falling back to "external" */}} - {{- $network_tag := or (first (groupByKeys $containers "Env.NETWORK_ACCESS")) "external" }} - {{- $upstream := $upstream_name }} - {{- $dest := "" }} - {{- if gt $nPaths 0 }} - {{- $sum := sha1 $path }} - {{- $upstream = printf "%s-%s" $upstream $sum }} - {{- $dest = (or (first (groupByKeys $containers "Env.VIRTUAL_DEST")) "") }} - {{- end }} - {{- template "location" (dict "Path" $path "Proto" $proto "Upstream" $upstream "Host" $host "VhostRoot" $vhost_root "Dest" $dest "NetworkTag" $network_tag) }} - {{- end }} - {{- if (not (contains $paths "/")) }} - location / { - return {{ $default_root_response }}; - } - {{- end }} + {{- /* Get the NETWORK_ACCESS defined by containers w/ the same vhost, falling back to "external" */}} + {{- $network_tag := or (first (groupByKeys $containers "Env.NETWORK_ACCESS")) "external" }} + {{- $upstream := $upstream_name }} + {{- $dest := "" }} + {{- if gt $nPaths 0 }} + {{- $sum := sha1 $path }} + {{- $upstream = printf "%s-%s" $upstream $sum }} + {{- $dest = (or (first (groupByKeys $containers "Env.VIRTUAL_DEST")) "") }} + {{- end }} + {{- template "location" (dict "Path" $path "Proto" $proto "Upstream" $upstream "Host" $host "VhostRoot" $vhost_root "Dest" $dest "NetworkTag" $network_tag) }} + {{- end }} + {{- if (not (contains $paths "/")) }} + location / { + return {{ $default_root_response }}; + } + {{- end }} } -{{- if (and (not $is_https) (exists "/etc/nginx/certs/default.crt") (exists "/etc/nginx/certs/default.key")) }} + {{- if (and (not $is_https) (exists "/etc/nginx/certs/default.crt") (exists "/etc/nginx/certs/default.key")) }} server { - server_name {{ $host }}; - {{- if $server_tokens }} - server_tokens {{ $server_tokens }}; - {{- end }} - listen {{ $external_https_port }} ssl http2 {{ $default_server }}; - {{- if $enable_ipv6 }} - listen [::]:{{ $external_https_port }} ssl http2 {{ $default_server }}; - {{- end }} - {{ $access_log }} - return 500; + server_name {{ $host }}; + {{- if $server_tokens }} + server_tokens {{ $server_tokens }}; + {{- end }} + listen {{ $external_https_port }} ssl http2 {{ $default_server }}; + {{- if $enable_ipv6 }} + listen [::]:{{ $external_https_port }} ssl http2 {{ $default_server }}; + {{- end }} + {{ $access_log }} + return 500; - ssl_certificate /etc/nginx/certs/default.crt; - ssl_certificate_key /etc/nginx/certs/default.key; + ssl_certificate /etc/nginx/certs/default.crt; + ssl_certificate_key /etc/nginx/certs/default.key; } -{{- end }} + {{- end }} {{- end }} From 1b253cd9086133fa0f9caa0e5b9a00a9aead4681 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Mon, 9 Jan 2023 17:21:35 -0500 Subject: [PATCH 108/300] chore: Wrap long comments --- nginx.tmpl | 68 +++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 54 insertions(+), 14 deletions(-) diff --git a/nginx.tmpl b/nginx.tmpl index 2cb0fe4..4f90880 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -11,9 +11,15 @@ {{- define "ssl_policy" }} {{- if eq .ssl_policy "Mozilla-Modern" }} ssl_protocols TLSv1.3; - {{- /* nginx currently lacks ability to choose ciphers in TLS 1.3 in configuration, see https://trac.nginx.org/nginx/ticket/1529 */}} - {{- /* a possible workaround can be modify /etc/ssl/openssl.cnf to change it globally (see https://trac.nginx.org/nginx/ticket/1529#comment:12 ) */}} - {{- /* explicitly set ngnix default value in order to allow single servers to override the global http value */}} + {{- /* + * nginx currently lacks ability to choose ciphers in TLS 1.3 in + * configuration; see https://trac.nginx.org/nginx/ticket/1529. A + * possible workaround can be modify /etc/ssl/openssl.cnf to change + * it globally (see + * https://trac.nginx.org/nginx/ticket/1529#comment:12). Explicitly + * set ngnix default value in order to allow single servers to + * override the global http value. + */}} ssl_ciphers HIGH:!aNULL:!MD5; ssl_prefer_server_ciphers off; {{- else if eq .ssl_policy "Mozilla-Intermediate" }} @@ -110,12 +116,19 @@ upstream {{ .Upstream }} { {{- if (and (ne $containerNetwork.Name "ingress") (or (eq $knownNetwork.Name $containerNetwork.Name) (eq $knownNetwork.Name "host"))) }} ## Can be connected with "{{ $containerNetwork.Name }}" network {{- if $address }} - {{- /* If we got the containers from swarm and this container's port is published to host, use host IP:PORT */}} + {{- /* + * If we got the containers from swarm and this + * container's port is published to host, use host + * IP:PORT. + */}} {{- if and $container.Node.ID $address.HostPort }} {{- $server_found = true }} # {{ $container.Node.Name }}/{{ $container.Name }} server {{ $container.Node.Address.IP }}:{{ $address.HostPort }}; - {{- /* If there is no swarm node or the port is not published on host, use container's IP:PORT */}} + {{- /* + * If there is no swarm node or the port is not + * published on host, use container's IP:PORT. + */}} {{- else if $containerNetwork }} {{- $server_found = true }} # {{ $container.Name }} @@ -197,7 +210,10 @@ log_format vhost '$host $remote_addr - $remote_user [$time_local] ' access_log off; -{{- /* Get the SSL_POLICY defined by this container, falling back to "Mozilla-Intermediate" */}} +{{- /* + * Get the SSL_POLICY defined by this container, falling back to + * "Mozilla-Intermediate". + */}} {{- $ssl_policy := or ($.Env.SSL_POLICY) "Mozilla-Intermediate" }} {{- template "ssl_policy" (dict "ssl_policy" $ssl_policy) }} error_log /dev/stderr; @@ -278,17 +294,29 @@ server { {{- $default_host := or ($.Env.DEFAULT_HOST) "" }} {{- $default_server := index (dict $host "" $default_host "default_server") $host }} - {{- /* Get the SERVER_TOKENS defined by containers w/ the same vhost, falling back to "" */}} + {{- /* + * Get the SERVER_TOKENS defined by containers w/ the same vhost, + * falling back to "". + */}} {{- $server_tokens := trim (or (first (groupByKeys $containers "Env.SERVER_TOKENS")) "") }} - {{- /* Get the HTTPS_METHOD defined by containers w/ the same vhost, falling back to "redirect" */}} + {{- /* + * Get the HTTPS_METHOD defined by containers w/ the same vhost, falling + * back to "redirect". + */}} {{- $https_method := or (first (groupByKeys $containers "Env.HTTPS_METHOD")) (or $.Env.HTTPS_METHOD "redirect") }} - {{- /* Get the SSL_POLICY defined by containers w/ the same vhost, falling back to empty string (use default) */}} + {{- /* + * Get the SSL_POLICY defined by containers w/ the same vhost, falling + * back to empty string (use default). + */}} {{- $ssl_policy := or (first (groupByKeys $containers "Env.SSL_POLICY")) "" }} - {{- /* Get the HSTS defined by containers w/ the same vhost, falling back to "max-age=31536000" */}} + {{- /* + * Get the HSTS defined by containers w/ the same vhost, falling back to + * "max-age=31536000". + */}} {{- $hsts := or (first (groupByKeys $containers "Env.HSTS")) (or $.Env.HSTS "max-age=31536000") }} {{- /* Get the VIRTUAL_ROOT By containers w/ use fastcgi root */}} @@ -301,11 +329,17 @@ server { {{- /* Get the best matching cert by name for the vhost. */}} {{- $vhostCert := (closest (dir "/etc/nginx/certs") (printf "%s.crt" $host))}} - {{- /* vhostCert is actually a filename so remove any suffixes since they are added later */}} + {{- /* + * vhostCert is actually a filename so remove any suffixes since they + * are added later. + */}} {{- $vhostCert := trimSuffix ".crt" $vhostCert }} {{- $vhostCert := trimSuffix ".key" $vhostCert }} - {{- /* Use the cert specified on the container or fallback to the best vhost match */}} + {{- /* + * Use the cert specified on the container or fallback to the best vhost + * match. + */}} {{- $cert := (coalesce $certName $vhostCert) }} {{- $is_https := (and (ne $https_method "nohttps") (ne $cert "") (exists (printf "/etc/nginx/certs/%s.crt" $cert)) (exists (printf "/etc/nginx/certs/%s.key" $cert))) }} @@ -395,10 +429,16 @@ server { {{- end }} {{- range $path, $containers := $paths }} - {{- /* Get the VIRTUAL_PROTO defined by containers w/ the same vhost-vpath, falling back to "http" */}} + {{- /* + * Get the VIRTUAL_PROTO defined by containers w/ the same + * vhost-vpath, falling back to "http". + */}} {{- $proto := trim (or (first (groupByKeys $containers "Env.VIRTUAL_PROTO")) "http") }} - {{- /* Get the NETWORK_ACCESS defined by containers w/ the same vhost, falling back to "external" */}} + {{- /* + * Get the NETWORK_ACCESS defined by containers w/ the same vhost, + * falling back to "external". + */}} {{- $network_tag := or (first (groupByKeys $containers "Env.NETWORK_ACCESS")) "external" }} {{- $upstream := $upstream_name }} {{- $dest := "" }} From 2427b383b5beedc5a04bb2e8fb91c66795539fcc Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Sat, 14 Jan 2023 22:59:33 -0500 Subject: [PATCH 109/300] chore: Move global variables to a `$globals` dict Planned future changes will introduce more embedded templates, and the ability to pass the globals to the templates will be useful. --- nginx.tmpl | 116 +++++++++++++++++++++++++++-------------------------- 1 file changed, 60 insertions(+), 56 deletions(-) diff --git a/nginx.tmpl b/nginx.tmpl index 4f90880..fb4f76f 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -1,12 +1,24 @@ -{{- $CurrentContainer := where $ "ID" .Docker.CurrentContainerID | first }} - -{{- $nginx_proxy_version := coalesce $.Env.NGINX_PROXY_VERSION "" }} -{{- $external_http_port := coalesce $.Env.HTTP_PORT "80" }} -{{- $external_https_port := coalesce $.Env.HTTPS_PORT "443" }} -{{- $debug_all := $.Env.DEBUG }} -{{- $sha1_upstream_name := parseBool (coalesce $.Env.SHA1_UPSTREAM_NAME "false") }} -{{- $default_root_response := coalesce $.Env.DEFAULT_ROOT "404" }} -{{- $trust_downstream_proxy := parseBool (coalesce $.Env.TRUST_DOWNSTREAM_PROXY "true") }} +{{- /* + * 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.) + */}} +{{- $globals := dict }} +{{- $_ := set $globals "containers" $ }} +{{- $_ := set $globals "Env" $.Env }} +{{- $_ := set $globals "Docker" $.Docker }} +{{- $_ := set $globals "CurrentContainer" (where $globals.containers "ID" $globals.Docker.CurrentContainerID | first) }} +{{- $_ := set $globals "nginx_proxy_version" (coalesce $globals.Env.NGINX_PROXY_VERSION "") }} +{{- $_ := set $globals "external_http_port" (coalesce $globals.Env.HTTP_PORT "80") }} +{{- $_ := set $globals "external_https_port" (coalesce $globals.Env.HTTPS_PORT "443") }} +{{- $_ := set $globals "debug_all" $globals.Env.DEBUG }} +{{- $_ := 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") }} {{- define "ssl_policy" }} {{- if eq .ssl_policy "Mozilla-Modern" }} @@ -157,26 +169,26 @@ upstream {{ .Upstream }} { } {{- end }} -{{- if ne $nginx_proxy_version "" }} -# nginx-proxy version : {{ $nginx_proxy_version }} +{{- if ne $globals.nginx_proxy_version "" }} +# nginx-proxy version : {{ $globals.nginx_proxy_version }} {{- 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 { - default {{ if $trust_downstream_proxy }}$http_x_forwarded_proto{{ else }}$scheme{{ end }}; + default {{ if $globals.trust_downstream_proxy }}$http_x_forwarded_proto{{ else }}$scheme{{ end }}; '' $scheme; } map $http_x_forwarded_host $proxy_x_forwarded_host { - default {{ if $trust_downstream_proxy }}$http_x_forwarded_host{{ else }}$http_host{{ end }}; + default {{ if $globals.trust_downstream_proxy }}$http_x_forwarded_host{{ else }}$http_host{{ end }}; '' $http_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 $trust_downstream_proxy }}$http_x_forwarded_port{{ else }}$server_port{{ end }}; + default {{ if $globals.trust_downstream_proxy }}$http_x_forwarded_port{{ else }}$server_port{{ end }}; '' $server_port; } @@ -210,16 +222,11 @@ log_format vhost '$host $remote_addr - $remote_user [$time_local] ' access_log off; -{{- /* - * Get the SSL_POLICY defined by this container, falling back to - * "Mozilla-Intermediate". - */}} -{{- $ssl_policy := or ($.Env.SSL_POLICY) "Mozilla-Intermediate" }} -{{- template "ssl_policy" (dict "ssl_policy" $ssl_policy) }} +{{- template "ssl_policy" (dict "ssl_policy" $globals.ssl_policy) }} error_log /dev/stderr; -{{- if $.Env.RESOLVERS }} -resolver {{ $.Env.RESOLVERS }}; +{{- if $globals.Env.RESOLVERS }} +resolver {{ $globals.Env.RESOLVERS }}; {{- end }} {{- if (exists "/etc/nginx/proxy.conf") }} @@ -243,23 +250,20 @@ proxy_set_header X-Original-URI $request_uri; proxy_set_header Proxy ""; {{- end }} -{{- $access_log := (or (and (not $.Env.DISABLE_ACCESS_LOGS) "access_log /var/log/nginx/access.log vhost;") "") }} - -{{- $enable_ipv6 := parseBool (coalesce $.Env.ENABLE_IPV6 "false") }} server { server_name _; # This is just an invalid value which will never trigger on a real hostname. server_tokens off; - listen {{ $external_http_port }}; -{{- if $enable_ipv6 }} - listen [::]:{{ $external_http_port }}; + listen {{ $globals.external_http_port }}; +{{- if $globals.enable_ipv6 }} + listen [::]:{{ $globals.external_http_port }}; {{- end }} - {{ $access_log }} + {{ $globals.access_log }} return 503; {{- if (and (exists "/etc/nginx/certs/default.crt") (exists "/etc/nginx/certs/default.key")) }} - listen {{ $external_https_port }} ssl http2; - {{- if $enable_ipv6 }} - listen [::]:{{ $external_https_port }} ssl http2; + listen {{ $globals.external_https_port }} ssl http2; + {{- if $globals.enable_ipv6 }} + listen [::]:{{ $globals.external_https_port }} ssl http2; {{- end }} ssl_session_cache shared:SSL:50m; @@ -269,11 +273,11 @@ server { {{- end }} } -{{- range $host, $containers := groupByMulti $ "Env.VIRTUAL_HOST" "," }} +{{- range $host, $containers := groupByMulti $globals.containers "Env.VIRTUAL_HOST" "," }} {{- $host := trim $host }} {{- $is_regexp := hasPrefix "~" $host }} - {{- $upstream_name := when (or $is_regexp $sha1_upstream_name) (sha1 $host) $host }} + {{- $upstream_name := when (or $is_regexp $globals.sha1_upstream_name) (sha1 $host) $host }} {{- $paths := groupBy $containers "Env.VIRTUAL_PATH" }} {{- $nPaths := len $paths }} @@ -288,10 +292,10 @@ server { {{- $upstream = printf "%s-%s" $upstream $sum }} {{- end }} # {{ $host }}{{ $path }} -{{ template "upstream" (dict "Upstream" $upstream "Containers" $containers "Networks" $CurrentContainer.Networks "Debug" $debug_all) }} +{{ template "upstream" (dict "Upstream" $upstream "Containers" $containers "Networks" $globals.CurrentContainer.Networks "Debug" $globals.debug_all) }} {{- end }} - {{- $default_host := or ($.Env.DEFAULT_HOST) "" }} + {{- $default_host := or ($globals.Env.DEFAULT_HOST) "" }} {{- $default_server := index (dict $host "" $default_host "default_server") $host }} {{- /* @@ -305,7 +309,7 @@ server { * Get the HTTPS_METHOD defined by containers w/ the same vhost, falling * back to "redirect". */}} - {{- $https_method := or (first (groupByKeys $containers "Env.HTTPS_METHOD")) (or $.Env.HTTPS_METHOD "redirect") }} + {{- $https_method := or (first (groupByKeys $containers "Env.HTTPS_METHOD")) (or $globals.Env.HTTPS_METHOD "redirect") }} {{- /* * Get the SSL_POLICY defined by containers w/ the same vhost, falling @@ -317,7 +321,7 @@ server { * Get the HSTS defined by containers w/ the same vhost, falling back to * "max-age=31536000". */}} - {{- $hsts := or (first (groupByKeys $containers "Env.HSTS")) (or $.Env.HSTS "max-age=31536000") }} + {{- $hsts := or (first (groupByKeys $containers "Env.HSTS")) (or $globals.Env.HSTS "max-age=31536000") }} {{- /* Get the VIRTUAL_ROOT By containers w/ use fastcgi root */}} {{- $vhost_root := or (first (groupByKeys $containers "Env.VIRTUAL_ROOT")) "/var/www/public" }} @@ -350,11 +354,11 @@ server { {{- if $server_tokens }} server_tokens {{ $server_tokens }}; {{- end }} - listen {{ $external_http_port }} {{ $default_server }}; - {{- if $enable_ipv6 }} - listen [::]:{{ $external_http_port }} {{ $default_server }}; + listen {{ $globals.external_http_port }} {{ $default_server }}; + {{- if $globals.enable_ipv6 }} + listen [::]:{{ $globals.external_http_port }} {{ $default_server }}; {{- end }} - {{ $access_log }} + {{ $globals.access_log }} # Do not HTTPS redirect Let's Encrypt ACME challenge location ^~ /.well-known/acme-challenge/ { @@ -367,10 +371,10 @@ server { } location / { - {{- if eq $external_https_port "443" }} + {{- if eq $globals.external_https_port "443" }} return 301 https://$host$request_uri; {{- else }} - return 301 https://$host:{{ $external_https_port }}$request_uri; + return 301 https://$host:{{ $globals.external_https_port }}$request_uri; {{- end }} } } @@ -381,17 +385,17 @@ server { {{- if $server_tokens }} server_tokens {{ $server_tokens }}; {{- end }} - {{ $access_log }} + {{ $globals.access_log }} {{- if or (not $is_https) (eq $https_method "noredirect") }} - listen {{ $external_http_port }} {{ $default_server }}; - {{- if $enable_ipv6 }} - listen [::]:{{ $external_http_port }} {{ $default_server }}; + listen {{ $globals.external_http_port }} {{ $default_server }}; + {{- if $globals.enable_ipv6 }} + listen [::]:{{ $globals.external_http_port }} {{ $default_server }}; {{- end }} {{- end }} {{- if $is_https }} - listen {{ $external_https_port }} ssl http2 {{ $default_server }}; - {{- if $enable_ipv6 }} - listen [::]:{{ $external_https_port }} ssl http2 {{ $default_server }}; + listen {{ $globals.external_https_port }} ssl http2 {{ $default_server }}; + {{- if $globals.enable_ipv6 }} + listen [::]:{{ $globals.external_https_port }} ssl http2 {{ $default_server }}; {{- end }} {{- template "ssl_policy" (dict "ssl_policy" $ssl_policy) }} @@ -451,7 +455,7 @@ server { {{- end }} {{- if (not (contains $paths "/")) }} location / { - return {{ $default_root_response }}; + return {{ $globals.default_root_response }}; } {{- end }} } @@ -462,11 +466,11 @@ server { {{- if $server_tokens }} server_tokens {{ $server_tokens }}; {{- end }} - listen {{ $external_https_port }} ssl http2 {{ $default_server }}; - {{- if $enable_ipv6 }} - listen [::]:{{ $external_https_port }} ssl http2 {{ $default_server }}; + listen {{ $globals.external_https_port }} ssl http2 {{ $default_server }}; + {{- if $globals.enable_ipv6 }} + listen [::]:{{ $globals.external_https_port }} ssl http2 {{ $default_server }}; {{- end }} - {{ $access_log }} + {{ $globals.access_log }} return 500; ssl_certificate /etc/nginx/certs/default.crt; From b16ad278780bc011aaff71c6233520aa95cf8619 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Tue, 17 Jan 2023 08:17:02 +0100 Subject: [PATCH 110/300] build: dockergen 0.9.2 -> 0.9.3 --- Dockerfile | 2 +- Dockerfile.alpine | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index fa227cf..54e3a67 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # setup build arguments for version of dependencies to use -ARG DOCKER_GEN_VERSION=0.9.2 +ARG DOCKER_GEN_VERSION=0.9.3 ARG FOREGO_VERSION=v0.17.0 # Use a specific version of golang to build both binaries diff --git a/Dockerfile.alpine b/Dockerfile.alpine index 5473e53..da8f06e 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -1,5 +1,5 @@ # setup build arguments for version of dependencies to use -ARG DOCKER_GEN_VERSION=0.9.2 +ARG DOCKER_GEN_VERSION=0.9.3 ARG FOREGO_VERSION=v0.17.0 # Use a specific version of golang to build both binaries From 26b0b05f730cd6dfdb8c77f9ee18fabce3a82019 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Mon, 16 Jan 2023 19:22:20 -0500 Subject: [PATCH 111/300] tests: Fix `test_debug/*` tests when IPv6 is enabled --- test/test_debug/test_proxy-debug-flag.py | 8 ++++---- test/test_debug/test_server-debug-flag.py | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/test/test_debug/test_proxy-debug-flag.py b/test/test_debug/test_proxy-debug-flag.py index af7f73a..6430d84 100644 --- a/test/test_debug/test_proxy-debug-flag.py +++ b/test/test_debug/test_proxy-debug-flag.py @@ -3,10 +3,10 @@ import re def test_debug_info_is_present_in_nginx_generated_conf(docker_compose, nginxproxy): conf = nginxproxy.get_conf().decode('ASCII') - assert re.search(r"# Exposed ports: \[\{\d+\.\d+\.\d+\.\d+\s+80\s+tcp \} \{\d+\.\d+\.\d+\.\d+\s+81\s+tcp \}\]", conf) or \ - re.search(r"# Exposed ports: \[\{\d+\.\d+\.\d+\.\d+\s+81\s+tcp \} \{\d+\.\d+\.\d+\.\d+\s+80\s+tcp \}\]", conf) - assert re.search(r"# Exposed ports: \[\{\d+\.\d+\.\d+\.\d+\s+82\s+tcp \} \{\d+\.\d+\.\d+\.\d+\s+83\s+tcp \}\]", conf) or \ - re.search(r"# Exposed ports: \[\{\d+\.\d+\.\d+\.\d+\s+83\s+tcp \} \{\d+\.\d+\.\d+\.\d+\s+82\s+tcp \}\]", conf) + assert re.search(r"# Exposed ports: \[\{[^}]+\s+80\s+tcp \} \{[^}]+\s+81\s+tcp \}\]", conf) or \ + re.search(r"# Exposed ports: \[\{[^}]+\s+81\s+tcp \} \{[^}]+\s+80\s+tcp \}\]", conf) + assert re.search(r"# Exposed ports: \[\{[^}]+\s+82\s+tcp \} \{[^}]+\s+83\s+tcp \}\]", conf) or \ + re.search(r"# Exposed ports: \[\{[^}]+\s+83\s+tcp \} \{[^}]+\s+82\s+tcp \}\]", conf) assert "# Default virtual port: 80" in conf assert "# VIRTUAL_PORT: 82" in conf assert conf.count("# /!\\ Virtual port not exposed") == 1 diff --git a/test/test_debug/test_server-debug-flag.py b/test/test_debug/test_server-debug-flag.py index 50ae737..c635175 100644 --- a/test/test_debug/test_server-debug-flag.py +++ b/test/test_debug/test_server-debug-flag.py @@ -3,6 +3,6 @@ import re def test_debug_info_is_present_in_nginx_generated_conf(docker_compose, nginxproxy): conf = nginxproxy.get_conf().decode('ASCII') - assert re.search(r"# Exposed ports: \[\{\d+\.\d+\.\d+\.\d+\s+80\s+tcp \} \{\d+\.\d+\.\d+\.\d+\s+81\s+tcp \}\]", conf) or \ - re.search(r"# Exposed ports: \[\{\d+\.\d+\.\d+\.\d+\s+81\s+tcp \} \{\d+\.\d+\.\d+\.\d+\s+80\s+tcp \}\]", conf) + assert re.search(r"# Exposed ports: \[\{[^}]+\s+80\s+tcp \} \{[^}]+\s+81\s+tcp \}\]", conf) or \ + re.search(r"# Exposed ports: \[\{[^}]+\s+81\s+tcp \} \{[^}]+\s+80\s+tcp \}\]", conf) assert conf.count("# Exposed ports: [{") == 1 From d56b5b370d8aef801ec2c1d7c13dfcf2a6f23c03 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Mon, 16 Jan 2023 23:37:48 -0500 Subject: [PATCH 112/300] tests: Whitespace fixes --- test/pytest.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/pytest.sh b/test/pytest.sh index 28275e5..beac0af 100755 --- a/test/pytest.sh +++ b/test/pytest.sh @@ -16,10 +16,10 @@ ARGS=("$@") echo "> Building nginx-proxy-tester image..." docker build -t nginx-proxy-tester -f "${DIR}/requirements/Dockerfile-nginx-proxy-tester" "${DIR}/requirements" -# run the nginx-proxy-tester container setting the correct value for the working dir in order for +# run the nginx-proxy-tester container setting the correct value for the working dir in order for # docker-compose to work properly when run from within that container. exec docker run --rm -it --name "nginx-proxy-pytest" \ --volume "/var/run/docker.sock:/var/run/docker.sock" \ --volume "${DIR}:${DIR}" \ --workdir "${DIR}" \ - nginx-proxy-tester "${ARGS[@]}" \ No newline at end of file + nginx-proxy-tester "${ARGS[@]}" From 55cfae963689f3b583c17ca22831361e5b8c901d Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Mon, 16 Jan 2023 23:39:20 -0500 Subject: [PATCH 113/300] tests: Avoid unnecessary bashisms --- test/pytest.sh | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/test/pytest.sh b/test/pytest.sh index beac0af..2ac281d 100755 --- a/test/pytest.sh +++ b/test/pytest.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/sh ############################################################################### # # # This script is meant to run the test suite from a Docker container. # @@ -9,8 +9,7 @@ ############################################################################### # Returns the absolute directory path to this script -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -ARGS=("$@") +DIR=$(cd "${0%/*}" && pwd) # check requirements echo "> Building nginx-proxy-tester image..." @@ -22,4 +21,4 @@ exec docker run --rm -it --name "nginx-proxy-pytest" \ --volume "/var/run/docker.sock:/var/run/docker.sock" \ --volume "${DIR}:${DIR}" \ --workdir "${DIR}" \ - nginx-proxy-tester "${ARGS[@]}" + nginx-proxy-tester "$@" From 569953521aa5eca5261d97f08785b5a9edf03880 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Mon, 16 Jan 2023 23:49:32 -0500 Subject: [PATCH 114/300] tests: Exit non-zero if creation of nginx-proxy-tester image fails --- test/pytest.sh | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/test/pytest.sh b/test/pytest.sh index 2ac281d..8e46ce0 100755 --- a/test/pytest.sh +++ b/test/pytest.sh @@ -9,11 +9,14 @@ ############################################################################### # Returns the absolute directory path to this script -DIR=$(cd "${0%/*}" && pwd) +DIR=$(cd "${0%/*}" && pwd) || exit 1 # check requirements echo "> Building nginx-proxy-tester image..." -docker build -t nginx-proxy-tester -f "${DIR}/requirements/Dockerfile-nginx-proxy-tester" "${DIR}/requirements" +docker build -t nginx-proxy-tester \ + -f "${DIR}/requirements/Dockerfile-nginx-proxy-tester" \ + "${DIR}/requirements" \ + || exit 1 # run the nginx-proxy-tester container setting the correct value for the working dir in order for # docker-compose to work properly when run from within that container. From 486addd14403f016ebd829e4611d81e6b830c9f8 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Mon, 16 Jan 2023 23:53:51 -0500 Subject: [PATCH 115/300] tests: Bind-mount the entire nginx-proxy directory in the container --- test/pytest.sh | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/test/pytest.sh b/test/pytest.sh index 8e46ce0..9088d10 100755 --- a/test/pytest.sh +++ b/test/pytest.sh @@ -9,13 +9,14 @@ ############################################################################### # Returns the absolute directory path to this script -DIR=$(cd "${0%/*}" && pwd) || exit 1 +TESTDIR=$(cd "${0%/*}" && pwd) || exit 1 +DIR=$(cd "${TESTDIR}/.." && pwd) || exit 1 # check requirements echo "> Building nginx-proxy-tester image..." docker build -t nginx-proxy-tester \ - -f "${DIR}/requirements/Dockerfile-nginx-proxy-tester" \ - "${DIR}/requirements" \ + -f "${TESTDIR}/requirements/Dockerfile-nginx-proxy-tester" \ + "${TESTDIR}/requirements" \ || exit 1 # run the nginx-proxy-tester container setting the correct value for the working dir in order for @@ -23,5 +24,5 @@ docker build -t nginx-proxy-tester \ exec docker run --rm -it --name "nginx-proxy-pytest" \ --volume "/var/run/docker.sock:/var/run/docker.sock" \ --volume "${DIR}:${DIR}" \ - --workdir "${DIR}" \ + --workdir "${TESTDIR}" \ nginx-proxy-tester "$@" From 92e1a6567ead9e2cdb7dea17774b0a20d187af6a Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Tue, 17 Jan 2023 00:02:02 -0500 Subject: [PATCH 116/300] tests: Remove extraction of `nginx.tmpl` (now unnecessary) --- test/test_dockergen/test_dockergen_v2.py | 36 ++--------------------- test/test_dockergen/test_dockergen_v2.yml | 2 +- test/test_dockergen/test_dockergen_v3.py | 33 ++------------------- test/test_dockergen/test_dockergen_v3.yml | 2 +- 4 files changed, 6 insertions(+), 67 deletions(-) diff --git a/test/test_dockergen/test_dockergen_v2.py b/test/test_dockergen/test_dockergen_v2.py index 43b1431..dbb15d4 100644 --- a/test/test_dockergen/test_dockergen_v2.py +++ b/test/test_dockergen/test_dockergen_v2.py @@ -1,41 +1,9 @@ -import os -import docker -import logging -import pytest - - -@pytest.fixture(scope="module") -def nginx_tmpl(): - """ - pytest fixture which extracts the the nginx config template from - the nginxproxy/nginx-proxy:test image - """ - script_dir = os.path.dirname(__file__) - logging.info("extracting nginx.tmpl from nginxproxy/nginx-proxy:test") - docker_client = docker.from_env() - print( - docker_client.containers.run( - image="nginxproxy/nginx-proxy:test", - remove=True, - volumes=["{current_dir}:{current_dir}".format(current_dir=script_dir)], - entrypoint="sh", - command='-xc "cp /app/nginx.tmpl {current_dir} && chmod 777 {current_dir}/nginx.tmpl"'.format( - current_dir=script_dir - ), - stderr=True, - ) - ) - yield - logging.info("removing nginx.tmpl") - os.remove(os.path.join(script_dir, "nginx.tmpl")) - - -def test_unknown_virtual_host_is_503(nginx_tmpl, docker_compose, nginxproxy): +def test_unknown_virtual_host_is_503(docker_compose, nginxproxy): r = nginxproxy.get("http://unknown.nginx.container.docker/") assert r.status_code == 503 -def test_forwards_to_whoami(nginx_tmpl, docker_compose, nginxproxy): +def test_forwards_to_whoami(docker_compose, nginxproxy): r = nginxproxy.get("http://whoami.nginx.container.docker/") assert r.status_code == 200 whoami_container = docker_compose.containers.get("whoami") diff --git a/test/test_dockergen/test_dockergen_v2.yml b/test/test_dockergen/test_dockergen_v2.yml index b1f443c..36ee1c1 100644 --- a/test/test_dockergen/test_dockergen_v2.yml +++ b/test/test_dockergen/test_dockergen_v2.yml @@ -14,7 +14,7 @@ services: - nginx volumes: - /var/run/docker.sock:/tmp/docker.sock:ro - - ./nginx.tmpl:/etc/docker-gen/templates/nginx.tmpl + - ../../nginx.tmpl:/etc/docker-gen/templates/nginx.tmpl web: image: web diff --git a/test/test_dockergen/test_dockergen_v3.py b/test/test_dockergen/test_dockergen_v3.py index 67561bf..b696e6c 100644 --- a/test/test_dockergen/test_dockergen_v3.py +++ b/test/test_dockergen/test_dockergen_v3.py @@ -1,8 +1,5 @@ -import os import docker -import logging import pytest -import re from distutils.version import LooseVersion @@ -13,38 +10,12 @@ pytestmark = pytest.mark.skipif( ) -@pytest.fixture(scope="module") -def nginx_tmpl(): - """ - pytest fixture which extracts the the nginx config template from - the nginxproxy/nginx-proxy:test image - """ - script_dir = os.path.dirname(__file__) - logging.info("extracting nginx.tmpl from nginxproxy/nginx-proxy:test") - docker_client = docker.from_env() - print( - docker_client.containers.run( - image="nginxproxy/nginx-proxy:test", - remove=True, - volumes=["{current_dir}:{current_dir}".format(current_dir=script_dir)], - entrypoint="sh", - command='-xc "cp /app/nginx.tmpl {current_dir} && chmod 777 {current_dir}/nginx.tmpl"'.format( - current_dir=script_dir - ), - stderr=True, - ) - ) - yield - logging.info("removing nginx.tmpl") - os.remove(os.path.join(script_dir, "nginx.tmpl")) - - -def test_unknown_virtual_host_is_503(nginx_tmpl, docker_compose, nginxproxy): +def test_unknown_virtual_host_is_503(docker_compose, nginxproxy): r = nginxproxy.get("http://unknown.nginx.container.docker/") assert r.status_code == 503 -def test_forwards_to_whoami(nginx_tmpl, docker_compose, nginxproxy): +def test_forwards_to_whoami(docker_compose, nginxproxy): r = nginxproxy.get("http://whoami.nginx.container.docker/") assert r.status_code == 200 whoami_container = docker_compose.containers.get("whoami") diff --git a/test/test_dockergen/test_dockergen_v3.yml b/test/test_dockergen/test_dockergen_v3.yml index 8339273..8b0411c 100644 --- a/test/test_dockergen/test_dockergen_v3.yml +++ b/test/test_dockergen/test_dockergen_v3.yml @@ -11,7 +11,7 @@ services: command: -notify-sighup nginx -watch /etc/docker-gen/templates/nginx.tmpl /etc/nginx/conf.d/default.conf volumes: - /var/run/docker.sock:/tmp/docker.sock:ro - - ./nginx.tmpl:/etc/docker-gen/templates/nginx.tmpl + - ../../nginx.tmpl:/etc/docker-gen/templates/nginx.tmpl - nginx_conf:/etc/nginx/conf.d web: From 8fbc8514ef3cd4a464c0ed7315590f8dee8b972c Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Tue, 17 Jan 2023 21:23:08 -0500 Subject: [PATCH 117/300] feat: Unconditionally produce debug comments Rationale for eliminating the check to see if the `DEBUG` environment variable holds a true value: * The `DEBUG` environment variable might be set on a container (for purposes specific to that container, not `nginx-proxy`) to a value that cannot be parsed as a bool, which would break `nginx-proxy`. * It simplifies the template. * It eliminates a cold code path. * It avoids heisenbugs. * It makes debugging easier for users. Also delete the debug info tests, as they are fragile and they provide limited value. Alternatively, we could avoid collision with the container's use of the `DEBUG` environment variable by using a container label [1] such as `com.google.nginx-proxy.nginx-proxy.debug`. I think doing so has dubious value, especially if we want to attempt backwards compatibility with the `DEBUG` environment variable. Fixes #2139 [1] https://docs.docker.com/engine/reference/commandline/run/#-set-metadata-on-container--l---label---label-file Co-authored-by: Nicolas Duchon --- README.md | 7 ++--- nginx.tmpl | 9 ++----- .../test_deleted_cert/docker-compose.yml | 4 +-- test/test_debug/test_proxy-debug-flag.py | 12 --------- test/test_debug/test_proxy-debug-flag.yml | 26 ------------------- test/test_debug/test_server-debug-flag.py | 8 ------ test/test_debug/test_server-debug-flag.yml | 25 ------------------ 7 files changed, 7 insertions(+), 84 deletions(-) delete mode 100644 test/test_debug/test_proxy-debug-flag.py delete mode 100644 test/test_debug/test_proxy-debug-flag.yml delete mode 100644 test/test_debug/test_server-debug-flag.py delete mode 100644 test/test_debug/test_server-debug-flag.yml diff --git a/README.md b/README.md index 0ca08d7..82b2dcf 100644 --- a/README.md +++ b/README.md @@ -490,12 +490,13 @@ Please note that using regular expressions in `VIRTUAL_HOST` will always result ### Troubleshooting -In case you can't access your VIRTUAL_HOST, set `DEBUG=true` in the client container's environment and have a look at the generated nginx configuration file `/etc/nginx/conf.d/default.conf`: +If you can't access your `VIRTUAL_HOST`, inspect the generated nginx configuration: ```console -docker exec cat /etc/nginx/conf.d/default.conf +docker exec nginx -T ``` -Especially at `upstream` definition blocks which should look like: + +Pay attention to the `upstream` definition blocks, which should look like this: ```Nginx # foo.example.com diff --git a/nginx.tmpl b/nginx.tmpl index fb4f76f..2abfb7c 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -12,7 +12,6 @@ {{- $_ := set $globals "nginx_proxy_version" (coalesce $globals.Env.NGINX_PROXY_VERSION "") }} {{- $_ := set $globals "external_http_port" (coalesce $globals.Env.HTTP_PORT "80") }} {{- $_ := set $globals "external_https_port" (coalesce $globals.Env.HTTPS_PORT "443") }} -{{- $_ := set $globals "debug_all" $globals.Env.DEBUG }} {{- $_ := 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")) }} @@ -106,22 +105,18 @@ {{- define "upstream" }} {{- $networks := .Networks }} - {{- $debug_all := .Debug }} upstream {{ .Upstream }} { {{- $server_found := false }} {{- range $container := .Containers }} - {{- $debug := parseBool (coalesce $container.Env.DEBUG $debug_all "false") }} {{- /* If only 1 port exposed, use that as a default, else 80 */}} {{- $defaultPort := (when (eq (len $container.Addresses) 1) (first $container.Addresses) (dict "Port" "80")).Port }} {{- $port := (coalesce $container.Env.VIRTUAL_PORT $defaultPort) }} {{- $address := where $container.Addresses "Port" $port | first }} - {{- if $debug }} # Exposed ports: {{ $container.Addresses }} # Default virtual port: {{ $defaultPort }} # VIRTUAL_PORT: {{ $container.Env.VIRTUAL_PORT }} - {{- if not $address }} + {{- if not $address }} # /!\ Virtual port not exposed - {{- end }} {{- end }} {{- range $knownNetwork := $networks }} {{- range $containerNetwork := sortObjectsByKeysAsc $container.Networks "Name" }} @@ -292,7 +287,7 @@ server { {{- $upstream = printf "%s-%s" $upstream $sum }} {{- end }} # {{ $host }}{{ $path }} -{{ template "upstream" (dict "Upstream" $upstream "Containers" $containers "Networks" $globals.CurrentContainer.Networks "Debug" $globals.debug_all) }} +{{ template "upstream" (dict "Upstream" $upstream "Containers" $containers "Networks" $globals.CurrentContainer.Networks) }} {{- end }} {{- $default_host := or ($globals.Env.DEFAULT_HOST) "" }} diff --git a/test/stress_tests/test_deleted_cert/docker-compose.yml b/test/stress_tests/test_deleted_cert/docker-compose.yml index 33c92a7..a42abac 100644 --- a/test/stress_tests/test_deleted_cert/docker-compose.yml +++ b/test/stress_tests/test_deleted_cert/docker-compose.yml @@ -10,8 +10,6 @@ web: reverseproxy: image: nginxproxy/nginx-proxy:test container_name: reverseproxy - environment: - DEBUG: "true" volumes: - /var/run/docker.sock:/tmp/docker.sock:ro - - ./tmp_certs:/etc/nginx/certs:ro \ No newline at end of file + - ./tmp_certs:/etc/nginx/certs:ro diff --git a/test/test_debug/test_proxy-debug-flag.py b/test/test_debug/test_proxy-debug-flag.py deleted file mode 100644 index 6430d84..0000000 --- a/test/test_debug/test_proxy-debug-flag.py +++ /dev/null @@ -1,12 +0,0 @@ -import pytest -import re - -def test_debug_info_is_present_in_nginx_generated_conf(docker_compose, nginxproxy): - conf = nginxproxy.get_conf().decode('ASCII') - assert re.search(r"# Exposed ports: \[\{[^}]+\s+80\s+tcp \} \{[^}]+\s+81\s+tcp \}\]", conf) or \ - re.search(r"# Exposed ports: \[\{[^}]+\s+81\s+tcp \} \{[^}]+\s+80\s+tcp \}\]", conf) - assert re.search(r"# Exposed ports: \[\{[^}]+\s+82\s+tcp \} \{[^}]+\s+83\s+tcp \}\]", conf) or \ - re.search(r"# Exposed ports: \[\{[^}]+\s+83\s+tcp \} \{[^}]+\s+82\s+tcp \}\]", conf) - assert "# Default virtual port: 80" in conf - assert "# VIRTUAL_PORT: 82" in conf - assert conf.count("# /!\\ Virtual port not exposed") == 1 diff --git a/test/test_debug/test_proxy-debug-flag.yml b/test/test_debug/test_proxy-debug-flag.yml deleted file mode 100644 index f930da3..0000000 --- a/test/test_debug/test_proxy-debug-flag.yml +++ /dev/null @@ -1,26 +0,0 @@ -web1: - image: web - expose: - - "80" - - "81" - environment: - WEB_PORTS: "80 81" - VIRTUAL_HOST: "web1.nginx-proxy.tld" - VIRTUAL_PORT: "82" - -web2: - image: web - expose: - - "82" - - "83" - environment: - WEB_PORTS: "82 83" - VIRTUAL_HOST: "web2.nginx-proxy.tld" - VIRTUAL_PORT: "82" - -sut: - image: nginxproxy/nginx-proxy:test - volumes: - - /var/run/docker.sock:/tmp/docker.sock:ro - environment: - DEBUG: "true" diff --git a/test/test_debug/test_server-debug-flag.py b/test/test_debug/test_server-debug-flag.py deleted file mode 100644 index c635175..0000000 --- a/test/test_debug/test_server-debug-flag.py +++ /dev/null @@ -1,8 +0,0 @@ -import pytest -import re - -def test_debug_info_is_present_in_nginx_generated_conf(docker_compose, nginxproxy): - conf = nginxproxy.get_conf().decode('ASCII') - assert re.search(r"# Exposed ports: \[\{[^}]+\s+80\s+tcp \} \{[^}]+\s+81\s+tcp \}\]", conf) or \ - re.search(r"# Exposed ports: \[\{[^}]+\s+81\s+tcp \} \{[^}]+\s+80\s+tcp \}\]", conf) - assert conf.count("# Exposed ports: [{") == 1 diff --git a/test/test_debug/test_server-debug-flag.yml b/test/test_debug/test_server-debug-flag.yml deleted file mode 100644 index 89bb6b5..0000000 --- a/test/test_debug/test_server-debug-flag.yml +++ /dev/null @@ -1,25 +0,0 @@ -web1: - image: web - expose: - - "80" - - "81" - environment: - WEB_PORTS: "80 81" - VIRTUAL_HOST: "web1.nginx-proxy.tld" - VIRTUAL_PORT: "82" - DEBUG: "true" - -web2: - image: web - expose: - - "82" - - "83" - environment: - WEB_PORTS: "82 83" - VIRTUAL_HOST: "web2.nginx-proxy.tld" - VIRTUAL_PORT: "82" - -sut: - image: nginxproxy/nginx-proxy:test - volumes: - - /var/run/docker.sock:/tmp/docker.sock:ro From 8df67cdde8cc3216a2f07ab1b35446655d63607d Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Mon, 23 Jan 2023 23:14:42 +0100 Subject: [PATCH 118/300] build: dockergen 0.9.3 -> 0.9.4 --- Dockerfile | 2 +- Dockerfile.alpine | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 54e3a67..548e2e3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # setup build arguments for version of dependencies to use -ARG DOCKER_GEN_VERSION=0.9.3 +ARG DOCKER_GEN_VERSION=0.9.4 ARG FOREGO_VERSION=v0.17.0 # Use a specific version of golang to build both binaries diff --git a/Dockerfile.alpine b/Dockerfile.alpine index da8f06e..5dc34a5 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -1,5 +1,5 @@ # setup build arguments for version of dependencies to use -ARG DOCKER_GEN_VERSION=0.9.3 +ARG DOCKER_GEN_VERSION=0.9.4 ARG FOREGO_VERSION=v0.17.0 # Use a specific version of golang to build both binaries From fa52426d5449766b3ffd6187536a65d465ebfaa3 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Mon, 23 Jan 2023 23:24:58 +0100 Subject: [PATCH 119/300] ci: set Dependabot commit prefixs --- .github/dependabot.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 81ddf73..eb6a749 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -5,6 +5,8 @@ updates: directory: "/" schedule: interval: "daily" + commit-message: + prefix: "build" labels: - "type/build" - "scope/dockerfile" @@ -14,5 +16,7 @@ updates: directory: "/test/requirements" schedule: interval: "daily" + commit-message: + prefix: "ci" labels: - "type/ci" From f8ae0a4b0020e3e59a3ba02ad889206d00d85857 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Wed, 18 Jan 2023 18:27:35 -0500 Subject: [PATCH 120/300] feat: `DEFAULT_ROOT=none` disables the default `location /` block --- README.md | 15 +++++++++++---- nginx.tmpl | 2 +- test/test_default-root-none.py | 8 ++++++++ test/test_default-root-none.yml | 15 +++++++++++++++ 4 files changed, 35 insertions(+), 5 deletions(-) create mode 100644 test/test_default-root-none.py create mode 100644 test/test_default-root-none.yml diff --git a/README.md b/README.md index 82b2dcf..951e2f6 100644 --- a/README.md +++ b/README.md @@ -152,10 +152,17 @@ The filename of the previous example would be `example.tld_8610f6c344b4096614eab This environment variable of the nginx proxy container can be used to customize the return error page if no matching path is found. Furthermore it is possible to use anything which is compatible with the `return` statement of nginx. -For example `DEFAULT_ROOT=418` will return a 418 error page instead of the normal 404 one. -Another example is `DEFAULT_ROOT="301 https://github.com/nginx-proxy/nginx-proxy/blob/main/README.md"` which would redirect an invalid request to this documentation. -Nginx variables such as $scheme, $host, and $request_uri can be used. However, care must be taken to make sure the $ signs are escaped properly. -If you want to use `301 $scheme://$host/myapp1$request_uri` you should use: +Exception: If this is set to the string `none`, no default `location /` directive will be generated. This makes it possible for you to provide your own `location /` directive in your [`/etc/nginx/vhost.d/VIRTUAL_HOST`](#per-virtual_host) or [`/etc/nginx/vhost.d/default`](#per-virtual_host-default-configuration) files. + +If unspecified, `DEFAULT_ROOT` defaults to `404`. + +Examples (YAML syntax): + + * `DEFAULT_ROOT: "none"` prevents `nginx-proxy` from generating a default `location /` directive. + * `DEFAULT_ROOT: "418"` returns a 418 error page instead of the normal 404 one. + * `DEFAULT_ROOT: "301 https://github.com/nginx-proxy/nginx-proxy/blob/main/README.md"` redirects the client to this documentation. + +Nginx variables such as `$scheme`, `$host`, and `$request_uri` can be used. However, care must be taken to make sure the `$` signs are escaped properly. For example, if you want to use `301 $scheme://$host/myapp1$request_uri` you should use: * Bash: `DEFAULT_ROOT='301 $scheme://$host/myapp1$request_uri'` * Docker Compose yaml: `- DEFAULT_ROOT: 301 $$scheme://$$host/myapp1$$request_uri` diff --git a/nginx.tmpl b/nginx.tmpl index 2abfb7c..18a2d23 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -448,7 +448,7 @@ server { {{- end }} {{- template "location" (dict "Path" $path "Proto" $proto "Upstream" $upstream "Host" $host "VhostRoot" $vhost_root "Dest" $dest "NetworkTag" $network_tag) }} {{- end }} - {{- if (not (contains $paths "/")) }} + {{- if and (not (contains $paths "/")) (ne $globals.default_root_response "none")}} location / { return {{ $globals.default_root_response }}; } diff --git a/test/test_default-root-none.py b/test/test_default-root-none.py new file mode 100644 index 0000000..742d87b --- /dev/null +++ b/test/test_default-root-none.py @@ -0,0 +1,8 @@ +import re + + +def test_default_root_none(docker_compose, nginxproxy): + conf = nginxproxy.get_conf().decode() + assert re.search(r"(?m)^\s*location\s+/path\s+\{", conf) + assert not re.search(r"(?m)^\s*location\s+/\s+\{", conf) + diff --git a/test/test_default-root-none.yml b/test/test_default-root-none.yml new file mode 100644 index 0000000..309d2ab --- /dev/null +++ b/test/test_default-root-none.yml @@ -0,0 +1,15 @@ +services: + sut: + image: nginxproxy/nginx-proxy:test + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro + environment: + DEFAULT_ROOT: none + web: + image: web + expose: + - "80" + environment: + WEB_PORTS: "80" + VIRTUAL_HOST: web.nginx-proxy.test + VIRTUAL_PATH: /path From 8346b68a288ed20eab50a8dbeb959ac6e2ef5f15 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Sat, 21 Jan 2023 19:11:28 -0500 Subject: [PATCH 121/300] fix: Ignore `VIRTUAL_HOST` set to the empty string Fixes #2144 --- nginx.tmpl | 4 ++++ test/test_vhost-empty-string.py | 10 +++++++++ test/test_vhost-empty-string.yml | 37 ++++++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+) create mode 100644 test/test_vhost-empty-string.py create mode 100644 test/test_vhost-empty-string.yml diff --git a/nginx.tmpl b/nginx.tmpl index 18a2d23..f2e2bcf 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -271,6 +271,10 @@ server { {{- range $host, $containers := groupByMulti $globals.containers "Env.VIRTUAL_HOST" "," }} {{- $host := trim $host }} + {{- if not $host }} + {{- /* Ignore containers with VIRTUAL_HOST set to the empty string. */}} + {{- continue }} + {{- end }} {{- $is_regexp := hasPrefix "~" $host }} {{- $upstream_name := when (or $is_regexp $globals.sha1_upstream_name) (sha1 $host) $host }} diff --git a/test/test_vhost-empty-string.py b/test/test_vhost-empty-string.py new file mode 100644 index 0000000..707becb --- /dev/null +++ b/test/test_vhost-empty-string.py @@ -0,0 +1,10 @@ +import re + + +def test_vhost_empty_string(docker_compose, nginxproxy): + conf = nginxproxy.get_conf().decode() + assert re.search(r"(?m)^\s*server_name\s+web2\.nginx-proxy\.test\s*;", conf) + assert re.search(r"(?m)^\s*server_name\s+web3\.nginx-proxy\.test\s*;", conf) + assert re.search(r"(?m)^\s*server_name\s+web4a\.nginx-proxy\.test\s*;", conf) + assert re.search(r"(?m)^\s*server_name\s+web4b\.nginx-proxy\.test\s*;", conf) + assert not re.search(r"(?m)^\s*server_name\s*;", conf) diff --git a/test/test_vhost-empty-string.yml b/test/test_vhost-empty-string.yml new file mode 100644 index 0000000..83dd554 --- /dev/null +++ b/test/test_vhost-empty-string.yml @@ -0,0 +1,37 @@ +services: + sut: + image: nginxproxy/nginx-proxy:test + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro + web1: + image: web + expose: + - "81" + environment: + WEB_PORTS: "81" + # The space is intentional (should be trimmed). + VIRTUAL_HOST: " " + web2: + image: web + expose: + - "82" + environment: + WEB_PORTS: "82" + # The space is intentional (should be trimmed). + VIRTUAL_HOST: "web2.nginx-proxy.test ," + web3: + image: web + expose: + - "83" + environment: + WEB_PORTS: "83" + # The space is intentional (should be trimmed). + VIRTUAL_HOST: " ,web3.nginx-proxy.test" + web4: + image: web + expose: + - "84" + environment: + WEB_PORTS: "84" + # The spaces are intentional (should be trimmed). + VIRTUAL_HOST: "web4a.nginx-proxy.test, , web4b.nginx-proxy.test" From 07cc80ac6bb2d390b4ba2b8e0332101a19df79e3 Mon Sep 17 00:00:00 2001 From: Vincent Herlemont Date: Fri, 27 Jan 2023 18:28:40 +0100 Subject: [PATCH 122/300] feat: Support LOG_FORMAT env variable (#2151) --- nginx.tmpl | 5 +---- test/test_log_format.py | 11 +++++++++++ test/test_log_format.yml | 15 +++++++++++++++ 3 files changed, 27 insertions(+), 4 deletions(-) create mode 100644 test/test_log_format.py create mode 100644 test/test_log_format.yml diff --git a/nginx.tmpl b/nginx.tmpl index f2e2bcf..54872e4 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -210,10 +210,7 @@ map $proxy_x_forwarded_proto $proxy_x_forwarded_ssl { gzip_types text/plain text/css application/javascript application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript; -log_format vhost '$host $remote_addr - $remote_user [$time_local] ' - '"$request" $status $body_bytes_sent ' - '"$http_referer" "$http_user_agent" ' - '"$upstream_addr"'; +log_format vhost '{{ or $globals.Env.LOG_FORMAT "$host $remote_addr - $remote_user [$time_local] \"$request\" $status $body_bytes_sent \"$http_referer\" \"$http_user_agent\" \"$upstream_addr\"" }}'; access_log off; diff --git a/test/test_log_format.py b/test/test_log_format.py new file mode 100644 index 0000000..589f0c7 --- /dev/null +++ b/test/test_log_format.py @@ -0,0 +1,11 @@ +import pytest + +def test_log_format(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 "request_time=" in docker_logs[0] diff --git a/test/test_log_format.yml b/test/test_log_format.yml new file mode 100644 index 0000000..ef3bbf6 --- /dev/null +++ b/test/test_log_format.yml @@ -0,0 +1,15 @@ +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: + LOG_FORMAT: "$$remote_addr - $$remote_user [$$time_local] \"$$request\" $$status $$body_bytes_sent \"$$http_referer\" \"$$http_user_agent\" request_time=$$request_time $$upstream_response_time" From aa50116272e3aa45ae85101757fa99bdd113712d Mon Sep 17 00:00:00 2001 From: Vincent Herlemont Date: Fri, 27 Jan 2023 23:16:49 +0100 Subject: [PATCH 123/300] Documentation custom log format. --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 951e2f6..51d7b80 100644 --- a/README.md +++ b/README.md @@ -227,6 +227,11 @@ If you would like to connect to FastCGI backend, set `VIRTUAL_PROTO=fastcgi` on If you use fastcgi,you can set `VIRTUAL_ROOT=xxx` for your root directory +### Custom log format + +If you want to use a custom log format, you can set `LOG_FORMAT=xxx` on the proxy container. + +With docker compose take care to escape the `$` character with `$$` to avoid variable interpolation. Example: `$remote_addr` becomes `$$remote_addr`. ### Default Host From e97bf606c8c45e708f5617f1f9a6e1dd9e99a243 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Wed, 25 Jan 2023 17:49:23 -0500 Subject: [PATCH 124/300] chore: Move version comment to the top of the template to ensure that the version is always the first output line. Also, always output `# nginx-proxy`, even if the version isn't known. This makes it easier to find the start of the generated config in the output of `nginx -T`. --- nginx.tmpl | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/nginx.tmpl b/nginx.tmpl index 54872e4..b44f4d5 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -1,3 +1,5 @@ +# 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 variables so that the values can be easily passed to embedded @@ -9,7 +11,6 @@ {{- $_ := set $globals "Env" $.Env }} {{- $_ := set $globals "Docker" $.Docker }} {{- $_ := set $globals "CurrentContainer" (where $globals.containers "ID" $globals.Docker.CurrentContainerID | first) }} -{{- $_ := set $globals "nginx_proxy_version" (coalesce $globals.Env.NGINX_PROXY_VERSION "") }} {{- $_ := 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")) }} @@ -164,10 +165,6 @@ upstream {{ .Upstream }} { } {{- end }} -{{- if ne $globals.nginx_proxy_version "" }} -# nginx-proxy version : {{ $globals.nginx_proxy_version }} -{{- 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 { From 2760ead49041fa6dafaab6fd55120e41c3c1ec28 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Thu, 26 Jan 2023 16:39:13 -0500 Subject: [PATCH 125/300] chore: Remove warning comment when port is not exposed Exposing ports is largely deprecated because it doesn't actually do anything in Docker. --- nginx.tmpl | 3 --- 1 file changed, 3 deletions(-) diff --git a/nginx.tmpl b/nginx.tmpl index b44f4d5..0982aaa 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -116,9 +116,6 @@ upstream {{ .Upstream }} { # Exposed ports: {{ $container.Addresses }} # Default virtual port: {{ $defaultPort }} # VIRTUAL_PORT: {{ $container.Env.VIRTUAL_PORT }} - {{- if not $address }} - # /!\ Virtual port not exposed - {{- end }} {{- range $knownNetwork := $networks }} {{- range $containerNetwork := sortObjectsByKeysAsc $container.Networks "Name" }} {{- if (and (ne $containerNetwork.Name "ingress") (or (eq $knownNetwork.Name $containerNetwork.Name) (eq $knownNetwork.Name "host"))) }} From 5a8a6ceae2cee36b3f60168bc496fa9ec568f3de Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Thu, 26 Jan 2023 16:53:52 -0500 Subject: [PATCH 126/300] chore: Improve debug comments in `upstream` template --- nginx.tmpl | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/nginx.tmpl b/nginx.tmpl index 0982aaa..9251948 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -109,17 +109,26 @@ upstream {{ .Upstream }} { {{- $server_found := false }} {{- range $container := .Containers }} + # Container: {{ $container.Name }} {{- /* If only 1 port exposed, use that as a default, else 80 */}} {{- $defaultPort := (when (eq (len $container.Addresses) 1) (first $container.Addresses) (dict "Port" "80")).Port }} {{- $port := (coalesce $container.Env.VIRTUAL_PORT $defaultPort) }} {{- $address := where $container.Addresses "Port" $port | first }} - # Exposed ports: {{ $container.Addresses }} - # Default virtual port: {{ $defaultPort }} - # VIRTUAL_PORT: {{ $container.Env.VIRTUAL_PORT }} + # Exposed ports:{{ range $container.Addresses }} {{ .Port }}/{{ .Proto }}{{ else }} (none){{ end }} + # Default virtual port: {{ $defaultPort }} + # VIRTUAL_PORT: {{ $container.Env.VIRTUAL_PORT }} + {{- if $container.Node.ID }} + # Swarm node name: {{ $container.Node.Name }} + {{- end }} {{- range $knownNetwork := $networks }} + # Container network reachability from {{ $knownNetwork.Name }}: {{- range $containerNetwork := sortObjectsByKeysAsc $container.Networks "Name" }} - {{- if (and (ne $containerNetwork.Name "ingress") (or (eq $knownNetwork.Name $containerNetwork.Name) (eq $knownNetwork.Name "host"))) }} - ## Can be connected with "{{ $containerNetwork.Name }}" network + {{- if eq $containerNetwork.Name "ingress" }} + # {{ $containerNetwork.Name }} (ignored) + {{- else if and (ne $knownNetwork.Name $containerNetwork.Name) (ne $knownNetwork.Name "host") }} + # {{ $containerNetwork.Name }} (unreachable) + {{- else }} + # {{ $containerNetwork.Name }} (reachable) {{- if $address }} {{- /* * If we got the containers from swarm and this @@ -128,7 +137,6 @@ upstream {{ .Upstream }} { */}} {{- if and $container.Node.ID $address.HostPort }} {{- $server_found = true }} - # {{ $container.Node.Name }}/{{ $container.Name }} server {{ $container.Node.Address.IP }}:{{ $address.HostPort }}; {{- /* * If there is no swarm node or the port is not @@ -136,21 +144,19 @@ upstream {{ .Upstream }} { */}} {{- else if $containerNetwork }} {{- $server_found = true }} - # {{ $container.Name }} server {{ $containerNetwork.IP }}:{{ $address.Port }}; {{- end }} {{- else if $containerNetwork }} - # {{ $container.Name }} {{- if $containerNetwork.IP }} {{- $server_found = true }} server {{ $containerNetwork.IP }}:{{ $port }}; {{- else }} - # /!\ No IP for this network! + # /!\ No IP for this network! {{- end }} {{- end }} - {{- else }} - # Cannot connect to network '{{ $containerNetwork.Name }}' of this container {{- end }} + {{- else }} + # (none) {{- end }} {{- end }} {{- end }} From daeed502cb639e0ffdeca25522af1538e125ccb5 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Thu, 26 Jan 2023 18:53:50 -0500 Subject: [PATCH 127/300] feat: Add a warning comment if the container port is published --- nginx.tmpl | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/nginx.tmpl b/nginx.tmpl index 9251948..f236000 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -117,6 +117,11 @@ upstream {{ .Upstream }} { # Exposed ports:{{ range $container.Addresses }} {{ .Port }}/{{ .Proto }}{{ else }} (none){{ end }} # Default virtual port: {{ $defaultPort }} # VIRTUAL_PORT: {{ $container.Env.VIRTUAL_PORT }} + {{- if and $address $address.HostPort }} + # /!\ WARNING: Virtual port published on host. Clients might be able to + # bypass nginx-proxy and access the container's server + # directly. + {{- end }} {{- if $container.Node.ID }} # Swarm node name: {{ $container.Node.Name }} {{- end }} From bcec2d9075c053b9930de52a32a712d69961a213 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Thu, 26 Jan 2023 19:13:36 -0500 Subject: [PATCH 128/300] chore: Refactor `upstream` template for readability In particular, reduce the nesting depth to make it easier to understand what the code is doing by: * converting an $O(nm)$ nested loop into two serial $O(n)+O(m)$ loops, and * consolidating similar nested `if` cases. --- nginx.tmpl | 72 +++++++++++++++++++++++++----------------------------- 1 file changed, 33 insertions(+), 39 deletions(-) diff --git a/nginx.tmpl b/nginx.tmpl index f236000..310b60e 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -19,6 +19,12 @@ {{- $_ := 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") }} +{{- $_ := set $globals "networks" (dict) }} +# networks available to nginx-proxy: +{{- range $globals.CurrentContainer.Networks }} + {{- $_ := set $globals.networks .Name . }} +# {{ .Name }} +{{- end }} {{- define "ssl_policy" }} {{- if eq .ssl_policy "Mozilla-Modern" }} @@ -113,11 +119,11 @@ upstream {{ .Upstream }} { {{- /* If only 1 port exposed, use that as a default, else 80 */}} {{- $defaultPort := (when (eq (len $container.Addresses) 1) (first $container.Addresses) (dict "Port" "80")).Port }} {{- $port := (coalesce $container.Env.VIRTUAL_PORT $defaultPort) }} - {{- $address := where $container.Addresses "Port" $port | first }} + {{- $addr_obj := where $container.Addresses "Port" $port | first }} # Exposed ports:{{ range $container.Addresses }} {{ .Port }}/{{ .Proto }}{{ else }} (none){{ end }} # Default virtual port: {{ $defaultPort }} # VIRTUAL_PORT: {{ $container.Env.VIRTUAL_PORT }} - {{- if and $address $address.HostPort }} + {{- if and $addr_obj $addr_obj.HostPort }} # /!\ WARNING: Virtual port published on host. Clients might be able to # bypass nginx-proxy and access the container's server # directly. @@ -125,44 +131,32 @@ upstream {{ .Upstream }} { {{- if $container.Node.ID }} # Swarm node name: {{ $container.Node.Name }} {{- end }} - {{- range $knownNetwork := $networks }} - # Container network reachability from {{ $knownNetwork.Name }}: - {{- range $containerNetwork := sortObjectsByKeysAsc $container.Networks "Name" }} - {{- if eq $containerNetwork.Name "ingress" }} + # Container networks: + {{- range $containerNetwork := sortObjectsByKeysAsc $container.Networks "Name" }} + {{- if eq $containerNetwork.Name "ingress" }} # {{ $containerNetwork.Name }} (ignored) - {{- else if and (ne $knownNetwork.Name $containerNetwork.Name) (ne $knownNetwork.Name "host") }} - # {{ $containerNetwork.Name }} (unreachable) - {{- else }} - # {{ $containerNetwork.Name }} (reachable) - {{- if $address }} - {{- /* - * If we got the containers from swarm and this - * container's port is published to host, use host - * IP:PORT. - */}} - {{- if and $container.Node.ID $address.HostPort }} - {{- $server_found = true }} - server {{ $container.Node.Address.IP }}:{{ $address.HostPort }}; - {{- /* - * If there is no swarm node or the port is not - * published on host, use container's IP:PORT. - */}} - {{- else if $containerNetwork }} - {{- $server_found = true }} - server {{ $containerNetwork.IP }}:{{ $address.Port }}; - {{- end }} - {{- else if $containerNetwork }} - {{- if $containerNetwork.IP }} - {{- $server_found = true }} - server {{ $containerNetwork.IP }}:{{ $port }}; - {{- else }} - # /!\ No IP for this network! - {{- end }} - {{- end }} - {{- end }} - {{- else }} - # (none) + {{- continue }} {{- end }} + {{- if and (not (index $networks $containerNetwork.Name)) (not $networks.host) }} + # {{ $containerNetwork.Name }} (unreachable) + {{- continue }} + {{- end }} + # {{ $containerNetwork.Name }} (reachable) + {{- /* + * If we got the containers from swarm and this container's + * port is published to host, use host IP:PORT. + */}} + {{- if and $container.Node.ID $addr_obj $addr_obj.HostPort }} + {{- $server_found = true }} + server {{ $container.Node.Address.IP }}:{{ $addr_obj.HostPort }}; + {{- else if and $containerNetwork $containerNetwork.IP }} + {{- $server_found = true }} + server {{ $containerNetwork.IP }}:{{ $port }}; + {{- else }} + # /!\ No IP for this network! + {{- end }} + {{- else }} + # (none) {{- end }} {{- end }} {{- /* nginx-proxy/nginx-proxy#1105 */}} @@ -293,7 +287,7 @@ server { {{- $upstream = printf "%s-%s" $upstream $sum }} {{- end }} # {{ $host }}{{ $path }} -{{ template "upstream" (dict "Upstream" $upstream "Containers" $containers "Networks" $globals.CurrentContainer.Networks) }} +{{ template "upstream" (dict "Upstream" $upstream "Containers" $containers "Networks" $globals.networks) }} {{- end }} {{- $default_host := or ($globals.Env.DEFAULT_HOST) "" }} From 6162427c4533a7c48881a5e666e206ba9b87084c Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Sat, 28 Jan 2023 00:19:21 -0500 Subject: [PATCH 129/300] fix: Generate at most one `server` directive per container --- nginx.tmpl | 23 +++++++++++++++++++---- test/test_multiple-networks.py | 19 ++++++++++++++++--- test/test_multiple-networks.yml | 15 +++++++++++++++ 3 files changed, 50 insertions(+), 7 deletions(-) diff --git a/nginx.tmpl b/nginx.tmpl index 310b60e..83f9222 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -118,6 +118,7 @@ upstream {{ .Upstream }} { # Container: {{ $container.Name }} {{- /* If only 1 port exposed, use that as a default, else 80 */}} {{- $defaultPort := (when (eq (len $container.Addresses) 1) (first $container.Addresses) (dict "Port" "80")).Port }} + {{- $ip := "" }} {{- $port := (coalesce $container.Env.VIRTUAL_PORT $defaultPort) }} {{- $addr_obj := where $container.Addresses "Port" $port | first }} # Exposed ports:{{ range $container.Addresses }} {{ .Port }}/{{ .Proto }}{{ else }} (none){{ end }} @@ -141,23 +142,37 @@ upstream {{ .Upstream }} { # {{ $containerNetwork.Name }} (unreachable) {{- continue }} {{- end }} + {{- /* + * Do not emit multiple `server` directives for this container + * if it is reachable over multiple networks. This avoids + * accidentally inflating the effective round-robin weight of + * this container due to the redundant upstreams that nginx sees + * as belonging to distinct servers. + */}} + {{- if $ip }} + # {{ $containerNetwork.Name }} (ignored; reachable but redundant) + {{- continue }} + {{- end }} # {{ $containerNetwork.Name }} (reachable) {{- /* * If we got the containers from swarm and this container's * port is published to host, use host IP:PORT. */}} {{- if and $container.Node.ID $addr_obj $addr_obj.HostPort }} - {{- $server_found = true }} - server {{ $container.Node.Address.IP }}:{{ $addr_obj.HostPort }}; + {{- $ip = $container.Node.Address.IP }} + {{- $port = $addr_obj.HostPort }} {{- else if and $containerNetwork $containerNetwork.IP }} - {{- $server_found = true }} - server {{ $containerNetwork.IP }}:{{ $port }}; + {{- $ip = $containerNetwork.IP }} {{- else }} # /!\ No IP for this network! {{- end }} {{- else }} # (none) {{- end }} + {{- if $ip }} + {{- $server_found = true }} + server {{ $ip }}:{{ $port }}; + {{- end }} {{- end }} {{- /* nginx-proxy/nginx-proxy#1105 */}} {{- if not $server_found }} diff --git a/test/test_multiple-networks.py b/test/test_multiple-networks.py index b9fa4c5..550d0a3 100644 --- a/test/test_multiple-networks.py +++ b/test/test_multiple-networks.py @@ -1,15 +1,28 @@ +import re + import pytest + def test_unknown_virtual_host(docker_compose, nginxproxy): r = nginxproxy.get("http://nginx-proxy/") assert r.status_code == 503 def test_forwards_to_web1(docker_compose, nginxproxy): r = nginxproxy.get("http://web1.nginx-proxy.local/port") - assert r.status_code == 200 + assert r.status_code == 200 assert r.text == "answer from port 81\n" def test_forwards_to_web2(docker_compose, nginxproxy): r = nginxproxy.get("http://web2.nginx-proxy.local/port") - assert r.status_code == 200 - assert r.text == "answer from port 82\n" \ No newline at end of file + assert r.status_code == 200 + assert r.text == "answer from port 82\n" + +def test_multipath(docker_compose, nginxproxy): + r = nginxproxy.get("http://web3.nginx-proxy.test/port") + assert r.status_code == 200 + assert r.text == "answer from port 83\n" + cfg = nginxproxy.get_conf().decode() + lines = cfg.splitlines() + web3_server_lines = [l for l in lines + if re.search(r'(?m)^\s*server\s+[^\s]*:83;\s*$', l)] + assert len(web3_server_lines) == 1 diff --git a/test/test_multiple-networks.yml b/test/test_multiple-networks.yml index e4548b5..7e79174 100644 --- a/test/test_multiple-networks.yml +++ b/test/test_multiple-networks.yml @@ -3,6 +3,8 @@ version: '2' networks: net1: {} net2: {} + net3a: {} + net3b: {} services: nginx-proxy: @@ -12,6 +14,8 @@ services: networks: - net1 - net2 + - net3a + - net3b web1: image: web @@ -32,3 +36,14 @@ services: VIRTUAL_HOST: web2.nginx-proxy.local networks: - net2 + + web3: + image: web + expose: + - "83" + environment: + WEB_PORTS: 83 + VIRTUAL_HOST: web3.nginx-proxy.test + networks: + - net3a + - net3b From 912a0654069097cc725eca74f7bae85df0e9c920 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Sat, 28 Jan 2023 18:14:59 -0500 Subject: [PATCH 130/300] chore: Pass `--pull` to `docker build` to get fresh images This is a no-op if the images are already up to date, and it prevents puzzling problems when the images are old. --- Makefile | 6 +++--- test/pytest.sh | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index ab44880..5e53e36 100644 --- a/Makefile +++ b/Makefile @@ -3,13 +3,13 @@ build-webserver: - docker build -t web test/requirements/web + docker build --pull -t web test/requirements/web build-nginx-proxy-test-debian: - docker build --build-arg NGINX_PROXY_VERSION="test" -t nginxproxy/nginx-proxy:test . + docker build --pull --build-arg NGINX_PROXY_VERSION="test" -t nginxproxy/nginx-proxy:test . build-nginx-proxy-test-alpine: - docker build --build-arg NGINX_PROXY_VERSION="test" -f Dockerfile.alpine -t nginxproxy/nginx-proxy:test . + docker build --pull --build-arg NGINX_PROXY_VERSION="test" -f Dockerfile.alpine -t nginxproxy/nginx-proxy:test . test-debian: build-webserver build-nginx-proxy-test-debian test/pytest.sh diff --git a/test/pytest.sh b/test/pytest.sh index 9088d10..19a8188 100755 --- a/test/pytest.sh +++ b/test/pytest.sh @@ -14,7 +14,7 @@ DIR=$(cd "${TESTDIR}/.." && pwd) || exit 1 # check requirements echo "> Building nginx-proxy-tester image..." -docker build -t nginx-proxy-tester \ +docker build --pull -t nginx-proxy-tester \ -f "${TESTDIR}/requirements/Dockerfile-nginx-proxy-tester" \ "${TESTDIR}/requirements" \ || exit 1 From 2115974e939d685f21b9e65041b5a9984451cd4a Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Sat, 28 Jan 2023 02:27:18 -0500 Subject: [PATCH 131/300] feat: Add ability to completely override location blocks Co-authored-by: Trent Harvey --- README.md | 26 +++++++++++ nginx.tmpl | 34 ++++++++------ test/test_location-override.py | 39 ++++++++++++++++ ...8b1b0f03eb30a1afd00e5696_location_override | 3 ++ ...d8fd4e056c2568d7c2e3ffa8_location_override | 4 ++ ...-nohash.nginx-proxy.test_location_override | 4 ++ ...d8fd4e056c2568d7c2e3ffa8_location_override | 3 ++ ...-nohash.nginx-proxy.test_location_override | 3 ++ ...d8fd4e056c2568d7c2e3ffa8_location_override | 4 ++ ...-nohash.nginx-proxy.test_location_override | 4 ++ ...d8fd4e056c2568d7c2e3ffa8_location_override | 3 ++ ...-nohash.nginx-proxy.test_location_override | 3 ++ test/test_location-override.yml | 44 +++++++++++++++++++ 13 files changed, 161 insertions(+), 13 deletions(-) create mode 100644 test/test_location-override.py create mode 100644 test/test_location-override.vhost.d/explicit-nonroot.nginx-proxy.test_8d960560c82f4e6c8b1b0f03eb30a1afd00e5696_location_override create mode 100644 test/test_location-override.vhost.d/explicit-root-hash-and-nohash.nginx-proxy.test_42099b4af021e53fd8fd4e056c2568d7c2e3ffa8_location_override create mode 100644 test/test_location-override.vhost.d/explicit-root-hash-and-nohash.nginx-proxy.test_location_override create mode 100644 test/test_location-override.vhost.d/explicit-root-hash.nginx-proxy.test_42099b4af021e53fd8fd4e056c2568d7c2e3ffa8_location_override create mode 100644 test/test_location-override.vhost.d/explicit-root-nohash.nginx-proxy.test_location_override create mode 100644 test/test_location-override.vhost.d/implicit-root-hash-and-nohash.nginx-proxy.test_42099b4af021e53fd8fd4e056c2568d7c2e3ffa8_location_override create mode 100644 test/test_location-override.vhost.d/implicit-root-hash-and-nohash.nginx-proxy.test_location_override create mode 100644 test/test_location-override.vhost.d/implicit-root-hash.nginx-proxy.test_42099b4af021e53fd8fd4e056c2568d7c2e3ffa8_location_override create mode 100644 test/test_location-override.vhost.d/implicit-root-nohash.nginx-proxy.test_location_override create mode 100644 test/test_location-override.yml diff --git a/README.md b/README.md index 51d7b80..1728467 100644 --- a/README.md +++ b/README.md @@ -491,6 +491,32 @@ ln -s /path/to/vhost.d/www.example.com /path/to/vhost.d/example.com If you want most of your virtual hosts to use a default single `location` block configuration and then override on a few specific ones, add those settings to the `/etc/nginx/vhost.d/default_location` file. This file will be used on any virtual host which does not have a `/etc/nginx/vhost.d/{VIRTUAL_HOST}_location` file associated with it. +#### Overriding `location` blocks + +The `${VIRTUAL_HOST}_${PATH_HASH}_location`, `${VIRTUAL_HOST}_location`, and `default_location` files documented above make it possible to *augment* the generated [`location` block(s)](https://nginx.org/en/docs/http/ngx_http_core_module.html#location) in a virtual host. In some circumstances, you may need to *completely override* the `location` block for a particular combination of virtual host and path. To do this, create a file whose name follows this pattern: + +``` +/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). + +For convenience, the `_${PATH_HASH}` part can be omitted if the path is `/`: + +``` +/etc/nginx/vhost.d/${VIRTUAL_HOST}_location_override +``` + +When an override file exists, the `location` block that is normally created by `nginx-proxy` is not generated. Instead, the override file is included via the [nginx `include` directive](https://nginx.org/en/docs/ngx_core_module.html#include). + +You are responsible for providing a suitable `location` block in your override file as required for your service. By default, `nginx-proxy` uses the `VIRTUAL_HOST` name as the upstream name for your application's Docker container; see [here](#unhashed-vs-sha1-upstream-names) for details. As an example, if your container has a `VIRTUAL_HOST` value of `app.example.com`, then to override the location block for `/` you would create a file named `/etc/nginx/vhost.d/app.example.com_location_override` that contains something like this: + +``` +location / { + proxy_pass http://app.example.com; +} +``` + #### Per-VIRTUAL_HOST `server_tokens` configuration Per virtual-host `servers_tokens` directive can be configured by passing appropriate value to the `SERVER_TOKENS` environment variable. Please see the [nginx http_core module configuration](https://nginx.org/en/docs/http/ngx_http_core_module.html#server_tokens) for more details. diff --git a/nginx.tmpl b/nginx.tmpl index 83f9222..f61cd20 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -76,38 +76,46 @@ {{- end }} {{- define "location" }} + {{- $override := printf "/etc/nginx/vhost.d/%s_%s_location_override" .Host (sha1 .Path) }} + {{- if and (eq .Path "/") (not (exists $override)) }} + {{- $override = printf "/etc/nginx/vhost.d/%s_location_override" .Host }} + {{- end }} + {{- if exists $override }} + include {{ $override }}; + {{- else }} location {{ .Path }} { - {{- if eq .NetworkTag "internal" }} + {{- if eq .NetworkTag "internal" }} # Only allow traffic from internal clients include /etc/nginx/network_internal.conf; - {{- end }} + {{- end }} - {{- if eq .Proto "uwsgi" }} + {{- if eq .Proto "uwsgi" }} include uwsgi_params; uwsgi_pass {{ trim .Proto }}://{{ trim .Upstream }}; - {{- else if eq .Proto "fastcgi" }} + {{- else if eq .Proto "fastcgi" }} root {{ trim .VhostRoot }}; include fastcgi_params; fastcgi_pass {{ trim .Upstream }}; - {{- else if eq .Proto "grpc" }} + {{- else if eq .Proto "grpc" }} grpc_pass {{ trim .Proto }}://{{ trim .Upstream }}; - {{- else }} + {{- else }} proxy_pass {{ trim .Proto }}://{{ trim .Upstream }}{{ trim .Dest }}; - {{- end }} + {{- end }} - {{- if (exists (printf "/etc/nginx/htpasswd/%s" .Host)) }} + {{- if (exists (printf "/etc/nginx/htpasswd/%s" .Host)) }} auth_basic "Restricted {{ .Host }}"; auth_basic_user_file {{ (printf "/etc/nginx/htpasswd/%s" .Host) }}; - {{- end }} + {{- end }} - {{- if (exists (printf "/etc/nginx/vhost.d/%s_%s_location" .Host (sha1 .Path) )) }} + {{- if (exists (printf "/etc/nginx/vhost.d/%s_%s_location" .Host (sha1 .Path) )) }} include {{ printf "/etc/nginx/vhost.d/%s_%s_location" .Host (sha1 .Path) }}; - {{- else if (exists (printf "/etc/nginx/vhost.d/%s_location" .Host)) }} + {{- else if (exists (printf "/etc/nginx/vhost.d/%s_location" .Host)) }} include {{ printf "/etc/nginx/vhost.d/%s_location" .Host}}; - {{- else if (exists "/etc/nginx/vhost.d/default_location") }} + {{- else if (exists "/etc/nginx/vhost.d/default_location") }} include /etc/nginx/vhost.d/default_location; - {{- end }} + {{- end }} } + {{- end }} {{- end }} {{- define "upstream" }} diff --git a/test/test_location-override.py b/test/test_location-override.py new file mode 100644 index 0000000..cbccbd9 --- /dev/null +++ b/test/test_location-override.py @@ -0,0 +1,39 @@ +def test_explicit_root_nohash(docker_compose, nginxproxy): + r = nginxproxy.get("http://explicit-root-nohash.nginx-proxy.test/port") + assert r.status_code == 418 + r = nginxproxy.get("http://explicit-root-nohash.nginx-proxy.test/foo/port") + assert r.status_code == 200 + assert r.text == "answer from port 82\n" + +def test_explicit_root_hash(docker_compose, nginxproxy): + r = nginxproxy.get("http://explicit-root-hash.nginx-proxy.test/port") + assert r.status_code == 418 + r = nginxproxy.get("http://explicit-root-hash.nginx-proxy.test/foo/port") + assert r.status_code == 200 + assert r.text == "answer from port 82\n" + +def test_explicit_root_hash_and_nohash(docker_compose, nginxproxy): + r = nginxproxy.get("http://explicit-root-hash-and-nohash.nginx-proxy.test/port") + assert r.status_code == 418 + r = nginxproxy.get("http://explicit-root-hash-and-nohash.nginx-proxy.test/foo/port") + assert r.status_code == 200 + assert r.text == "answer from port 82\n" + +def test_explicit_nonroot(docker_compose, nginxproxy): + r = nginxproxy.get("http://explicit-nonroot.nginx-proxy.test/port") + assert r.status_code == 200 + assert r.text == "answer from port 81\n" + r = nginxproxy.get("http://explicit-nonroot.nginx-proxy.test/foo/port") + assert r.status_code == 418 + +def test_implicit_root_nohash(docker_compose, nginxproxy): + r = nginxproxy.get("http://implicit-root-nohash.nginx-proxy.test/port") + assert r.status_code == 418 + +def test_implicit_root_hash(docker_compose, nginxproxy): + r = nginxproxy.get("http://implicit-root-hash.nginx-proxy.test/port") + assert r.status_code == 418 + +def test_implicit_root_hash_and_nohash(docker_compose, nginxproxy): + r = nginxproxy.get("http://implicit-root-hash-and-nohash.nginx-proxy.test/port") + assert r.status_code == 418 diff --git a/test/test_location-override.vhost.d/explicit-nonroot.nginx-proxy.test_8d960560c82f4e6c8b1b0f03eb30a1afd00e5696_location_override b/test/test_location-override.vhost.d/explicit-nonroot.nginx-proxy.test_8d960560c82f4e6c8b1b0f03eb30a1afd00e5696_location_override new file mode 100644 index 0000000..f955c57 --- /dev/null +++ b/test/test_location-override.vhost.d/explicit-nonroot.nginx-proxy.test_8d960560c82f4e6c8b1b0f03eb30a1afd00e5696_location_override @@ -0,0 +1,3 @@ +location /foo/ { + return 418; +} diff --git a/test/test_location-override.vhost.d/explicit-root-hash-and-nohash.nginx-proxy.test_42099b4af021e53fd8fd4e056c2568d7c2e3ffa8_location_override b/test/test_location-override.vhost.d/explicit-root-hash-and-nohash.nginx-proxy.test_42099b4af021e53fd8fd4e056c2568d7c2e3ffa8_location_override new file mode 100644 index 0000000..f289d30 --- /dev/null +++ b/test/test_location-override.vhost.d/explicit-root-hash-and-nohash.nginx-proxy.test_42099b4af021e53fd8fd4e056c2568d7c2e3ffa8_location_override @@ -0,0 +1,4 @@ +# This file should trump the file without the hash. +location / { + return 418; +} diff --git a/test/test_location-override.vhost.d/explicit-root-hash-and-nohash.nginx-proxy.test_location_override b/test/test_location-override.vhost.d/explicit-root-hash-and-nohash.nginx-proxy.test_location_override new file mode 100644 index 0000000..4993313 --- /dev/null +++ b/test/test_location-override.vhost.d/explicit-root-hash-and-nohash.nginx-proxy.test_location_override @@ -0,0 +1,4 @@ +# The file with the hash should trump this file. +location / { + return 503; +} diff --git a/test/test_location-override.vhost.d/explicit-root-hash.nginx-proxy.test_42099b4af021e53fd8fd4e056c2568d7c2e3ffa8_location_override b/test/test_location-override.vhost.d/explicit-root-hash.nginx-proxy.test_42099b4af021e53fd8fd4e056c2568d7c2e3ffa8_location_override new file mode 100644 index 0000000..cbbf1e1 --- /dev/null +++ b/test/test_location-override.vhost.d/explicit-root-hash.nginx-proxy.test_42099b4af021e53fd8fd4e056c2568d7c2e3ffa8_location_override @@ -0,0 +1,3 @@ +location / { + return 418; +} diff --git a/test/test_location-override.vhost.d/explicit-root-nohash.nginx-proxy.test_location_override b/test/test_location-override.vhost.d/explicit-root-nohash.nginx-proxy.test_location_override new file mode 100644 index 0000000..cbbf1e1 --- /dev/null +++ b/test/test_location-override.vhost.d/explicit-root-nohash.nginx-proxy.test_location_override @@ -0,0 +1,3 @@ +location / { + return 418; +} diff --git a/test/test_location-override.vhost.d/implicit-root-hash-and-nohash.nginx-proxy.test_42099b4af021e53fd8fd4e056c2568d7c2e3ffa8_location_override b/test/test_location-override.vhost.d/implicit-root-hash-and-nohash.nginx-proxy.test_42099b4af021e53fd8fd4e056c2568d7c2e3ffa8_location_override new file mode 100644 index 0000000..f289d30 --- /dev/null +++ b/test/test_location-override.vhost.d/implicit-root-hash-and-nohash.nginx-proxy.test_42099b4af021e53fd8fd4e056c2568d7c2e3ffa8_location_override @@ -0,0 +1,4 @@ +# This file should trump the file without the hash. +location / { + return 418; +} diff --git a/test/test_location-override.vhost.d/implicit-root-hash-and-nohash.nginx-proxy.test_location_override b/test/test_location-override.vhost.d/implicit-root-hash-and-nohash.nginx-proxy.test_location_override new file mode 100644 index 0000000..4993313 --- /dev/null +++ b/test/test_location-override.vhost.d/implicit-root-hash-and-nohash.nginx-proxy.test_location_override @@ -0,0 +1,4 @@ +# The file with the hash should trump this file. +location / { + return 503; +} diff --git a/test/test_location-override.vhost.d/implicit-root-hash.nginx-proxy.test_42099b4af021e53fd8fd4e056c2568d7c2e3ffa8_location_override b/test/test_location-override.vhost.d/implicit-root-hash.nginx-proxy.test_42099b4af021e53fd8fd4e056c2568d7c2e3ffa8_location_override new file mode 100644 index 0000000..cbbf1e1 --- /dev/null +++ b/test/test_location-override.vhost.d/implicit-root-hash.nginx-proxy.test_42099b4af021e53fd8fd4e056c2568d7c2e3ffa8_location_override @@ -0,0 +1,3 @@ +location / { + return 418; +} diff --git a/test/test_location-override.vhost.d/implicit-root-nohash.nginx-proxy.test_location_override b/test/test_location-override.vhost.d/implicit-root-nohash.nginx-proxy.test_location_override new file mode 100644 index 0000000..cbbf1e1 --- /dev/null +++ b/test/test_location-override.vhost.d/implicit-root-nohash.nginx-proxy.test_location_override @@ -0,0 +1,3 @@ +location / { + return 418; +} diff --git a/test/test_location-override.yml b/test/test_location-override.yml new file mode 100644 index 0000000..f36b206 --- /dev/null +++ b/test/test_location-override.yml @@ -0,0 +1,44 @@ +services: + sut: + image: nginxproxy/nginx-proxy:test + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro + - ./test_location-override.vhost.d:/etc/nginx/vhost.d:ro + + explicit-root: + image: web + expose: + - "81" + environment: + WEB_PORTS: "81" + VIRTUAL_HOST: >- + explicit-root-nohash.nginx-proxy.test, + explicit-root-hash.nginx-proxy.test, + explicit-root-hash-and-nohash.nginx-proxy.test, + explicit-nonroot.nginx-proxy.test + VIRTUAL_PATH: / + explicit-foo: + image: web + expose: + - "82" + environment: + WEB_PORTS: "82" + VIRTUAL_HOST: >- + explicit-root-nohash.nginx-proxy.test, + explicit-root-hash.nginx-proxy.test, + explicit-root-hash-and-nohash.nginx-proxy.test, + explicit-nonroot.nginx-proxy.test + VIRTUAL_PATH: /foo/ + VIRTUAL_DEST: / + + # Same as explicit-root except VIRTUAL_PATH is left unset. + implicit-root: + image: web + expose: + - "83" + environment: + WEB_PORTS: "83" + VIRTUAL_HOST: >- + implicit-root-nohash.nginx-proxy.test, + implicit-root-hash.nginx-proxy.test, + implicit-root-hash-and-nohash.nginx-proxy.test, From 2494e207843c92a715da3e8e65ed763fd0d2d624 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Thu, 26 Jan 2023 19:27:21 -0500 Subject: [PATCH 132/300] chore: Remove support for legacy swarm It doesn't work with the newer Docker Swarm mode so it doesn't have much value anymore. --- nginx.tmpl | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/nginx.tmpl b/nginx.tmpl index f61cd20..6f3bf91 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -137,15 +137,8 @@ upstream {{ .Upstream }} { # bypass nginx-proxy and access the container's server # directly. {{- end }} - {{- if $container.Node.ID }} - # Swarm node name: {{ $container.Node.Name }} - {{- end }} # Container networks: {{- range $containerNetwork := sortObjectsByKeysAsc $container.Networks "Name" }} - {{- if eq $containerNetwork.Name "ingress" }} - # {{ $containerNetwork.Name }} (ignored) - {{- continue }} - {{- end }} {{- if and (not (index $networks $containerNetwork.Name)) (not $networks.host) }} # {{ $containerNetwork.Name }} (unreachable) {{- continue }} @@ -162,14 +155,7 @@ upstream {{ .Upstream }} { {{- continue }} {{- end }} # {{ $containerNetwork.Name }} (reachable) - {{- /* - * If we got the containers from swarm and this container's - * port is published to host, use host IP:PORT. - */}} - {{- if and $container.Node.ID $addr_obj $addr_obj.HostPort }} - {{- $ip = $container.Node.Address.IP }} - {{- $port = $addr_obj.HostPort }} - {{- else if and $containerNetwork $containerNetwork.IP }} + {{- if and $containerNetwork $containerNetwork.IP }} {{- $ip = $containerNetwork.IP }} {{- else }} # /!\ No IP for this network! From 11a46f728c476854ddb42f78f468c8fca6c5d505 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Tue, 31 Jan 2023 15:07:59 -0500 Subject: [PATCH 133/300] chore: Factor out container IP:port lookup This will make planned future changes easier. --- nginx.tmpl | 117 ++++++++++++++++++++++++++++++++++------------------- 1 file changed, 76 insertions(+), 41 deletions(-) diff --git a/nginx.tmpl b/nginx.tmpl index 6f3bf91..2ec7b43 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -26,6 +26,75 @@ # {{ .Name }} {{- end }} +{{- /* + * Template used as a function to get a container's IP address. This + * template only outputs debug comments; the IP address is "returned" by + * storing the value in the provided dot dict. + * + * The provided dot dict is expected to have the following entries: + * - "globals": Global values. + * - "container": The container's RuntimeContainer struct. + * + * The return value will be added to the dot dict with key "ip". + */}} +{{- define "container_ip" }} + {{- $ip := "" }} + # networks: + {{- range sortObjectsByKeysAsc $.container.Networks "Name" }} + {{- if and (not (index $.globals.networks .Name)) (not $.globals.networks.host) }} + # {{ .Name }} (unreachable) + {{- continue }} + {{- end }} + {{- /* + * Do not emit multiple `server` directives for this container if it + * is reachable over multiple networks. This avoids accidentally + * inflating the effective round-robin weight of a server due to the + * redundant upstream addresses that nginx sees as belonging to + * distinct servers. + */}} + {{- if $ip }} + # {{ .Name }} (ignored; reachable but redundant) + {{- continue }} + {{- end }} + # {{ .Name }} (reachable) + {{- if and . .IP }} + {{- $ip = .IP }} + {{- else }} + # /!\ No IP for this network! + {{- end }} + {{- else }} + # (none) + {{- end }} + # IP address: {{ if $ip }}{{ $ip }}{{ else }}(none usable){{ end }} + {{- $_ := set $ "ip" $ip }} +{{- end }} + +{{- /* + * Template used as a function to get the port of the server in the given + * container. This template only outputs debug comments; the port is + * "returned" by storing the value in the provided dot dict. + * + * The provided dot dict is expected to have the following entries: + * - "container": The container's RuntimeContainer struct. + * + * The return value will be added to the dot dict with key "port". + */}} +{{- define "container_port" }} + {{- /* If only 1 port exposed, use that as a default, else 80. */}} + # exposed ports:{{ range $.container.Addresses }} {{ .Port }}/{{ .Proto }}{{ else }} (none){{ end }} + {{- $default_port := when (eq (len $.container.Addresses) 1) (first $.container.Addresses).Port "80" }} + # default port: {{ $default_port }} + {{- $port := or $.container.Env.VIRTUAL_PORT $default_port }} + # using port: {{ $port }} + {{- $addr_obj := where $.container.Addresses "Port" $port | first }} + {{- if and $addr_obj $addr_obj.HostPort }} + # /!\ WARNING: Virtual port published on host. Clients + # might be able to bypass nginx-proxy and + # access the container's server directly. + {{- end }} + {{- $_ := set $ "port" $port }} +{{- end }} + {{- define "ssl_policy" }} {{- if eq .ssl_policy "Mozilla-Modern" }} ssl_protocols TLSv1.3; @@ -119,50 +188,16 @@ {{- end }} {{- define "upstream" }} - {{- $networks := .Networks }} upstream {{ .Upstream }} { {{- $server_found := false }} {{- range $container := .Containers }} # Container: {{ $container.Name }} - {{- /* If only 1 port exposed, use that as a default, else 80 */}} - {{- $defaultPort := (when (eq (len $container.Addresses) 1) (first $container.Addresses) (dict "Port" "80")).Port }} - {{- $ip := "" }} - {{- $port := (coalesce $container.Env.VIRTUAL_PORT $defaultPort) }} - {{- $addr_obj := where $container.Addresses "Port" $port | first }} - # Exposed ports:{{ range $container.Addresses }} {{ .Port }}/{{ .Proto }}{{ else }} (none){{ end }} - # Default virtual port: {{ $defaultPort }} - # VIRTUAL_PORT: {{ $container.Env.VIRTUAL_PORT }} - {{- if and $addr_obj $addr_obj.HostPort }} - # /!\ WARNING: Virtual port published on host. Clients might be able to - # bypass nginx-proxy and access the container's server - # directly. - {{- end }} - # Container networks: - {{- range $containerNetwork := sortObjectsByKeysAsc $container.Networks "Name" }} - {{- if and (not (index $networks $containerNetwork.Name)) (not $networks.host) }} - # {{ $containerNetwork.Name }} (unreachable) - {{- continue }} - {{- end }} - {{- /* - * Do not emit multiple `server` directives for this container - * if it is reachable over multiple networks. This avoids - * accidentally inflating the effective round-robin weight of - * this container due to the redundant upstreams that nginx sees - * as belonging to distinct servers. - */}} - {{- if $ip }} - # {{ $containerNetwork.Name }} (ignored; reachable but redundant) - {{- continue }} - {{- end }} - # {{ $containerNetwork.Name }} (reachable) - {{- if and $containerNetwork $containerNetwork.IP }} - {{- $ip = $containerNetwork.IP }} - {{- else }} - # /!\ No IP for this network! - {{- end }} - {{- else }} - # (none) - {{- end }} + {{- $args := dict "globals" $.globals "container" $container }} + {{- template "container_ip" $args }} + {{- $ip := $args.ip }} + {{- $args := dict "container" $container }} + {{- template "container_port" $args }} + {{- $port := $args.port }} {{- if $ip }} {{- $server_found = true }} server {{ $ip }}:{{ $port }}; @@ -296,7 +331,7 @@ server { {{- $upstream = printf "%s-%s" $upstream $sum }} {{- end }} # {{ $host }}{{ $path }} -{{ template "upstream" (dict "Upstream" $upstream "Containers" $containers "Networks" $globals.networks) }} +{{ template "upstream" (dict "globals" $globals "Upstream" $upstream "Containers" $containers) }} {{- end }} {{- $default_host := or ($globals.Env.DEFAULT_HOST) "" }} From 7a2b1f8833d33fa99d20c34e104e4041f857422d Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Wed, 1 Feb 2023 18:17:43 -0500 Subject: [PATCH 134/300] chore: Split `$is_https` variable into two separate checks for improved readability. --- nginx.tmpl | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/nginx.tmpl b/nginx.tmpl index 98ab38e..5e26ce3 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -444,10 +444,9 @@ server { * match. */}} {{- $cert := (coalesce $certName $vhostCert) }} + {{- $cert_ok := and (ne $cert "") (exists (printf "/etc/nginx/certs/%s.crt" $cert)) (exists (printf "/etc/nginx/certs/%s.key" $cert)) }} - {{- $is_https := (and (ne $https_method "nohttps") (ne $cert "") (exists (printf "/etc/nginx/certs/%s.crt" $cert)) (exists (printf "/etc/nginx/certs/%s.key" $cert))) }} - - {{- if and $is_https (eq $https_method "redirect") }} + {{- if and $cert_ok (eq $https_method "redirect") }} server { server_name {{ $host }}; {{- if $server_tokens }} @@ -485,13 +484,13 @@ server { server_tokens {{ $server_tokens }}; {{- end }} {{ $globals.access_log }} - {{- if or (not $is_https) (eq $https_method "noredirect") }} + {{- if or (eq $https_method "nohttps") (not $cert_ok) (eq $https_method "noredirect") }} listen {{ $globals.external_http_port }} {{ $default_server }}; {{- if $globals.enable_ipv6 }} listen [::]:{{ $globals.external_http_port }} {{ $default_server }}; {{- end }} {{- end }} - {{- if $is_https }} + {{- if and (ne $https_method "nohttps") $cert_ok }} listen {{ $globals.external_https_port }} ssl http2 {{ $default_server }}; {{- if $globals.enable_ipv6 }} listen [::]:{{ $globals.external_https_port }} ssl http2 {{ $default_server }}; @@ -559,7 +558,7 @@ server { {{- end }} } - {{- if (and (not $is_https) (exists "/etc/nginx/certs/default.crt") (exists "/etc/nginx/certs/default.key")) }} + {{- if and (or (eq $https_method "nohttps") (not $cert_ok)) (exists "/etc/nginx/certs/default.crt") (exists "/etc/nginx/certs/default.key") }} server { server_name {{ $host }}; {{- if $server_tokens }} From 18d0671312fa81245b3bbbe35495c61760b7c46a Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Wed, 1 Feb 2023 18:56:16 -0500 Subject: [PATCH 135/300] chore: Factor out duplicate checks for `default.crt` for improved readability. --- nginx.tmpl | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/nginx.tmpl b/nginx.tmpl index 5e26ce3..bc7e12b 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -11,6 +11,7 @@ {{- $_ := 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")) }} @@ -355,7 +356,7 @@ server { {{ $globals.access_log }} return 503; -{{- if (and (exists "/etc/nginx/certs/default.crt") (exists "/etc/nginx/certs/default.key")) }} +{{- if $globals.default_cert_ok }} listen {{ $globals.external_https_port }} ssl http2; {{- if $globals.enable_ipv6 }} listen [::]:{{ $globals.external_https_port }} ssl http2; @@ -558,7 +559,7 @@ server { {{- end }} } - {{- if and (or (eq $https_method "nohttps") (not $cert_ok)) (exists "/etc/nginx/certs/default.crt") (exists "/etc/nginx/certs/default.key") }} + {{- if and (or (eq $https_method "nohttps") (not $cert_ok)) $globals.default_cert_ok }} server { server_name {{ $host }}; {{- if $server_tokens }} From 7b6b2f773d47b10c41085694e836b29e8be4c90b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 2 Feb 2023 04:01:39 +0000 Subject: [PATCH 136/300] build: bump golang from 1.19.5 to 1.20.0 Bumps golang from 1.19.5 to 1.20.0. --- updated-dependencies: - dependency-name: golang dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- Dockerfile | 2 +- Dockerfile.alpine | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 548e2e3..7669314 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,7 +3,7 @@ ARG DOCKER_GEN_VERSION=0.9.4 ARG FOREGO_VERSION=v0.17.0 # Use a specific version of golang to build both binaries -FROM golang:1.19.5 as gobuilder +FROM golang:1.20.0 as gobuilder # Build docker-gen from scratch FROM gobuilder as dockergen diff --git a/Dockerfile.alpine b/Dockerfile.alpine index 5dc34a5..6902b41 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -3,7 +3,7 @@ ARG DOCKER_GEN_VERSION=0.9.4 ARG FOREGO_VERSION=v0.17.0 # Use a specific version of golang to build both binaries -FROM golang:1.19.5-alpine as gobuilder +FROM golang:1.20.0-alpine as gobuilder RUN apk add --no-cache git musl-dev # Build docker-gen from scratch From 16066cab61aa10547f1b87c740ce2b34ec8fb0c0 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Thu, 2 Feb 2023 17:17:00 -0500 Subject: [PATCH 137/300] fix: Don't create cert error https server if https is not enabled --- nginx.tmpl | 2 +- .../withdefault.certs/default.crt | 70 ++++++++++++++++++ .../withdefault.certs/default.key | 27 +++++++ .../http-only.nginx-proxy.test.crt | 71 +++++++++++++++++++ .../http-only.nginx-proxy.test.key | 27 +++++++ .../https-and-http.nginx-proxy.test.crt | 71 +++++++++++++++++++ .../https-and-http.nginx-proxy.test.key | 27 +++++++ .../https-only.nginx-proxy.test.crt | 71 +++++++++++++++++++ .../https-only.nginx-proxy.test.key | 27 +++++++ test/test_fallback.data/withdefault.yml | 36 ++++++++++ test/test_fallback.py | 53 ++++++++++++++ .../test_wildcard_cert_nohttps.py | 4 +- 12 files changed, 483 insertions(+), 3 deletions(-) create mode 100644 test/test_fallback.data/withdefault.certs/default.crt create mode 100644 test/test_fallback.data/withdefault.certs/default.key create mode 100644 test/test_fallback.data/withdefault.certs/http-only.nginx-proxy.test.crt create mode 100644 test/test_fallback.data/withdefault.certs/http-only.nginx-proxy.test.key create mode 100644 test/test_fallback.data/withdefault.certs/https-and-http.nginx-proxy.test.crt create mode 100644 test/test_fallback.data/withdefault.certs/https-and-http.nginx-proxy.test.key create mode 100644 test/test_fallback.data/withdefault.certs/https-only.nginx-proxy.test.crt create mode 100644 test/test_fallback.data/withdefault.certs/https-only.nginx-proxy.test.key create mode 100644 test/test_fallback.data/withdefault.yml create mode 100644 test/test_fallback.py diff --git a/nginx.tmpl b/nginx.tmpl index bc7e12b..c8b704d 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -559,7 +559,7 @@ server { {{- end }} } - {{- if and (or (eq $https_method "nohttps") (not $cert_ok)) $globals.default_cert_ok }} + {{- if and (ne $https_method "nohttps") (not $cert_ok) $globals.default_cert_ok }} server { server_name {{ $host }}; {{- if $server_tokens }} diff --git a/test/test_fallback.data/withdefault.certs/default.crt b/test/test_fallback.data/withdefault.certs/default.crt new file mode 100644 index 0000000..f855457 --- /dev/null +++ b/test/test_fallback.data/withdefault.certs/default.crt @@ -0,0 +1,70 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 4096 (0x1000) + Signature Algorithm: sha256WithRSAEncryption + Issuer: O=nginx-proxy test suite, CN=www.nginx-proxy.tld + Validity + Not Before: Feb 9 04:02:23 2023 GMT + Not After : Jun 27 04:02:23 2050 GMT + Subject: CN=*.nginx-proxy.test + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (2048 bit) + Modulus: + 00:db:bd:54:de:01:7e:82:4e:c0:f1:5d:12:fd:3a: + fb:21:19:4d:44:25:47:ea:ad:d8:11:5c:d1:65:88: + af:49:fc:8e:4b:c3:01:c1:0d:6d:22:67:bd:31:66: + 9f:4a:50:17:9e:47:b3:3b:b3:21:73:1f:81:55:73: + 52:47:9b:fb:85:6b:e8:d8:09:cc:e1:7d:1c:14:03: + 1c:ae:84:b4:5b:e5:e5:c7:71:fc:1f:74:33:4f:ae: + f7:8d:21:1f:55:8d:93:c7:84:4d:93:01:a1:1c:37: + ae:85:5c:70:2c:21:ec:87:35:c3:86:d3:b3:0f:9a: + b0:9d:8a:cd:0e:49:e8:99:c5:4c:50:bd:a8:6e:a7: + 01:3e:a7:dc:cf:c3:48:37:8e:c6:8a:89:b0:41:01: + 58:ee:45:94:fa:90:eb:df:c8:0e:b7:dd:79:75:13: + 1e:07:69:ee:54:47:92:18:9d:e0:a9:ee:4e:22:d1: + f4:a2:4d:a1:47:ed:9b:35:2a:70:cc:66:fb:3e:f0: + 49:f7:ee:62:2a:27:a1:d3:52:7b:ff:e9:12:d9:5b: + 6b:f6:18:bf:9c:9d:5f:00:29:d2:54:b5:f8:a4:a2: + 9b:3f:fe:a6:ed:14:ae:a0:fe:13:33:18:33:17:a9: + 8b:fe:fc:75:65:0c:fb:c2:d1:1e:81:ca:43:89:bd: + 78:dd + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Alternative Name: + DNS:*.nginx-proxy.test + Signature Algorithm: sha256WithRSAEncryption + 43:a7:1f:4b:ec:ff:1d:70:c7:f8:6e:eb:fd:15:25:27:b2:54: + c7:92:cf:ed:51:31:28:56:76:5c:da:8b:17:31:55:8c:a1:c2: + 37:95:27:7b:b6:58:e5:92:ef:1e:fe:35:f1:44:ca:c7:1b:7b: + 75:bf:e1:91:61:6d:8a:6f:35:8b:73:f4:d9:08:60:25:07:7a: + 3e:c2:79:e7:ae:b4:70:cc:8a:30:cb:80:aa:47:1a:40:82:00: + a0:5e:01:67:d1:95:21:3c:b1:52:7d:f5:87:b6:43:41:df:b2: + a7:ee:3b:73:17:c4:19:2c:6b:7b:3c:26:9e:4c:00:e3:e8:07: + f2:e1:a1:31:79:57:be:b6:b1:a7:93:70:4e:e1:7d:bf:08:c5: + e7:a0:de:7d:82:20:24:f7:b0:3f:c2:94:36:88:ef:7b:7d:c0: + 7f:8a:78:a1:8e:56:42:82:ce:82:e6:8e:3d:1b:b7:ca:dd:a9: + a8:e6:f9:a3:f4:4a:a4:a0:9c:15:6f:44:8c:48:20:e5:85:ed: + 6f:85:22:41:1d:1f:fe:58:e5:43:ad:f2:c4:10:5a:10:ed:36: + 10:98:ad:73:97:6a:e0:19:18:d6:32:26:03:3d:dd:84:5c:2e: + 97:ca:a2:f5:63:f2:7a:16:f1:55:ca:d2:a1:54:09:8a:bb:23: + f0:53:36:51 +-----BEGIN CERTIFICATE----- +MIIC+zCCAeOgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwPzEfMB0GA1UECgwWbmdp +bngtcHJveHkgdGVzdCBzdWl0ZTEcMBoGA1UEAwwTd3d3Lm5naW54LXByb3h5LnRs +ZDAgFw0yMzAyMDkwNDAyMjNaGA8yMDUwMDYyNzA0MDIyM1owHTEbMBkGA1UEAwwS +Ki5uZ2lueC1wcm94eS50ZXN0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEA271U3gF+gk7A8V0S/Tr7IRlNRCVH6q3YEVzRZYivSfyOS8MBwQ1tIme9MWaf +SlAXnkezO7Mhcx+BVXNSR5v7hWvo2AnM4X0cFAMcroS0W+Xlx3H8H3QzT673jSEf +VY2Tx4RNkwGhHDeuhVxwLCHshzXDhtOzD5qwnYrNDknomcVMUL2obqcBPqfcz8NI +N47GiomwQQFY7kWU+pDr38gOt915dRMeB2nuVEeSGJ3gqe5OItH0ok2hR+2bNSpw +zGb7PvBJ9+5iKieh01J7/+kS2Vtr9hi/nJ1fACnSVLX4pKKbP/6m7RSuoP4TMxgz +F6mL/vx1ZQz7wtEegcpDib143QIDAQABoyEwHzAdBgNVHREEFjAUghIqLm5naW54 +LXByb3h5LnRlc3QwDQYJKoZIhvcNAQELBQADggEBAEOnH0vs/x1wx/hu6/0VJSey +VMeSz+1RMShWdlzaixcxVYyhwjeVJ3u2WOWS7x7+NfFEyscbe3W/4ZFhbYpvNYtz +9NkIYCUHej7CeeeutHDMijDLgKpHGkCCAKBeAWfRlSE8sVJ99Ye2Q0HfsqfuO3MX +xBksa3s8Jp5MAOPoB/LhoTF5V762saeTcE7hfb8Ixeeg3n2CICT3sD/ClDaI73t9 +wH+KeKGOVkKCzoLmjj0bt8rdqajm+aP0SqSgnBVvRIxIIOWF7W+FIkEdH/5Y5UOt +8sQQWhDtNhCYrXOXauAZGNYyJgM93YRcLpfKovVj8noW8VXK0qFUCYq7I/BTNlE= +-----END CERTIFICATE----- diff --git a/test/test_fallback.data/withdefault.certs/default.key b/test/test_fallback.data/withdefault.certs/default.key new file mode 100644 index 0000000..79ccb0b --- /dev/null +++ b/test/test_fallback.data/withdefault.certs/default.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEA271U3gF+gk7A8V0S/Tr7IRlNRCVH6q3YEVzRZYivSfyOS8MB +wQ1tIme9MWafSlAXnkezO7Mhcx+BVXNSR5v7hWvo2AnM4X0cFAMcroS0W+Xlx3H8 +H3QzT673jSEfVY2Tx4RNkwGhHDeuhVxwLCHshzXDhtOzD5qwnYrNDknomcVMUL2o +bqcBPqfcz8NIN47GiomwQQFY7kWU+pDr38gOt915dRMeB2nuVEeSGJ3gqe5OItH0 +ok2hR+2bNSpwzGb7PvBJ9+5iKieh01J7/+kS2Vtr9hi/nJ1fACnSVLX4pKKbP/6m +7RSuoP4TMxgzF6mL/vx1ZQz7wtEegcpDib143QIDAQABAoIBAGUd9QXMTjkMoIDx +QaHCGHocuI+ZUETQBtPGkJ1WjsNPMvPuIsqBsSzZ7Bflj3uU66lseTAJuGTPpKZ7 +0Ose/llhVN7Fc8B34AndfL9aVdzMKDblXw3iXRJYA5awHUkzQ0PWwBPb9hWUEf1Q +klXcrolx1i4fEREnMArvKnlezWikpXcqDYRcmUfEvVozaq75heavHpOcOq2dg7vo +N/gcJmfG4aDOhrZC1f22u5cNePvbVj+DdXOUHMEEfXOFbxk97VhmcIaH75ugvVh4 +EMMg87mcGLZiqPO5k6SYcuGyquc32Tf5sK80mpt/+SAEHCvSmUt9c1ynQrS9IhNp +OGfZhQkCgYEA+LonwScVGVEgHg1A9E7BKhIrgUOlwWNM43s+o8Uuz1T72VUVZ6N/ +aO0+2Panw1qjsb0CUC2zft3zZTiZd81gWRmBYQ0R9dHWyWHbJlOv8rAmJ+60Gr2a +UVTLHEdZKx6svSDNhL0HfxxfWwePgHB4NVa2RUA3KQ5y5C96EXb8WbsCgYEA4iow +nIIbRZ9ILDz1oThxE+dFifKWXWFOwa58EFBY+/y34itL7kXRu2+4ZIltwL0L8m5j +GUALUabuoOASKg4CFBhCvoAAlWZRr6L6EOecrElUnrefUrKuCWPCVo3MnCMuLXDp +p1mEGIwEZBCY+jrSBMrRCawsMRkcymLJhEBFYkcCgYB6xIey0vObF2ve6XPSIr09 +YtKObzF1jun4rnBwrXc5Zx0YXOK/0PemdtO6i6SqzCZYKI7nvGcIi80DfThi5cBU +uj4eBTGEQBrgM6jT9iK2izOKKkxDlqqA0nWec6kTm4Rvpa1Lg3Ibz4lRiR3Pq7Pp +v+8fp16SqUsUTkrWLADK2QKBgCRIhHf3X4yx2xBNz1JIDcwVpFBXPMxKWio0Ze7w +FPaIOq/sJkhZpyYc7EYkzhjHu2zvTLK2VZqJ32qrx/47NRYoNjz9qBpPyfcVfGzN +25LASPUVnFfWFpmnCXx9T0AVXMkpfjK857ZQcDvldcVfPmZKa3LTzlsqHjZR1uaC +sR7tAoGBANBfInPZVZRJfqqkPN1K8j4P7uCGjTIBmys/vxoilh1d0scTgZrdqt92 +EKi/3UsJW2ndqQNDLbvi5kcW8a6UU3UB1LLvpyQ5zuS81x3+kKfv+5cDM8rt/M4A +MXnJA5eDZZ4SlHFzdblUv/MZdT+1x0tivMn3zFKNNj2SmaSGkQ0m +-----END RSA PRIVATE KEY----- diff --git a/test/test_fallback.data/withdefault.certs/http-only.nginx-proxy.test.crt b/test/test_fallback.data/withdefault.certs/http-only.nginx-proxy.test.crt new file mode 100644 index 0000000..33fa2f7 --- /dev/null +++ b/test/test_fallback.data/withdefault.certs/http-only.nginx-proxy.test.crt @@ -0,0 +1,71 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 4096 (0x1000) + Signature Algorithm: sha256WithRSAEncryption + Issuer: O=nginx-proxy test suite, CN=www.nginx-proxy.tld + Validity + Not Before: Feb 7 21:54:16 2023 GMT + Not After : Jun 25 21:54:16 2050 GMT + Subject: CN=http-only.nginx-proxy.test + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (2048 bit) + Modulus: + 00:b4:62:61:07:54:2e:6d:55:83:2d:24:b7:e2:15: + 34:13:bd:79:21:e9:10:75:3f:4c:f8:ba:60:29:87: + e5:8e:2a:1e:fd:33:51:5a:8a:3a:6f:60:ff:24:f1: + 1b:27:30:8c:ac:43:04:b7:79:cb:7a:ec:c6:08:a4: + a0:15:b0:0f:ee:6b:15:84:24:11:bc:85:2b:48:06: + 04:0a:58:bb:8c:e8:4d:48:f5:06:c5:91:fe:5d:99: + 0a:29:31:8a:f1:9b:0c:e0:39:75:a1:06:9b:d4:f5: + 06:74:8f:46:5e:64:ba:2f:d0:3d:7c:3d:30:03:e9: + 7c:35:17:69:04:f6:2e:29:d4:93:d6:d6:d2:6c:04: + 38:06:21:06:05:30:8a:b9:9d:05:8d:12:6e:48:39: + bb:f6:93:4f:ba:a5:84:c7:96:2f:be:92:25:e9:d0: + 95:2a:d9:23:8a:b3:28:0b:b6:19:1c:3b:be:a2:91: + 70:44:a8:77:18:94:4b:df:61:f4:5c:c9:78:76:34: + b5:87:0f:c0:92:04:26:b6:ca:62:cd:9b:5d:eb:bf: + 10:ac:df:af:72:5f:af:09:38:b1:dc:e1:3d:13:db: + a0:ac:b7:2e:ca:39:5c:4c:f1:1e:81:a8:b4:44:a2: + 72:d5:3b:c0:71:cc:dc:16:0d:fa:38:96:44:b3:00: + d6:65 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Alternative Name: + DNS:http-only.nginx-proxy.test + Signature Algorithm: sha256WithRSAEncryption + 3b:54:95:48:4d:f6:93:38:42:40:02:ab:b7:17:3b:50:3b:ca: + c7:12:69:b0:da:cb:d7:3e:0e:1f:bf:a2:59:c7:fe:c2:5c:43: + 84:92:b9:3a:be:8f:7e:2e:81:3c:ed:f3:a9:77:21:c2:35:f1: + da:cf:3a:1e:e2:ee:a2:ce:72:55:97:87:0e:ad:59:61:f7:75: + 46:c0:2b:d4:88:b7:36:97:11:fb:5e:28:89:e9:2a:92:f1:15: + f1:43:8e:c1:38:85:8d:3a:26:7d:25:72:93:17:96:8d:5a:ed: + e8:73:3a:d5:8d:80:f2:af:38:84:ff:85:2e:d1:36:7d:2e:e1: + f0:2c:d8:15:5f:fc:c5:70:5d:25:6a:22:f3:2a:cd:0f:25:ad: + d4:93:d3:9a:3e:50:bc:da:a5:6c:86:ea:1d:d9:b9:c5:90:db: + f5:02:c8:c9:77:5c:ef:77:fe:74:60:41:33:d9:3c:a2:e1:73: + aa:14:18:5d:36:58:c8:41:63:4c:59:0e:4b:3d:c5:65:5a:01: + b0:16:50:0f:d0:4f:0d:ca:97:f6:11:47:06:6b:b1:ae:bb:26: + 30:34:8b:7a:91:5d:8a:22:c7:f9:05:0d:bb:a5:b7:60:c0:20: + ce:d0:0e:c0:66:b3:e7:c4:61:ec:c5:40:e6:52:11:41:c3:11: + 18:04:c7:1e +-----BEGIN CERTIFICATE----- +MIIDCzCCAfOgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwPzEfMB0GA1UECgwWbmdp +bngtcHJveHkgdGVzdCBzdWl0ZTEcMBoGA1UEAwwTd3d3Lm5naW54LXByb3h5LnRs +ZDAgFw0yMzAyMDcyMTU0MTZaGA8yMDUwMDYyNTIxNTQxNlowJTEjMCEGA1UEAwwa +aHR0cC1vbmx5Lm5naW54LXByb3h5LnRlc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IB +DwAwggEKAoIBAQC0YmEHVC5tVYMtJLfiFTQTvXkh6RB1P0z4umAph+WOKh79M1Fa +ijpvYP8k8RsnMIysQwS3ect67MYIpKAVsA/uaxWEJBG8hStIBgQKWLuM6E1I9QbF +kf5dmQopMYrxmwzgOXWhBpvU9QZ0j0ZeZLov0D18PTAD6Xw1F2kE9i4p1JPW1tJs +BDgGIQYFMIq5nQWNEm5IObv2k0+6pYTHli++kiXp0JUq2SOKsygLthkcO76ikXBE +qHcYlEvfYfRcyXh2NLWHD8CSBCa2ymLNm13rvxCs369yX68JOLHc4T0T26Csty7K +OVxM8R6BqLREonLVO8BxzNwWDfo4lkSzANZlAgMBAAGjKTAnMCUGA1UdEQQeMByC +Gmh0dHAtb25seS5uZ2lueC1wcm94eS50ZXN0MA0GCSqGSIb3DQEBCwUAA4IBAQA7 +VJVITfaTOEJAAqu3FztQO8rHEmmw2svXPg4fv6JZx/7CXEOEkrk6vo9+LoE87fOp +dyHCNfHazzoe4u6iznJVl4cOrVlh93VGwCvUiLc2lxH7XiiJ6SqS8RXxQ47BOIWN +OiZ9JXKTF5aNWu3oczrVjYDyrziE/4Uu0TZ9LuHwLNgVX/zFcF0laiLzKs0PJa3U +k9OaPlC82qVshuod2bnFkNv1AsjJd1zvd/50YEEz2Tyi4XOqFBhdNljIQWNMWQ5L +PcVlWgGwFlAP0E8Nypf2EUcGa7GuuyYwNIt6kV2KIsf5BQ27pbdgwCDO0A7AZrPn +xGHsxUDmUhFBwxEYBMce +-----END CERTIFICATE----- diff --git a/test/test_fallback.data/withdefault.certs/http-only.nginx-proxy.test.key b/test/test_fallback.data/withdefault.certs/http-only.nginx-proxy.test.key new file mode 100644 index 0000000..3834584 --- /dev/null +++ b/test/test_fallback.data/withdefault.certs/http-only.nginx-proxy.test.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEAtGJhB1QubVWDLSS34hU0E715IekQdT9M+LpgKYfljioe/TNR +Woo6b2D/JPEbJzCMrEMEt3nLeuzGCKSgFbAP7msVhCQRvIUrSAYECli7jOhNSPUG +xZH+XZkKKTGK8ZsM4Dl1oQab1PUGdI9GXmS6L9A9fD0wA+l8NRdpBPYuKdST1tbS +bAQ4BiEGBTCKuZ0FjRJuSDm79pNPuqWEx5YvvpIl6dCVKtkjirMoC7YZHDu+opFw +RKh3GJRL32H0XMl4djS1hw/AkgQmtspizZtd678QrN+vcl+vCTix3OE9E9ugrLcu +yjlcTPEegai0RKJy1TvAcczcFg36OJZEswDWZQIDAQABAoIBAAfDA/HQyX6i41YZ +8l+kEe2XhZLT+IVTB/jb7C9dTZ9kaJj0kFeZAxKv1cq9JTH2gNcYuyc58muDrLHK +g6jrPoQ/z1k0RB8ci9Q5jgrz7n4NsOWmxXfS5GMaprlHDHeA+HjdgBZBtorfUDvL +vndpVimgiETETUCd115hd39jKHFcRcdV6yCix7ObywK3dMgLVpagCcnlyCWffS/r +nhhMfJ+VstW0nUtfZ7JEYwT6Cg7lLAVtDkqPX8zGjJiRwUKH808bUyqEw1y5Cc8U +U5hbmMgPWfXsKxsEC6FSVHBG9ZX2jymOMQXijLFcBSuWvADHmyU+ZxXcbtd1rv4E +cGFj3wECgYEA5cNrr5WjrpEin6MYYVWxiQ+xEWPU2R17eApagrDRLM41JJpv7a5m +TYuZRfIxb59CBPi718Gi168P3T2KMvo2/BTh9Lq5ZBYHx3aDqW2QvMFn7/tgamj8 +0DBxccd2QWfGIBrT1rAF7lD8TC86wtDDVKrvhucRSEXVKF/jWFFRGfUCgYEAyPt6 +48khr7sfNMVdkDLjQjZVV6H7ZUMoSn0FGybgKWxW+b0XCBPObUQWIpyCNTRr1+4A +1TAUS+F/OVVfwnLNgemeE2wd6CaduxwiK1U4pHbyXCElH1ifonHWV3MoXOefYsiY +q5z2jfJzUi0JZVUKsveu9rQsFLsc//1s/I5T1LECgYEAldY6fNg2VVp63OZsuNU8 +oSiljbSwEyMh6Oe/nOkYkIKtr4AzrCoGt11piG7ohGW0lS9suMijnMqiquI+JP5+ +KyinLoUy761aR17nf+9e62mpkZw6hUqQTGi7Irs0SHUXhMpaCfDi/Ua9MiW+yVuB +ds6+xBgeciZwWxMlXOwy2p0CgYEAm+YWiSK3Mq0fo7uEvBn9Fps2z+ciLoZNdppL +n6gkMX2MaeQ3PVi/wxoRYX+tsL+c973yf2vwEnw0R7Dlutt6dc9VgxNWj4GE0GMe +Tiao7Uom7Tf4p7wC9+r9rI/zOz2f8OxRIK18wtbShWfR5fx1dCWUXmGb3+jUse1O +4Qk2FcECgYAvSvGFoJb8tuHFEYYHBbjficmvTUsrTE+EhxPqWKFhKfF19fFFIupy +XBCrN6nwrh+/YMxZXeIRbbTTf814cOO7PjLeNhnfhJZkaJq1HzbYe3bOurna3qrm +Ra3xiM8Ld2PyGnZPXf8+AWhMhuPkLX1KFVTCAxwCpmTZCHtiGCmXMA== +-----END RSA PRIVATE KEY----- diff --git a/test/test_fallback.data/withdefault.certs/https-and-http.nginx-proxy.test.crt b/test/test_fallback.data/withdefault.certs/https-and-http.nginx-proxy.test.crt new file mode 100644 index 0000000..8b04cb9 --- /dev/null +++ b/test/test_fallback.data/withdefault.certs/https-and-http.nginx-proxy.test.crt @@ -0,0 +1,71 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 4096 (0x1000) + Signature Algorithm: sha256WithRSAEncryption + Issuer: O=nginx-proxy test suite, CN=www.nginx-proxy.tld + Validity + Not Before: Feb 7 21:53:19 2023 GMT + Not After : Jun 25 21:53:19 2050 GMT + Subject: CN=https-and-http.nginx-proxy.test + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (2048 bit) + Modulus: + 00:b7:97:85:d1:7f:6b:50:29:f3:87:b7:4e:f5:25: + 40:6a:d8:fa:a1:63:3c:4a:2e:68:4a:c6:8b:38:df: + 07:81:d0:08:9d:fc:17:f5:37:28:7f:31:e6:f3:81: + 28:4e:22:b6:bd:a2:4e:f2:2f:e5:0f:dd:55:3c:e1: + 04:84:4c:45:1b:1a:ae:b7:f0:2a:da:43:05:71:91: + 92:b8:d1:49:fe:80:0a:53:b9:66:da:54:60:9a:fc: + e1:b2:e8:28:48:7f:96:94:3c:92:a3:b2:37:f6:7a: + c2:de:0b:12:f0:ae:4e:92:fe:2d:c1:b2:95:28:1f: + 88:8d:79:99:81:19:ae:22:a4:95:f5:9f:db:25:8e: + 1d:cf:43:cd:6f:85:93:5f:79:ee:f8:f3:d4:82:e1: + e9:4d:c9:ad:ae:5b:92:43:3a:3c:71:51:70:f7:3e: + bd:1b:24:52:6a:a3:cf:54:72:57:ed:fe:72:ea:96: + 9b:5a:02:02:a7:df:85:b7:68:ae:1e:07:77:9f:59: + a5:a0:8b:28:c2:c8:b7:bb:8a:42:50:df:05:73:bf: + 9c:55:13:b5:82:79:77:40:57:a4:8f:88:a5:71:50: + d7:70:b0:4d:0c:d9:86:b3:9b:db:8a:20:bd:19:68: + 10:52:2d:53:ba:0e:2e:1c:ad:80:54:bb:b6:c9:ab: + 11:39 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Alternative Name: + DNS:https-and-http.nginx-proxy.test + Signature Algorithm: sha256WithRSAEncryption + 2c:f3:e5:47:3f:8e:5a:28:b1:df:e5:95:50:85:6f:27:2f:a6: + 8d:f1:5e:cf:df:e2:52:66:97:61:36:59:81:26:25:19:99:c9: + 93:e5:85:cb:ca:69:af:4b:21:a3:d2:7a:bf:b5:5e:2d:42:fb: + 99:f8:22:58:e5:bf:79:b8:8a:74:7e:c6:94:14:d9:f2:27:63: + b6:e5:74:21:5b:59:fb:f6:c8:a9:28:fb:60:f7:5e:bd:c2:e6: + 74:24:14:96:61:95:6c:c2:66:b4:52:25:a1:85:5a:97:e5:68: + 5c:62:cf:69:3b:b0:a9:56:d8:e3:5f:74:dc:84:18:d5:3e:4f: + c9:35:39:26:88:dc:9b:80:d9:40:e1:4f:09:27:8d:d2:89:55: + 30:91:02:86:35:04:95:1e:1d:58:14:5b:c6:e0:2e:a7:bf:a8: + f6:2b:76:8a:4e:71:79:bc:c0:04:cd:db:81:73:46:ce:68:ed: + 25:b0:0e:42:8d:96:64:77:3b:f4:9d:1a:c9:f6:78:4c:56:4f: + 92:17:29:3d:80:50:71:77:4b:a8:29:c2:12:fc:ad:0a:37:81: + 38:4c:fb:54:99:4d:12:5f:98:dc:d1:a9:7b:08:45:c4:6f:7e: + fe:00:e0:db:79:fe:d1:28:e3:8e:82:d1:fb:bc:0a:c4:42:93: + c9:5e:eb:ba +-----BEGIN CERTIFICATE----- +MIIDFTCCAf2gAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwPzEfMB0GA1UECgwWbmdp +bngtcHJveHkgdGVzdCBzdWl0ZTEcMBoGA1UEAwwTd3d3Lm5naW54LXByb3h5LnRs +ZDAgFw0yMzAyMDcyMTUzMTlaGA8yMDUwMDYyNTIxNTMxOVowKjEoMCYGA1UEAwwf +aHR0cHMtYW5kLWh0dHAubmdpbngtcHJveHkudGVzdDCCASIwDQYJKoZIhvcNAQEB +BQADggEPADCCAQoCggEBALeXhdF/a1Ap84e3TvUlQGrY+qFjPEouaErGizjfB4HQ +CJ38F/U3KH8x5vOBKE4itr2iTvIv5Q/dVTzhBIRMRRsarrfwKtpDBXGRkrjRSf6A +ClO5ZtpUYJr84bLoKEh/lpQ8kqOyN/Z6wt4LEvCuTpL+LcGylSgfiI15mYEZriKk +lfWf2yWOHc9DzW+Fk1957vjz1ILh6U3Jra5bkkM6PHFRcPc+vRskUmqjz1RyV+3+ +cuqWm1oCAqffhbdorh4Hd59ZpaCLKMLIt7uKQlDfBXO/nFUTtYJ5d0BXpI+IpXFQ +13CwTQzZhrOb24ogvRloEFItU7oOLhytgFS7tsmrETkCAwEAAaMuMCwwKgYDVR0R +BCMwIYIfaHR0cHMtYW5kLWh0dHAubmdpbngtcHJveHkudGVzdDANBgkqhkiG9w0B +AQsFAAOCAQEALPPlRz+OWiix3+WVUIVvJy+mjfFez9/iUmaXYTZZgSYlGZnJk+WF +y8ppr0sho9J6v7VeLUL7mfgiWOW/ebiKdH7GlBTZ8idjtuV0IVtZ+/bIqSj7YPde +vcLmdCQUlmGVbMJmtFIloYVal+VoXGLPaTuwqVbY41903IQY1T5PyTU5Jojcm4DZ +QOFPCSeN0olVMJEChjUElR4dWBRbxuAup7+o9it2ik5xebzABM3bgXNGzmjtJbAO +Qo2WZHc79J0ayfZ4TFZPkhcpPYBQcXdLqCnCEvytCjeBOEz7VJlNEl+Y3NGpewhF +xG9+/gDg23n+0SjjjoLR+7wKxEKTyV7rug== +-----END CERTIFICATE----- diff --git a/test/test_fallback.data/withdefault.certs/https-and-http.nginx-proxy.test.key b/test/test_fallback.data/withdefault.certs/https-and-http.nginx-proxy.test.key new file mode 100644 index 0000000..11f5210 --- /dev/null +++ b/test/test_fallback.data/withdefault.certs/https-and-http.nginx-proxy.test.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEAt5eF0X9rUCnzh7dO9SVAatj6oWM8Si5oSsaLON8HgdAInfwX +9TcofzHm84EoTiK2vaJO8i/lD91VPOEEhExFGxqut/Aq2kMFcZGSuNFJ/oAKU7lm +2lRgmvzhsugoSH+WlDySo7I39nrC3gsS8K5Okv4twbKVKB+IjXmZgRmuIqSV9Z/b +JY4dz0PNb4WTX3nu+PPUguHpTcmtrluSQzo8cVFw9z69GyRSaqPPVHJX7f5y6pab +WgICp9+Ft2iuHgd3n1mloIsowsi3u4pCUN8Fc7+cVRO1gnl3QFekj4ilcVDXcLBN +DNmGs5vbiiC9GWgQUi1Tug4uHK2AVLu2yasROQIDAQABAoIBACT4KSVHoEdzOyvw +GME6sB8T9Fw9TG2vrKaqFmzsVGmqh6Gwmu5xHgGG/fe44XHigaPsJDOWu2yXaEur +ECrH5P6RP++gODDdYCI/ayk2U80g4XN8mR6L8Swkkhphr4Lx1lOhYvH9uFE05Tqr +RjQbFY16C6K+oFSFDQ1YGDYsAqnM3RD7PH+lHpo8UN1TO/vogdSQEpMYZDwLAYnW +uD5G3c0u2PsGu9YLuz2p8hcs3chh+cqKJWXOeW0JLrNGx1bqeQWkn6nXRDdRYi9V +cJlTgDqGuF54bieSyq9ABDZQP4Ol+moYKDoIz5PwurNjcYSklrT1tw0gqHZoQK1L +fDjw3QECgYEA7QMRU1AFKTvO7/8WLHLN5BT63n31wm0e9PYpz/XVLWEfxBcp9Xmf +xAIhXZ/U9P4dfNqxTjN9mVGzCHh5KfDJnUFqOXFy/zvfMeRzJf6dJo6/4OX9Bijr +Tgd454vyGXYQP2t+F14UAwl6vlGOAjttiP5qY5Ef1gllBEeIPe9Ts9kCgYEAxkzZ +pq4HJ/5/iDquMEHXNXzpNPavSvgxQdl1ILvJ49LJImmQFBCP9PqiOTIfePz1OqUI +C4baFuc0FEDJ3x9CUNmMY1lEi2ZUq2agPSXaQNsMcKtEJH8SoJlJIRpkQA7unX09 +zb4dam6g79OaGmb8scePuezXMLv1Ee6WWtXbzGECgYEA6PYn9Gzl9cacu9dOUzgw +2ewpPcIvawDY+cxwAsHO3MDneVWPX4JBoGa7pwvwRTL1hwBqYMRJwwbD5CKObcQI +V/KxV28Eqo2N77tt1z2x9/E99u/4yTI1P0gm9ejfeVlL1RpyIMPPBcEujZ0Z6WXC +X3I63k0KLtajHRa2erIf4tkCgYAfunAgwTuX5JqXO3xfcEl033WY6deGUUvgU2Dw +Sdu1viY8gVNyQmwmMGwAZsquWxsJtRoibgM7IucsTml+b8v2j7hstP3IqCjn+9Wr +swDG28WTyXNvu31JgP04dLaRoVIAlOdsofym6OiLNvozO0M3VsziXMjZnVlK8zfP +dORkQQKBgQDXAJEJPygxVA+bF104dzCMWGmU7K8ShEWC5eOdKK4KWf9bNDpY6M6c +i6zga/xBbj7e3Bxqprpp8Wy2gIsnYiVo4V9EQethbLdomPxOpBMNMARw81rL1CpO +jbHB7bIDcKs2tQoZEXUW86ZxC8sdaDaWTJTfUO0RpJow6ZO3yvxVIQ== +-----END RSA PRIVATE KEY----- diff --git a/test/test_fallback.data/withdefault.certs/https-only.nginx-proxy.test.crt b/test/test_fallback.data/withdefault.certs/https-only.nginx-proxy.test.crt new file mode 100644 index 0000000..a93e728 --- /dev/null +++ b/test/test_fallback.data/withdefault.certs/https-only.nginx-proxy.test.crt @@ -0,0 +1,71 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 4096 (0x1000) + Signature Algorithm: sha256WithRSAEncryption + Issuer: O=nginx-proxy test suite, CN=www.nginx-proxy.tld + Validity + Not Before: Feb 7 21:53:49 2023 GMT + Not After : Jun 25 21:53:49 2050 GMT + Subject: CN=https-only.nginx-proxy.test + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (2048 bit) + Modulus: + 00:d9:87:48:02:85:f4:5f:0d:90:7e:4c:4f:13:89: + 41:ca:41:15:c2:6f:fd:a8:c7:17:83:c6:dd:8c:fe: + 19:a4:b2:6b:0b:35:4f:b4:3d:7c:40:0a:04:33:2a: + fd:10:72:f7:63:63:99:5b:3d:ec:78:ee:c6:4d:c8: + 0e:4c:be:f2:3f:e3:02:74:57:9a:c1:fe:15:95:63: + 4e:e7:2c:eb:70:f2:6b:c8:ba:01:a2:ca:a1:c7:76: + ff:38:e4:c2:b0:66:fc:85:d2:af:0f:22:81:d4:82: + eb:d5:b0:e6:69:14:37:dd:8d:ad:29:ce:93:68:5a: + ce:f4:77:76:6f:78:13:b6:c8:2f:fe:e0:b6:7e:fb: + 29:16:be:e2:f5:45:3b:39:5b:52:dc:26:b7:ca:0c: + b6:1c:fc:a8:38:0b:dd:c1:f4:04:9b:2d:38:c9:a5: + 2d:3e:f1:42:88:53:a2:3b:17:cf:d5:3c:2b:d6:6a: + 7f:6f:05:8d:c5:b7:5d:64:1e:83:1b:e7:ec:80:3d: + 6d:34:c1:66:b2:e6:5d:d9:a7:6e:46:75:14:bf:10: + 16:c5:fc:47:8e:63:fa:e5:b4:bd:f2:b9:e0:cb:ea: + 75:f9:68:ee:7d:8f:ea:8f:1a:9f:34:27:7a:4a:9f: + 85:fd:3e:17:a7:96:c3:d0:4e:50:a2:a2:e0:45:92: + d0:b5 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Alternative Name: + DNS:https-only.nginx-proxy.test + Signature Algorithm: sha256WithRSAEncryption + 8a:52:46:42:a9:74:18:6a:52:90:ef:a4:e9:c5:54:d5:97:3a: + ff:8b:c2:76:4f:9e:47:aa:e1:ea:e5:b9:af:9d:33:e3:85:17: + 54:7d:32:bd:ac:90:3f:5c:d2:a1:42:17:52:2b:b1:83:e5:c3: + bf:81:f0:e7:38:e2:88:67:7b:d8:59:fe:f9:94:99:ba:be:f4: + 3c:24:b2:c7:9e:f0:98:21:c6:2d:c2:e8:f3:67:bd:62:00:aa: + ce:34:fa:b4:53:6d:c1:09:5e:55:bd:43:aa:86:c6:f8:c5:83: + 46:3a:49:12:a2:ec:30:36:0c:99:44:74:09:9d:cc:4b:98:1f: + 7e:c9:9b:68:a0:f8:1e:00:14:d0:da:2a:bf:c8:ca:a8:1c:10: + b5:68:a2:f1:41:93:0c:f3:3f:c0:c6:53:3c:8d:a7:dd:a5:7b: + 35:cc:44:e0:5b:6d:c5:cb:33:6f:c1:43:7e:06:df:21:99:11: + b3:91:41:b4:5e:f0:37:1e:8e:e5:73:85:dc:4a:21:d5:41:f9: + 4e:b8:f5:ed:21:93:09:91:c2:8c:6b:04:a4:84:ab:3a:fe:35: + 64:fa:6b:a7:8d:40:a6:64:89:30:84:ac:28:99:5a:01:79:77: + c0:df:88:da:a9:75:5f:c4:51:ae:a8:45:7b:d2:e1:a2:81:29: + 60:cd:7b:cd +-----BEGIN CERTIFICATE----- +MIIDDTCCAfWgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwPzEfMB0GA1UECgwWbmdp +bngtcHJveHkgdGVzdCBzdWl0ZTEcMBoGA1UEAwwTd3d3Lm5naW54LXByb3h5LnRs +ZDAgFw0yMzAyMDcyMTUzNDlaGA8yMDUwMDYyNTIxNTM0OVowJjEkMCIGA1UEAwwb +aHR0cHMtb25seS5uZ2lueC1wcm94eS50ZXN0MIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEA2YdIAoX0Xw2QfkxPE4lBykEVwm/9qMcXg8bdjP4ZpLJrCzVP +tD18QAoEMyr9EHL3Y2OZWz3seO7GTcgOTL7yP+MCdFeawf4VlWNO5yzrcPJryLoB +osqhx3b/OOTCsGb8hdKvDyKB1ILr1bDmaRQ33Y2tKc6TaFrO9Hd2b3gTtsgv/uC2 +fvspFr7i9UU7OVtS3Ca3ygy2HPyoOAvdwfQEmy04yaUtPvFCiFOiOxfP1Twr1mp/ +bwWNxbddZB6DG+fsgD1tNMFmsuZd2aduRnUUvxAWxfxHjmP65bS98rngy+p1+Wju +fY/qjxqfNCd6Sp+F/T4Xp5bD0E5QoqLgRZLQtQIDAQABoyowKDAmBgNVHREEHzAd +ghtodHRwcy1vbmx5Lm5naW54LXByb3h5LnRlc3QwDQYJKoZIhvcNAQELBQADggEB +AIpSRkKpdBhqUpDvpOnFVNWXOv+LwnZPnkeq4erlua+dM+OFF1R9Mr2skD9c0qFC +F1IrsYPlw7+B8Oc44ohne9hZ/vmUmbq+9Dwkssee8Jghxi3C6PNnvWIAqs40+rRT +bcEJXlW9Q6qGxvjFg0Y6SRKi7DA2DJlEdAmdzEuYH37Jm2ig+B4AFNDaKr/Iyqgc +ELVoovFBkwzzP8DGUzyNp92lezXMROBbbcXLM2/BQ34G3yGZEbORQbRe8DcejuVz +hdxKIdVB+U649e0hkwmRwoxrBKSEqzr+NWT6a6eNQKZkiTCErCiZWgF5d8DfiNqp +dV/EUa6oRXvS4aKBKWDNe80= +-----END CERTIFICATE----- diff --git a/test/test_fallback.data/withdefault.certs/https-only.nginx-proxy.test.key b/test/test_fallback.data/withdefault.certs/https-only.nginx-proxy.test.key new file mode 100644 index 0000000..17976ce --- /dev/null +++ b/test/test_fallback.data/withdefault.certs/https-only.nginx-proxy.test.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEA2YdIAoX0Xw2QfkxPE4lBykEVwm/9qMcXg8bdjP4ZpLJrCzVP +tD18QAoEMyr9EHL3Y2OZWz3seO7GTcgOTL7yP+MCdFeawf4VlWNO5yzrcPJryLoB +osqhx3b/OOTCsGb8hdKvDyKB1ILr1bDmaRQ33Y2tKc6TaFrO9Hd2b3gTtsgv/uC2 +fvspFr7i9UU7OVtS3Ca3ygy2HPyoOAvdwfQEmy04yaUtPvFCiFOiOxfP1Twr1mp/ +bwWNxbddZB6DG+fsgD1tNMFmsuZd2aduRnUUvxAWxfxHjmP65bS98rngy+p1+Wju +fY/qjxqfNCd6Sp+F/T4Xp5bD0E5QoqLgRZLQtQIDAQABAoIBAAWs//YA5MVuJy0E +dLO/yxWp6RVvsqCqwTRRBgrdvnGLrjtWosPDLvDE0iM7peq99TKEsMWusfLd2BLD +e4wJF20PUUsT1hflt050juR9SY9i4+kS4WQMAXig5DvpzCKqLUCYpLSyY8zVta2X +tgtb2bFQNwp2N2ZrqCa8zzxNV8ZXGoW+ZlvBJEDtBwt1DCDhY39/pqHfIhFl4Vwk +YhhbVjID145D1j/fP6vLceM2YA4uRmF1itj1iQ6YNNpXRspUGE4DXdqR6HcbduiX +trZjmdtKXY8mJg6jyLZxYbjFlKV/LvqKRYF3Jb9K0vdd4juBdZoy7DQzoLhcnzui +pEnPLakCgYEA9tN6KdQGKGBXGuF+ZqhXfB/XSkKUf8o/5j62cbu11ZIJ+iEBx+d6 +lQAxTz5hHUL6a3c5qiM+AWBxYuFD6oqptIlTlBfIXI978neDNvEWWffivPvQLbt9 +o9ohOirfK1iGPvtrpAwjv5ylE5SiTmJ/6wDvQWjNGAnJ3aaxkesJUSMCgYEA4Z0K +UHZVtnKLtzzIY7KfLbuKF/fJEDfMNr4Wgl6ny21vqO9kJGmA7SaoNdhx8RDcKmeV +/Vey4ug6YlOG48eapKLTthdRz5mx+jIkUfdOhj81m28xm/OPTqCrviTHCNOHeYDy +NKAIlJMo2z0vTKJn5eP6CsYmDWLpHQNyXY5qcEcCgYAzDBWt5O3JF/Or2Yr8zEAb +qbIq544yx69jfQDakMnQe72Yf48Quuz9N+b6zpnjJWEJLMU+TL+cJUgN/SzAqyDh +96zTaf/ENOCbiuAWUtIelUfNcf7iFm6rnodUsl0pZ8uL5w+iA+i4zjrNy+WtdG2k +OrNAwd345L1dHAaJeSSaJQKBgQCUnF3r7Fa/TCpt87LHwSQK+sqWyRf+/9IbiRDI +pVL/s8FmVPHw7jIHhHwuo7lCImnz4LGy5C6oOnIizIRAy/04Ty0Hd8ri5YmPlbHI +8A8gbMiB7zeNU1zlXP5jzFPyo2tMhLyGH5gnTdwOtfnPD/dCPe45ZJYyISIOg3O0 +3peMBwKBgH20cskAOCNclfoG+Nis52h8FqmDlflJ8waUarvk26JhO1e009kOytw8 +x/qSuttpGtTG+4fdc2wJvFNczr4h9ZlftBdgZXj8PKgRpcIe8q97Xg8PUj+Xfu/t +vD/QV+tVcGoAMsQq4NeFxiTbPfwVyXdYFT1XVCu6JEdLL+gpWh5W +-----END RSA PRIVATE KEY----- diff --git a/test/test_fallback.data/withdefault.yml b/test/test_fallback.data/withdefault.yml new file mode 100644 index 0000000..00f7ee7 --- /dev/null +++ b/test/test_fallback.data/withdefault.yml @@ -0,0 +1,36 @@ +services: + sut: + image: nginxproxy/nginx-proxy:test + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro + - ./withdefault.certs:/etc/nginx/certs:ro + https-and-http: + image: web + expose: + - "81" + environment: + WEB_PORTS: "81" + VIRTUAL_HOST: https-and-http.nginx-proxy.test + https-only: + image: web + expose: + - "82" + environment: + WEB_PORTS: "82" + VIRTUAL_HOST: https-only.nginx-proxy.test + HTTPS_METHOD: nohttp + http-only: + image: web + expose: + - "83" + environment: + WEB_PORTS: "83" + VIRTUAL_HOST: http-only.nginx-proxy.test + HTTPS_METHOD: nohttps + missing-cert: + image: web + expose: + - "84" + environment: + WEB_PORTS: "84" + VIRTUAL_HOST: missing-cert.nginx-proxy.test diff --git a/test/test_fallback.py b/test/test_fallback.py new file mode 100644 index 0000000..1e687a3 --- /dev/null +++ b/test/test_fallback.py @@ -0,0 +1,53 @@ +import os.path + +import backoff +import pytest +import requests + + +@pytest.fixture +def data_dir(): + return f"{os.path.splitext(__file__)[0]}.data" + + +@pytest.fixture +def docker_compose_file(data_dir, compose_file): + return os.path.join(data_dir, compose_file) + + +@pytest.fixture +def get(docker_compose, nginxproxy, want_err_re): + + @backoff.on_exception( + backoff.constant, + requests.exceptions.RequestException, + giveup=lambda e: want_err_re and want_err_re.search(str(e)), + interval=.3, + max_tries=30, + jitter=None) + def _get(url): + return nginxproxy.get(url, allow_redirects=False) + + return _get + + +@pytest.mark.parametrize("compose_file,url,want_code,want_err_re", [ + # Has default.crt. + ("withdefault.yml", "http://https-and-http.nginx-proxy.test/", 301, None), + ("withdefault.yml", "https://https-and-http.nginx-proxy.test/", 200, None), + ("withdefault.yml", "http://https-only.nginx-proxy.test/", 503, None), + ("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", "https://missing-cert.nginx-proxy.test/", 500, None), + ("withdefault.yml", "http://unknown.nginx-proxy.test/", 503, None), + ("withdefault.yml", "https://unknown.nginx-proxy.test/", 503, None), +]) +def test_fallback(get, url, want_code, want_err_re): + if want_err_re is None: + r = get(url) + assert r.status_code == want_code + else: + with pytest.raises(requests.exceptions.RequestException, match=want_err_re): + get(url) diff --git a/test/test_ssl/wildcard_cert_and_nohttps/test_wildcard_cert_nohttps.py b/test/test_ssl/wildcard_cert_and_nohttps/test_wildcard_cert_nohttps.py index 68b0329..603d281 100644 --- a/test/test_ssl/wildcard_cert_and_nohttps/test_wildcard_cert_nohttps.py +++ b/test/test_ssl/wildcard_cert_and_nohttps/test_wildcard_cert_nohttps.py @@ -24,10 +24,10 @@ def test_https_get_served(docker_compose, nginxproxy, subdomain): assert f"answer from port 8{subdomain}\n" == r.text @pytest.mark.filterwarnings('ignore::urllib3.exceptions.InsecureRequestWarning') -def test_web3_https_is_500_and_SSL_validation_fails(docker_compose, nginxproxy): +def test_https_request_to_nohttps_vhost_goes_to_fallback_server(docker_compose, nginxproxy): with pytest.raises( (CertificateError, SSLError) ) as excinfo: nginxproxy.get("https://3.web.nginx-proxy.tld/port") assert """hostname '3.web.nginx-proxy.tld' doesn't match 'nginx-proxy.tld'""" in str(excinfo.value) r = nginxproxy.get("https://3.web.nginx-proxy.tld/port", verify=False) - assert r.status_code == 500 + assert r.status_code == 503 From 9297e9438901df2898c2daf2145a28cb761f880d Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Thu, 2 Feb 2023 22:02:06 -0500 Subject: [PATCH 138/300] fix: Emit TLS error if there are no certs available Before, if neither the vhost-specific cert nor `default.crt` existed, nginx-proxy would not create the https vhost. This resulted in nginx either refusing the connection or serving the wrong vhost depending on whether there was another https vhost with a certificate. Now nginx-proxy always creates an https server for a vhost, even if the vhost-specific certificate and the default certificate are both missing. When both certs are missing, nginx is given empty certificate data to make it possible for it to start up without an error. The empty certificate data causes the user to see a TLS error, which is much easier to troubleshoot than a connection refused error or serving the wrong vhost. --- README.md | 32 ++++++- nginx.tmpl | 83 +++++++++++-------- .../http-only.nginx-proxy.test.crt | 71 ++++++++++++++++ .../http-only.nginx-proxy.test.key | 27 ++++++ .../https-and-http.nginx-proxy.test.crt | 71 ++++++++++++++++ .../https-and-http.nginx-proxy.test.key | 27 ++++++ .../https-only.nginx-proxy.test.crt | 71 ++++++++++++++++ .../https-only.nginx-proxy.test.key | 27 ++++++ test/test_fallback.data/nodefault.yml | 36 ++++++++ test/test_fallback.py | 15 ++++ 10 files changed, 423 insertions(+), 37 deletions(-) create mode 100644 test/test_fallback.data/nodefault.certs/http-only.nginx-proxy.test.crt create mode 100644 test/test_fallback.data/nodefault.certs/http-only.nginx-proxy.test.key create mode 100644 test/test_fallback.data/nodefault.certs/https-and-http.nginx-proxy.test.crt create mode 100644 test/test_fallback.data/nodefault.certs/https-and-http.nginx-proxy.test.key create mode 100644 test/test_fallback.data/nodefault.certs/https-only.nginx-proxy.test.crt create mode 100644 test/test_fallback.data/nodefault.certs/https-only.nginx-proxy.test.key create mode 100644 test/test_fallback.data/nodefault.yml diff --git a/README.md b/README.md index 4e0d9d4..2757c33 100644 --- a/README.md +++ b/README.md @@ -347,10 +347,9 @@ Note that the `Mozilla-Old` policy should use a 1024 bits DH key for compatibili The default behavior for the proxy when port 80 and 443 are exposed is as follows: -* If a container has a usable cert, port 80 will redirect to 443 for that container so that HTTPS is always preferred when available. -* If the container does not have a usable cert, a 503 will be returned. - -Note that in the latter case, a browser may get an connection error as no certificate is available to establish a connection. A self-signed or generic cert named `default.crt` and `default.key` will allow a client browser to make a SSL connection (likely w/ a warning) and subsequently receive a 500. +* If a virtual host has a usable cert, port 80 will redirect to 443 for that virtual host so that HTTPS is always preferred when available. +* If the virtual host does not have a usable cert, but `default.crt` and `default.key` exist, those will be used as the virtual host's certificate and the client browser will receive a 500 error. +* If the virtual host does not have a usable cert, and `default.crt` and `default.key` do not exist, TLS negotiation will fail (see [Missing Certificate](#missing-certificate) below). To serve traffic in both SSL and non-SSL modes without redirecting to SSL, you can include the environment variable `HTTPS_METHOD=noredirect` (the default is `HTTPS_METHOD=redirect`). You can also disable the non-SSL site entirely with `HTTPS_METHOD=nohttp`, or disable the HTTPS site with `HTTPS_METHOD=nohttps`. `HTTPS_METHOD` can be specified on each container for which you want to override the default behavior or on the proxy container to set it globally. If `HTTPS_METHOD=noredirect` is used, Strict Transport Security (HSTS) is disabled to prevent HTTPS users from being redirected by the client. If you cannot get to the HTTP site after changing this setting, your browser has probably cached the HSTS policy and is automatically redirecting you back to HTTPS. You will need to clear your browser's HSTS cache or use an incognito window / different browser. @@ -358,6 +357,31 @@ By default, [HTTP Strict Transport Security (HSTS)](https://developer.mozilla.or *WARNING*: HSTS will force your users to visit the HTTPS version of your site for the `max-age` time - even if they type in `http://` manually. The only way to get to an HTTP site after receiving an HSTS response is to clear your browser's HSTS cache. +#### Missing Certificate + +If HTTPS is enabled for a virtual host but its certificate is missing, nginx-proxy will configure nginx to use the default certificate (`default.crt` with `default.key`) and return a 500 error. + +If the default certificate is also missing, nginx-proxy will configure nginx to accept HTTPS connections but fail the TLS negotiation. Client browsers will render a TLS error page. As of March 2023, web browsers display the following error messages: + + * Chrome: + + > This site can't provide a secure connection + > + > example.test sent an invalid response. + > + > Try running Connectivity Diagnostics. + > + > `ERR_SSL_PROTOCOL_ERROR` + + * Firefox: + + > Secure Connection Failed + > + > An error occurred during a connection to example.test. + > Peer reports it experienced an internal error. + > + > Error code: `SSL_ERROR_INTERNAL_ERROR_ALERT` "TLS error". + ### 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 on directory diff --git a/nginx.tmpl b/nginx.tmpl index c8b704d..d2ccd8f 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -350,23 +350,30 @@ server { server_name _; # This is just an invalid value which will never trigger on a real hostname. server_tokens off; listen {{ $globals.external_http_port }}; + listen {{ $globals.external_https_port }} ssl http2; {{- if $globals.enable_ipv6 }} listen [::]:{{ $globals.external_http_port }}; + listen [::]:{{ $globals.external_https_port }} ssl http2; {{- end }} {{ $globals.access_log }} - return 503; - {{- if $globals.default_cert_ok }} - listen {{ $globals.external_https_port }} ssl http2; - {{- if $globals.enable_ipv6 }} - listen [::]:{{ $globals.external_https_port }} ssl http2; - {{- end }} - ssl_session_cache shared:SSL:50m; ssl_session_tickets off; ssl_certificate /etc/nginx/certs/default.crt; ssl_certificate_key /etc/nginx/certs/default.key; +{{- else }} + # No default.crt certificate found for this vhost, so force nginx to emit a + # TLS error if the client connects via https. + {{- /* See the comment in the main `server` directive for rationale. */}} + ssl_ciphers aNULL; + set $empty ""; + ssl_certificate data:$empty; + ssl_certificate_key data:$empty; + if ($https) { + return 444; + } {{- end }} + return 503; } {{- range $host, $containers := groupByMulti $globals.containers "Env.VIRTUAL_HOST" "," }} @@ -491,13 +498,14 @@ server { listen [::]:{{ $globals.external_http_port }} {{ $default_server }}; {{- end }} {{- end }} - {{- if and (ne $https_method "nohttps") $cert_ok }} + {{- if ne $https_method "nohttps" }} listen {{ $globals.external_https_port }} ssl http2 {{ $default_server }}; {{- if $globals.enable_ipv6 }} listen [::]:{{ $globals.external_https_port }} ssl http2 {{ $default_server }}; {{- end }} - {{- template "ssl_policy" (dict "ssl_policy" $ssl_policy) }} + {{- if $cert_ok }} + {{- template "ssl_policy" (dict "ssl_policy" $ssl_policy) }} ssl_session_timeout 5m; ssl_session_cache shared:SSL:50m; @@ -506,22 +514,50 @@ server { ssl_certificate /etc/nginx/certs/{{ (printf "%s.crt" $cert) }}; ssl_certificate_key /etc/nginx/certs/{{ (printf "%s.key" $cert) }}; - {{- if (exists (printf "/etc/nginx/certs/%s.dhparam.pem" $cert)) }} + {{- if (exists (printf "/etc/nginx/certs/%s.dhparam.pem" $cert)) }} ssl_dhparam {{ printf "/etc/nginx/certs/%s.dhparam.pem" $cert }}; - {{- end }} + {{- end }} - {{- if (exists (printf "/etc/nginx/certs/%s.chain.pem" $cert)) }} + {{- if (exists (printf "/etc/nginx/certs/%s.chain.pem" $cert)) }} ssl_stapling on; ssl_stapling_verify on; ssl_trusted_certificate {{ printf "/etc/nginx/certs/%s.chain.pem" $cert }}; - {{- end }} + {{- end }} - {{- if (not (or (eq $https_method "noredirect") (eq $hsts "off"))) }} + {{- if (not (or (eq $https_method "noredirect") (eq $hsts "off"))) }} set $sts_header ""; if ($https) { set $sts_header "{{ trim $hsts }}"; } add_header Strict-Transport-Security $sts_header always; + {{- end }} + {{- else if $globals.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; + ssl_certificate_key /etc/nginx/certs/default.key; + if ($https) { + return 500; + } + {{- else }} + # No certificate found for this vhost, so force nginx to emit a TLS error if + # the client connects via https. + {{- /* + * The alternative is to not provide an https server for this + * vhost, which would either cause the user to see the wrong + * vhost (if there is another vhost with a certificate) or a + * connection refused error (if there is no other vhost with a + * certificate). A TLS error is easier to troubleshoot, and is + * safer than serving the wrong vhost. Also see + * . + */}} + ssl_ciphers aNULL; + set $empty ""; + ssl_certificate data:$empty; + ssl_certificate_key data:$empty; + if ($https) { + return 444; + } {{- end }} {{- end }} @@ -558,23 +594,4 @@ server { } {{- end }} } - - {{- if and (ne $https_method "nohttps") (not $cert_ok) $globals.default_cert_ok }} -server { - server_name {{ $host }}; - {{- if $server_tokens }} - server_tokens {{ $server_tokens }}; - {{- end }} - listen {{ $globals.external_https_port }} ssl http2 {{ $default_server }}; - {{- if $globals.enable_ipv6 }} - listen [::]:{{ $globals.external_https_port }} ssl http2 {{ $default_server }}; - {{- end }} - {{ $globals.access_log }} - return 500; - - ssl_certificate /etc/nginx/certs/default.crt; - ssl_certificate_key /etc/nginx/certs/default.key; -} - {{- end }} - {{- end }} diff --git a/test/test_fallback.data/nodefault.certs/http-only.nginx-proxy.test.crt b/test/test_fallback.data/nodefault.certs/http-only.nginx-proxy.test.crt new file mode 100644 index 0000000..33fa2f7 --- /dev/null +++ b/test/test_fallback.data/nodefault.certs/http-only.nginx-proxy.test.crt @@ -0,0 +1,71 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 4096 (0x1000) + Signature Algorithm: sha256WithRSAEncryption + Issuer: O=nginx-proxy test suite, CN=www.nginx-proxy.tld + Validity + Not Before: Feb 7 21:54:16 2023 GMT + Not After : Jun 25 21:54:16 2050 GMT + Subject: CN=http-only.nginx-proxy.test + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (2048 bit) + Modulus: + 00:b4:62:61:07:54:2e:6d:55:83:2d:24:b7:e2:15: + 34:13:bd:79:21:e9:10:75:3f:4c:f8:ba:60:29:87: + e5:8e:2a:1e:fd:33:51:5a:8a:3a:6f:60:ff:24:f1: + 1b:27:30:8c:ac:43:04:b7:79:cb:7a:ec:c6:08:a4: + a0:15:b0:0f:ee:6b:15:84:24:11:bc:85:2b:48:06: + 04:0a:58:bb:8c:e8:4d:48:f5:06:c5:91:fe:5d:99: + 0a:29:31:8a:f1:9b:0c:e0:39:75:a1:06:9b:d4:f5: + 06:74:8f:46:5e:64:ba:2f:d0:3d:7c:3d:30:03:e9: + 7c:35:17:69:04:f6:2e:29:d4:93:d6:d6:d2:6c:04: + 38:06:21:06:05:30:8a:b9:9d:05:8d:12:6e:48:39: + bb:f6:93:4f:ba:a5:84:c7:96:2f:be:92:25:e9:d0: + 95:2a:d9:23:8a:b3:28:0b:b6:19:1c:3b:be:a2:91: + 70:44:a8:77:18:94:4b:df:61:f4:5c:c9:78:76:34: + b5:87:0f:c0:92:04:26:b6:ca:62:cd:9b:5d:eb:bf: + 10:ac:df:af:72:5f:af:09:38:b1:dc:e1:3d:13:db: + a0:ac:b7:2e:ca:39:5c:4c:f1:1e:81:a8:b4:44:a2: + 72:d5:3b:c0:71:cc:dc:16:0d:fa:38:96:44:b3:00: + d6:65 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Alternative Name: + DNS:http-only.nginx-proxy.test + Signature Algorithm: sha256WithRSAEncryption + 3b:54:95:48:4d:f6:93:38:42:40:02:ab:b7:17:3b:50:3b:ca: + c7:12:69:b0:da:cb:d7:3e:0e:1f:bf:a2:59:c7:fe:c2:5c:43: + 84:92:b9:3a:be:8f:7e:2e:81:3c:ed:f3:a9:77:21:c2:35:f1: + da:cf:3a:1e:e2:ee:a2:ce:72:55:97:87:0e:ad:59:61:f7:75: + 46:c0:2b:d4:88:b7:36:97:11:fb:5e:28:89:e9:2a:92:f1:15: + f1:43:8e:c1:38:85:8d:3a:26:7d:25:72:93:17:96:8d:5a:ed: + e8:73:3a:d5:8d:80:f2:af:38:84:ff:85:2e:d1:36:7d:2e:e1: + f0:2c:d8:15:5f:fc:c5:70:5d:25:6a:22:f3:2a:cd:0f:25:ad: + d4:93:d3:9a:3e:50:bc:da:a5:6c:86:ea:1d:d9:b9:c5:90:db: + f5:02:c8:c9:77:5c:ef:77:fe:74:60:41:33:d9:3c:a2:e1:73: + aa:14:18:5d:36:58:c8:41:63:4c:59:0e:4b:3d:c5:65:5a:01: + b0:16:50:0f:d0:4f:0d:ca:97:f6:11:47:06:6b:b1:ae:bb:26: + 30:34:8b:7a:91:5d:8a:22:c7:f9:05:0d:bb:a5:b7:60:c0:20: + ce:d0:0e:c0:66:b3:e7:c4:61:ec:c5:40:e6:52:11:41:c3:11: + 18:04:c7:1e +-----BEGIN CERTIFICATE----- +MIIDCzCCAfOgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwPzEfMB0GA1UECgwWbmdp +bngtcHJveHkgdGVzdCBzdWl0ZTEcMBoGA1UEAwwTd3d3Lm5naW54LXByb3h5LnRs +ZDAgFw0yMzAyMDcyMTU0MTZaGA8yMDUwMDYyNTIxNTQxNlowJTEjMCEGA1UEAwwa +aHR0cC1vbmx5Lm5naW54LXByb3h5LnRlc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IB +DwAwggEKAoIBAQC0YmEHVC5tVYMtJLfiFTQTvXkh6RB1P0z4umAph+WOKh79M1Fa +ijpvYP8k8RsnMIysQwS3ect67MYIpKAVsA/uaxWEJBG8hStIBgQKWLuM6E1I9QbF +kf5dmQopMYrxmwzgOXWhBpvU9QZ0j0ZeZLov0D18PTAD6Xw1F2kE9i4p1JPW1tJs +BDgGIQYFMIq5nQWNEm5IObv2k0+6pYTHli++kiXp0JUq2SOKsygLthkcO76ikXBE +qHcYlEvfYfRcyXh2NLWHD8CSBCa2ymLNm13rvxCs369yX68JOLHc4T0T26Csty7K +OVxM8R6BqLREonLVO8BxzNwWDfo4lkSzANZlAgMBAAGjKTAnMCUGA1UdEQQeMByC +Gmh0dHAtb25seS5uZ2lueC1wcm94eS50ZXN0MA0GCSqGSIb3DQEBCwUAA4IBAQA7 +VJVITfaTOEJAAqu3FztQO8rHEmmw2svXPg4fv6JZx/7CXEOEkrk6vo9+LoE87fOp +dyHCNfHazzoe4u6iznJVl4cOrVlh93VGwCvUiLc2lxH7XiiJ6SqS8RXxQ47BOIWN +OiZ9JXKTF5aNWu3oczrVjYDyrziE/4Uu0TZ9LuHwLNgVX/zFcF0laiLzKs0PJa3U +k9OaPlC82qVshuod2bnFkNv1AsjJd1zvd/50YEEz2Tyi4XOqFBhdNljIQWNMWQ5L +PcVlWgGwFlAP0E8Nypf2EUcGa7GuuyYwNIt6kV2KIsf5BQ27pbdgwCDO0A7AZrPn +xGHsxUDmUhFBwxEYBMce +-----END CERTIFICATE----- diff --git a/test/test_fallback.data/nodefault.certs/http-only.nginx-proxy.test.key b/test/test_fallback.data/nodefault.certs/http-only.nginx-proxy.test.key new file mode 100644 index 0000000..3834584 --- /dev/null +++ b/test/test_fallback.data/nodefault.certs/http-only.nginx-proxy.test.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEAtGJhB1QubVWDLSS34hU0E715IekQdT9M+LpgKYfljioe/TNR +Woo6b2D/JPEbJzCMrEMEt3nLeuzGCKSgFbAP7msVhCQRvIUrSAYECli7jOhNSPUG +xZH+XZkKKTGK8ZsM4Dl1oQab1PUGdI9GXmS6L9A9fD0wA+l8NRdpBPYuKdST1tbS +bAQ4BiEGBTCKuZ0FjRJuSDm79pNPuqWEx5YvvpIl6dCVKtkjirMoC7YZHDu+opFw +RKh3GJRL32H0XMl4djS1hw/AkgQmtspizZtd678QrN+vcl+vCTix3OE9E9ugrLcu +yjlcTPEegai0RKJy1TvAcczcFg36OJZEswDWZQIDAQABAoIBAAfDA/HQyX6i41YZ +8l+kEe2XhZLT+IVTB/jb7C9dTZ9kaJj0kFeZAxKv1cq9JTH2gNcYuyc58muDrLHK +g6jrPoQ/z1k0RB8ci9Q5jgrz7n4NsOWmxXfS5GMaprlHDHeA+HjdgBZBtorfUDvL +vndpVimgiETETUCd115hd39jKHFcRcdV6yCix7ObywK3dMgLVpagCcnlyCWffS/r +nhhMfJ+VstW0nUtfZ7JEYwT6Cg7lLAVtDkqPX8zGjJiRwUKH808bUyqEw1y5Cc8U +U5hbmMgPWfXsKxsEC6FSVHBG9ZX2jymOMQXijLFcBSuWvADHmyU+ZxXcbtd1rv4E +cGFj3wECgYEA5cNrr5WjrpEin6MYYVWxiQ+xEWPU2R17eApagrDRLM41JJpv7a5m +TYuZRfIxb59CBPi718Gi168P3T2KMvo2/BTh9Lq5ZBYHx3aDqW2QvMFn7/tgamj8 +0DBxccd2QWfGIBrT1rAF7lD8TC86wtDDVKrvhucRSEXVKF/jWFFRGfUCgYEAyPt6 +48khr7sfNMVdkDLjQjZVV6H7ZUMoSn0FGybgKWxW+b0XCBPObUQWIpyCNTRr1+4A +1TAUS+F/OVVfwnLNgemeE2wd6CaduxwiK1U4pHbyXCElH1ifonHWV3MoXOefYsiY +q5z2jfJzUi0JZVUKsveu9rQsFLsc//1s/I5T1LECgYEAldY6fNg2VVp63OZsuNU8 +oSiljbSwEyMh6Oe/nOkYkIKtr4AzrCoGt11piG7ohGW0lS9suMijnMqiquI+JP5+ +KyinLoUy761aR17nf+9e62mpkZw6hUqQTGi7Irs0SHUXhMpaCfDi/Ua9MiW+yVuB +ds6+xBgeciZwWxMlXOwy2p0CgYEAm+YWiSK3Mq0fo7uEvBn9Fps2z+ciLoZNdppL +n6gkMX2MaeQ3PVi/wxoRYX+tsL+c973yf2vwEnw0R7Dlutt6dc9VgxNWj4GE0GMe +Tiao7Uom7Tf4p7wC9+r9rI/zOz2f8OxRIK18wtbShWfR5fx1dCWUXmGb3+jUse1O +4Qk2FcECgYAvSvGFoJb8tuHFEYYHBbjficmvTUsrTE+EhxPqWKFhKfF19fFFIupy +XBCrN6nwrh+/YMxZXeIRbbTTf814cOO7PjLeNhnfhJZkaJq1HzbYe3bOurna3qrm +Ra3xiM8Ld2PyGnZPXf8+AWhMhuPkLX1KFVTCAxwCpmTZCHtiGCmXMA== +-----END RSA PRIVATE KEY----- diff --git a/test/test_fallback.data/nodefault.certs/https-and-http.nginx-proxy.test.crt b/test/test_fallback.data/nodefault.certs/https-and-http.nginx-proxy.test.crt new file mode 100644 index 0000000..8b04cb9 --- /dev/null +++ b/test/test_fallback.data/nodefault.certs/https-and-http.nginx-proxy.test.crt @@ -0,0 +1,71 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 4096 (0x1000) + Signature Algorithm: sha256WithRSAEncryption + Issuer: O=nginx-proxy test suite, CN=www.nginx-proxy.tld + Validity + Not Before: Feb 7 21:53:19 2023 GMT + Not After : Jun 25 21:53:19 2050 GMT + Subject: CN=https-and-http.nginx-proxy.test + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (2048 bit) + Modulus: + 00:b7:97:85:d1:7f:6b:50:29:f3:87:b7:4e:f5:25: + 40:6a:d8:fa:a1:63:3c:4a:2e:68:4a:c6:8b:38:df: + 07:81:d0:08:9d:fc:17:f5:37:28:7f:31:e6:f3:81: + 28:4e:22:b6:bd:a2:4e:f2:2f:e5:0f:dd:55:3c:e1: + 04:84:4c:45:1b:1a:ae:b7:f0:2a:da:43:05:71:91: + 92:b8:d1:49:fe:80:0a:53:b9:66:da:54:60:9a:fc: + e1:b2:e8:28:48:7f:96:94:3c:92:a3:b2:37:f6:7a: + c2:de:0b:12:f0:ae:4e:92:fe:2d:c1:b2:95:28:1f: + 88:8d:79:99:81:19:ae:22:a4:95:f5:9f:db:25:8e: + 1d:cf:43:cd:6f:85:93:5f:79:ee:f8:f3:d4:82:e1: + e9:4d:c9:ad:ae:5b:92:43:3a:3c:71:51:70:f7:3e: + bd:1b:24:52:6a:a3:cf:54:72:57:ed:fe:72:ea:96: + 9b:5a:02:02:a7:df:85:b7:68:ae:1e:07:77:9f:59: + a5:a0:8b:28:c2:c8:b7:bb:8a:42:50:df:05:73:bf: + 9c:55:13:b5:82:79:77:40:57:a4:8f:88:a5:71:50: + d7:70:b0:4d:0c:d9:86:b3:9b:db:8a:20:bd:19:68: + 10:52:2d:53:ba:0e:2e:1c:ad:80:54:bb:b6:c9:ab: + 11:39 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Alternative Name: + DNS:https-and-http.nginx-proxy.test + Signature Algorithm: sha256WithRSAEncryption + 2c:f3:e5:47:3f:8e:5a:28:b1:df:e5:95:50:85:6f:27:2f:a6: + 8d:f1:5e:cf:df:e2:52:66:97:61:36:59:81:26:25:19:99:c9: + 93:e5:85:cb:ca:69:af:4b:21:a3:d2:7a:bf:b5:5e:2d:42:fb: + 99:f8:22:58:e5:bf:79:b8:8a:74:7e:c6:94:14:d9:f2:27:63: + b6:e5:74:21:5b:59:fb:f6:c8:a9:28:fb:60:f7:5e:bd:c2:e6: + 74:24:14:96:61:95:6c:c2:66:b4:52:25:a1:85:5a:97:e5:68: + 5c:62:cf:69:3b:b0:a9:56:d8:e3:5f:74:dc:84:18:d5:3e:4f: + c9:35:39:26:88:dc:9b:80:d9:40:e1:4f:09:27:8d:d2:89:55: + 30:91:02:86:35:04:95:1e:1d:58:14:5b:c6:e0:2e:a7:bf:a8: + f6:2b:76:8a:4e:71:79:bc:c0:04:cd:db:81:73:46:ce:68:ed: + 25:b0:0e:42:8d:96:64:77:3b:f4:9d:1a:c9:f6:78:4c:56:4f: + 92:17:29:3d:80:50:71:77:4b:a8:29:c2:12:fc:ad:0a:37:81: + 38:4c:fb:54:99:4d:12:5f:98:dc:d1:a9:7b:08:45:c4:6f:7e: + fe:00:e0:db:79:fe:d1:28:e3:8e:82:d1:fb:bc:0a:c4:42:93: + c9:5e:eb:ba +-----BEGIN CERTIFICATE----- +MIIDFTCCAf2gAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwPzEfMB0GA1UECgwWbmdp +bngtcHJveHkgdGVzdCBzdWl0ZTEcMBoGA1UEAwwTd3d3Lm5naW54LXByb3h5LnRs +ZDAgFw0yMzAyMDcyMTUzMTlaGA8yMDUwMDYyNTIxNTMxOVowKjEoMCYGA1UEAwwf +aHR0cHMtYW5kLWh0dHAubmdpbngtcHJveHkudGVzdDCCASIwDQYJKoZIhvcNAQEB +BQADggEPADCCAQoCggEBALeXhdF/a1Ap84e3TvUlQGrY+qFjPEouaErGizjfB4HQ +CJ38F/U3KH8x5vOBKE4itr2iTvIv5Q/dVTzhBIRMRRsarrfwKtpDBXGRkrjRSf6A +ClO5ZtpUYJr84bLoKEh/lpQ8kqOyN/Z6wt4LEvCuTpL+LcGylSgfiI15mYEZriKk +lfWf2yWOHc9DzW+Fk1957vjz1ILh6U3Jra5bkkM6PHFRcPc+vRskUmqjz1RyV+3+ +cuqWm1oCAqffhbdorh4Hd59ZpaCLKMLIt7uKQlDfBXO/nFUTtYJ5d0BXpI+IpXFQ +13CwTQzZhrOb24ogvRloEFItU7oOLhytgFS7tsmrETkCAwEAAaMuMCwwKgYDVR0R +BCMwIYIfaHR0cHMtYW5kLWh0dHAubmdpbngtcHJveHkudGVzdDANBgkqhkiG9w0B +AQsFAAOCAQEALPPlRz+OWiix3+WVUIVvJy+mjfFez9/iUmaXYTZZgSYlGZnJk+WF +y8ppr0sho9J6v7VeLUL7mfgiWOW/ebiKdH7GlBTZ8idjtuV0IVtZ+/bIqSj7YPde +vcLmdCQUlmGVbMJmtFIloYVal+VoXGLPaTuwqVbY41903IQY1T5PyTU5Jojcm4DZ +QOFPCSeN0olVMJEChjUElR4dWBRbxuAup7+o9it2ik5xebzABM3bgXNGzmjtJbAO +Qo2WZHc79J0ayfZ4TFZPkhcpPYBQcXdLqCnCEvytCjeBOEz7VJlNEl+Y3NGpewhF +xG9+/gDg23n+0SjjjoLR+7wKxEKTyV7rug== +-----END CERTIFICATE----- diff --git a/test/test_fallback.data/nodefault.certs/https-and-http.nginx-proxy.test.key b/test/test_fallback.data/nodefault.certs/https-and-http.nginx-proxy.test.key new file mode 100644 index 0000000..11f5210 --- /dev/null +++ b/test/test_fallback.data/nodefault.certs/https-and-http.nginx-proxy.test.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEAt5eF0X9rUCnzh7dO9SVAatj6oWM8Si5oSsaLON8HgdAInfwX +9TcofzHm84EoTiK2vaJO8i/lD91VPOEEhExFGxqut/Aq2kMFcZGSuNFJ/oAKU7lm +2lRgmvzhsugoSH+WlDySo7I39nrC3gsS8K5Okv4twbKVKB+IjXmZgRmuIqSV9Z/b +JY4dz0PNb4WTX3nu+PPUguHpTcmtrluSQzo8cVFw9z69GyRSaqPPVHJX7f5y6pab +WgICp9+Ft2iuHgd3n1mloIsowsi3u4pCUN8Fc7+cVRO1gnl3QFekj4ilcVDXcLBN +DNmGs5vbiiC9GWgQUi1Tug4uHK2AVLu2yasROQIDAQABAoIBACT4KSVHoEdzOyvw +GME6sB8T9Fw9TG2vrKaqFmzsVGmqh6Gwmu5xHgGG/fe44XHigaPsJDOWu2yXaEur +ECrH5P6RP++gODDdYCI/ayk2U80g4XN8mR6L8Swkkhphr4Lx1lOhYvH9uFE05Tqr +RjQbFY16C6K+oFSFDQ1YGDYsAqnM3RD7PH+lHpo8UN1TO/vogdSQEpMYZDwLAYnW +uD5G3c0u2PsGu9YLuz2p8hcs3chh+cqKJWXOeW0JLrNGx1bqeQWkn6nXRDdRYi9V +cJlTgDqGuF54bieSyq9ABDZQP4Ol+moYKDoIz5PwurNjcYSklrT1tw0gqHZoQK1L +fDjw3QECgYEA7QMRU1AFKTvO7/8WLHLN5BT63n31wm0e9PYpz/XVLWEfxBcp9Xmf +xAIhXZ/U9P4dfNqxTjN9mVGzCHh5KfDJnUFqOXFy/zvfMeRzJf6dJo6/4OX9Bijr +Tgd454vyGXYQP2t+F14UAwl6vlGOAjttiP5qY5Ef1gllBEeIPe9Ts9kCgYEAxkzZ +pq4HJ/5/iDquMEHXNXzpNPavSvgxQdl1ILvJ49LJImmQFBCP9PqiOTIfePz1OqUI +C4baFuc0FEDJ3x9CUNmMY1lEi2ZUq2agPSXaQNsMcKtEJH8SoJlJIRpkQA7unX09 +zb4dam6g79OaGmb8scePuezXMLv1Ee6WWtXbzGECgYEA6PYn9Gzl9cacu9dOUzgw +2ewpPcIvawDY+cxwAsHO3MDneVWPX4JBoGa7pwvwRTL1hwBqYMRJwwbD5CKObcQI +V/KxV28Eqo2N77tt1z2x9/E99u/4yTI1P0gm9ejfeVlL1RpyIMPPBcEujZ0Z6WXC +X3I63k0KLtajHRa2erIf4tkCgYAfunAgwTuX5JqXO3xfcEl033WY6deGUUvgU2Dw +Sdu1viY8gVNyQmwmMGwAZsquWxsJtRoibgM7IucsTml+b8v2j7hstP3IqCjn+9Wr +swDG28WTyXNvu31JgP04dLaRoVIAlOdsofym6OiLNvozO0M3VsziXMjZnVlK8zfP +dORkQQKBgQDXAJEJPygxVA+bF104dzCMWGmU7K8ShEWC5eOdKK4KWf9bNDpY6M6c +i6zga/xBbj7e3Bxqprpp8Wy2gIsnYiVo4V9EQethbLdomPxOpBMNMARw81rL1CpO +jbHB7bIDcKs2tQoZEXUW86ZxC8sdaDaWTJTfUO0RpJow6ZO3yvxVIQ== +-----END RSA PRIVATE KEY----- diff --git a/test/test_fallback.data/nodefault.certs/https-only.nginx-proxy.test.crt b/test/test_fallback.data/nodefault.certs/https-only.nginx-proxy.test.crt new file mode 100644 index 0000000..a93e728 --- /dev/null +++ b/test/test_fallback.data/nodefault.certs/https-only.nginx-proxy.test.crt @@ -0,0 +1,71 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 4096 (0x1000) + Signature Algorithm: sha256WithRSAEncryption + Issuer: O=nginx-proxy test suite, CN=www.nginx-proxy.tld + Validity + Not Before: Feb 7 21:53:49 2023 GMT + Not After : Jun 25 21:53:49 2050 GMT + Subject: CN=https-only.nginx-proxy.test + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (2048 bit) + Modulus: + 00:d9:87:48:02:85:f4:5f:0d:90:7e:4c:4f:13:89: + 41:ca:41:15:c2:6f:fd:a8:c7:17:83:c6:dd:8c:fe: + 19:a4:b2:6b:0b:35:4f:b4:3d:7c:40:0a:04:33:2a: + fd:10:72:f7:63:63:99:5b:3d:ec:78:ee:c6:4d:c8: + 0e:4c:be:f2:3f:e3:02:74:57:9a:c1:fe:15:95:63: + 4e:e7:2c:eb:70:f2:6b:c8:ba:01:a2:ca:a1:c7:76: + ff:38:e4:c2:b0:66:fc:85:d2:af:0f:22:81:d4:82: + eb:d5:b0:e6:69:14:37:dd:8d:ad:29:ce:93:68:5a: + ce:f4:77:76:6f:78:13:b6:c8:2f:fe:e0:b6:7e:fb: + 29:16:be:e2:f5:45:3b:39:5b:52:dc:26:b7:ca:0c: + b6:1c:fc:a8:38:0b:dd:c1:f4:04:9b:2d:38:c9:a5: + 2d:3e:f1:42:88:53:a2:3b:17:cf:d5:3c:2b:d6:6a: + 7f:6f:05:8d:c5:b7:5d:64:1e:83:1b:e7:ec:80:3d: + 6d:34:c1:66:b2:e6:5d:d9:a7:6e:46:75:14:bf:10: + 16:c5:fc:47:8e:63:fa:e5:b4:bd:f2:b9:e0:cb:ea: + 75:f9:68:ee:7d:8f:ea:8f:1a:9f:34:27:7a:4a:9f: + 85:fd:3e:17:a7:96:c3:d0:4e:50:a2:a2:e0:45:92: + d0:b5 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Alternative Name: + DNS:https-only.nginx-proxy.test + Signature Algorithm: sha256WithRSAEncryption + 8a:52:46:42:a9:74:18:6a:52:90:ef:a4:e9:c5:54:d5:97:3a: + ff:8b:c2:76:4f:9e:47:aa:e1:ea:e5:b9:af:9d:33:e3:85:17: + 54:7d:32:bd:ac:90:3f:5c:d2:a1:42:17:52:2b:b1:83:e5:c3: + bf:81:f0:e7:38:e2:88:67:7b:d8:59:fe:f9:94:99:ba:be:f4: + 3c:24:b2:c7:9e:f0:98:21:c6:2d:c2:e8:f3:67:bd:62:00:aa: + ce:34:fa:b4:53:6d:c1:09:5e:55:bd:43:aa:86:c6:f8:c5:83: + 46:3a:49:12:a2:ec:30:36:0c:99:44:74:09:9d:cc:4b:98:1f: + 7e:c9:9b:68:a0:f8:1e:00:14:d0:da:2a:bf:c8:ca:a8:1c:10: + b5:68:a2:f1:41:93:0c:f3:3f:c0:c6:53:3c:8d:a7:dd:a5:7b: + 35:cc:44:e0:5b:6d:c5:cb:33:6f:c1:43:7e:06:df:21:99:11: + b3:91:41:b4:5e:f0:37:1e:8e:e5:73:85:dc:4a:21:d5:41:f9: + 4e:b8:f5:ed:21:93:09:91:c2:8c:6b:04:a4:84:ab:3a:fe:35: + 64:fa:6b:a7:8d:40:a6:64:89:30:84:ac:28:99:5a:01:79:77: + c0:df:88:da:a9:75:5f:c4:51:ae:a8:45:7b:d2:e1:a2:81:29: + 60:cd:7b:cd +-----BEGIN CERTIFICATE----- +MIIDDTCCAfWgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwPzEfMB0GA1UECgwWbmdp +bngtcHJveHkgdGVzdCBzdWl0ZTEcMBoGA1UEAwwTd3d3Lm5naW54LXByb3h5LnRs +ZDAgFw0yMzAyMDcyMTUzNDlaGA8yMDUwMDYyNTIxNTM0OVowJjEkMCIGA1UEAwwb +aHR0cHMtb25seS5uZ2lueC1wcm94eS50ZXN0MIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEA2YdIAoX0Xw2QfkxPE4lBykEVwm/9qMcXg8bdjP4ZpLJrCzVP +tD18QAoEMyr9EHL3Y2OZWz3seO7GTcgOTL7yP+MCdFeawf4VlWNO5yzrcPJryLoB +osqhx3b/OOTCsGb8hdKvDyKB1ILr1bDmaRQ33Y2tKc6TaFrO9Hd2b3gTtsgv/uC2 +fvspFr7i9UU7OVtS3Ca3ygy2HPyoOAvdwfQEmy04yaUtPvFCiFOiOxfP1Twr1mp/ +bwWNxbddZB6DG+fsgD1tNMFmsuZd2aduRnUUvxAWxfxHjmP65bS98rngy+p1+Wju +fY/qjxqfNCd6Sp+F/T4Xp5bD0E5QoqLgRZLQtQIDAQABoyowKDAmBgNVHREEHzAd +ghtodHRwcy1vbmx5Lm5naW54LXByb3h5LnRlc3QwDQYJKoZIhvcNAQELBQADggEB +AIpSRkKpdBhqUpDvpOnFVNWXOv+LwnZPnkeq4erlua+dM+OFF1R9Mr2skD9c0qFC +F1IrsYPlw7+B8Oc44ohne9hZ/vmUmbq+9Dwkssee8Jghxi3C6PNnvWIAqs40+rRT +bcEJXlW9Q6qGxvjFg0Y6SRKi7DA2DJlEdAmdzEuYH37Jm2ig+B4AFNDaKr/Iyqgc +ELVoovFBkwzzP8DGUzyNp92lezXMROBbbcXLM2/BQ34G3yGZEbORQbRe8DcejuVz +hdxKIdVB+U649e0hkwmRwoxrBKSEqzr+NWT6a6eNQKZkiTCErCiZWgF5d8DfiNqp +dV/EUa6oRXvS4aKBKWDNe80= +-----END CERTIFICATE----- diff --git a/test/test_fallback.data/nodefault.certs/https-only.nginx-proxy.test.key b/test/test_fallback.data/nodefault.certs/https-only.nginx-proxy.test.key new file mode 100644 index 0000000..17976ce --- /dev/null +++ b/test/test_fallback.data/nodefault.certs/https-only.nginx-proxy.test.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEA2YdIAoX0Xw2QfkxPE4lBykEVwm/9qMcXg8bdjP4ZpLJrCzVP +tD18QAoEMyr9EHL3Y2OZWz3seO7GTcgOTL7yP+MCdFeawf4VlWNO5yzrcPJryLoB +osqhx3b/OOTCsGb8hdKvDyKB1ILr1bDmaRQ33Y2tKc6TaFrO9Hd2b3gTtsgv/uC2 +fvspFr7i9UU7OVtS3Ca3ygy2HPyoOAvdwfQEmy04yaUtPvFCiFOiOxfP1Twr1mp/ +bwWNxbddZB6DG+fsgD1tNMFmsuZd2aduRnUUvxAWxfxHjmP65bS98rngy+p1+Wju +fY/qjxqfNCd6Sp+F/T4Xp5bD0E5QoqLgRZLQtQIDAQABAoIBAAWs//YA5MVuJy0E +dLO/yxWp6RVvsqCqwTRRBgrdvnGLrjtWosPDLvDE0iM7peq99TKEsMWusfLd2BLD +e4wJF20PUUsT1hflt050juR9SY9i4+kS4WQMAXig5DvpzCKqLUCYpLSyY8zVta2X +tgtb2bFQNwp2N2ZrqCa8zzxNV8ZXGoW+ZlvBJEDtBwt1DCDhY39/pqHfIhFl4Vwk +YhhbVjID145D1j/fP6vLceM2YA4uRmF1itj1iQ6YNNpXRspUGE4DXdqR6HcbduiX +trZjmdtKXY8mJg6jyLZxYbjFlKV/LvqKRYF3Jb9K0vdd4juBdZoy7DQzoLhcnzui +pEnPLakCgYEA9tN6KdQGKGBXGuF+ZqhXfB/XSkKUf8o/5j62cbu11ZIJ+iEBx+d6 +lQAxTz5hHUL6a3c5qiM+AWBxYuFD6oqptIlTlBfIXI978neDNvEWWffivPvQLbt9 +o9ohOirfK1iGPvtrpAwjv5ylE5SiTmJ/6wDvQWjNGAnJ3aaxkesJUSMCgYEA4Z0K +UHZVtnKLtzzIY7KfLbuKF/fJEDfMNr4Wgl6ny21vqO9kJGmA7SaoNdhx8RDcKmeV +/Vey4ug6YlOG48eapKLTthdRz5mx+jIkUfdOhj81m28xm/OPTqCrviTHCNOHeYDy +NKAIlJMo2z0vTKJn5eP6CsYmDWLpHQNyXY5qcEcCgYAzDBWt5O3JF/Or2Yr8zEAb +qbIq544yx69jfQDakMnQe72Yf48Quuz9N+b6zpnjJWEJLMU+TL+cJUgN/SzAqyDh +96zTaf/ENOCbiuAWUtIelUfNcf7iFm6rnodUsl0pZ8uL5w+iA+i4zjrNy+WtdG2k +OrNAwd345L1dHAaJeSSaJQKBgQCUnF3r7Fa/TCpt87LHwSQK+sqWyRf+/9IbiRDI +pVL/s8FmVPHw7jIHhHwuo7lCImnz4LGy5C6oOnIizIRAy/04Ty0Hd8ri5YmPlbHI +8A8gbMiB7zeNU1zlXP5jzFPyo2tMhLyGH5gnTdwOtfnPD/dCPe45ZJYyISIOg3O0 +3peMBwKBgH20cskAOCNclfoG+Nis52h8FqmDlflJ8waUarvk26JhO1e009kOytw8 +x/qSuttpGtTG+4fdc2wJvFNczr4h9ZlftBdgZXj8PKgRpcIe8q97Xg8PUj+Xfu/t +vD/QV+tVcGoAMsQq4NeFxiTbPfwVyXdYFT1XVCu6JEdLL+gpWh5W +-----END RSA PRIVATE KEY----- diff --git a/test/test_fallback.data/nodefault.yml b/test/test_fallback.data/nodefault.yml new file mode 100644 index 0000000..ecd4359 --- /dev/null +++ b/test/test_fallback.data/nodefault.yml @@ -0,0 +1,36 @@ +services: + sut: + image: nginxproxy/nginx-proxy:test + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro + - ./nodefault.certs:/etc/nginx/certs:ro + https-and-http: + image: web + expose: + - "81" + environment: + WEB_PORTS: "81" + VIRTUAL_HOST: https-and-http.nginx-proxy.test + https-only: + image: web + expose: + - "82" + environment: + WEB_PORTS: "82" + VIRTUAL_HOST: https-only.nginx-proxy.test + HTTPS_METHOD: nohttp + http-only: + image: web + expose: + - "83" + environment: + WEB_PORTS: "83" + VIRTUAL_HOST: http-only.nginx-proxy.test + HTTPS_METHOD: nohttps + missing-cert: + image: web + expose: + - "84" + environment: + WEB_PORTS: "84" + VIRTUAL_HOST: missing-cert.nginx-proxy.test diff --git a/test/test_fallback.py b/test/test_fallback.py index 1e687a3..cdaeef3 100644 --- a/test/test_fallback.py +++ b/test/test_fallback.py @@ -1,4 +1,5 @@ import os.path +import re import backoff import pytest @@ -31,6 +32,9 @@ def get(docker_compose, nginxproxy, want_err_re): return _get +INTERNAL_ERR_RE = re.compile("TLSV1_ALERT_INTERNAL_ERROR") + + @pytest.mark.parametrize("compose_file,url,want_code,want_err_re", [ # Has default.crt. ("withdefault.yml", "http://https-and-http.nginx-proxy.test/", 301, None), @@ -43,6 +47,17 @@ def get(docker_compose, nginxproxy, want_err_re): ("withdefault.yml", "https://missing-cert.nginx-proxy.test/", 500, None), ("withdefault.yml", "http://unknown.nginx-proxy.test/", 503, None), ("withdefault.yml", "https://unknown.nginx-proxy.test/", 503, None), + # Same as withdefault.yml, except there is no default.crt. + ("nodefault.yml", "http://https-and-http.nginx-proxy.test/", 301, None), + ("nodefault.yml", "https://https-and-http.nginx-proxy.test/", 200, None), + ("nodefault.yml", "http://https-only.nginx-proxy.test/", 503, None), + ("nodefault.yml", "https://https-only.nginx-proxy.test/", 200, None), + ("nodefault.yml", "http://http-only.nginx-proxy.test/", 200, None), + ("nodefault.yml", "https://http-only.nginx-proxy.test/", None, INTERNAL_ERR_RE), + ("nodefault.yml", "http://missing-cert.nginx-proxy.test/", 200, None), + ("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), ]) def test_fallback(get, url, want_code, want_err_re): if want_err_re is None: From 9b4bb07b348dc5a428b94416517291adb30794c3 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Sat, 4 Feb 2023 18:59:38 -0500 Subject: [PATCH 139/300] fix: Don't create fallback http(s) server when http(s) disabled Before, a fallback http server was created to handle requests for unknown virtual hosts even when `HTTPS_METHOD=nohttp`. (In this case, all http vhosts would be unknown.) Likewise, a catch-all fallback https server was still created even if `HTTPS_METHOD=nohttps`. Now the fallback servers are created only if needed. This brings the behavior in line with the documentation and user expectation. It will also make it easier to implement a planned feature: different servers on different ports. --- nginx.tmpl | 124 +++++++++++------- test/test_fallback.data/nohttp-on-app.yml | 16 +++ .../nohttp-with-missing-cert.yml | 22 ++++ test/test_fallback.data/nohttp.yml | 15 +++ test/test_fallback.data/nohttps-on-app.yml | 15 +++ test/test_fallback.data/nohttps.yml | 14 ++ test/test_fallback.py | 31 +++++ test/test_ssl/test_nohttp.py | 7 +- 8 files changed, 194 insertions(+), 50 deletions(-) create mode 100644 test/test_fallback.data/nohttp-on-app.yml create mode 100644 test/test_fallback.data/nohttp-with-missing-cert.yml create mode 100644 test/test_fallback.data/nohttp.yml create mode 100644 test/test_fallback.data/nohttps-on-app.yml create mode 100644 test/test_fallback.data/nohttps.yml diff --git a/nginx.tmpl b/nginx.tmpl index d2ccd8f..5733351 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -20,6 +20,7 @@ {{- $_ := 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") }} +{{- $_ := set $globals "vhosts" (dict) }} {{- $_ := set $globals "networks" (dict) }} # Networks available to the container running docker-gen (which are assumed to # match the networks available to the container running nginx): @@ -346,22 +347,80 @@ proxy_set_header X-Original-URI $request_uri; proxy_set_header Proxy ""; {{- end }} +{{- /* + * Precompute some information about each vhost. This is done early because + * the creation of fallback servers depends on DEFAULT_HOST, HTTPS_METHOD, + * and whether there are any missing certs. + */}} +{{- range $vhost, $containers := groupByMulti $globals.containers "Env.VIRTUAL_HOST" "," }} + {{- $vhost := trim $vhost }} + {{- if not $vhost }} + {{- /* Ignore containers with VIRTUAL_HOST set to the empty string. */}} + {{- continue }} + {{- end }} + {{- $certName := first (groupByKeys $containers "Env.CERT_NAME") }} + {{- $vhostCert := closest (dir "/etc/nginx/certs") (printf "%s.crt" $vhost) }} + {{- $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)) }} + {{- $default := eq $globals.Env.DEFAULT_HOST $vhost }} + {{- $https_method := or (first (groupByKeys $containers "Env.HTTPS_METHOD")) $globals.Env.HTTPS_METHOD "redirect" }} + {{- $_ := set $globals.vhosts $vhost (dict "cert" $cert "cert_ok" $cert_ok "containers" $containers "default" $default "https_method" $https_method) }} +{{- end }} + +{{- /* + * If needed, create a catch-all fallback server to send an error code to + * clients that request something from an unknown vhost. + */}} +{{- block "fallback_server" $globals }} + {{- $globals := . }} + {{- $http_exists := false }} + {{- $https_exists := false }} + {{- $default_http_exists := false }} + {{- $default_https_exists := false }} + {{- range $vhost := $globals.vhosts }} + {{- $http := or (ne $vhost.https_method "nohttp") (not $vhost.cert_ok) }} + {{- $https := ne $vhost.https_method "nohttps" }} + {{- $http_exists = or $http_exists $http }} + {{- $https_exists = or $https_exists $https }} + {{- $default_http_exists = or $default_http_exists (and $http $vhost.default) }} + {{- $default_https_exists = or $default_https_exists (and $https $vhost.default) }} + {{- end }} + {{- $fallback_http := and $http_exists (not $default_http_exists) }} + {{- $fallback_https := and $https_exists (not $default_https_exists) }} + {{- /* + * If there are no vhosts at all, create fallbacks for both plain http + * and https so that clients get something more useful than a connection + * refused error. + */}} + {{- if and (not $http_exists) (not $https_exists) }} + {{- $fallback_http = true }} + {{- $fallback_https = true }} + {{- end }} + {{- if or $fallback_http $fallback_https }} server { server_name _; # This is just an invalid value which will never trigger on a real hostname. server_tokens off; - listen {{ $globals.external_http_port }}; - listen {{ $globals.external_https_port }} ssl http2; -{{- if $globals.enable_ipv6 }} - listen [::]:{{ $globals.external_http_port }}; - listen [::]:{{ $globals.external_https_port }} ssl http2; -{{- end }} + {{- if $fallback_http }} + listen {{ $globals.external_http_port }} default_server; + {{- if $globals.enable_ipv6 }} + listen [::]:{{ $globals.external_http_port }} default_server; + {{- end }} + {{- end }} + {{- if $fallback_https }} + listen {{ $globals.external_https_port }} ssl http2 default_server; + {{- if $globals.enable_ipv6 }} + listen [::]:{{ $globals.external_https_port }} ssl http2 default_server; + {{- end }} + {{- end }} {{ $globals.access_log }} -{{- if $globals.default_cert_ok }} + {{- if $globals.default_cert_ok }} ssl_session_cache shared:SSL:50m; ssl_session_tickets off; ssl_certificate /etc/nginx/certs/default.crt; ssl_certificate_key /etc/nginx/certs/default.key; -{{- else }} + {{- else }} # No default.crt certificate found for this vhost, so force nginx to emit a # TLS error if the client connects via https. {{- /* See the comment in the main `server` directive for rationale. */}} @@ -372,17 +431,19 @@ server { if ($https) { return 444; } -{{- end }} + {{- end }} return 503; } - -{{- range $host, $containers := groupByMulti $globals.containers "Env.VIRTUAL_HOST" "," }} - - {{- $host := trim $host }} - {{- if not $host }} - {{- /* Ignore containers with VIRTUAL_HOST set to the empty string. */}} - {{- continue }} {{- end }} +{{- end }} + +{{- range $host, $vhost := $globals.vhosts }} + {{- $cert := $vhost.cert }} + {{- $cert_ok := $vhost.cert_ok }} + {{- $containers := $vhost.containers }} + {{- $default_server := when $vhost.default "default_server" "" }} + {{- $https_method := $vhost.https_method }} + {{- $is_regexp := hasPrefix "~" $host }} {{- $upstream_name := when (or $is_regexp $globals.sha1_upstream_name) (sha1 $host) $host }} @@ -402,22 +463,12 @@ server { {{ template "upstream" (dict "globals" $globals "Upstream" $upstream "Containers" $containers) }} {{- end }} - {{- $default_host := or ($globals.Env.DEFAULT_HOST) "" }} - {{- $default_server := index (dict $host "" $default_host "default_server") $host }} - {{- /* * Get the SERVER_TOKENS defined by containers w/ the same vhost, * falling back to "". */}} {{- $server_tokens := trim (or (first (groupByKeys $containers "Env.SERVER_TOKENS")) "") }} - - {{- /* - * Get the HTTPS_METHOD defined by containers w/ the same vhost, falling - * back to "redirect". - */}} - {{- $https_method := or (first (groupByKeys $containers "Env.HTTPS_METHOD")) (or $globals.Env.HTTPS_METHOD "redirect") }} - {{- /* * Get the SSL_POLICY defined by containers w/ the same vhost, falling * back to empty string (use default). @@ -433,27 +484,6 @@ server { {{- /* Get the VIRTUAL_ROOT By containers w/ use fastcgi root */}} {{- $vhost_root := or (first (groupByKeys $containers "Env.VIRTUAL_ROOT")) "/var/www/public" }} - - {{- /* Get the first cert name defined by containers w/ the same vhost */}} - {{- $certName := (first (groupByKeys $containers "Env.CERT_NAME")) }} - - {{- /* Get the best matching cert by name for the vhost. */}} - {{- $vhostCert := (closest (dir "/etc/nginx/certs") (printf "%s.crt" $host))}} - - {{- /* - * vhostCert is actually a filename so remove any suffixes since they - * are added later. - */}} - {{- $vhostCert := trimSuffix ".crt" $vhostCert }} - {{- $vhostCert := trimSuffix ".key" $vhostCert }} - - {{- /* - * Use the cert specified on the container or fallback to the best vhost - * match. - */}} - {{- $cert := (coalesce $certName $vhostCert) }} - {{- $cert_ok := and (ne $cert "") (exists (printf "/etc/nginx/certs/%s.crt" $cert)) (exists (printf "/etc/nginx/certs/%s.key" $cert)) }} - {{- if and $cert_ok (eq $https_method "redirect") }} server { server_name {{ $host }}; diff --git a/test/test_fallback.data/nohttp-on-app.yml b/test/test_fallback.data/nohttp-on-app.yml new file mode 100644 index 0000000..d81c9ca --- /dev/null +++ b/test/test_fallback.data/nohttp-on-app.yml @@ -0,0 +1,16 @@ +services: + sut: + image: nginxproxy/nginx-proxy:test + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro + - ./withdefault.certs:/etc/nginx/certs:ro + environment: + HTTPS_METHOD: redirect + https-only: + image: web + expose: + - "82" + environment: + WEB_PORTS: "82" + HTTPS_METHOD: nohttp + VIRTUAL_HOST: https-only.nginx-proxy.test diff --git a/test/test_fallback.data/nohttp-with-missing-cert.yml b/test/test_fallback.data/nohttp-with-missing-cert.yml new file mode 100644 index 0000000..3593a32 --- /dev/null +++ b/test/test_fallback.data/nohttp-with-missing-cert.yml @@ -0,0 +1,22 @@ +services: + sut: + image: nginxproxy/nginx-proxy:test + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro + - ./withdefault.certs:/etc/nginx/certs:ro + environment: + HTTPS_METHOD: nohttp + https-only: + image: web + expose: + - "82" + environment: + WEB_PORTS: "82" + VIRTUAL_HOST: https-only.nginx-proxy.test + missing-cert: + image: web + expose: + - "84" + environment: + WEB_PORTS: "84" + VIRTUAL_HOST: missing-cert.nginx-proxy.test diff --git a/test/test_fallback.data/nohttp.yml b/test/test_fallback.data/nohttp.yml new file mode 100644 index 0000000..3ed0c0e --- /dev/null +++ b/test/test_fallback.data/nohttp.yml @@ -0,0 +1,15 @@ +services: + sut: + image: nginxproxy/nginx-proxy:test + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro + - ./withdefault.certs:/etc/nginx/certs:ro + environment: + HTTPS_METHOD: nohttp + https-only: + image: web + expose: + - "82" + environment: + WEB_PORTS: "82" + VIRTUAL_HOST: https-only.nginx-proxy.test diff --git a/test/test_fallback.data/nohttps-on-app.yml b/test/test_fallback.data/nohttps-on-app.yml new file mode 100644 index 0000000..690d656 --- /dev/null +++ b/test/test_fallback.data/nohttps-on-app.yml @@ -0,0 +1,15 @@ +services: + sut: + image: nginxproxy/nginx-proxy:test + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro + environment: + HTTPS_METHOD: redirect + http-only: + image: web + expose: + - "83" + environment: + WEB_PORTS: "83" + HTTPS_METHOD: nohttps + VIRTUAL_HOST: http-only.nginx-proxy.test diff --git a/test/test_fallback.data/nohttps.yml b/test/test_fallback.data/nohttps.yml new file mode 100644 index 0000000..f07ddf9 --- /dev/null +++ b/test/test_fallback.data/nohttps.yml @@ -0,0 +1,14 @@ +services: + sut: + image: nginxproxy/nginx-proxy:test + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro + environment: + HTTPS_METHOD: nohttps + http-only: + image: web + expose: + - "83" + environment: + WEB_PORTS: "83" + VIRTUAL_HOST: http-only.nginx-proxy.test diff --git a/test/test_fallback.py b/test/test_fallback.py index cdaeef3..ce3d68f 100644 --- a/test/test_fallback.py +++ b/test/test_fallback.py @@ -33,6 +33,7 @@ def get(docker_compose, nginxproxy, want_err_re): INTERNAL_ERR_RE = re.compile("TLSV1_ALERT_INTERNAL_ERROR") +CONNECTION_REFUSED_RE = re.compile("Connection refused") @pytest.mark.parametrize("compose_file,url,want_code,want_err_re", [ @@ -58,6 +59,36 @@ INTERNAL_ERR_RE = re.compile("TLSV1_ALERT_INTERNAL_ERROR") ("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. + ("nohttp.yml", "http://https-only.nginx-proxy.test/", None, CONNECTION_REFUSED_RE), + ("nohttp.yml", "https://https-only.nginx-proxy.test/", 200, None), + ("nohttp.yml", "http://unknown.nginx-proxy.test/", None, CONNECTION_REFUSED_RE), + ("nohttp.yml", "https://unknown.nginx-proxy.test/", 503, None), + # HTTPS_METHOD=redirect on nginx-proxy, HTTPS_METHOD=nohttp on the app container. + ("nohttp-on-app.yml", "http://https-only.nginx-proxy.test/", None, CONNECTION_REFUSED_RE), + ("nohttp-on-app.yml", "https://https-only.nginx-proxy.test/", 200, None), + ("nohttp-on-app.yml", "http://unknown.nginx-proxy.test/", None, CONNECTION_REFUSED_RE), + ("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 + # HTTPS_METHOD=nohttp setting to effectively become HTTPS_METHOD=noredirect. This means that + # there will be a plain http server solely to support that vhost, so http requests to other + # vhosts get a 503, not a connection refused error. + ("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/", 500, None), + ("nohttp-with-missing-cert.yml", "http://unknown.nginx-proxy.test/", 503, None), + ("nohttp-with-missing-cert.yml", "https://unknown.nginx-proxy.test/", 503, None), + # 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, CONNECTION_REFUSED_RE), + ("nohttps.yml", "http://unknown.nginx-proxy.test/", 503, None), + ("nohttps.yml", "https://unknown.nginx-proxy.test/", None, CONNECTION_REFUSED_RE), + # HTTPS_METHOD=redirect on nginx-proxy, HTTPS_METHOD=nohttps on the app container. + ("nohttps-on-app.yml", "http://http-only.nginx-proxy.test/", 200, None), + ("nohttps-on-app.yml", "https://http-only.nginx-proxy.test/", None, CONNECTION_REFUSED_RE), + ("nohttps-on-app.yml", "http://unknown.nginx-proxy.test/", 503, None), + ("nohttps-on-app.yml", "https://unknown.nginx-proxy.test/", None, CONNECTION_REFUSED_RE), ]) def test_fallback(get, url, want_code, want_err_re): if want_err_re is None: diff --git a/test/test_ssl/test_nohttp.py b/test/test_ssl/test_nohttp.py index d7f0d92..5b650db 100644 --- a/test/test_ssl/test_nohttp.py +++ b/test/test_ssl/test_nohttp.py @@ -1,9 +1,10 @@ import pytest +import requests -def test_web2_http_is_not_forwarded(docker_compose, nginxproxy): - r = nginxproxy.get("http://web2.nginx-proxy.tld/", allow_redirects=False) - assert r.status_code == 503 +def test_web2_http_is_connection_refused(docker_compose, nginxproxy): + with pytest.raises(requests.exceptions.RequestException, match="Connection refused"): + nginxproxy.get("http://web2.nginx-proxy.tld/") def test_web2_https_is_forwarded(docker_compose, nginxproxy): From c10c7bcbe93cd2060c5fbfabbde6b07e29131627 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Thu, 9 Feb 2023 08:10:43 +0100 Subject: [PATCH 140/300] build: dockergen 0.9.4 -> 0.10.0 --- Dockerfile | 2 +- Dockerfile.alpine | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 7669314..e178013 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # setup build arguments for version of dependencies to use -ARG DOCKER_GEN_VERSION=0.9.4 +ARG DOCKER_GEN_VERSION=0.10.0 ARG FOREGO_VERSION=v0.17.0 # Use a specific version of golang to build both binaries diff --git a/Dockerfile.alpine b/Dockerfile.alpine index 6902b41..0d2f560 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -1,5 +1,5 @@ # setup build arguments for version of dependencies to use -ARG DOCKER_GEN_VERSION=0.9.4 +ARG DOCKER_GEN_VERSION=0.10.0 ARG FOREGO_VERSION=v0.17.0 # Use a specific version of golang to build both binaries From de4386e44070ce3a35a360e533d99c448bf10b6a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 15 Feb 2023 04:57:57 +0000 Subject: [PATCH 141/300] build: bump golang from 1.20.0 to 1.20.1 Bumps golang from 1.20.0 to 1.20.1. --- updated-dependencies: - dependency-name: golang dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Dockerfile | 2 +- Dockerfile.alpine | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index e178013..0f42c8c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,7 +3,7 @@ ARG DOCKER_GEN_VERSION=0.10.0 ARG FOREGO_VERSION=v0.17.0 # Use a specific version of golang to build both binaries -FROM golang:1.20.0 as gobuilder +FROM golang:1.20.1 as gobuilder # Build docker-gen from scratch FROM gobuilder as dockergen diff --git a/Dockerfile.alpine b/Dockerfile.alpine index 0d2f560..724bdf1 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -3,7 +3,7 @@ ARG DOCKER_GEN_VERSION=0.10.0 ARG FOREGO_VERSION=v0.17.0 # Use a specific version of golang to build both binaries -FROM golang:1.20.0-alpine as gobuilder +FROM golang:1.20.1-alpine as gobuilder RUN apk add --no-cache git musl-dev # Build docker-gen from scratch From 6207be5f8ff62ecd9a446c92506ab06b51e4ba01 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Fri, 17 Feb 2023 01:52:05 -0500 Subject: [PATCH 142/300] fix: Partially revert "chore: Remove support for legacy swarm" This partially reverts commit 2494e207843c92a715da3e8e65ed763fd0d2d624 by ignoring any network named "ingress" when searching for a container's IP address. That commit was technically a backwards-incompatible change: Some users use nginx-proxy with Swarm mode even though it is not fully supported. In such cases nginx-proxy should ignore the `ingress` network, otherwise nginx will not be able to reach the server (container-to-container traffic apparently doesn't work over the Swarm `ingress` network). The parts of that commit that examine the `SwarmNode` structure are not reverted here because docker-gen does not currently populate that structure -- not even when both docker-gen and the service task container are running on the same manager node. --- nginx.tmpl | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/nginx.tmpl b/nginx.tmpl index 2ec7b43..1388636 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -41,6 +41,14 @@ {{- $ip := "" }} # networks: {{- range sortObjectsByKeysAsc $.container.Networks "Name" }} + {{- /* + * TODO: Only ignore the "ingress" network for Swarm tasks (in case + * the user is not using Swarm mode and names a network "ingress"). + */}} + {{- if eq .Name "ingress" }} + # {{ .Name }} (ignored) + {{- continue }} + {{- end }} {{- if and (not (index $.globals.networks .Name)) (not $.globals.networks.host) }} # {{ .Name }} (unreachable) {{- continue }} From 01745a836fc6d5687c26efff26c5713b8e4b5d2f Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Sun, 5 Feb 2023 02:44:12 -0500 Subject: [PATCH 143/300] tests: Fix path to `ca-root.crt` `os.getcwd()` is not guaranteed to always return the `test/` directory. --- test/conftest.py | 6 ++++++ test/test_ssl/test_dhparam.py | 5 ++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/test/conftest.py b/test/conftest.py index 1121e96..128f57d 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -425,6 +425,12 @@ def connect_to_all_networks(): # ############################################################################### + +@pytest.fixture +def ca_root_certificate(): + return CA_ROOT_CERTIFICATE + + @pytest.fixture(scope="module") def docker_compose(request): """ diff --git a/test/test_ssl/test_dhparam.py b/test/test_ssl/test_dhparam.py index 2f69ad3..d4d64a3 100644 --- a/test/test_ssl/test_dhparam.py +++ b/test/test_ssl/test_dhparam.py @@ -1,6 +1,5 @@ import re import subprocess -import os import backoff import docker @@ -219,7 +218,7 @@ def test_custom_dhparam_is_supported(docker_compose): # Only `web2` has a site-specific DH param file (which overrides all other DH config) # Other tests here use `web5` explicitly, or implicitly (via ENV `DEFAULT_HOST`, otherwise first HTTPS server) -def test_custom_dhparam_is_supported_per_site(docker_compose): +def test_custom_dhparam_is_supported_per_site(docker_compose, ca_root_certificate): container_name="dh-file" sut_container = docker_client.containers.get(container_name) assert sut_container.status == "running" @@ -242,7 +241,7 @@ def test_custom_dhparam_is_supported_per_site(docker_compose): # - `web2` has it's own cert provisioned at `/etc/nginx/certs/web2.nginx-proxy.tld.crt`. can_verify_chain_of_trust( sut_container, - ca_cert = f"{os.getcwd()}/certs/ca-root.crt", + ca_cert = ca_root_certificate, fqdn = 'web2.nginx-proxy.tld' ) From 09a2f40633a9c77179b3e26523fda04aab86c9ea Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Fri, 6 Jan 2023 01:25:35 -0500 Subject: [PATCH 144/300] tests: Turn helper function into `docker_compose_file` fixture This makes it easier for tests to override the filename. --- test/conftest.py | 40 ++++++++++++++++++---------------------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/test/conftest.py b/test/conftest.py index 128f57d..3cffe9b 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -322,31 +322,28 @@ def wait_for_nginxproxy_to_be_ready(): logging.debug("nginx-proxy ready") break -def find_docker_compose_file(request): - """ - helper for fixture functions to figure out the name of the docker-compose file to consider. - - if the test module provides a `docker_compose_file` variable, take that - - else, if a yaml file exists with the same name as the test module (but for the `.yml` extension), use that - - otherwise use `docker-compose.yml`. +@pytest.fixture(scope="module") +def docker_compose_file(request): + """Fixture naming the docker-compose file to consider. + + If a YAML file exists with the same name as the test module (with the `.py` extension replaced + with `.yml` or `.yaml`), use that. Otherwise, use `docker-compose.yml` in the same directory + as the test module. + + Tests can override this fixture to specify a custom location. """ test_module_dir = os.path.dirname(request.module.__file__) yml_file = os.path.join(test_module_dir, request.module.__name__ + '.yml') yaml_file = os.path.join(test_module_dir, request.module.__name__ + '.yaml') default_file = os.path.join(test_module_dir, 'docker-compose.yml') - docker_compose_file_module_variable = getattr(request.module, "docker_compose_file", None) - if docker_compose_file_module_variable is not None: - docker_compose_file = os.path.join( test_module_dir, docker_compose_file_module_variable) - if not os.path.isfile(docker_compose_file): - raise ValueError(f"docker compose file {docker_compose_file!r} could not be found. Check your test module `docker_compose_file` variable value.") + if os.path.isfile(yml_file): + docker_compose_file = yml_file + elif os.path.isfile(yaml_file): + docker_compose_file = yaml_file else: - if os.path.isfile(yml_file): - docker_compose_file = yml_file - elif os.path.isfile(yaml_file): - docker_compose_file = yaml_file - else: - docker_compose_file = default_file + docker_compose_file = default_file if not os.path.isfile(docker_compose_file): logging.error("Could not find any docker-compose file named either '{0}.yml', '{0}.yaml' or 'docker-compose.yml'".format(request.module.__name__)) @@ -432,16 +429,15 @@ def ca_root_certificate(): @pytest.fixture(scope="module") -def docker_compose(request): - """ - pytest fixture providing containers described in a docker compose file. After the tests, remove the created containers +def docker_compose(docker_compose_file): + """Ensures containers described in a docker compose file are started. - A custom docker compose file name can be defined in a variable named `docker_compose_file`. + A custom docker compose file name can be specified by overriding the `docker_compose_file` + fixture. Also, in the case where pytest is running from a docker container, this fixture makes sure our container will be attached to all the docker networks. """ - docker_compose_file = find_docker_compose_file(request) original_dns_resolver = monkey_patch_urllib_dns_resolver() remove_all_containers() docker_compose_up(docker_compose_file) From f5a3492926985b45a6e1f2e5d477d3fc007fc012 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Sun, 5 Feb 2023 19:28:30 -0500 Subject: [PATCH 145/300] tests: Factor out DNS monkey patching to its own fixture --- test/conftest.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/test/conftest.py b/test/conftest.py index 3cffe9b..8e80bf4 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -429,7 +429,14 @@ def ca_root_certificate(): @pytest.fixture(scope="module") -def docker_compose(docker_compose_file): +def monkey_patched_dns(): + original_dns_resolver = monkey_patch_urllib_dns_resolver() + yield + restore_urllib_dns_resolver(original_dns_resolver) + + +@pytest.fixture(scope="module") +def docker_compose(monkey_patched_dns, docker_compose_file): """Ensures containers described in a docker compose file are started. A custom docker compose file name can be specified by overriding the `docker_compose_file` @@ -438,7 +445,6 @@ def docker_compose(docker_compose_file): Also, in the case where pytest is running from a docker container, this fixture makes sure our container will be attached to all the docker networks. """ - original_dns_resolver = monkey_patch_urllib_dns_resolver() remove_all_containers() docker_compose_up(docker_compose_file) networks = connect_to_all_networks() @@ -448,7 +454,6 @@ def docker_compose(docker_compose_file): for network in networks: disconnect_from_network(network) docker_compose_down(docker_compose_file) - restore_urllib_dns_resolver(original_dns_resolver) @pytest.fixture() From 4d8f878ba7e25c25f0f781bf2f89291b2a2e599e Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Sun, 5 Feb 2023 19:38:55 -0500 Subject: [PATCH 146/300] tests: Fixture that simplifies Docker compose file changes --- test/conftest.py | 46 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 37 insertions(+), 9 deletions(-) diff --git a/test/conftest.py b/test/conftest.py index 8e80bf4..13ff689 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -416,6 +416,35 @@ def connect_to_all_networks(): return [connect_to_network(network) for network in networks] +class DockerComposer(contextlib.AbstractContextManager): + def __init__(self): + self._docker_compose_file = None + + def __exit__(self, *exc_info): + self._down() + + def _down(self): + if self._docker_compose_file is None: + return + for network in self._networks: + disconnect_from_network(network) + docker_compose_down(self._docker_compose_file) + self._docker_compose_file = None + + def compose(self, docker_compose_file): + if docker_compose_file == self._docker_compose_file: + return + self._down() + if docker_compose_file is None: + return + remove_all_containers() + docker_compose_up(docker_compose_file) + self._networks = connect_to_all_networks() + wait_for_nginxproxy_to_be_ready() + time.sleep(3) # give time to containers to be ready + self._docker_compose_file = docker_compose_file + + ############################################################################### # # Py.test fixtures @@ -423,6 +452,12 @@ def connect_to_all_networks(): ############################################################################### +@pytest.fixture(scope="module") +def docker_composer(): + with DockerComposer() as d: + yield d + + @pytest.fixture def ca_root_certificate(): return CA_ROOT_CERTIFICATE @@ -436,7 +471,7 @@ def monkey_patched_dns(): @pytest.fixture(scope="module") -def docker_compose(monkey_patched_dns, docker_compose_file): +def docker_compose(monkey_patched_dns, docker_composer, docker_compose_file): """Ensures containers described in a docker compose file are started. A custom docker compose file name can be specified by overriding the `docker_compose_file` @@ -445,15 +480,8 @@ def docker_compose(monkey_patched_dns, docker_compose_file): Also, in the case where pytest is running from a docker container, this fixture makes sure our container will be attached to all the docker networks. """ - remove_all_containers() - docker_compose_up(docker_compose_file) - networks = connect_to_all_networks() - wait_for_nginxproxy_to_be_ready() - time.sleep(3) # give time to containers to be ready + docker_composer.compose(docker_compose_file) yield docker_client - for network in networks: - disconnect_from_network(network) - docker_compose_down(docker_compose_file) @pytest.fixture() From b5a54ac2191041dfa06c151fea6f5a832862c0cb Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Sun, 5 Feb 2023 19:56:14 -0500 Subject: [PATCH 147/300] tests: Reduce scope of `docker_compose` fixture (and friends) This makes it possible to bring up different compose files for different tests in the same test module. This change does not negatively affect performance because the fixture is a no-op if the docker compose filename is unchanged between tests. --- test/conftest.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/conftest.py b/test/conftest.py index 13ff689..e7133e7 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -323,7 +323,7 @@ def wait_for_nginxproxy_to_be_ready(): break -@pytest.fixture(scope="module") +@pytest.fixture def docker_compose_file(request): """Fixture naming the docker-compose file to consider. @@ -463,14 +463,14 @@ def ca_root_certificate(): return CA_ROOT_CERTIFICATE -@pytest.fixture(scope="module") +@pytest.fixture def monkey_patched_dns(): original_dns_resolver = monkey_patch_urllib_dns_resolver() yield restore_urllib_dns_resolver(original_dns_resolver) -@pytest.fixture(scope="module") +@pytest.fixture def docker_compose(monkey_patched_dns, docker_composer, docker_compose_file): """Ensures containers described in a docker compose file are started. From 37134c44d7fbf96bd7f8402c54180a8c05ac50e2 Mon Sep 17 00:00:00 2001 From: Jan Malte Gerth Date: Mon, 20 Feb 2023 22:46:24 +0100 Subject: [PATCH 148/300] fix: Sort networks and ports before iterating This avoids unnecessary nginx restarts caused by config file churn. --- nginx.tmpl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nginx.tmpl b/nginx.tmpl index 2ec7b43..6ba7954 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -21,7 +21,7 @@ {{- $_ := set $globals "ssl_policy" (or ($globals.Env.SSL_POLICY) "Mozilla-Intermediate") }} {{- $_ := set $globals "networks" (dict) }} # networks available to nginx-proxy: -{{- range $globals.CurrentContainer.Networks }} +{{- range sortObjectsByKeysAsc $globals.CurrentContainer.Networks "Name" }} {{- $_ := set $globals.networks .Name . }} # {{ .Name }} {{- end }} @@ -81,7 +81,7 @@ */}} {{- define "container_port" }} {{- /* If only 1 port exposed, use that as a default, else 80. */}} - # exposed ports:{{ range $.container.Addresses }} {{ .Port }}/{{ .Proto }}{{ else }} (none){{ end }} + # exposed ports:{{ range sortObjectsByKeysAsc $.container.Addresses "Port" }} {{ .Port }}/{{ .Proto }}{{ else }} (none){{ end }} {{- $default_port := when (eq (len $.container.Addresses) 1) (first $.container.Addresses).Port "80" }} # default port: {{ $default_port }} {{- $port := or $.container.Env.VIRTUAL_PORT $default_port }} From 16b8cde8e4a931eabdb3745675ca904d09acc741 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Tue, 28 Feb 2023 08:36:27 +0100 Subject: [PATCH 149/300] build: dockergen 0.10.0 -> 0.10.1 --- Dockerfile | 2 +- Dockerfile.alpine | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 0f42c8c..43568c1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # setup build arguments for version of dependencies to use -ARG DOCKER_GEN_VERSION=0.10.0 +ARG DOCKER_GEN_VERSION=0.10.1 ARG FOREGO_VERSION=v0.17.0 # Use a specific version of golang to build both binaries diff --git a/Dockerfile.alpine b/Dockerfile.alpine index 724bdf1..b98682a 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -1,5 +1,5 @@ # setup build arguments for version of dependencies to use -ARG DOCKER_GEN_VERSION=0.10.0 +ARG DOCKER_GEN_VERSION=0.10.1 ARG FOREGO_VERSION=v0.17.0 # Use a specific version of golang to build both binaries From 2fc3e6c28cbecdd11dc96726171a7f0ffaec7ecd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Mar 2023 05:04:42 +0000 Subject: [PATCH 150/300] ci: bump pytest from 7.2.1 to 7.2.2 in /test/requirements Bumps [pytest](https://github.com/pytest-dev/pytest) from 7.2.1 to 7.2.2. - [Release notes](https://github.com/pytest-dev/pytest/releases) - [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst) - [Commits](https://github.com/pytest-dev/pytest/compare/7.2.1...7.2.2) --- updated-dependencies: - dependency-name: pytest dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- test/requirements/python-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/requirements/python-requirements.txt b/test/requirements/python-requirements.txt index 6d7d495..422f2b1 100644 --- a/test/requirements/python-requirements.txt +++ b/test/requirements/python-requirements.txt @@ -1,5 +1,5 @@ backoff==2.2.1 docker-compose==1.29.2 docker==6.0.1 -pytest==7.2.1 +pytest==7.2.2 requests==2.28.2 From 9906ccda425e2150beac11adbd2d786d9764c5b2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Mar 2023 04:58:06 +0000 Subject: [PATCH 151/300] build: bump golang from 1.20.1-alpine to 1.20.2-alpine Bumps golang from 1.20.1-alpine to 1.20.2-alpine. --- updated-dependencies: - dependency-name: golang dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Dockerfile | 2 +- Dockerfile.alpine | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 43568c1..249fa6c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,7 +3,7 @@ ARG DOCKER_GEN_VERSION=0.10.1 ARG FOREGO_VERSION=v0.17.0 # Use a specific version of golang to build both binaries -FROM golang:1.20.1 as gobuilder +FROM golang:1.20.2 as gobuilder # Build docker-gen from scratch FROM gobuilder as dockergen diff --git a/Dockerfile.alpine b/Dockerfile.alpine index b98682a..006b045 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -3,7 +3,7 @@ ARG DOCKER_GEN_VERSION=0.10.1 ARG FOREGO_VERSION=v0.17.0 # Use a specific version of golang to build both binaries -FROM golang:1.20.1-alpine as gobuilder +FROM golang:1.20.2-alpine as gobuilder RUN apk add --no-cache git musl-dev # Build docker-gen from scratch From 364beed773e7f70274341a2c5a5e2e58e8fe08fe Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Fri, 10 Mar 2023 05:05:21 -0500 Subject: [PATCH 152/300] fix: Don't error if `$globals.CurrentContainer` is `nil` Also: * Note when there are no networks. * Fix "networks available" comment. --- nginx.tmpl | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/nginx.tmpl b/nginx.tmpl index 902f82d..6f84eb7 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -20,10 +20,26 @@ {{- $_ := set $globals "enable_ipv6" (parseBool (coalesce $globals.Env.ENABLE_IPV6 "false")) }} {{- $_ := set $globals "ssl_policy" (or ($globals.Env.SSL_POLICY) "Mozilla-Intermediate") }} {{- $_ := set $globals "networks" (dict) }} -# networks available to nginx-proxy: -{{- range sortObjectsByKeysAsc $globals.CurrentContainer.Networks "Name" }} - {{- $_ := set $globals.networks .Name . }} +# Networks available to the container running docker-gen (which are assumed to +# match the networks available to the container running nginx): +{{- /* + * Note: $globals.CurrentContainer may be nil in some circumstances due to + * . For more context + * see . + */}} +{{- if $globals.CurrentContainer }} + {{- range sortObjectsByKeysAsc $globals.CurrentContainer.Networks "Name" }} + {{- $_ := set $globals.networks .Name . }} # {{ .Name }} + {{- else }} +# (none) + {{- end }} +{{- else }} +# /!\ WARNING: Failed to find the Docker container running docker-gen. All +# upstream (backend) application containers will appear to be +# unreachable. Try removing the -only-exposed and -only-published +# arguments to docker-gen if you pass either of those. See +# . {{- end }} {{- /* From 49bb37dfdb3e4222f1f303d8e2eca748d0edfcbd Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Mon, 28 Mar 2022 02:56:36 -0400 Subject: [PATCH 153/300] feat: Add support for HTTP keep-alive between the proxy and upstream --- README.md | 7 +++++++ nginx.tmpl | 39 +++++++++++++++++++++++++++++++++++---- test/test_keepalive.py | 31 +++++++++++++++++++++++++++++++ test/test_keepalive.yml | 25 +++++++++++++++++++++++++ 4 files changed, 98 insertions(+), 4 deletions(-) create mode 100644 test/test_keepalive.py create mode 100644 test/test_keepalive.yml diff --git a/README.md b/README.md index 1728467..1ff960b 100644 --- a/README.md +++ b/README.md @@ -373,6 +373,13 @@ docker run -d -p 80:80 -p 443:443 \ You'll need apache2-utils on the machine where you plan to create the htpasswd file. Follow these [instructions](http://httpd.apache.org/docs/2.2/programs/htpasswd.html) +### Upstream (Backend) Server HTTP Keep-Alive Support + +> **Warning** +> This feature is experimental. The behavior may change (or the feature may be removed entirely) without warning in a future release, even if the release is not a new major version. If you use this feature, or if you would like to use this feature but you require changes to it first, please [provide feedback in #2194](https://github.com/nginx-proxy/nginx-proxy/discussions/2194). Once we have collected enough feedback we will promote this feature to officially supported. + +To enable HTTP keep-alive between `nginx-proxy` and a backend server, set the `com.github.nginx-proxy.nginx-proxy.keepalive` label on the server's container to the desired maximum number of idle connections. See the [nginx keepalive documentation](https://nginx.org/en/docs/http/ngx_http_upstream_module.html#keepalive) and the [Docker label documentation](https://docs.docker.com/config/labels-custom-metadata/) for details. + ### Headers By default, `nginx-proxy` forwards all incoming request headers from the client to the backend server unmodified, with the following exceptions: diff --git a/nginx.tmpl b/nginx.tmpl index 6f84eb7..e35258f 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -176,6 +176,7 @@ {{- if exists $override }} include {{ $override }}; {{- else }} + {{- $keepalive := first (keys (groupByLabel .Containers "com.github.nginx-proxy.nginx-proxy.keepalive")) }} location {{ .Path }} { {{- if eq .NetworkTag "internal" }} # Only allow traffic from internal clients @@ -189,10 +190,14 @@ root {{ trim .VhostRoot }}; include fastcgi_params; fastcgi_pass {{ trim .Upstream }}; + {{- if $keepalive }} + fastcgi_keep_conn on; + {{- end }} {{- else if eq .Proto "grpc" }} grpc_pass {{ trim .Proto }}://{{ trim .Upstream }}; {{- else }} proxy_pass {{ trim .Proto }}://{{ trim .Upstream }}{{ trim .Dest }}; + set $upstream_keepalive {{ if $keepalive }}true{{ else }}false{{ end }}; {{- end }} {{- if (exists (printf "/etc/nginx/htpasswd/%s" .Host)) }} @@ -232,6 +237,10 @@ upstream {{ .Upstream }} { # Fallback entry server 127.0.0.1 down; {{- end }} + {{- $keepalive := first (keys (groupByLabel .Containers "com.github.nginx-proxy.nginx-proxy.keepalive")) }} + {{- if $keepalive }} + keepalive {{ $keepalive }}; + {{- end }} } {{- end }} @@ -254,11 +263,33 @@ map $http_x_forwarded_port $proxy_x_forwarded_port { '' $server_port; } -# If we receive Upgrade, set Connection to "upgrade"; otherwise, preserve -# NGINX's default behavior ("Connection: close"). +# If the request from the downstream client has an "Upgrade:" header (set to any +# non-empty value), pass "Connection: upgrade" to the upstream (backend) server. +# Otherwise, the value for the "Connection" header depends on whether the user +# has enabled keepalive to the upstream server. map $http_upgrade $proxy_connection { default upgrade; - '' close; + '' $proxy_connection_noupgrade; +} +map $upstream_keepalive $proxy_connection_noupgrade { + # Preserve nginx's default behavior (send "Connection: close"). + default close; + # Use an empty string to cancel nginx's default behavior. + true ''; +} +# Abuse the map directive (see ) to ensure +# that $upstream_keepalive is always defined. This is necessary because: +# - The $proxy_connection variable is indirectly derived from +# $upstream_keepalive, so $upstream_keepalive must be defined whenever +# $proxy_connection is resolved. +# - The $proxy_connection variable is used in a proxy_set_header directive in +# the http block, so it is always fully resolved for every request -- even +# those where proxy_pass is not used (e.g., unknown virtual host). +map "" $upstream_keepalive { + # The value here should not matter because it should always be overridden in + # a location block (see the "location" template) for all requests where the + # value actually matters. + default false; } # Apply fix for very long server names @@ -514,7 +545,7 @@ server { {{- $upstream = printf "%s-%s" $upstream $sum }} {{- $dest = (or (first (groupByKeys $containers "Env.VIRTUAL_DEST")) "") }} {{- end }} - {{- template "location" (dict "Path" $path "Proto" $proto "Upstream" $upstream "Host" $host "VhostRoot" $vhost_root "Dest" $dest "NetworkTag" $network_tag) }} + {{- template "location" (dict "Path" $path "Proto" $proto "Upstream" $upstream "Host" $host "VhostRoot" $vhost_root "Dest" $dest "NetworkTag" $network_tag "Containers" $containers) }} {{- end }} {{- if and (not (contains $paths "/")) (ne $globals.default_root_response "none")}} location / { diff --git a/test/test_keepalive.py b/test/test_keepalive.py new file mode 100644 index 0000000..b5b8353 --- /dev/null +++ b/test/test_keepalive.py @@ -0,0 +1,31 @@ +import re + + +def test_keepalive_disabled(docker_compose, nginxproxy): + r = nginxproxy.get("http://keepalive-disabled.nginx-proxy.test/headers") + assert r.status_code == 200 + assert re.search(fr'(?m)^(?i:Connection): close$', r.text) + +def test_keepalive_disabled_other_headers_ok(docker_compose, nginxproxy): + """Make sure the other proxy_set_header headers are still set. + + According to the nginx docs [1], any proxy_set_header directive in a block + disables inheritance of proxy_set_header directives in a parent block. Make + sure that doesn't happen. + + [1] https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_set_header + """ + r = nginxproxy.get("http://keepalive-disabled.nginx-proxy.test/headers") + assert r.status_code == 200 + assert re.search(fr'(?m)^(?i:X-Real-IP): ', r.text) + +def test_keepalive_enabled(docker_compose, nginxproxy): + r = nginxproxy.get("http://keepalive-enabled.nginx-proxy.test/headers") + assert r.status_code == 200 + assert not re.search(fr'(?m)^(?i:Connection):', r.text) + +def test_keepalive_enabled_other_headers_ok(docker_compose, nginxproxy): + """See the docstring for the disabled case above.""" + r = nginxproxy.get("http://keepalive-enabled.nginx-proxy.test/headers") + assert r.status_code == 200 + assert re.search(fr'(?m)^(?i:X-Real-IP): ', r.text) diff --git a/test/test_keepalive.yml b/test/test_keepalive.yml new file mode 100644 index 0000000..541b69d --- /dev/null +++ b/test/test_keepalive.yml @@ -0,0 +1,25 @@ +keepalive-disabled: + image: web + expose: + - "80" + environment: + WEB_PORTS: 80 + VIRTUAL_HOST: keepalive-disabled.nginx-proxy.test + +keepalive-enabled: + image: web + expose: + - "80" + environment: + WEB_PORTS: 80 + VIRTUAL_HOST: keepalive-enabled.nginx-proxy.test + labels: + com.github.nginx-proxy.nginx-proxy.keepalive: "64" + + +sut: + image: nginxproxy/nginx-proxy:test + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro + environment: + HTTPS_METHOD: nohttps From 4696944245570f5d21901885a45ed17e04f9bf51 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Tue, 21 Mar 2023 07:15:34 +0100 Subject: [PATCH 154/300] build: dockergen 0.10.1 -> 0.10.2 --- Dockerfile | 2 +- Dockerfile.alpine | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 249fa6c..9775f0a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # setup build arguments for version of dependencies to use -ARG DOCKER_GEN_VERSION=0.10.1 +ARG DOCKER_GEN_VERSION=0.10.2 ARG FOREGO_VERSION=v0.17.0 # Use a specific version of golang to build both binaries diff --git a/Dockerfile.alpine b/Dockerfile.alpine index 006b045..bd5b81d 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -1,5 +1,5 @@ # setup build arguments for version of dependencies to use -ARG DOCKER_GEN_VERSION=0.10.1 +ARG DOCKER_GEN_VERSION=0.10.2 ARG FOREGO_VERSION=v0.17.0 # Use a specific version of golang to build both binaries From 7ca1da8358879fe54b3861f590c1c43af7abde5e Mon Sep 17 00:00:00 2001 From: Niek <100143256+SchoNie@users.noreply.github.com> Date: Tue, 21 Mar 2023 07:49:27 +0100 Subject: [PATCH 155/300] feat: Add support for HTTP load balancing between the proxy and upstream server groups (#2173) Add initial tests Newlines Remove unused variable Co-authored-by: Richard Hansen Change comment value Co-authored-by: Richard Hansen add missing services line Co-authored-by: Richard Hansen Use deploy.replicas Remove details about choosing a load balancing method Feedback note Co-authored-by: Nicolas Duchon --- README.md | 36 ++++++++++++++++++++++++++++++++++++ nginx.tmpl | 5 +++++ test/test_loadbalancing.py | 16 ++++++++++++++++ test/test_loadbalancing.yml | 27 +++++++++++++++++++++++++++ 4 files changed, 84 insertions(+) create mode 100644 test/test_loadbalancing.py create mode 100644 test/test_loadbalancing.yml diff --git a/README.md b/README.md index 1ff960b..4e0d9d4 100644 --- a/README.md +++ b/README.md @@ -373,6 +373,42 @@ docker run -d -p 80:80 -p 443:443 \ You'll need apache2-utils on the machine where you plan to create the htpasswd file. Follow these [instructions](http://httpd.apache.org/docs/2.2/programs/htpasswd.html) +### Upstream (Backend) Server HTTP Load Balancing Support + +> **Warning** +> This feature is experimental. The behavior may change (or the feature may be removed entirely) without warning in a future release, even if the release is not a new major version. If you use this feature, or if you would like to use this feature but you require changes to it first, please [provide feedback in #2195](https://github.com/nginx-proxy/nginx-proxy/discussions/2195). Once we have collected enough feedback we will promote this feature to officially supported. + +If you have multiple containers with the same `VIRTUAL_HOST` and `VIRTUAL_PATH` settings, nginx will spread the load across all of them. To change the load balancing algorithm from nginx's default (round-robin), set the `com.github.nginx-proxy.nginx-proxy.loadbalance` label on one or more of your application containers to the desired load balancing directive. See the [`ngx_http_upstream_module` documentation](https://nginx.org/en/docs/http/ngx_http_upstream_module.html) for available directives. + +> **Note** +> * Don't forget the terminating semicolon (`;`). +> * If you are using Docker Compose, remember to escape any dollar sign (`$`) characters (`$` becomes `$$`). + +Docker Compose example: + +```yaml +services: + nginx-proxy: + image: nginxproxy/nginx-proxy + ports: + - "80:80" + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro + environment: + HTTPS_METHOD: nohttps + myapp: + image: jwilder/whoami + expose: + - "8000" + environment: + VIRTUAL_HOST: myapp.example + VIRTUAL_PORT: "8000" + labels: + com.github.nginx-proxy.nginx-proxy.loadbalance: "hash $$remote_addr;" + deploy: + replicas: 4 +``` + ### Upstream (Backend) Server HTTP Keep-Alive Support > **Warning** diff --git a/nginx.tmpl b/nginx.tmpl index e35258f..98ab38e 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -219,6 +219,11 @@ {{- define "upstream" }} upstream {{ .Upstream }} { {{- $server_found := false }} + {{- $loadbalance := first (keys (groupByLabel .Containers "com.github.nginx-proxy.nginx-proxy.loadbalance")) }} + {{- if $loadbalance }} + # From the container's loadbalance label: + {{ $loadbalance }} + {{- end }} {{- range $container := .Containers }} # Container: {{ $container.Name }} {{- $args := dict "globals" $.globals "container" $container }} diff --git a/test/test_loadbalancing.py b/test/test_loadbalancing.py new file mode 100644 index 0000000..4b43aa5 --- /dev/null +++ b/test/test_loadbalancing.py @@ -0,0 +1,16 @@ +import pytest +import re + +def test_loadbalance_hash(docker_compose, nginxproxy): + conf = nginxproxy.get_conf().decode('ASCII') + r1 = nginxproxy.get("http://loadbalance-enabled.nginx-proxy.tld") + r2 = nginxproxy.get("http://loadbalance-enabled.nginx-proxy.tld") + assert re.search(r"hash \$remote_addr\;", conf) + assert r1.status_code == 200 + assert r2.text == r1.text + +def test_loadbalance_roundrobin(docker_compose, nginxproxy): + r1 = nginxproxy.get("http://loadbalance-disabled.nginx-proxy.tld") + r2 = nginxproxy.get("http://loadbalance-disabled.nginx-proxy.tld") + assert r1.status_code == 200 + assert r2.text != r1.text diff --git a/test/test_loadbalancing.yml b/test/test_loadbalancing.yml new file mode 100644 index 0000000..b8f42eb --- /dev/null +++ b/test/test_loadbalancing.yml @@ -0,0 +1,27 @@ +services: + loadbalance-hash: + image: web + expose: + - "81" + environment: + WEB_PORTS: 81 + VIRTUAL_HOST: loadbalance-enabled.nginx-proxy.tld + labels: + com.github.nginx-proxy.nginx-proxy.loadbalance: "hash $$remote_addr;" + deploy: + replicas: 2 + + loadbalance-roundrobin: + image: web + expose: + - "82" + environment: + WEB_PORTS: 82 + VIRTUAL_HOST: loadbalance-disabled.nginx-proxy.tld + deploy: + replicas: 2 + + sut: + image: nginxproxy/nginx-proxy:test + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro From 87ffa7a5a8842f16668085f6e4f1b98de0f33fa5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 29 Mar 2023 04:58:26 +0000 Subject: [PATCH 156/300] build: bump nginx from 1.23.3-alpine to 1.23.4-alpine Bumps nginx from 1.23.3-alpine to 1.23.4-alpine. --- updated-dependencies: - dependency-name: nginx dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Dockerfile | 2 +- Dockerfile.alpine | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 9775f0a..e067408 100644 --- a/Dockerfile +++ b/Dockerfile @@ -36,7 +36,7 @@ RUN git clone https://github.com/nginx-proxy/forego/ \ && rm -rf /go/forego # Build the final image -FROM nginx:1.23.3 +FROM nginx:1.23.4 ARG NGINX_PROXY_VERSION # Add DOCKER_GEN_VERSION environment variable diff --git a/Dockerfile.alpine b/Dockerfile.alpine index bd5b81d..b2da6fd 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -37,7 +37,7 @@ RUN git clone https://github.com/nginx-proxy/forego/ \ && rm -rf /go/forego # Build the final image -FROM nginx:1.23.3-alpine +FROM nginx:1.23.4-alpine ARG NGINX_PROXY_VERSION # Add DOCKER_GEN_VERSION environment variable From 2056dc4429b936c22c2d05a2d2bbbfbb6b36329d Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Thu, 30 Mar 2023 01:10:05 +0200 Subject: [PATCH 157/300] build: dockergen 0.10.2 -> 0.10.3 --- Dockerfile | 2 +- Dockerfile.alpine | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 9775f0a..db02a1d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # setup build arguments for version of dependencies to use -ARG DOCKER_GEN_VERSION=0.10.2 +ARG DOCKER_GEN_VERSION=0.10.3 ARG FOREGO_VERSION=v0.17.0 # Use a specific version of golang to build both binaries diff --git a/Dockerfile.alpine b/Dockerfile.alpine index bd5b81d..85100ee 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -1,5 +1,5 @@ # setup build arguments for version of dependencies to use -ARG DOCKER_GEN_VERSION=0.10.2 +ARG DOCKER_GEN_VERSION=0.10.3 ARG FOREGO_VERSION=v0.17.0 # Use a specific version of golang to build both binaries From 130fd908fbd0a72ffbef862ee7da576fc2a8ec8c Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Thu, 30 Mar 2023 20:58:56 +0200 Subject: [PATCH 158/300] docs: update nginx version badge --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2757c33..106a2df 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ [![Test](https://github.com/nginx-proxy/nginx-proxy/actions/workflows/test.yml/badge.svg)](https://github.com/nginx-proxy/nginx-proxy/actions/workflows/test.yml) [![GitHub release](https://img.shields.io/github/v/release/nginx-proxy/nginx-proxy)](https://github.com/nginx-proxy/nginx-proxy/releases) -![nginx 1.23.3](https://img.shields.io/badge/nginx-1.23.3-brightgreen.svg) +![nginx 1.23.4](https://img.shields.io/badge/nginx-1.23.4-brightgreen.svg) [![Docker Image Size](https://img.shields.io/docker/image-size/nginxproxy/nginx-proxy?sort=semver)](https://hub.docker.com/r/nginxproxy/nginx-proxy "Click to view the image on Docker Hub") [![Docker stars](https://img.shields.io/docker/stars/nginxproxy/nginx-proxy.svg)](https://hub.docker.com/r/nginxproxy/nginx-proxy 'DockerHub') [![Docker pulls](https://img.shields.io/docker/pulls/nginxproxy/nginx-proxy.svg)](https://hub.docker.com/r/nginxproxy/nginx-proxy 'DockerHub') From a3d3baf2599f26b905d999b55c11e402b686d92a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 5 Apr 2023 04:58:03 +0000 Subject: [PATCH 159/300] build: bump golang from 1.20.2-alpine to 1.20.3-alpine Bumps golang from 1.20.2-alpine to 1.20.3-alpine. --- updated-dependencies: - dependency-name: golang dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Dockerfile | 2 +- Dockerfile.alpine | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 2da6832..ccf62fc 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,7 +3,7 @@ ARG DOCKER_GEN_VERSION=0.10.3 ARG FOREGO_VERSION=v0.17.0 # Use a specific version of golang to build both binaries -FROM golang:1.20.2 as gobuilder +FROM golang:1.20.3 as gobuilder # Build docker-gen from scratch FROM gobuilder as dockergen diff --git a/Dockerfile.alpine b/Dockerfile.alpine index cc31704..68de02a 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -3,7 +3,7 @@ ARG DOCKER_GEN_VERSION=0.10.3 ARG FOREGO_VERSION=v0.17.0 # Use a specific version of golang to build both binaries -FROM golang:1.20.2-alpine as gobuilder +FROM golang:1.20.3-alpine as gobuilder RUN apk add --no-cache git musl-dev # Build docker-gen from scratch From 695ad54dcf637e47458c1328b13071daceeeac61 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 Apr 2023 05:00:55 +0000 Subject: [PATCH 160/300] ci: bump pytest from 7.2.2 to 7.3.0 in /test/requirements Bumps [pytest](https://github.com/pytest-dev/pytest) from 7.2.2 to 7.3.0. - [Release notes](https://github.com/pytest-dev/pytest/releases) - [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst) - [Commits](https://github.com/pytest-dev/pytest/compare/7.2.2...7.3.0) --- updated-dependencies: - dependency-name: pytest dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- test/requirements/python-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/requirements/python-requirements.txt b/test/requirements/python-requirements.txt index 422f2b1..0357d65 100644 --- a/test/requirements/python-requirements.txt +++ b/test/requirements/python-requirements.txt @@ -1,5 +1,5 @@ backoff==2.2.1 docker-compose==1.29.2 docker==6.0.1 -pytest==7.2.2 +pytest==7.3.0 requests==2.28.2 From 035bd2b5ac9f0f7ee3ce7c5e2690a2b71b6b78ff Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Fri, 7 Apr 2023 18:05:48 -0400 Subject: [PATCH 161/300] fix: Remove `default_server` listen option from fallback server This fixes a bug introduced in commit 9b4bb07b348dc5a428b94416517291adb30794c3. --- nginx.tmpl | 17 +++++++++++++---- test/test_fallback.data/custom-fallback.conf | 5 +++++ test/test_fallback.data/custom-fallback.yml | 14 ++++++++++++++ test/test_fallback.py | 5 +++++ 4 files changed, 37 insertions(+), 4 deletions(-) create mode 100644 test/test_fallback.data/custom-fallback.conf create mode 100644 test/test_fallback.data/custom-fallback.yml diff --git a/nginx.tmpl b/nginx.tmpl index 5733351..2556acf 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -372,6 +372,15 @@ proxy_set_header Proxy ""; {{- /* * If needed, create a catch-all fallback server to send an error code to * clients that request something from an unknown vhost. + * + * This server must appear first in the generated config because nginx uses + * the first `server` directive to handle requests that don't match any of + * the other `server` directives. An alternative approach would be to add + * the `default_server` option to the `listen` directives inside this + * `server`, but some users inject a custom `server` directive that uses + * `default_server`. Using `default_server` here would cause nginx to fail + * to start for those users. See + * . */}} {{- block "fallback_server" $globals }} {{- $globals := . }} @@ -403,15 +412,15 @@ server { server_name _; # This is just an invalid value which will never trigger on a real hostname. server_tokens off; {{- if $fallback_http }} - listen {{ $globals.external_http_port }} default_server; + listen {{ $globals.external_http_port }}; {{- /* Do not add `default_server` (see comment above). */}} {{- if $globals.enable_ipv6 }} - listen [::]:{{ $globals.external_http_port }} default_server; + listen [::]:{{ $globals.external_http_port }}; {{- /* Do not add `default_server` (see comment above). */}} {{- end }} {{- end }} {{- if $fallback_https }} - listen {{ $globals.external_https_port }} ssl http2 default_server; + listen {{ $globals.external_https_port }} ssl http2; {{- /* Do not add `default_server` (see comment above). */}} {{- if $globals.enable_ipv6 }} - listen [::]:{{ $globals.external_https_port }} ssl http2 default_server; + listen [::]:{{ $globals.external_https_port }} ssl http2; {{- /* Do not add `default_server` (see comment above). */}} {{- end }} {{- end }} {{ $globals.access_log }} diff --git a/test/test_fallback.data/custom-fallback.conf b/test/test_fallback.data/custom-fallback.conf new file mode 100644 index 0000000..ebe8814 --- /dev/null +++ b/test/test_fallback.data/custom-fallback.conf @@ -0,0 +1,5 @@ +server { + server_name __; + listen 80 default_server; + return 418; +} diff --git a/test/test_fallback.data/custom-fallback.yml b/test/test_fallback.data/custom-fallback.yml new file mode 100644 index 0000000..bc44b11 --- /dev/null +++ b/test/test_fallback.data/custom-fallback.yml @@ -0,0 +1,14 @@ +services: + sut: + image: nginxproxy/nginx-proxy:test + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro + - ./custom-fallback.conf:/etc/nginx/conf.d/zzz-custom-fallback.conf:ro + http-only: + image: web + expose: + - "83" + environment: + WEB_PORTS: "83" + VIRTUAL_HOST: http-only.nginx-proxy.test + HTTPS_METHOD: nohttps diff --git a/test/test_fallback.py b/test/test_fallback.py index ce3d68f..1ee923a 100644 --- a/test/test_fallback.py +++ b/test/test_fallback.py @@ -89,6 +89,11 @@ CONNECTION_REFUSED_RE = re.compile("Connection refused") ("nohttps-on-app.yml", "https://http-only.nginx-proxy.test/", None, CONNECTION_REFUSED_RE), ("nohttps-on-app.yml", "http://unknown.nginx-proxy.test/", 503, None), ("nohttps-on-app.yml", "https://unknown.nginx-proxy.test/", None, CONNECTION_REFUSED_RE), + # Custom nginx config that has a `server` directive that uses `default_server` and simply + # returns 418. Nginx should successfully start (in particular, the `default_server` in the + # custom config should not conflict with the fallback server generated by nginx-proxy) and nginx + # should prefer that server for handling requests for unknown vhosts. + ("custom-fallback.yml", "http://unknown.nginx-proxy.test/", 418, None), ]) def test_fallback(get, url, want_code, want_err_re): if want_err_re is None: From b34c9179775dc7bfb5f5f1a8aa97f3bcc9e8a0cb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 17 Apr 2023 05:01:01 +0000 Subject: [PATCH 162/300] ci: bump pytest from 7.3.0 to 7.3.1 in /test/requirements Bumps [pytest](https://github.com/pytest-dev/pytest) from 7.3.0 to 7.3.1. - [Release notes](https://github.com/pytest-dev/pytest/releases) - [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst) - [Commits](https://github.com/pytest-dev/pytest/compare/7.3.0...7.3.1) --- updated-dependencies: - dependency-name: pytest dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- test/requirements/python-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/requirements/python-requirements.txt b/test/requirements/python-requirements.txt index 0357d65..95e3e03 100644 --- a/test/requirements/python-requirements.txt +++ b/test/requirements/python-requirements.txt @@ -1,5 +1,5 @@ backoff==2.2.1 docker-compose==1.29.2 docker==6.0.1 -pytest==7.3.0 +pytest==7.3.1 requests==2.28.2 From 9f735aab821ebc1063f616e9677698716d446e5c Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Tue, 18 Apr 2023 07:58:38 +0200 Subject: [PATCH 163/300] build: dockergen 0.10.3 -> 0.10.4 --- Dockerfile | 2 +- Dockerfile.alpine | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index ccf62fc..85c7296 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # setup build arguments for version of dependencies to use -ARG DOCKER_GEN_VERSION=0.10.3 +ARG DOCKER_GEN_VERSION=0.10.4 ARG FOREGO_VERSION=v0.17.0 # Use a specific version of golang to build both binaries diff --git a/Dockerfile.alpine b/Dockerfile.alpine index 68de02a..a51a893 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -1,5 +1,5 @@ # setup build arguments for version of dependencies to use -ARG DOCKER_GEN_VERSION=0.10.3 +ARG DOCKER_GEN_VERSION=0.10.4 ARG FOREGO_VERSION=v0.17.0 # Use a specific version of golang to build both binaries From 325fd01ebbbe8af8fb684819e3db58dcc9c3091b Mon Sep 17 00:00:00 2001 From: Andy <59445582+rot169@users.noreply.github.com> Date: Sun, 23 Apr 2023 14:09:33 +0100 Subject: [PATCH 164/300] Support containers running --net=host (#1537) Detect if a target container is running host networking, and if so, use the IP address of the first bridge net gateway. --- nginx.tmpl | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/nginx.tmpl b/nginx.tmpl index 2556acf..f322db9 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -67,6 +67,11 @@ # {{ .Name }} (ignored) {{- continue }} {{- end }} + {{- if eq .Name "host" }} + # {{ .Name }} (host network; using {{ (index $.globals.CurrentContainer.Networks 0).Name }} gateway) + {{- $ip = (index $.globals.CurrentContainer.Networks 0).Gateway }} + {{- continue }} + {{- end }} {{- if and (not (index $.globals.networks .Name)) (not $.globals.networks.host) }} # {{ .Name }} (unreachable) {{- continue }} From 00a1e5ef5cc20d88e19176eccb093aba101483c9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 27 Apr 2023 05:00:28 +0000 Subject: [PATCH 165/300] ci: bump requests from 2.28.2 to 2.29.0 in /test/requirements Bumps [requests](https://github.com/psf/requests) from 2.28.2 to 2.29.0. - [Release notes](https://github.com/psf/requests/releases) - [Changelog](https://github.com/psf/requests/blob/main/HISTORY.md) - [Commits](https://github.com/psf/requests/compare/v2.28.2...v2.29.0) --- updated-dependencies: - dependency-name: requests dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- test/requirements/python-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/requirements/python-requirements.txt b/test/requirements/python-requirements.txt index 95e3e03..0344210 100644 --- a/test/requirements/python-requirements.txt +++ b/test/requirements/python-requirements.txt @@ -2,4 +2,4 @@ backoff==2.2.1 docker-compose==1.29.2 docker==6.0.1 pytest==7.3.1 -requests==2.28.2 +requests==2.29.0 From 882e9a3b3c4f99c2361b0191a106b34f09dfc4ce Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Fri, 28 Apr 2023 22:23:09 +0200 Subject: [PATCH 166/300] test: add tests for host mode fix --- .../test_host-network-mode.py | 13 +++++++++ .../test_host-network-mode.yml | 28 +++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 test/test_host-network-mode/test_host-network-mode.py create mode 100644 test/test_host-network-mode/test_host-network-mode.yml diff --git a/test/test_host-network-mode/test_host-network-mode.py b/test/test_host-network-mode/test_host-network-mode.py new file mode 100644 index 0000000..0c21348 --- /dev/null +++ b/test/test_host-network-mode/test_host-network-mode.py @@ -0,0 +1,13 @@ +import pytest + + +def test_forwards_to_bridge_network_container(docker_compose, nginxproxy): + r = nginxproxy.get("http://bridge-network.nginx-proxy.tld/port") + assert r.status_code == 200 + assert r.text == "answer from port 80\n" + + +def test_forwards_to_host_network_container(docker_compose, nginxproxy): + r = nginxproxy.get("http://host-network.nginx-proxy.tld/port") + assert r.status_code == 200 + assert r.text == "answer from port 8080\n" diff --git a/test/test_host-network-mode/test_host-network-mode.yml b/test/test_host-network-mode/test_host-network-mode.yml new file mode 100644 index 0000000..d8803ba --- /dev/null +++ b/test/test_host-network-mode/test_host-network-mode.yml @@ -0,0 +1,28 @@ +version: "2" + +networks: + net1: + +services: + bridge-network: + image: web + environment: + WEB_PORTS: "80" + VIRTUAL_HOST: "bridge-network.nginx-proxy.tld" + networks: + - net1 + + host-network: + image: web + environment: + WEB_PORTS: "8080" + VIRTUAL_HOST: "host-network.nginx-proxy.tld" + VIRTUAL_PORT: "8080" + network_mode: host + + sut: + image: nginxproxy/nginx-proxy:test + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro + networks: + - net1 From 21321a4495c31d8b29c04ac62e300c36c6ecc2ea Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Sun, 30 Apr 2023 15:02:09 +0200 Subject: [PATCH 167/300] ci: add GitHub Actions to Dependabot config --- .github/dependabot.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index eb6a749..fb8c8fc 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -20,3 +20,13 @@ updates: prefix: "ci" labels: - "type/ci" + + # Maintain GitHub Actions + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + commit-message: + prefix: "ci" + labels: + - "type/ci" From 43eed7d0dfbf48412cf5834550f49f8281d778fa Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Sun, 30 Apr 2023 15:02:44 +0200 Subject: [PATCH 168/300] ci: check test suite dependencies weekly --- .github/dependabot.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index fb8c8fc..a21c2b1 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -15,7 +15,7 @@ updates: - package-ecosystem: "pip" directory: "/test/requirements" schedule: - interval: "daily" + interval: "weekly" commit-message: prefix: "ci" labels: From edb6c5dfd88e40455b08b15f5ca964be8e045759 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 30 Apr 2023 13:17:20 +0000 Subject: [PATCH 169/300] ci: bump docker/build-push-action from 3 to 4 Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 3 to 4. - [Release notes](https://github.com/docker/build-push-action/releases) - [Commits](https://github.com/docker/build-push-action/compare/v3...v4) --- updated-dependencies: - dependency-name: docker/build-push-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/dockerhub.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/dockerhub.yml b/.github/workflows/dockerhub.yml index 8b33fb2..1226e8b 100644 --- a/.github/workflows/dockerhub.yml +++ b/.github/workflows/dockerhub.yml @@ -67,7 +67,7 @@ jobs: - name: Build and push the Debian based image id: docker_build_debian - uses: docker/build-push-action@v3 + uses: docker/build-push-action@v4 with: context: . file: Dockerfile @@ -129,7 +129,7 @@ jobs: - name: Build and push the Alpine based image id: docker_build_alpine - uses: docker/build-push-action@v3 + uses: docker/build-push-action@v4 with: context: . file: Dockerfile.alpine From 4655ba9f51f2e235854e1fb38424371ce0840def Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Sun, 30 Apr 2023 15:30:29 +0200 Subject: [PATCH 170/300] ci: only trigger test workflow on push for main branch --- .github/workflows/test.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 3dd2674..e58e632 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -3,6 +3,8 @@ name: Tests on: workflow_dispatch: push: + branches: + - main paths-ignore: - "LICENSE" - "**.md" From 70c9ea6ccc311ac0651c34e5c6c17bde787e07fa Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 30 Apr 2023 13:17:16 +0000 Subject: [PATCH 171/300] ci: bump actions/setup-python from 2 to 4 Bumps [actions/setup-python](https://github.com/actions/setup-python) from 2 to 4. - [Release notes](https://github.com/actions/setup-python/releases) - [Commits](https://github.com/actions/setup-python/compare/v2...v4) --- updated-dependencies: - dependency-name: actions/setup-python dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e58e632..c549094 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -26,7 +26,7 @@ jobs: - uses: actions/checkout@v3 - name: Set up Python 3.9 - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: 3.9 From eabb808b85e4e08324e5660577dfde5801d6df3f Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Sun, 30 Apr 2023 15:51:46 +0200 Subject: [PATCH 172/300] ci: rename build / publish workflow --- .github/workflows/{dockerhub.yml => build-publish.yml} | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) rename .github/workflows/{dockerhub.yml => build-publish.yml} (97%) diff --git a/.github/workflows/dockerhub.yml b/.github/workflows/build-publish.yml similarity index 97% rename from .github/workflows/dockerhub.yml rename to .github/workflows/build-publish.yml index 1226e8b..5eac674 100644 --- a/.github/workflows/dockerhub.yml +++ b/.github/workflows/build-publish.yml @@ -1,4 +1,4 @@ -name: DockerHub +name: Build and publish Docker images on: workflow_dispatch: @@ -20,6 +20,7 @@ on: jobs: multiarch-build-debian: + name: Build and publish Debian image runs-on: ubuntu-latest steps: - name: Checkout @@ -81,6 +82,7 @@ jobs: run: echo ${{ steps.docker_build_debian.outputs.digest }} multiarch-build-alpine: + name: Build and publish Alpine image runs-on: ubuntu-latest steps: - name: Checkout From 0501c540029918d617007fa44f7087be64ed1d81 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Tue, 2 May 2023 05:21:41 +0200 Subject: [PATCH 173/300] build: get docker-gen from pre-built image (#2230) * build: get docker-gen from pre-built image * build: requested changes --- .github/workflows/build-publish.yml | 26 +++++++++++++++++------ Dockerfile | 29 ++++++------------------- Dockerfile.alpine | 33 +++++++---------------------- 3 files changed, 34 insertions(+), 54 deletions(-) diff --git a/.github/workflows/build-publish.yml b/.github/workflows/build-publish.yml index 5eac674..2b4eb3e 100644 --- a/.github/workflows/build-publish.yml +++ b/.github/workflows/build-publish.yml @@ -28,8 +28,9 @@ jobs: with: fetch-depth: 0 - - name: Retrieve version - run: echo "GIT_DESCRIBE=$(git describe --tags)" >> $GITHUB_ENV + - name: Retrieve nginx-proxy version + id: nginx-proxy_version + run: echo "VERSION=$(git describe --tags)" >> "$GITHUB_OUTPUT" - name: Get Docker tags for Debian based image id: docker_meta_debian @@ -66,13 +67,19 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} + - name: Retrieve docker-gen version + id: docker-gen_version + run: sed -n -e 's;^FROM nginxproxy/docker-gen:\([0-9.]*\).*;VERSION=\1;p' Dockerfile >> "$GITHUB_OUTPUT" + - name: Build and push the Debian based image id: docker_build_debian uses: docker/build-push-action@v4 with: context: . file: Dockerfile - build-args: NGINX_PROXY_VERSION=${{ env.GIT_DESCRIBE }} + build-args: | + NGINX_PROXY_VERSION=${{ steps.nginx-proxy_version.outputs.VERSION }} + DOCKER_GEN_VERSION=${{ steps.docker-gen_version.outputs.VERSION }} platforms: linux/amd64,linux/arm64,linux/arm/v7 push: true tags: ${{ steps.docker_meta_debian.outputs.tags }} @@ -90,8 +97,9 @@ jobs: with: fetch-depth: 0 - - name: Retrieve version - run: echo "GIT_DESCRIBE=$(git describe --tags)" >> $GITHUB_ENV + - name: Retrieve nginx-proxy version + id: nginx-proxy_version + run: echo "VERSION=$(git describe --tags)" >> "$GITHUB_OUTPUT" - name: Get Docker tags for Alpine based image id: docker_meta_alpine @@ -129,13 +137,19 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} + - name: Retrieve docker-gen version + id: docker-gen_version + run: sed -n -e 's;^FROM nginxproxy/docker-gen:\([0-9.]*\).*;VERSION=\1;p' Dockerfile >> "$GITHUB_OUTPUT" + - name: Build and push the Alpine based image id: docker_build_alpine uses: docker/build-push-action@v4 with: context: . file: Dockerfile.alpine - build-args: NGINX_PROXY_VERSION=${{ env.GIT_DESCRIBE }} + build-args: | + NGINX_PROXY_VERSION=${{ steps.nginx-proxy_version.outputs.VERSION }} + DOCKER_GEN_VERSION=${{ steps.docker-gen_version.outputs.VERSION }} platforms: linux/amd64,linux/arm64,linux/arm/v7 push: true tags: ${{ steps.docker_meta_alpine.outputs.tags }} diff --git a/Dockerfile b/Dockerfile index 85c7296..7617c83 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,27 +1,10 @@ # setup build arguments for version of dependencies to use -ARG DOCKER_GEN_VERSION=0.10.4 ARG FOREGO_VERSION=v0.17.0 -# Use a specific version of golang to build both binaries -FROM golang:1.20.3 as gobuilder - -# Build docker-gen from scratch -FROM gobuilder as dockergen - -ARG DOCKER_GEN_VERSION - -RUN git clone https://github.com/nginx-proxy/docker-gen \ - && cd /go/docker-gen \ - && git -c advice.detachedHead=false checkout $DOCKER_GEN_VERSION \ - && go mod download \ - && CGO_ENABLED=0 GOOS=linux go build -ldflags "-X main.buildVersion=${DOCKER_GEN_VERSION}" ./cmd/docker-gen \ - && go clean -cache \ - && mv docker-gen /usr/local/bin/ \ - && cd - \ - && rm -rf /go/docker-gen +FROM nginxproxy/docker-gen:0.10.4-debian AS docker-gen # Build forego from scratch -FROM gobuilder as forego +FROM golang:1.20.3 as forego ARG FOREGO_VERSION @@ -39,9 +22,9 @@ RUN git clone https://github.com/nginx-proxy/forego/ \ FROM nginx:1.23.4 ARG NGINX_PROXY_VERSION -# Add DOCKER_GEN_VERSION environment variable -# Because some external projects rely on it -ARG DOCKER_GEN_VERSION +# Add DOCKER_GEN_VERSION environment variable because +# acme-companion rely on it (but the actual value is not important) +ARG DOCKER_GEN_VERSION="unknown" ENV NGINX_PROXY_VERSION=${NGINX_PROXY_VERSION} \ DOCKER_GEN_VERSION=${DOCKER_GEN_VERSION} \ DOCKER_HOST=unix:///tmp/docker.sock @@ -63,7 +46,7 @@ RUN echo "daemon off;" >> /etc/nginx/nginx.conf \ # Install Forego + docker-gen COPY --from=forego /usr/local/bin/forego /usr/local/bin/forego -COPY --from=dockergen /usr/local/bin/docker-gen /usr/local/bin/docker-gen +COPY --from=docker-gen /usr/local/bin/docker-gen /usr/local/bin/docker-gen COPY network_internal.conf /etc/nginx/ diff --git a/Dockerfile.alpine b/Dockerfile.alpine index a51a893..c3ab0f7 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -1,32 +1,15 @@ # setup build arguments for version of dependencies to use -ARG DOCKER_GEN_VERSION=0.10.4 ARG FOREGO_VERSION=v0.17.0 -# Use a specific version of golang to build both binaries -FROM golang:1.20.3-alpine as gobuilder -RUN apk add --no-cache git musl-dev - -# Build docker-gen from scratch -FROM gobuilder as dockergen - -ARG DOCKER_GEN_VERSION - -RUN git clone https://github.com/nginx-proxy/docker-gen \ - && cd /go/docker-gen \ - && git -c advice.detachedHead=false checkout $DOCKER_GEN_VERSION \ - && go mod download \ - && CGO_ENABLED=0 go build -ldflags "-X main.buildVersion=${DOCKER_GEN_VERSION}" ./cmd/docker-gen \ - && go clean -cache \ - && mv docker-gen /usr/local/bin/ \ - && cd - \ - && rm -rf /go/docker-gen +FROM nginxproxy/docker-gen:0.10.4 AS docker-gen # Build forego from scratch -FROM gobuilder as forego +FROM golang:1.20.3-alpine as forego ARG FOREGO_VERSION -RUN git clone https://github.com/nginx-proxy/forego/ \ +RUN apk add --no-cache git musl-dev \ + && git clone https://github.com/nginx-proxy/forego/ \ && cd /go/forego \ && git -c advice.detachedHead=false checkout $FOREGO_VERSION \ && go mod download \ @@ -40,9 +23,9 @@ RUN git clone https://github.com/nginx-proxy/forego/ \ FROM nginx:1.23.4-alpine ARG NGINX_PROXY_VERSION -# Add DOCKER_GEN_VERSION environment variable -# Because some external projects rely on it -ARG DOCKER_GEN_VERSION +# Add DOCKER_GEN_VERSION environment variable because +# acme-companion rely on it (but the actual value is not important) +ARG DOCKER_GEN_VERSION="unknown" ENV NGINX_PROXY_VERSION=${NGINX_PROXY_VERSION} \ DOCKER_GEN_VERSION=${DOCKER_GEN_VERSION} \ DOCKER_HOST=unix:///tmp/docker.sock @@ -60,7 +43,7 @@ RUN echo "daemon off;" >> /etc/nginx/nginx.conf \ # Install Forego + docker-gen COPY --from=forego /usr/local/bin/forego /usr/local/bin/forego -COPY --from=dockergen /usr/local/bin/docker-gen /usr/local/bin/docker-gen +COPY --from=docker-gen /usr/local/bin/docker-gen /usr/local/bin/docker-gen COPY network_internal.conf /etc/nginx/ From 64e21100d3d8b16faad3322930cd54bd3a694b82 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Sun, 30 Apr 2023 17:31:56 +0200 Subject: [PATCH 174/300] build: don't install wget --- Dockerfile | 6 ++---- Dockerfile.alpine | 6 ++++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Dockerfile b/Dockerfile index 7617c83..6a70317 100644 --- a/Dockerfile +++ b/Dockerfile @@ -29,11 +29,9 @@ ENV NGINX_PROXY_VERSION=${NGINX_PROXY_VERSION} \ DOCKER_GEN_VERSION=${DOCKER_GEN_VERSION} \ DOCKER_HOST=unix:///tmp/docker.sock -# Install wget and install/updates certificates +# Install/update certificates RUN apt-get update \ - && apt-get install -y -q --no-install-recommends \ - ca-certificates \ - wget \ + && apt-get install -y -q --no-install-recommends ca-certificates \ && apt-get clean \ && rm -r /var/lib/apt/lists/* diff --git a/Dockerfile.alpine b/Dockerfile.alpine index c3ab0f7..233d9f1 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -30,9 +30,11 @@ ENV NGINX_PROXY_VERSION=${NGINX_PROXY_VERSION} \ DOCKER_GEN_VERSION=${DOCKER_GEN_VERSION} \ DOCKER_HOST=unix:///tmp/docker.sock -# Install wget and install/updates certificates +# Install dependencies RUN apk add --no-cache --virtual .run-deps \ - ca-certificates bash wget openssl \ + bash \ + ca-certificates \ + openssl \ && update-ca-certificates # Configure Nginx From 442e577c0ef2dda4aac9650f1064a858b88d722b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 3 May 2023 04:57:51 +0000 Subject: [PATCH 175/300] build: bump golang from 1.20.3-alpine to 1.20.4-alpine Bumps golang from 1.20.3-alpine to 1.20.4-alpine. --- updated-dependencies: - dependency-name: golang dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Dockerfile | 2 +- Dockerfile.alpine | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 7617c83..a4cfcb1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,7 +4,7 @@ ARG FOREGO_VERSION=v0.17.0 FROM nginxproxy/docker-gen:0.10.4-debian AS docker-gen # Build forego from scratch -FROM golang:1.20.3 as forego +FROM golang:1.20.4 as forego ARG FOREGO_VERSION diff --git a/Dockerfile.alpine b/Dockerfile.alpine index c3ab0f7..c23e60f 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -4,7 +4,7 @@ ARG FOREGO_VERSION=v0.17.0 FROM nginxproxy/docker-gen:0.10.4 AS docker-gen # Build forego from scratch -FROM golang:1.20.3-alpine as forego +FROM golang:1.20.4-alpine as forego ARG FOREGO_VERSION From 28fef687adcafcbf78e2f987fb26c2bb3a84e61d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 May 2023 04:58:23 +0000 Subject: [PATCH 176/300] ci: bump docker from 6.0.1 to 6.1.1 in /test/requirements Bumps [docker](https://github.com/docker/docker-py) from 6.0.1 to 6.1.1. - [Release notes](https://github.com/docker/docker-py/releases) - [Commits](https://github.com/docker/docker-py/compare/6.0.1...6.1.1) --- updated-dependencies: - dependency-name: docker dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- test/requirements/python-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/requirements/python-requirements.txt b/test/requirements/python-requirements.txt index 0344210..25f439a 100644 --- a/test/requirements/python-requirements.txt +++ b/test/requirements/python-requirements.txt @@ -1,5 +1,5 @@ backoff==2.2.1 docker-compose==1.29.2 -docker==6.0.1 +docker==6.1.1 pytest==7.3.1 requests==2.29.0 From faad1cc29e111d897e5a78f6c618e6bc8d1f2cd7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 May 2023 10:48:18 +0000 Subject: [PATCH 177/300] ci: bump requests from 2.29.0 to 2.30.0 in /test/requirements Bumps [requests](https://github.com/psf/requests) from 2.29.0 to 2.30.0. - [Release notes](https://github.com/psf/requests/releases) - [Changelog](https://github.com/psf/requests/blob/main/HISTORY.md) - [Commits](https://github.com/psf/requests/compare/v2.29.0...v2.30.0) --- updated-dependencies: - dependency-name: requests dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- test/requirements/python-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/requirements/python-requirements.txt b/test/requirements/python-requirements.txt index 25f439a..f10abfa 100644 --- a/test/requirements/python-requirements.txt +++ b/test/requirements/python-requirements.txt @@ -2,4 +2,4 @@ backoff==2.2.1 docker-compose==1.29.2 docker==6.1.1 pytest==7.3.1 -requests==2.29.0 +requests==2.30.0 From 6e5e8f4c9d360c0b13f37053d18b55d4eb3ba35c Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Mon, 8 May 2023 15:36:04 +0200 Subject: [PATCH 178/300] ci: fix image version labelling --- .github/workflows/build-publish.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-publish.yml b/.github/workflows/build-publish.yml index 2b4eb3e..7d9143b 100644 --- a/.github/workflows/build-publish.yml +++ b/.github/workflows/build-publish.yml @@ -46,7 +46,7 @@ jobs: type=raw,value=latest,enable={{is_default_branch}} labels: | org.opencontainers.image.authors=Nicolas Duchon (@buchdag), Jason Wilder - org.opencontainers.image.version=${{ env.GIT_DESCRIBE }} + org.opencontainers.image.version=${{ steps.nginx-proxy_version.outputs.VERSION }} - name: Set up QEMU uses: docker/setup-qemu-action@v2 @@ -115,7 +115,7 @@ jobs: type=raw,value=alpine,enable={{is_default_branch}} labels: | org.opencontainers.image.authors=Nicolas Duchon (@buchdag), Jason Wilder - org.opencontainers.image.version=${{ env.GIT_DESCRIBE }} + org.opencontainers.image.version=${{ steps.nginx-proxy_version.outputs.VERSION }} flavor: latest=false - name: Set up QEMU From 2b621599ffbdd3f7849f7819985b3fbc0b96ce83 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Mon, 8 May 2023 21:20:47 +0200 Subject: [PATCH 179/300] test: fix wildcard_certs_and_nohttps test --- .../wildcard_cert_and_nohttps/test_wildcard_cert_nohttps.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_ssl/wildcard_cert_and_nohttps/test_wildcard_cert_nohttps.py b/test/test_ssl/wildcard_cert_and_nohttps/test_wildcard_cert_nohttps.py index 603d281..590eafc 100644 --- a/test/test_ssl/wildcard_cert_and_nohttps/test_wildcard_cert_nohttps.py +++ b/test/test_ssl/wildcard_cert_and_nohttps/test_wildcard_cert_nohttps.py @@ -27,7 +27,7 @@ def test_https_get_served(docker_compose, nginxproxy, subdomain): def test_https_request_to_nohttps_vhost_goes_to_fallback_server(docker_compose, nginxproxy): with pytest.raises( (CertificateError, SSLError) ) as excinfo: nginxproxy.get("https://3.web.nginx-proxy.tld/port") - assert """hostname '3.web.nginx-proxy.tld' doesn't match 'nginx-proxy.tld'""" in str(excinfo.value) + assert """certificate is not valid for '3.web.nginx-proxy.tld'""" in str(excinfo.value) r = nginxproxy.get("https://3.web.nginx-proxy.tld/port", verify=False) assert r.status_code == 503 From e2539b04f58a640444e61813531cb4eac0cec7e4 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Mon, 8 May 2023 23:14:09 +0200 Subject: [PATCH 180/300] fix: always on session cache on HTTPS fallback listener --- nginx.tmpl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nginx.tmpl b/nginx.tmpl index 2556acf..f9d9a03 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -422,11 +422,11 @@ server { {{- if $globals.enable_ipv6 }} listen [::]:{{ $globals.external_https_port }} ssl http2; {{- /* Do not add `default_server` (see comment above). */}} {{- end }} + ssl_session_cache shared:SSL:50m; + ssl_session_tickets off; {{- end }} {{ $globals.access_log }} {{- if $globals.default_cert_ok }} - ssl_session_cache shared:SSL:50m; - ssl_session_tickets off; ssl_certificate /etc/nginx/certs/default.crt; ssl_certificate_key /etc/nginx/certs/default.key; {{- else }} From b88d33d2f35b268c8e20f5f1dececa633bea1387 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Tue, 9 May 2023 00:58:05 +0200 Subject: [PATCH 181/300] feat: handle multiple proxy networks --- nginx.tmpl | 13 ++++++++++--- .../test_host-network-mode.yml | 5 ++++- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/nginx.tmpl b/nginx.tmpl index f322db9..4aca11c 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -68,9 +68,16 @@ {{- continue }} {{- end }} {{- if eq .Name "host" }} - # {{ .Name }} (host network; using {{ (index $.globals.CurrentContainer.Networks 0).Name }} gateway) - {{- $ip = (index $.globals.CurrentContainer.Networks 0).Gateway }} - {{- continue }} + {{- range sortObjectsByKeysAsc $.globals.CurrentContainer.Networks "Name" }} + {{- if and . .Gateway }} + # container is in host network mode, using {{ .Name }} gateway IP + {{- $ip = .Gateway }} + {{- break }} + {{- end }} + {{- end }} + {{- if $ip }} + {{- continue }} + {{- end }} {{- end }} {{- if and (not (index $.globals.networks .Name)) (not $.globals.networks.host) }} # {{ .Name }} (unreachable) diff --git a/test/test_host-network-mode/test_host-network-mode.yml b/test/test_host-network-mode/test_host-network-mode.yml index d8803ba..1f2769c 100644 --- a/test/test_host-network-mode/test_host-network-mode.yml +++ b/test/test_host-network-mode/test_host-network-mode.yml @@ -2,6 +2,8 @@ version: "2" networks: net1: + internal: true + net2: services: bridge-network: @@ -10,7 +12,7 @@ services: WEB_PORTS: "80" VIRTUAL_HOST: "bridge-network.nginx-proxy.tld" networks: - - net1 + - net2 host-network: image: web @@ -26,3 +28,4 @@ services: - /var/run/docker.sock:/tmp/docker.sock:ro networks: - net1 + - net2 From 35b1493e16a504a2bce15ffb7bb7be4ba4a0296a Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Tue, 9 May 2023 19:31:42 +0200 Subject: [PATCH 182/300] feat: support proxy + container in host network mode --- nginx.tmpl | 6 +++++ test/conftest.py | 8 ++++++ .../test_proxy-host-network-mode.py | 13 ++++++++++ .../test_proxy-host-network-mode.yml | 26 +++++++++++++++++++ 4 files changed, 53 insertions(+) create mode 100644 test/test_host-network-mode/test_proxy-host-network-mode.py create mode 100644 test/test_host-network-mode/test_proxy-host-network-mode.yml diff --git a/nginx.tmpl b/nginx.tmpl index 4aca11c..3f4b019 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -68,6 +68,12 @@ {{- continue }} {{- end }} {{- if eq .Name "host" }} + {{- /* Handle containers in host nework mode */}} + {{- if (index $.globals.networks "host") }} + # both container and proxy are in host network mode, using localhost IP + {{- $ip = "127.0.0.1" }} + {{- continue }} + {{- end }} {{- range sortObjectsByKeysAsc $.globals.CurrentContainer.Networks "Name" }} {{- if and . .Gateway }} # container is in host network mode, using {{ .Name }} gateway IP diff --git a/test/conftest.py b/test/conftest.py index e7133e7..d58d504 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -160,6 +160,10 @@ def container_ip(container: Container): net_info = container.attrs["NetworkSettings"]["Networks"] if "bridge" in net_info: return net_info["bridge"]["IPAddress"] + + # container is running in host network mode + if "host" in net_info: + return "127.0.0.1" # not default bridge network, fallback on first network defined network_name = list(net_info.keys())[0] @@ -173,6 +177,10 @@ def container_ipv6(container): net_info = container.attrs["NetworkSettings"]["Networks"] if "bridge" in net_info: return net_info["bridge"]["GlobalIPv6Address"] + + # container is running in host network mode + if "host" in net_info: + return "::1" # not default bridge network, fallback on first network defined network_name = list(net_info.keys())[0] diff --git a/test/test_host-network-mode/test_proxy-host-network-mode.py b/test/test_host-network-mode/test_proxy-host-network-mode.py new file mode 100644 index 0000000..330334b --- /dev/null +++ b/test/test_host-network-mode/test_proxy-host-network-mode.py @@ -0,0 +1,13 @@ +import pytest + + +def test_forwards_to_host_network_container_1(docker_compose, nginxproxy): + r = nginxproxy.get("http://host-network-1.nginx-proxy.tld:8888/port") + assert r.status_code == 200 + assert r.text == "answer from port 8080\n" + + +def test_forwards_to_host_network_container_2(docker_compose, nginxproxy): + r = nginxproxy.get("http://host-network-2.nginx-proxy.tld:8888/port") + assert r.status_code == 200 + assert r.text == "answer from port 8181\n" diff --git a/test/test_host-network-mode/test_proxy-host-network-mode.yml b/test/test_host-network-mode/test_proxy-host-network-mode.yml new file mode 100644 index 0000000..32106e2 --- /dev/null +++ b/test/test_host-network-mode/test_proxy-host-network-mode.yml @@ -0,0 +1,26 @@ +version: "2" + +services: + host-network-1: + image: web + environment: + WEB_PORTS: "8080" + VIRTUAL_HOST: "host-network-1.nginx-proxy.tld" + VIRTUAL_PORT: "8080" + network_mode: host + + host-network-2: + image: web + environment: + WEB_PORTS: "8181" + VIRTUAL_HOST: "host-network-2.nginx-proxy.tld" + VIRTUAL_PORT: "8181" + network_mode: host + + sut: + image: nginxproxy/nginx-proxy:test + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro + environment: + HTTP_PORT: 8888 + network_mode: host From 27f6cebb05d1d86998b62bfd025670c738d63c6f Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Tue, 9 May 2023 21:08:10 +0200 Subject: [PATCH 183/300] docs: host networking support documentation --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 106a2df..edcb91a 100644 --- a/README.md +++ b/README.md @@ -182,6 +182,12 @@ docker network connect my-other-network my-nginx-proxy In this example, the `my-nginx-proxy` container will be connected to `my-network` and `my-other-network` and will be able to proxy to other containers attached to those networks. +### Host networking + +`nginx-proxy` is compatible with containers using Docker's [host networking](https://docs.docker.com/network/host/), both with the proxy connected to one or more [bridge network](https://docs.docker.com/network/bridge/) (default or user created) or running in host network mode itself. + +Proxyed containers running in host network mode **must** use the [`VIRTUAL_PORT](#virtual-ports) environment variable, as this is the only way for `nginx-proxy` to get the correct port (or a port at all) for those containers running. + ### Custom external HTTP/HTTPS ports If you want to use `nginx-proxy` with different external ports that the default ones of `80` for `HTTP` traffic and `443` for `HTTPS` traffic, you'll have to use the environment variable(s) `HTTP_PORT` and/or `HTTPS_PORT` in addition to the changes to the Docker port mapping. If you change the `HTTPS` port, the redirect for `HTTPS` traffic will also be configured to redirect to the custom port. Typical usage, here with the custom ports `1080` and `10443`: From 5d237b7a0aa0e0497afc75defaea39751640760c Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Mon, 8 May 2023 20:00:34 +0200 Subject: [PATCH 184/300] build: get Forego from pre-built image --- Dockerfile | 19 +------------------ Dockerfile.alpine | 19 +------------------ 2 files changed, 2 insertions(+), 36 deletions(-) diff --git a/Dockerfile b/Dockerfile index 30389b3..55a8a37 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,22 +1,6 @@ -# setup build arguments for version of dependencies to use -ARG FOREGO_VERSION=v0.17.0 - FROM nginxproxy/docker-gen:0.10.4-debian AS docker-gen -# Build forego from scratch -FROM golang:1.20.4 as forego - -ARG FOREGO_VERSION - -RUN git clone https://github.com/nginx-proxy/forego/ \ - && cd /go/forego \ - && git -c advice.detachedHead=false checkout $FOREGO_VERSION \ - && go mod download \ - && CGO_ENABLED=0 GOOS=linux go build -o forego . \ - && go clean -cache \ - && mv forego /usr/local/bin/ \ - && cd - \ - && rm -rf /go/forego +FROM nginxproxy/forego:0.17.1-debian AS forego # Build the final image FROM nginx:1.23.4 @@ -35,7 +19,6 @@ RUN apt-get update \ && apt-get clean \ && rm -r /var/lib/apt/lists/* - # Configure Nginx RUN echo "daemon off;" >> /etc/nginx/nginx.conf \ && sed -i 's/worker_processes 1/worker_processes auto/' /etc/nginx/nginx.conf \ diff --git a/Dockerfile.alpine b/Dockerfile.alpine index 04343e1..b3d3304 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -1,23 +1,6 @@ -# setup build arguments for version of dependencies to use -ARG FOREGO_VERSION=v0.17.0 - FROM nginxproxy/docker-gen:0.10.4 AS docker-gen -# Build forego from scratch -FROM golang:1.20.4-alpine as forego - -ARG FOREGO_VERSION - -RUN apk add --no-cache git musl-dev \ - && git clone https://github.com/nginx-proxy/forego/ \ - && cd /go/forego \ - && git -c advice.detachedHead=false checkout $FOREGO_VERSION \ - && go mod download \ - && CGO_ENABLED=0 go build -o forego . \ - && go clean -cache \ - && mv forego /usr/local/bin/ \ - && cd - \ - && rm -rf /go/forego +FROM nginxproxy/forego:0.17.1 AS forego # Build the final image FROM nginx:1.23.4-alpine From bd5816b7059e063581e1504a9641daa45f5da440 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 May 2023 04:58:28 +0000 Subject: [PATCH 185/300] ci: bump docker from 6.1.1 to 6.1.2 in /test/requirements Bumps [docker](https://github.com/docker/docker-py) from 6.1.1 to 6.1.2. - [Release notes](https://github.com/docker/docker-py/releases) - [Commits](https://github.com/docker/docker-py/compare/6.1.1...6.1.2) --- updated-dependencies: - dependency-name: docker dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- test/requirements/python-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/requirements/python-requirements.txt b/test/requirements/python-requirements.txt index f10abfa..6206dcc 100644 --- a/test/requirements/python-requirements.txt +++ b/test/requirements/python-requirements.txt @@ -1,5 +1,5 @@ backoff==2.2.1 docker-compose==1.29.2 -docker==6.1.1 +docker==6.1.2 pytest==7.3.1 requests==2.30.0 From a06bb9e68b28ac0be72716e3a232200ba7f0d45d Mon Sep 17 00:00:00 2001 From: azlux Date: Mon, 22 May 2023 12:21:35 +0200 Subject: [PATCH 186/300] fix: add missing cipher suite to Mozilla-Intermediate (#2247) --- nginx.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nginx.tmpl b/nginx.tmpl index f9d9a03..e7b5914 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -137,7 +137,7 @@ ssl_prefer_server_ciphers off; {{- else if eq .ssl_policy "Mozilla-Intermediate" }} ssl_protocols TLSv1.2 TLSv1.3; - ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384'; + ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305'; ssl_prefer_server_ciphers off; {{- else if eq .ssl_policy "Mozilla-Old" }} ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; From 13eb61a6392acfe8809e4852648c37f0c4892879 Mon Sep 17 00:00:00 2001 From: SaturnIC <> Date: Mon, 22 May 2023 12:14:28 +0200 Subject: [PATCH 187/300] fix: Replace mDNS .local domain with .example domain See RFC 6762 for details on mDNS .local domain: https://datatracker.ietf.org/doc/html/rfc6762 And RFC 6761 for details on .example domain: https://datatracker.ietf.org/doc/html/rfc6761 --- README.md | 6 +++--- docker-compose-separate-containers.yml | 2 +- docker-compose.yml | 2 +- test/conftest.py | 4 ++-- test/test_composev2.py | 2 +- test/test_composev2.yml | 2 +- test/test_custom/test_defaults-location.py | 6 +++--- test/test_custom/test_defaults-location.yml | 8 ++++---- test/test_custom/test_defaults.py | 4 ++-- test/test_custom/test_defaults.yml | 4 ++-- test/test_custom/test_location-per-vhost.py | 6 +++--- test/test_custom/test_location-per-vhost.yml | 6 +++--- test/test_custom/test_per-vhost.py | 4 ++-- test/test_custom/test_per-vhost.yml | 6 +++--- test/test_custom/test_proxy-wide.py | 4 ++-- test/test_custom/test_proxy-wide.yml | 4 ++-- test/test_internal/test_internal-per-vhost.py | 4 ++-- test/test_internal/test_internal-per-vhost.yml | 4 ++-- test/test_internal/test_internal-per-vpath.py | 4 ++-- test/test_internal/test_internal-per-vpath.yml | 4 ++-- test/test_multiple-networks.py | 4 ++-- test/test_multiple-networks.yml | 4 ++-- test/test_vhost-in-multiple-networks.py | 2 +- test/test_vhost-in-multiple-networks.yml | 2 +- 24 files changed, 49 insertions(+), 49 deletions(-) diff --git a/README.md b/README.md index 106a2df..41893cd 100644 --- a/README.md +++ b/README.md @@ -68,13 +68,13 @@ services: expose: - "8000" environment: - - VIRTUAL_HOST=whoami.local + - VIRTUAL_HOST=whoami.example - VIRTUAL_PORT=8000 ``` ```console docker-compose up -curl -H "Host: whoami.local" localhost +curl -H "Host: whoami.example" localhost ``` Example output: @@ -257,7 +257,7 @@ You can demo this pattern with docker-compose: ```console docker-compose --file docker-compose-separate-containers.yml up -curl -H "Host: whoami.local" localhost +curl -H "Host: whoami.example" localhost ``` Example output: diff --git a/docker-compose-separate-containers.yml b/docker-compose-separate-containers.yml index 254b742..4277632 100644 --- a/docker-compose-separate-containers.yml +++ b/docker-compose-separate-containers.yml @@ -21,4 +21,4 @@ services: whoami: image: jwilder/whoami environment: - - VIRTUAL_HOST=whoami.local + - VIRTUAL_HOST=whoami.example diff --git a/docker-compose.yml b/docker-compose.yml index 138f396..931c364 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,4 +11,4 @@ services: whoami: image: jwilder/whoami environment: - - VIRTUAL_HOST=whoami.local + - VIRTUAL_HOST=whoami.example diff --git a/test/conftest.py b/test/conftest.py index e7133e7..8e32650 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -45,10 +45,10 @@ def ipv6(force_ipv6=True): Meant to be used as a context manager to force IPv6 sockets: with ipv6(): - nginxproxy.get("http://something.nginx-proxy.local") # force use of IPv6 + nginxproxy.get("http://something.nginx-proxy.example") # force use of IPv6 with ipv6(False): - nginxproxy.get("http://something.nginx-proxy.local") # legacy behavior + nginxproxy.get("http://something.nginx-proxy.example") # legacy behavior """ diff --git a/test/test_composev2.py b/test/test_composev2.py index 88a4f80..695857e 100644 --- a/test/test_composev2.py +++ b/test/test_composev2.py @@ -5,6 +5,6 @@ def test_unknown_virtual_host(docker_compose, nginxproxy): assert r.status_code == 503 def test_forwards_to_whoami(docker_compose, nginxproxy): - r = nginxproxy.get("http://web.nginx-proxy.local/port") + r = nginxproxy.get("http://web.nginx-proxy.example/port") assert r.status_code == 200 assert r.text == "answer from port 81\n" diff --git a/test/test_composev2.yml b/test/test_composev2.yml index 4a0c9fa..dff434c 100644 --- a/test/test_composev2.yml +++ b/test/test_composev2.yml @@ -11,4 +11,4 @@ services: - "81" environment: WEB_PORTS: 81 - VIRTUAL_HOST: web.nginx-proxy.local + VIRTUAL_HOST: web.nginx-proxy.example diff --git a/test/test_custom/test_defaults-location.py b/test/test_custom/test_defaults-location.py index 2b47f71..5af359d 100644 --- a/test/test_custom/test_defaults-location.py +++ b/test/test_custom/test_defaults-location.py @@ -6,14 +6,14 @@ def test_custom_default_conf_does_not_apply_to_unknown_vhost(docker_compose, ngi assert "X-test" not in r.headers def test_custom_default_conf_applies_to_web1(docker_compose, nginxproxy): - r = nginxproxy.get("http://web1.nginx-proxy.local/port") + r = nginxproxy.get("http://web1.nginx-proxy.example/port") assert r.status_code == 200 assert r.text == "answer from port 81\n" assert "X-test" in r.headers assert "f00" == r.headers["X-test"] def test_custom_default_conf_applies_to_web2(docker_compose, nginxproxy): - r = nginxproxy.get("http://web2.nginx-proxy.local/port") + r = nginxproxy.get("http://web2.nginx-proxy.example/port") assert r.status_code == 200 assert r.text == "answer from port 82\n" assert "X-test" in r.headers @@ -21,7 +21,7 @@ def test_custom_default_conf_applies_to_web2(docker_compose, nginxproxy): def test_custom_default_conf_is_overriden_for_web3(docker_compose, nginxproxy): - r = nginxproxy.get("http://web3.nginx-proxy.local/port") + r = nginxproxy.get("http://web3.nginx-proxy.example/port") assert r.status_code == 200 assert r.text == "answer from port 83\n" assert "X-test" in r.headers diff --git a/test/test_custom/test_defaults-location.yml b/test/test_custom/test_defaults-location.yml index 8b185f7..195d232 100644 --- a/test/test_custom/test_defaults-location.yml +++ b/test/test_custom/test_defaults-location.yml @@ -3,7 +3,7 @@ nginx-proxy: 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_bar.conf:/etc/nginx/vhost.d/web3.nginx-proxy.local_location:ro + - ./my_custom_proxy_settings_bar.conf:/etc/nginx/vhost.d/web3.nginx-proxy.example_location:ro web1: image: web @@ -11,7 +11,7 @@ web1: - "81" environment: WEB_PORTS: 81 - VIRTUAL_HOST: web1.nginx-proxy.local + VIRTUAL_HOST: web1.nginx-proxy.example web2: image: web @@ -19,7 +19,7 @@ web2: - "82" environment: WEB_PORTS: 82 - VIRTUAL_HOST: web2.nginx-proxy.local + VIRTUAL_HOST: web2.nginx-proxy.example web3: image: web @@ -27,4 +27,4 @@ web3: - "83" environment: WEB_PORTS: 83 - VIRTUAL_HOST: web3.nginx-proxy.local + VIRTUAL_HOST: web3.nginx-proxy.example diff --git a/test/test_custom/test_defaults.py b/test/test_custom/test_defaults.py index c338628..c9cb2df 100644 --- a/test/test_custom/test_defaults.py +++ b/test/test_custom/test_defaults.py @@ -6,14 +6,14 @@ def test_custom_conf_does_not_apply_to_unknown_vhost(docker_compose, nginxproxy) assert "X-test" not in r.headers def test_custom_conf_applies_to_web1(docker_compose, nginxproxy): - r = nginxproxy.get("http://web1.nginx-proxy.local/port") + r = nginxproxy.get("http://web1.nginx-proxy.example/port") assert r.status_code == 200 assert r.text == "answer from port 81\n" assert "X-test" in r.headers assert "f00" == r.headers["X-test"] def test_custom_conf_applies_to_web2(docker_compose, nginxproxy): - r = nginxproxy.get("http://web2.nginx-proxy.local/port") + r = nginxproxy.get("http://web2.nginx-proxy.example/port") assert r.status_code == 200 assert r.text == "answer from port 82\n" assert "X-test" in r.headers diff --git a/test/test_custom/test_defaults.yml b/test/test_custom/test_defaults.yml index 6086f40..2983e25 100644 --- a/test/test_custom/test_defaults.yml +++ b/test/test_custom/test_defaults.yml @@ -12,7 +12,7 @@ services: - "81" environment: WEB_PORTS: 81 - VIRTUAL_HOST: web1.nginx-proxy.local + VIRTUAL_HOST: web1.nginx-proxy.example web2: image: web @@ -20,4 +20,4 @@ services: - "82" environment: WEB_PORTS: 82 - VIRTUAL_HOST: web2.nginx-proxy.local + VIRTUAL_HOST: web2.nginx-proxy.example diff --git a/test/test_custom/test_location-per-vhost.py b/test/test_custom/test_location-per-vhost.py index f67b501..53a146b 100644 --- a/test/test_custom/test_location-per-vhost.py +++ b/test/test_custom/test_location-per-vhost.py @@ -6,17 +6,17 @@ def test_custom_conf_does_not_apply_to_unknown_vhost(docker_compose, nginxproxy) assert "X-test" not in r.headers def test_custom_conf_applies_to_web1(docker_compose, nginxproxy): - r = nginxproxy.get("http://web1.nginx-proxy.local/port") + r = nginxproxy.get("http://web1.nginx-proxy.example/port") assert r.status_code == 200 assert r.text == "answer from port 81\n" assert "X-test" in r.headers assert "f00" == r.headers["X-test"] def test_custom_conf_does_not_apply_to_web2(docker_compose, nginxproxy): - r = nginxproxy.get("http://web2.nginx-proxy.local/port") + r = nginxproxy.get("http://web2.nginx-proxy.example/port") assert r.status_code == 200 assert r.text == "answer from port 82\n" assert "X-test" not in r.headers def test_custom_block_is_present_in_nginx_generated_conf(docker_compose, nginxproxy): - assert b"include /etc/nginx/vhost.d/web1.nginx-proxy.local_location;" in nginxproxy.get_conf() \ No newline at end of file + assert b"include /etc/nginx/vhost.d/web1.nginx-proxy.example_location;" in nginxproxy.get_conf() \ No newline at end of file diff --git a/test/test_custom/test_location-per-vhost.yml b/test/test_custom/test_location-per-vhost.yml index 99f31f3..6bf69f9 100644 --- a/test/test_custom/test_location-per-vhost.yml +++ b/test/test_custom/test_location-per-vhost.yml @@ -4,7 +4,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.local_location:ro + - ./my_custom_proxy_settings.conf:/etc/nginx/vhost.d/web1.nginx-proxy.example_location:ro web1: image: web @@ -12,7 +12,7 @@ services: - "81" environment: WEB_PORTS: 81 - VIRTUAL_HOST: web1.nginx-proxy.local + VIRTUAL_HOST: web1.nginx-proxy.example web2: image: web @@ -20,4 +20,4 @@ services: - "82" environment: WEB_PORTS: 82 - VIRTUAL_HOST: web2.nginx-proxy.local + VIRTUAL_HOST: web2.nginx-proxy.example diff --git a/test/test_custom/test_per-vhost.py b/test/test_custom/test_per-vhost.py index 57c3bca..6a85e69 100644 --- a/test/test_custom/test_per-vhost.py +++ b/test/test_custom/test_per-vhost.py @@ -6,14 +6,14 @@ def test_custom_conf_does_not_apply_to_unknown_vhost(docker_compose, nginxproxy) assert "X-test" not in r.headers def test_custom_conf_applies_to_web1(docker_compose, nginxproxy): - r = nginxproxy.get("http://web1.nginx-proxy.local/port") + r = nginxproxy.get("http://web1.nginx-proxy.example/port") assert r.status_code == 200 assert r.text == "answer from port 81\n" assert "X-test" in r.headers assert "f00" == r.headers["X-test"] def test_custom_conf_does_not_apply_to_web2(docker_compose, nginxproxy): - r = nginxproxy.get("http://web2.nginx-proxy.local/port") + r = nginxproxy.get("http://web2.nginx-proxy.example/port") assert r.status_code == 200 assert r.text == "answer from port 82\n" assert "X-test" not in r.headers diff --git a/test/test_custom/test_per-vhost.yml b/test/test_custom/test_per-vhost.yml index 5eba9f6..e7e50b4 100644 --- a/test/test_custom/test_per-vhost.yml +++ b/test/test_custom/test_per-vhost.yml @@ -4,7 +4,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.local:ro + - ./my_custom_proxy_settings.conf:/etc/nginx/vhost.d/web1.nginx-proxy.example:ro web1: image: web @@ -12,7 +12,7 @@ services: - "81" environment: WEB_PORTS: 81 - VIRTUAL_HOST: web1.nginx-proxy.local + VIRTUAL_HOST: web1.nginx-proxy.example web2: image: web @@ -20,4 +20,4 @@ services: - "82" environment: WEB_PORTS: 82 - VIRTUAL_HOST: web2.nginx-proxy.local + VIRTUAL_HOST: web2.nginx-proxy.example diff --git a/test/test_custom/test_proxy-wide.py b/test/test_custom/test_proxy-wide.py index c338628..c9cb2df 100644 --- a/test/test_custom/test_proxy-wide.py +++ b/test/test_custom/test_proxy-wide.py @@ -6,14 +6,14 @@ def test_custom_conf_does_not_apply_to_unknown_vhost(docker_compose, nginxproxy) assert "X-test" not in r.headers def test_custom_conf_applies_to_web1(docker_compose, nginxproxy): - r = nginxproxy.get("http://web1.nginx-proxy.local/port") + r = nginxproxy.get("http://web1.nginx-proxy.example/port") assert r.status_code == 200 assert r.text == "answer from port 81\n" assert "X-test" in r.headers assert "f00" == r.headers["X-test"] def test_custom_conf_applies_to_web2(docker_compose, nginxproxy): - r = nginxproxy.get("http://web2.nginx-proxy.local/port") + r = nginxproxy.get("http://web2.nginx-proxy.example/port") assert r.status_code == 200 assert r.text == "answer from port 82\n" assert "X-test" in r.headers diff --git a/test/test_custom/test_proxy-wide.yml b/test/test_custom/test_proxy-wide.yml index 0cd6c40..0c4a2a0 100644 --- a/test/test_custom/test_proxy-wide.yml +++ b/test/test_custom/test_proxy-wide.yml @@ -12,7 +12,7 @@ services: - "81" environment: WEB_PORTS: 81 - VIRTUAL_HOST: web1.nginx-proxy.local + VIRTUAL_HOST: web1.nginx-proxy.example web2: image: web @@ -20,4 +20,4 @@ services: - "82" environment: WEB_PORTS: 82 - VIRTUAL_HOST: web2.nginx-proxy.local + VIRTUAL_HOST: web2.nginx-proxy.example diff --git a/test/test_internal/test_internal-per-vhost.py b/test/test_internal/test_internal-per-vhost.py index 4586cc0..e64cc62 100644 --- a/test/test_internal/test_internal-per-vhost.py +++ b/test/test_internal/test_internal-per-vhost.py @@ -1,14 +1,14 @@ import pytest def test_network_web1(docker_compose, nginxproxy): - r = nginxproxy.get("http://web1.nginx-proxy.local/port") + r = nginxproxy.get("http://web1.nginx-proxy.example/port") assert r.status_code == 200 assert r.text == "answer from port 81\n" assert "X-network" in r.headers assert "internal" == r.headers["X-network"] def test_network_web2(docker_compose, nginxproxy): - r = nginxproxy.get("http://web2.nginx-proxy.local/port") + r = nginxproxy.get("http://web2.nginx-proxy.example/port") assert r.status_code == 200 assert r.text == "answer from port 82\n" assert "X-network" not in r.headers diff --git a/test/test_internal/test_internal-per-vhost.yml b/test/test_internal/test_internal-per-vhost.yml index 5c732ee..3763723 100644 --- a/test/test_internal/test_internal-per-vhost.yml +++ b/test/test_internal/test_internal-per-vhost.yml @@ -4,7 +4,7 @@ web1: - "81" environment: WEB_PORTS: 81 - VIRTUAL_HOST: web1.nginx-proxy.local + VIRTUAL_HOST: web1.nginx-proxy.example NETWORK_ACCESS: internal web2: @@ -13,7 +13,7 @@ web2: - "82" environment: WEB_PORTS: 82 - VIRTUAL_HOST: web2.nginx-proxy.local + VIRTUAL_HOST: web2.nginx-proxy.example sut: image: nginxproxy/nginx-proxy:test diff --git a/test/test_internal/test_internal-per-vpath.py b/test/test_internal/test_internal-per-vpath.py index e95fe00..def806c 100644 --- a/test/test_internal/test_internal-per-vpath.py +++ b/test/test_internal/test_internal-per-vpath.py @@ -1,14 +1,14 @@ import pytest def test_network_web1(docker_compose, nginxproxy): - r = nginxproxy.get("http://nginx-proxy.local/web1/port") + r = nginxproxy.get("http://nginx-proxy.example/web1/port") assert r.status_code == 200 assert r.text == "answer from port 81\n" assert "X-network" in r.headers assert "internal" == r.headers["X-network"] def test_network_web2(docker_compose, nginxproxy): - r = nginxproxy.get("http://nginx-proxy.local/web2/port") + r = nginxproxy.get("http://nginx-proxy.example/web2/port") assert r.status_code == 200 assert r.text == "answer from port 82\n" assert "X-network" not in r.headers diff --git a/test/test_internal/test_internal-per-vpath.yml b/test/test_internal/test_internal-per-vpath.yml index f5bac55..3cc4a05 100644 --- a/test/test_internal/test_internal-per-vpath.yml +++ b/test/test_internal/test_internal-per-vpath.yml @@ -4,7 +4,7 @@ web1: - "81" environment: WEB_PORTS: 81 - VIRTUAL_HOST: nginx-proxy.local + VIRTUAL_HOST: nginx-proxy.example VIRTUAL_PATH: /web1/ VIRTUAL_DEST: / NETWORK_ACCESS: internal @@ -15,7 +15,7 @@ web2: - "82" environment: WEB_PORTS: 82 - VIRTUAL_HOST: nginx-proxy.local + VIRTUAL_HOST: nginx-proxy.example VIRTUAL_PATH: /web2/ VIRTUAL_DEST: / diff --git a/test/test_multiple-networks.py b/test/test_multiple-networks.py index 550d0a3..9d48cbe 100644 --- a/test/test_multiple-networks.py +++ b/test/test_multiple-networks.py @@ -8,12 +8,12 @@ def test_unknown_virtual_host(docker_compose, nginxproxy): assert r.status_code == 503 def test_forwards_to_web1(docker_compose, nginxproxy): - r = nginxproxy.get("http://web1.nginx-proxy.local/port") + r = nginxproxy.get("http://web1.nginx-proxy.example/port") assert r.status_code == 200 assert r.text == "answer from port 81\n" def test_forwards_to_web2(docker_compose, nginxproxy): - r = nginxproxy.get("http://web2.nginx-proxy.local/port") + r = nginxproxy.get("http://web2.nginx-proxy.example/port") assert r.status_code == 200 assert r.text == "answer from port 82\n" diff --git a/test/test_multiple-networks.yml b/test/test_multiple-networks.yml index 7e79174..1247cb3 100644 --- a/test/test_multiple-networks.yml +++ b/test/test_multiple-networks.yml @@ -23,7 +23,7 @@ services: - "81" environment: WEB_PORTS: 81 - VIRTUAL_HOST: web1.nginx-proxy.local + VIRTUAL_HOST: web1.nginx-proxy.example networks: - net1 @@ -33,7 +33,7 @@ services: - "82" environment: WEB_PORTS: 82 - VIRTUAL_HOST: web2.nginx-proxy.local + VIRTUAL_HOST: web2.nginx-proxy.example networks: - net2 diff --git a/test/test_vhost-in-multiple-networks.py b/test/test_vhost-in-multiple-networks.py index 97a48fc..02ef19e 100644 --- a/test/test_vhost-in-multiple-networks.py +++ b/test/test_vhost-in-multiple-networks.py @@ -3,7 +3,7 @@ import logging import time def test_forwards_to_web1(docker_compose, nginxproxy): - r = nginxproxy.get("http://web1.nginx-proxy.local/port") + r = nginxproxy.get("http://web1.nginx-proxy.example/port") assert r.status_code == 200 assert r.text == "answer from port 81\n" diff --git a/test/test_vhost-in-multiple-networks.yml b/test/test_vhost-in-multiple-networks.yml index bd01b7e..280af04 100644 --- a/test/test_vhost-in-multiple-networks.yml +++ b/test/test_vhost-in-multiple-networks.yml @@ -19,7 +19,7 @@ services: - "81" environment: WEB_PORTS: 81 - VIRTUAL_HOST: web1.nginx-proxy.local + VIRTUAL_HOST: web1.nginx-proxy.example networks: - net1 - net2 From 3a66659e6301edf94c5ab2ba1acae60d4cb442b0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 25 May 2023 04:57:50 +0000 Subject: [PATCH 188/300] build: bump nginx from 1.23.4-alpine to 1.25.0-alpine Bumps nginx from 1.23.4-alpine to 1.25.0-alpine. --- updated-dependencies: - dependency-name: nginx dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- Dockerfile | 2 +- Dockerfile.alpine | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 55a8a37..905457a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,7 +3,7 @@ FROM nginxproxy/docker-gen:0.10.4-debian AS docker-gen FROM nginxproxy/forego:0.17.1-debian AS forego # Build the final image -FROM nginx:1.23.4 +FROM nginx:1.25.0 ARG NGINX_PROXY_VERSION # Add DOCKER_GEN_VERSION environment variable because diff --git a/Dockerfile.alpine b/Dockerfile.alpine index b3d3304..9cd449c 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -3,7 +3,7 @@ FROM nginxproxy/docker-gen:0.10.4 AS docker-gen FROM nginxproxy/forego:0.17.1 AS forego # Build the final image -FROM nginx:1.23.4-alpine +FROM nginx:1.25.0-alpine ARG NGINX_PROXY_VERSION # Add DOCKER_GEN_VERSION environment variable because From e34d00f42c57525435282105f2161e3487041a11 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 May 2023 04:57:57 +0000 Subject: [PATCH 189/300] ci: bump requests from 2.30.0 to 2.31.0 in /test/requirements Bumps [requests](https://github.com/psf/requests) from 2.30.0 to 2.31.0. - [Release notes](https://github.com/psf/requests/releases) - [Changelog](https://github.com/psf/requests/blob/main/HISTORY.md) - [Commits](https://github.com/psf/requests/compare/v2.30.0...v2.31.0) --- updated-dependencies: - dependency-name: requests dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- test/requirements/python-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/requirements/python-requirements.txt b/test/requirements/python-requirements.txt index 6206dcc..53ecf2b 100644 --- a/test/requirements/python-requirements.txt +++ b/test/requirements/python-requirements.txt @@ -2,4 +2,4 @@ backoff==2.2.1 docker-compose==1.29.2 docker==6.1.2 pytest==7.3.1 -requests==2.30.0 +requests==2.31.0 From edb58755c997aa77bedd754a2653cb8702141c92 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Tue, 30 May 2023 07:09:23 +0200 Subject: [PATCH 190/300] docs: nginx badge 1.25.0 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 106a2df..196cf21 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ [![Test](https://github.com/nginx-proxy/nginx-proxy/actions/workflows/test.yml/badge.svg)](https://github.com/nginx-proxy/nginx-proxy/actions/workflows/test.yml) [![GitHub release](https://img.shields.io/github/v/release/nginx-proxy/nginx-proxy)](https://github.com/nginx-proxy/nginx-proxy/releases) -![nginx 1.23.4](https://img.shields.io/badge/nginx-1.23.4-brightgreen.svg) +![nginx 1.25.0](https://img.shields.io/badge/nginx-1.25.0-brightgreen.svg) [![Docker Image Size](https://img.shields.io/docker/image-size/nginxproxy/nginx-proxy?sort=semver)](https://hub.docker.com/r/nginxproxy/nginx-proxy "Click to view the image on Docker Hub") [![Docker stars](https://img.shields.io/docker/stars/nginxproxy/nginx-proxy.svg)](https://hub.docker.com/r/nginxproxy/nginx-proxy 'DockerHub') [![Docker pulls](https://img.shields.io/docker/pulls/nginxproxy/nginx-proxy.svg)](https://hub.docker.com/r/nginxproxy/nginx-proxy 'DockerHub') From bebb3bba868eeb724bb2178428a206af0800e979 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 5 Jun 2023 04:57:33 +0000 Subject: [PATCH 191/300] ci: bump docker from 6.1.2 to 6.1.3 in /test/requirements Bumps [docker](https://github.com/docker/docker-py) from 6.1.2 to 6.1.3. - [Release notes](https://github.com/docker/docker-py/releases) - [Commits](https://github.com/docker/docker-py/compare/6.1.2...6.1.3) --- updated-dependencies: - dependency-name: docker dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- test/requirements/python-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/requirements/python-requirements.txt b/test/requirements/python-requirements.txt index 53ecf2b..7e237ca 100644 --- a/test/requirements/python-requirements.txt +++ b/test/requirements/python-requirements.txt @@ -1,5 +1,5 @@ backoff==2.2.1 docker-compose==1.29.2 -docker==6.1.2 +docker==6.1.3 pytest==7.3.1 requests==2.31.0 From e22caf7df9717aa695cd859588a79f5a3e1f276b Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Wed, 7 Jun 2023 07:45:01 +0200 Subject: [PATCH 192/300] doc: typo in documentation --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index edcb91a..9173339 100644 --- a/README.md +++ b/README.md @@ -186,7 +186,7 @@ In this example, the `my-nginx-proxy` container will be connected to `my-network `nginx-proxy` is compatible with containers using Docker's [host networking](https://docs.docker.com/network/host/), both with the proxy connected to one or more [bridge network](https://docs.docker.com/network/bridge/) (default or user created) or running in host network mode itself. -Proxyed containers running in host network mode **must** use the [`VIRTUAL_PORT](#virtual-ports) environment variable, as this is the only way for `nginx-proxy` to get the correct port (or a port at all) for those containers running. +Proxyed containers running in host network mode **must** use the [`VIRTUAL_PORT](#virtual-ports) environment variable, as this is the only way for `nginx-proxy` to get the correct port (or a port at all) for those containers. ### Custom external HTTP/HTTPS ports From af62e14bb16b2a5467348009337a4f1bd71496b7 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Wed, 7 Jun 2023 20:21:44 +0200 Subject: [PATCH 193/300] docs: fix typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index aa9e491..257b2ec 100644 --- a/README.md +++ b/README.md @@ -186,7 +186,7 @@ In this example, the `my-nginx-proxy` container will be connected to `my-network `nginx-proxy` is compatible with containers using Docker's [host networking](https://docs.docker.com/network/host/), both with the proxy connected to one or more [bridge network](https://docs.docker.com/network/bridge/) (default or user created) or running in host network mode itself. -Proxyed containers running in host network mode **must** use the [`VIRTUAL_PORT](#virtual-ports) environment variable, as this is the only way for `nginx-proxy` to get the correct port (or a port at all) for those containers. +Proxyed containers running in host network mode **must** use the [`VIRTUAL_PORT`](#virtual-ports) environment variable, as this is the only way for `nginx-proxy` to get the correct port (or a port at all) for those containers. ### Custom external HTTP/HTTPS ports From 893eefc99d970b51d2859809dbc304742e5ae516 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Jun 2023 04:57:57 +0000 Subject: [PATCH 194/300] ci: bump pytest from 7.3.1 to 7.3.2 in /test/requirements Bumps [pytest](https://github.com/pytest-dev/pytest) from 7.3.1 to 7.3.2. - [Release notes](https://github.com/pytest-dev/pytest/releases) - [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst) - [Commits](https://github.com/pytest-dev/pytest/compare/7.3.1...7.3.2) --- updated-dependencies: - dependency-name: pytest dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- test/requirements/python-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/requirements/python-requirements.txt b/test/requirements/python-requirements.txt index 7e237ca..fcd23a5 100644 --- a/test/requirements/python-requirements.txt +++ b/test/requirements/python-requirements.txt @@ -1,5 +1,5 @@ backoff==2.2.1 docker-compose==1.29.2 docker==6.1.3 -pytest==7.3.1 +pytest==7.3.2 requests==2.31.0 From f9e0cd4f68b05e371d6e61f71b74e41197e4eb03 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 15 Jun 2023 04:57:37 +0000 Subject: [PATCH 195/300] build: bump nginx from 1.25.0-alpine to 1.25.1-alpine Bumps nginx from 1.25.0-alpine to 1.25.1-alpine. --- updated-dependencies: - dependency-name: nginx dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Dockerfile | 2 +- Dockerfile.alpine | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 905457a..c2915ef 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,7 +3,7 @@ FROM nginxproxy/docker-gen:0.10.4-debian AS docker-gen FROM nginxproxy/forego:0.17.1-debian AS forego # Build the final image -FROM nginx:1.25.0 +FROM nginx:1.25.1 ARG NGINX_PROXY_VERSION # Add DOCKER_GEN_VERSION environment variable because diff --git a/Dockerfile.alpine b/Dockerfile.alpine index 9cd449c..7a159eb 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -3,7 +3,7 @@ FROM nginxproxy/docker-gen:0.10.4 AS docker-gen FROM nginxproxy/forego:0.17.1 AS forego # Build the final image -FROM nginx:1.25.0-alpine +FROM nginx:1.25.1-alpine ARG NGINX_PROXY_VERSION # Add DOCKER_GEN_VERSION environment variable because From f878cd8c04605f5c341d3c4b3d9be3801a0e3500 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 26 Jun 2023 04:58:03 +0000 Subject: [PATCH 196/300] ci: bump pytest from 7.3.2 to 7.4.0 in /test/requirements Bumps [pytest](https://github.com/pytest-dev/pytest) from 7.3.2 to 7.4.0. - [Release notes](https://github.com/pytest-dev/pytest/releases) - [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst) - [Commits](https://github.com/pytest-dev/pytest/compare/7.3.2...7.4.0) --- updated-dependencies: - dependency-name: pytest dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- test/requirements/python-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/requirements/python-requirements.txt b/test/requirements/python-requirements.txt index fcd23a5..d66f927 100644 --- a/test/requirements/python-requirements.txt +++ b/test/requirements/python-requirements.txt @@ -1,5 +1,5 @@ backoff==2.2.1 docker-compose==1.29.2 docker==6.1.3 -pytest==7.3.2 +pytest==7.4.0 requests==2.31.0 From 45c181b9728e4fcd6484994258868b4ad9fa4e8e Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Tue, 4 Jul 2023 07:54:38 +0200 Subject: [PATCH 197/300] build: update template for nginx 1.25.1 http2 on the listen directive have been deprecated and replaced by the server level http2 directive. --- nginx.tmpl | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/nginx.tmpl b/nginx.tmpl index fc6bca8..fb0766b 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -429,6 +429,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; + http2 on; {{- if $fallback_http }} listen {{ $globals.external_http_port }}; {{- /* Do not add `default_server` (see comment above). */}} {{- if $globals.enable_ipv6 }} @@ -436,9 +437,9 @@ server { {{- end }} {{- end }} {{- if $fallback_https }} - listen {{ $globals.external_https_port }} ssl http2; {{- /* Do not add `default_server` (see comment above). */}} + listen {{ $globals.external_https_port }} ssl; {{- /* Do not add `default_server` (see comment above). */}} {{- if $globals.enable_ipv6 }} - listen [::]:{{ $globals.external_https_port }} ssl http2; {{- /* Do not add `default_server` (see comment above). */}} + listen [::]:{{ $globals.external_https_port }} ssl; {{- /* Do not add `default_server` (see comment above). */}} {{- end }} ssl_session_cache shared:SSL:50m; ssl_session_tickets off; @@ -548,6 +549,7 @@ server { {{- if $server_tokens }} server_tokens {{ $server_tokens }}; {{- end }} + http2 on; {{ $globals.access_log }} {{- if or (eq $https_method "nohttps") (not $cert_ok) (eq $https_method "noredirect") }} listen {{ $globals.external_http_port }} {{ $default_server }}; @@ -556,9 +558,9 @@ server { {{- end }} {{- end }} {{- if ne $https_method "nohttps" }} - listen {{ $globals.external_https_port }} ssl http2 {{ $default_server }}; + listen {{ $globals.external_https_port }} ssl {{ $default_server }}; {{- if $globals.enable_ipv6 }} - listen [::]:{{ $globals.external_https_port }} ssl http2 {{ $default_server }}; + listen [::]:{{ $globals.external_https_port }} ssl {{ $default_server }}; {{- end }} {{- if $cert_ok }} From d6234b9b7a282153a90e79b26125efc426af3a03 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Tue, 4 Jul 2023 08:06:22 +0200 Subject: [PATCH 198/300] docs: update nginx version badge --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 257b2ec..9374d4b 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ [![Test](https://github.com/nginx-proxy/nginx-proxy/actions/workflows/test.yml/badge.svg)](https://github.com/nginx-proxy/nginx-proxy/actions/workflows/test.yml) [![GitHub release](https://img.shields.io/github/v/release/nginx-proxy/nginx-proxy)](https://github.com/nginx-proxy/nginx-proxy/releases) -![nginx 1.25.0](https://img.shields.io/badge/nginx-1.25.0-brightgreen.svg) +![nginx 1.25.1](https://img.shields.io/badge/nginx-1.25.1-brightgreen.svg) [![Docker Image Size](https://img.shields.io/docker/image-size/nginxproxy/nginx-proxy?sort=semver)](https://hub.docker.com/r/nginxproxy/nginx-proxy "Click to view the image on Docker Hub") [![Docker stars](https://img.shields.io/docker/stars/nginxproxy/nginx-proxy.svg)](https://hub.docker.com/r/nginxproxy/nginx-proxy 'DockerHub') [![Docker pulls](https://img.shields.io/docker/pulls/nginxproxy/nginx-proxy.svg)](https://hub.docker.com/r/nginxproxy/nginx-proxy 'DockerHub') From 1e02cb7486e1ccd2a7e7dd364ac1c1f313311dba Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 4 Jul 2023 06:13:58 +0000 Subject: [PATCH 199/300] build: bump nginxproxy/docker-gen from 0.10.4-debian to 0.10.5-debian Bumps nginxproxy/docker-gen from 0.10.4-debian to 0.10.5-debian. --- updated-dependencies: - dependency-name: nginxproxy/docker-gen dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Dockerfile | 2 +- Dockerfile.alpine | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index c2915ef..e7f99c6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM nginxproxy/docker-gen:0.10.4-debian AS docker-gen +FROM nginxproxy/docker-gen:0.10.5-debian AS docker-gen FROM nginxproxy/forego:0.17.1-debian AS forego diff --git a/Dockerfile.alpine b/Dockerfile.alpine index 7a159eb..c45ec90 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -1,4 +1,4 @@ -FROM nginxproxy/docker-gen:0.10.4 AS docker-gen +FROM nginxproxy/docker-gen:0.10.5 AS docker-gen FROM nginxproxy/forego:0.17.1 AS forego From 19f8d7e37535a4330d0cf20dfcba226502ea499f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 4 Jul 2023 06:27:05 +0000 Subject: [PATCH 200/300] build: bump nginxproxy/forego from 0.17.1-debian to 0.17.2-debian Bumps nginxproxy/forego from 0.17.1-debian to 0.17.2-debian. --- updated-dependencies: - dependency-name: nginxproxy/forego dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Dockerfile | 2 +- Dockerfile.alpine | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index e7f99c6..2c22d37 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ FROM nginxproxy/docker-gen:0.10.5-debian AS docker-gen -FROM nginxproxy/forego:0.17.1-debian AS forego +FROM nginxproxy/forego:0.17.2-debian AS forego # Build the final image FROM nginx:1.25.1 diff --git a/Dockerfile.alpine b/Dockerfile.alpine index c45ec90..1f8ac43 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -1,6 +1,6 @@ FROM nginxproxy/docker-gen:0.10.5 AS docker-gen -FROM nginxproxy/forego:0.17.1 AS forego +FROM nginxproxy/forego:0.17.2 AS forego # Build the final image FROM nginx:1.25.1-alpine From cff658a28e120d18bf99888df73617bcec59f922 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 12 Jul 2023 11:58:05 +0000 Subject: [PATCH 201/300] build: bump nginxproxy/docker-gen from 0.10.5-debian to 0.10.6-debian Bumps nginxproxy/docker-gen from 0.10.5-debian to 0.10.6-debian. --- updated-dependencies: - dependency-name: nginxproxy/docker-gen dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Dockerfile | 2 +- Dockerfile.alpine | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 2c22d37..cc391f1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM nginxproxy/docker-gen:0.10.5-debian AS docker-gen +FROM nginxproxy/docker-gen:0.10.6-debian AS docker-gen FROM nginxproxy/forego:0.17.2-debian AS forego diff --git a/Dockerfile.alpine b/Dockerfile.alpine index 1f8ac43..9d4e729 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -1,4 +1,4 @@ -FROM nginxproxy/docker-gen:0.10.5 AS docker-gen +FROM nginxproxy/docker-gen:0.10.6 AS docker-gen FROM nginxproxy/forego:0.17.2 AS forego From 0cbc99838167332e0aebd530efc98648112c37a2 Mon Sep 17 00:00:00 2001 From: Niek <100143256+SchoNie@users.noreply.github.com> Date: Mon, 31 Jul 2023 13:04:19 +0200 Subject: [PATCH 202/300] Bump create_server_certificate.sh to nginx:1.25.1 --- test/certs/create_server_certificate.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/certs/create_server_certificate.sh b/test/certs/create_server_certificate.sh index bcbfdca..8c32ee6 100755 --- a/test/certs/create_server_certificate.sh +++ b/test/certs/create_server_certificate.sh @@ -24,7 +24,7 @@ fi # Create a nginx container (which conveniently provides the `openssl` command) ############################################################################### -CONTAINER=$(docker run -d -v $DIR:/work -w /work -e SAN="$ALTERNATE_DOMAINS" nginx:1.19.10) +CONTAINER=$(docker run -d -v $DIR:/work -w /work -e SAN="$ALTERNATE_DOMAINS" nginx:1.25.1) # Configure openssl docker exec $CONTAINER bash -c ' mkdir -p /ca/{certs,crl,private,newcerts} 2>/dev/null From e623b68eb35619c6b03e35bd30049516834af19b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 16 Aug 2023 04:34:23 +0000 Subject: [PATCH 203/300] build: bump nginx from 1.25.1-alpine to 1.25.2-alpine Bumps nginx from 1.25.1-alpine to 1.25.2-alpine. --- updated-dependencies: - dependency-name: nginx dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Dockerfile | 2 +- Dockerfile.alpine | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index cc391f1..52d8c9b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,7 +3,7 @@ FROM nginxproxy/docker-gen:0.10.6-debian AS docker-gen FROM nginxproxy/forego:0.17.2-debian AS forego # Build the final image -FROM nginx:1.25.1 +FROM nginx:1.25.2 ARG NGINX_PROXY_VERSION # Add DOCKER_GEN_VERSION environment variable because diff --git a/Dockerfile.alpine b/Dockerfile.alpine index 9d4e729..f16e997 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -3,7 +3,7 @@ FROM nginxproxy/docker-gen:0.10.6 AS docker-gen FROM nginxproxy/forego:0.17.2 AS forego # Build the final image -FROM nginx:1.25.1-alpine +FROM nginx:1.25.2-alpine ARG NGINX_PROXY_VERSION # Add DOCKER_GEN_VERSION environment variable because From 39fb91675fbd9cfaff5502ee99fdfb49e8bf1ae0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Sep 2023 04:53:51 +0000 Subject: [PATCH 204/300] ci: bump pytest from 7.4.0 to 7.4.1 in /test/requirements Bumps [pytest](https://github.com/pytest-dev/pytest) from 7.4.0 to 7.4.1. - [Release notes](https://github.com/pytest-dev/pytest/releases) - [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst) - [Commits](https://github.com/pytest-dev/pytest/compare/7.4.0...7.4.1) --- updated-dependencies: - dependency-name: pytest dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- test/requirements/python-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/requirements/python-requirements.txt b/test/requirements/python-requirements.txt index d66f927..d7742d9 100644 --- a/test/requirements/python-requirements.txt +++ b/test/requirements/python-requirements.txt @@ -1,5 +1,5 @@ backoff==2.2.1 docker-compose==1.29.2 docker==6.1.3 -pytest==7.4.0 +pytest==7.4.1 requests==2.31.0 From 3b32dff071b1cd7af2d9a0c969ee12506ba0fe82 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Sep 2023 04:10:00 +0000 Subject: [PATCH 205/300] ci: bump actions/checkout from 3 to 4 Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/build-publish.yml | 4 ++-- .github/workflows/test.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-publish.yml b/.github/workflows/build-publish.yml index 7d9143b..3d6b742 100644 --- a/.github/workflows/build-publish.yml +++ b/.github/workflows/build-publish.yml @@ -24,7 +24,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 @@ -93,7 +93,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c549094..2d8db92 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -23,7 +23,7 @@ jobs: base_docker_image: [alpine, debian] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python 3.9 uses: actions/setup-python@v4 From 1ea872051e09af0836574f8b9c5a1c7414203e2e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Sep 2023 04:08:08 +0000 Subject: [PATCH 206/300] ci: bump docker/setup-buildx-action from 2 to 3 Bumps [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action) from 2 to 3. - [Release notes](https://github.com/docker/setup-buildx-action/releases) - [Commits](https://github.com/docker/setup-buildx-action/compare/v2...v3) --- updated-dependencies: - dependency-name: docker/setup-buildx-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/build-publish.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-publish.yml b/.github/workflows/build-publish.yml index 7d9143b..4444880 100644 --- a/.github/workflows/build-publish.yml +++ b/.github/workflows/build-publish.yml @@ -52,7 +52,7 @@ jobs: uses: docker/setup-qemu-action@v2 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 + uses: docker/setup-buildx-action@v3 - name: Login to DockerHub uses: docker/login-action@v2 @@ -122,7 +122,7 @@ jobs: uses: docker/setup-qemu-action@v2 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 + uses: docker/setup-buildx-action@v3 - name: Login to DockerHub uses: docker/login-action@v2 From 9a162ba38438d121e53982a920227d23c25ccc55 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Sep 2023 04:08:10 +0000 Subject: [PATCH 207/300] ci: bump docker/setup-qemu-action from 2 to 3 Bumps [docker/setup-qemu-action](https://github.com/docker/setup-qemu-action) from 2 to 3. - [Release notes](https://github.com/docker/setup-qemu-action/releases) - [Commits](https://github.com/docker/setup-qemu-action/compare/v2...v3) --- updated-dependencies: - dependency-name: docker/setup-qemu-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/build-publish.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-publish.yml b/.github/workflows/build-publish.yml index 7d9143b..f7b4a1d 100644 --- a/.github/workflows/build-publish.yml +++ b/.github/workflows/build-publish.yml @@ -49,7 +49,7 @@ jobs: org.opencontainers.image.version=${{ steps.nginx-proxy_version.outputs.VERSION }} - name: Set up QEMU - uses: docker/setup-qemu-action@v2 + uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v2 @@ -119,7 +119,7 @@ jobs: flavor: latest=false - name: Set up QEMU - uses: docker/setup-qemu-action@v2 + uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v2 From 00dbe25e191c4ed831edfcffed3f2ee2348398d7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Sep 2023 04:08:13 +0000 Subject: [PATCH 208/300] ci: bump docker/metadata-action from 4 to 5 Bumps [docker/metadata-action](https://github.com/docker/metadata-action) from 4 to 5. - [Release notes](https://github.com/docker/metadata-action/releases) - [Upgrade guide](https://github.com/docker/metadata-action/blob/master/UPGRADE.md) - [Commits](https://github.com/docker/metadata-action/compare/v4...v5) --- updated-dependencies: - dependency-name: docker/metadata-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/build-publish.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-publish.yml b/.github/workflows/build-publish.yml index 7d9143b..fa71874 100644 --- a/.github/workflows/build-publish.yml +++ b/.github/workflows/build-publish.yml @@ -34,7 +34,7 @@ jobs: - name: Get Docker tags for Debian based image id: docker_meta_debian - uses: docker/metadata-action@v4 + uses: docker/metadata-action@v5 with: images: | ghcr.io/nginx-proxy/nginx-proxy @@ -103,7 +103,7 @@ jobs: - name: Get Docker tags for Alpine based image id: docker_meta_alpine - uses: docker/metadata-action@v4 + uses: docker/metadata-action@v5 with: images: | ghcr.io/nginx-proxy/nginx-proxy From 4464afa219759f759e67eb18e1f5e51a4930bc49 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Sep 2023 04:08:20 +0000 Subject: [PATCH 209/300] ci: bump docker/login-action from 2 to 3 Bumps [docker/login-action](https://github.com/docker/login-action) from 2 to 3. - [Release notes](https://github.com/docker/login-action/releases) - [Commits](https://github.com/docker/login-action/compare/v2...v3) --- updated-dependencies: - dependency-name: docker/login-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/build-publish.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build-publish.yml b/.github/workflows/build-publish.yml index 7d9143b..f0a1d9a 100644 --- a/.github/workflows/build-publish.yml +++ b/.github/workflows/build-publish.yml @@ -55,13 +55,13 @@ jobs: uses: docker/setup-buildx-action@v2 - name: Login to DockerHub - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Log in to GitHub Container Registry - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} @@ -125,13 +125,13 @@ jobs: uses: docker/setup-buildx-action@v2 - name: Login to DockerHub - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Log in to GitHub Container Registry - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} From a5566f5e8f92503bb21cc318f85834839def4ec6 Mon Sep 17 00:00:00 2001 From: Francesco Cattoni Date: Sun, 22 Oct 2023 00:34:32 +0200 Subject: [PATCH 210/300] Added support for grpcs protocol --- nginx.tmpl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/nginx.tmpl b/nginx.tmpl index fb0766b..c108fa2 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -215,6 +215,8 @@ {{- end }} {{- else if eq .Proto "grpc" }} grpc_pass {{ trim .Proto }}://{{ trim .Upstream }}; + {{- else if eq .Proto "grpcs" }} + grpc_pass {{ trim .Proto }}://{{ trim .Upstream }}; {{- else }} proxy_pass {{ trim .Proto }}://{{ trim .Upstream }}{{ trim .Dest }}; set $upstream_keepalive {{ if $keepalive }}true{{ else }}false{{ end }}; From 94259dd22c3eba688ee283334b94c4a1eeab600f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Oct 2023 04:38:05 +0000 Subject: [PATCH 211/300] ci: bump pytest from 7.4.1 to 7.4.3 in /test/requirements Bumps [pytest](https://github.com/pytest-dev/pytest) from 7.4.1 to 7.4.3. - [Release notes](https://github.com/pytest-dev/pytest/releases) - [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst) - [Commits](https://github.com/pytest-dev/pytest/compare/7.4.1...7.4.3) --- updated-dependencies: - dependency-name: pytest dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- test/requirements/python-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/requirements/python-requirements.txt b/test/requirements/python-requirements.txt index d7742d9..15182fd 100644 --- a/test/requirements/python-requirements.txt +++ b/test/requirements/python-requirements.txt @@ -1,5 +1,5 @@ backoff==2.2.1 docker-compose==1.29.2 docker==6.1.3 -pytest==7.4.1 +pytest==7.4.3 requests==2.31.0 From 67369c16c558630e37a594d985082318f5db55a6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 7 Dec 2023 23:22:02 +0000 Subject: [PATCH 212/300] ci: bump docker/build-push-action from 4 to 5 Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 4 to 5. - [Release notes](https://github.com/docker/build-push-action/releases) - [Commits](https://github.com/docker/build-push-action/compare/v4...v5) --- updated-dependencies: - dependency-name: docker/build-push-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/build-publish.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-publish.yml b/.github/workflows/build-publish.yml index 52d1804..aede706 100644 --- a/.github/workflows/build-publish.yml +++ b/.github/workflows/build-publish.yml @@ -73,7 +73,7 @@ jobs: - name: Build and push the Debian based image id: docker_build_debian - uses: docker/build-push-action@v4 + uses: docker/build-push-action@v5 with: context: . file: Dockerfile @@ -143,7 +143,7 @@ jobs: - name: Build and push the Alpine based image id: docker_build_alpine - uses: docker/build-push-action@v4 + uses: docker/build-push-action@v5 with: context: . file: Dockerfile.alpine From 3f764a5f8475f3c7866783837c558d8004fbdee6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 25 Oct 2023 04:45:44 +0000 Subject: [PATCH 213/300] build: bump nginx from 1.25.2-alpine to 1.25.3-alpine Bumps nginx from 1.25.2-alpine to 1.25.3-alpine. --- updated-dependencies: - dependency-name: nginx dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Dockerfile | 2 +- Dockerfile.alpine | 2 +- README.md | 2 +- test/certs/create_server_certificate.sh | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Dockerfile b/Dockerfile index 52d8c9b..1f77670 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,7 +3,7 @@ FROM nginxproxy/docker-gen:0.10.6-debian AS docker-gen FROM nginxproxy/forego:0.17.2-debian AS forego # Build the final image -FROM nginx:1.25.2 +FROM nginx:1.25.3 ARG NGINX_PROXY_VERSION # Add DOCKER_GEN_VERSION environment variable because diff --git a/Dockerfile.alpine b/Dockerfile.alpine index f16e997..a00b28f 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -3,7 +3,7 @@ FROM nginxproxy/docker-gen:0.10.6 AS docker-gen FROM nginxproxy/forego:0.17.2 AS forego # Build the final image -FROM nginx:1.25.2-alpine +FROM nginx:1.25.3-alpine ARG NGINX_PROXY_VERSION # Add DOCKER_GEN_VERSION environment variable because diff --git a/README.md b/README.md index 9374d4b..6d918e0 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ [![Test](https://github.com/nginx-proxy/nginx-proxy/actions/workflows/test.yml/badge.svg)](https://github.com/nginx-proxy/nginx-proxy/actions/workflows/test.yml) [![GitHub release](https://img.shields.io/github/v/release/nginx-proxy/nginx-proxy)](https://github.com/nginx-proxy/nginx-proxy/releases) -![nginx 1.25.1](https://img.shields.io/badge/nginx-1.25.1-brightgreen.svg) +![nginx 1.25.3](https://img.shields.io/badge/nginx-1.25.3-brightgreen.svg) [![Docker Image Size](https://img.shields.io/docker/image-size/nginxproxy/nginx-proxy?sort=semver)](https://hub.docker.com/r/nginxproxy/nginx-proxy "Click to view the image on Docker Hub") [![Docker stars](https://img.shields.io/docker/stars/nginxproxy/nginx-proxy.svg)](https://hub.docker.com/r/nginxproxy/nginx-proxy 'DockerHub') [![Docker pulls](https://img.shields.io/docker/pulls/nginxproxy/nginx-proxy.svg)](https://hub.docker.com/r/nginxproxy/nginx-proxy 'DockerHub') diff --git a/test/certs/create_server_certificate.sh b/test/certs/create_server_certificate.sh index 8c32ee6..0789a22 100755 --- a/test/certs/create_server_certificate.sh +++ b/test/certs/create_server_certificate.sh @@ -24,7 +24,7 @@ fi # Create a nginx container (which conveniently provides the `openssl` command) ############################################################################### -CONTAINER=$(docker run -d -v $DIR:/work -w /work -e SAN="$ALTERNATE_DOMAINS" nginx:1.25.1) +CONTAINER=$(docker run -d -v $DIR:/work -w /work -e SAN="$ALTERNATE_DOMAINS" nginx:1.25.3) # Configure openssl docker exec $CONTAINER bash -c ' mkdir -p /ca/{certs,crl,private,newcerts} 2>/dev/null From 5af973b193e5b67b64e247e9996c475310c5f5db Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Tue, 18 Jul 2023 22:32:50 +0200 Subject: [PATCH 214/300] feat: optionally disable HTTP/2 --- nginx.tmpl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/nginx.tmpl b/nginx.tmpl index fb0766b..1a8f82c 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -471,6 +471,7 @@ server { {{- $containers := $vhost.containers }} {{- $default_server := when $vhost.default "default_server" "" }} {{- $https_method := $vhost.https_method }} + {{- $http2 := parseBool (or (first (keys (groupByLabel $containers "com.github.nginx-proxy.nginx-proxy.http2.enable"))) $globals.Env.ENABLE_HTTP2 "true")}} {{- $is_regexp := hasPrefix "~" $host }} {{- $upstream_name := when (or $is_regexp $globals.sha1_upstream_name) (sha1 $host) $host }} @@ -549,7 +550,9 @@ server { {{- if $server_tokens }} server_tokens {{ $server_tokens }}; {{- end }} + {{- if $http2 }} http2 on; + {{- end }} {{ $globals.access_log }} {{- if or (eq $https_method "nohttps") (not $cert_ok) (eq $https_method "noredirect") }} listen {{ $globals.external_http_port }} {{ $default_server }}; From b5cc9b1aa2582749b5e556e3e15316a7f4effcad Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Tue, 18 Jul 2023 22:44:36 +0200 Subject: [PATCH 215/300] feat: experimental http3 support Co-authored-by: Nicolas Duchon Co-authored-by: Knapoc --- nginx.tmpl | 46 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 42 insertions(+), 4 deletions(-) diff --git a/nginx.tmpl b/nginx.tmpl index 1a8f82c..7e5a52e 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -203,6 +203,10 @@ include /etc/nginx/network_internal.conf; {{- end }} + {{- if .http3 }} + add_header alt-svc 'h3=":{{ $.globals.external_https_port }}"; ma=86400;'; + {{- end }} + {{- if eq .Proto "uwsgi" }} include uwsgi_params; uwsgi_pass {{ trim .Proto }}://{{ trim .Upstream }}; @@ -333,7 +337,7 @@ map $proxy_x_forwarded_proto $proxy_x_forwarded_ssl { gzip_types text/plain text/css application/javascript application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript; -log_format vhost '{{ or $globals.Env.LOG_FORMAT "$host $remote_addr - $remote_user [$time_local] \"$request\" $status $body_bytes_sent \"$http_referer\" \"$http_user_agent\" \"$upstream_addr\"" }}'; +log_format vhost '{{ or $globals.Env.LOG_FORMAT "$host $remote_addr - $remote_user [$time_local] \"$request\" $status $body_bytes_sent \"$http_referer\" \"$http_user_agent\" \"$upstream_addr\" $http3" }}'; access_log off; @@ -350,7 +354,7 @@ include /etc/nginx/proxy.conf; # HTTP 1.1 support proxy_http_version 1.1; proxy_buffering off; -proxy_set_header Host $http_host; +proxy_set_header Host $host; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $proxy_connection; proxy_set_header X-Real-IP $remote_addr; @@ -384,7 +388,15 @@ 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)) }} {{- $default := eq $globals.Env.DEFAULT_HOST $vhost }} {{- $https_method := or (first (groupByKeys $containers "Env.HTTPS_METHOD")) $globals.Env.HTTPS_METHOD "redirect" }} - {{- $_ := set $globals.vhosts $vhost (dict "cert" $cert "cert_ok" $cert_ok "containers" $containers "default" $default "https_method" $https_method) }} + {{- $http3 := parseBool (or (first (keys (groupByLabel $containers "com.github.nginx-proxy.nginx-proxy.http3.enable"))) $globals.Env.ENABLE_HTTP3 "false")}} + {{- $_ := set $globals.vhosts $vhost (dict + "cert" $cert + "cert_ok" $cert_ok + "containers" $containers + "default" $default + "https_method" $https_method + "http3" $http3 + ) }} {{- end }} {{- /* @@ -406,6 +418,7 @@ proxy_set_header Proxy ""; {{- $https_exists := false }} {{- $default_http_exists := false }} {{- $default_https_exists := false }} + {{- $http3 := false }} {{- range $vhost := $globals.vhosts }} {{- $http := or (ne $vhost.https_method "nohttp") (not $vhost.cert_ok) }} {{- $https := ne $vhost.https_method "nohttps" }} @@ -413,6 +426,7 @@ proxy_set_header Proxy ""; {{- $https_exists = or $https_exists $https }} {{- $default_http_exists = or $default_http_exists (and $http $vhost.default) }} {{- $default_https_exists = or $default_https_exists (and $https $vhost.default) }} + {{- $http3 = or $http3 $vhost.http3 }} {{- end }} {{- $fallback_http := and $http_exists (not $default_http_exists) }} {{- $fallback_https := and $https_exists (not $default_https_exists) }} @@ -438,8 +452,14 @@ server { {{- end }} {{- if $fallback_https }} listen {{ $globals.external_https_port }} ssl; {{- /* Do not add `default_server` (see comment above). */}} + {{- if $http3 }} + listen {{ $globals.external_https_port }} quic reuseport; {{- /* Do not add `default_server` (see comment above). */}} + {{- end }} {{- if $globals.enable_ipv6 }} listen [::]:{{ $globals.external_https_port }} ssl; {{- /* Do not add `default_server` (see comment above). */}} + {{- if $http3 }} + listen [::]:{{ $globals.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; @@ -472,6 +492,7 @@ server { {{- $default_server := when $vhost.default "default_server" "" }} {{- $https_method := $vhost.https_method }} {{- $http2 := parseBool (or (first (keys (groupByLabel $containers "com.github.nginx-proxy.nginx-proxy.http2.enable"))) $globals.Env.ENABLE_HTTP2 "true")}} + {{- $http3 := parseBool (or (first (keys (groupByLabel $containers "com.github.nginx-proxy.nginx-proxy.http3.enable"))) $globals.Env.ENABLE_HTTP3 "false")}} {{- $is_regexp := hasPrefix "~" $host }} {{- $upstream_name := when (or $is_regexp $globals.sha1_upstream_name) (sha1 $host) $host }} @@ -562,8 +583,14 @@ server { {{- end }} {{- if ne $https_method "nohttps" }} listen {{ $globals.external_https_port }} ssl {{ $default_server }}; + {{- if $http3 }} + listen {{ $globals.external_https_port }} quic {{ $default_server }}; + {{- end }} {{- if $globals.enable_ipv6 }} listen [::]:{{ $globals.external_https_port }} ssl {{ $default_server }}; + {{- if $http3 }} + listen [::]:{{ $globals.external_https_port }} quic {{ $default_server }}; + {{- end }} {{- end }} {{- if $cert_ok }} @@ -648,7 +675,18 @@ server { {{- $upstream = printf "%s-%s" $upstream $sum }} {{- $dest = (or (first (groupByKeys $containers "Env.VIRTUAL_DEST")) "") }} {{- end }} - {{- template "location" (dict "Path" $path "Proto" $proto "Upstream" $upstream "Host" $host "VhostRoot" $vhost_root "Dest" $dest "NetworkTag" $network_tag "Containers" $containers) }} + {{- template "location" (dict + "globals" $globals + "Path" $path + "http3" $http3 + "Proto" $proto + "Upstream" $upstream + "Host" $host + "VhostRoot" $vhost_root + "Dest" $dest + "NetworkTag" $network_tag + "Containers" $containers + ) }} {{- end }} {{- if and (not (contains $paths "/")) (ne $globals.default_root_response "none")}} location / { From 018db70367b2c4c6900c02d909681e18ff82e23c Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Sat, 22 Jul 2023 10:42:17 +0200 Subject: [PATCH 216/300] refactor: re-organise template for HTTP/3 feature Co-authored-by: Nicolas Duchon Co-authored-by: Niek <100143256+SchoNie@users.noreply.github.com> --- nginx.tmpl | 38 ++++++++++++++++++-------------------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/nginx.tmpl b/nginx.tmpl index 7e5a52e..db2d54b 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -203,10 +203,6 @@ include /etc/nginx/network_internal.conf; {{- end }} - {{- if .http3 }} - add_header alt-svc 'h3=":{{ $.globals.external_https_port }}"; ma=86400;'; - {{- end }} - {{- if eq .Proto "uwsgi" }} include uwsgi_params; uwsgi_pass {{ trim .Proto }}://{{ trim .Upstream }}; @@ -281,8 +277,8 @@ map $http_x_forwarded_proto $proxy_x_forwarded_proto { } map $http_x_forwarded_host $proxy_x_forwarded_host { - default {{ if $globals.trust_downstream_proxy }}$http_x_forwarded_host{{ else }}$http_host{{ end }}; - '' $http_host; + default {{ if $globals.trust_downstream_proxy }}$http_x_forwarded_host{{ else }}$host{{ end }}; + '' $host; } # If we receive X-Forwarded-Port, pass it through; otherwise, pass along the @@ -337,7 +333,7 @@ map $proxy_x_forwarded_proto $proxy_x_forwarded_ssl { gzip_types text/plain text/css application/javascript application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript; -log_format vhost '{{ or $globals.Env.LOG_FORMAT "$host $remote_addr - $remote_user [$time_local] \"$request\" $status $body_bytes_sent \"$http_referer\" \"$http_user_agent\" \"$upstream_addr\" $http3" }}'; +log_format vhost '{{ or $globals.Env.LOG_FORMAT "$host $remote_addr - $remote_user [$time_local] \"$request\" $status $body_bytes_sent \"$http_referer\" \"$http_user_agent\" \"$upstream_addr\"" }}'; access_log off; @@ -443,6 +439,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.access_log }} http2 on; {{- if $fallback_http }} listen {{ $globals.external_http_port }}; {{- /* Do not add `default_server` (see comment above). */}} @@ -452,19 +449,19 @@ server { {{- end }} {{- if $fallback_https }} listen {{ $globals.external_https_port }} ssl; {{- /* Do not add `default_server` (see comment above). */}} - {{- if $http3 }} - listen {{ $globals.external_https_port }} quic reuseport; {{- /* Do not add `default_server` (see comment above). */}} - {{- end }} {{- if $globals.enable_ipv6 }} listen [::]:{{ $globals.external_https_port }} ssl; {{- /* Do not add `default_server` (see comment above). */}} - {{- if $http3 }} + {{- end }} + {{- if $http3 }} + 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). */}} {{- end }} {{- end }} ssl_session_cache shared:SSL:50m; ssl_session_tickets off; {{- end }} - {{ $globals.access_log }} {{- if $globals.default_cert_ok }} ssl_certificate /etc/nginx/certs/default.crt; ssl_certificate_key /etc/nginx/certs/default.key; @@ -540,11 +537,11 @@ server { {{- if $server_tokens }} server_tokens {{ $server_tokens }}; {{- end }} + {{ $globals.access_log }} listen {{ $globals.external_http_port }} {{ $default_server }}; {{- if $globals.enable_ipv6 }} listen [::]:{{ $globals.external_http_port }} {{ $default_server }}; {{- end }} - {{ $globals.access_log }} # Do not HTTPS redirect Let's Encrypt ACME challenge location ^~ /.well-known/acme-challenge/ { @@ -571,10 +568,10 @@ server { {{- if $server_tokens }} server_tokens {{ $server_tokens }}; {{- end }} + {{ $globals.access_log }} {{- if $http2 }} http2 on; {{- end }} - {{ $globals.access_log }} {{- if or (eq $https_method "nohttps") (not $cert_ok) (eq $https_method "noredirect") }} listen {{ $globals.external_http_port }} {{ $default_server }}; {{- if $globals.enable_ipv6 }} @@ -583,12 +580,15 @@ server { {{- end }} {{- if ne $https_method "nohttps" }} listen {{ $globals.external_https_port }} ssl {{ $default_server }}; - {{- if $http3 }} - listen {{ $globals.external_https_port }} quic {{ $default_server }}; - {{- end }} {{- if $globals.enable_ipv6 }} listen [::]:{{ $globals.external_https_port }} ssl {{ $default_server }}; - {{- if $http3 }} + {{- end }} + + {{- if $http3 }} + 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 }}; {{- end }} {{- end }} @@ -676,9 +676,7 @@ server { {{- $dest = (or (first (groupByKeys $containers "Env.VIRTUAL_DEST")) "") }} {{- end }} {{- template "location" (dict - "globals" $globals "Path" $path - "http3" $http3 "Proto" $proto "Upstream" $upstream "Host" $host From ae5beca0fee13edfde5436db2ff48f3432bb8daa Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Thu, 27 Jul 2023 21:47:06 +0200 Subject: [PATCH 217/300] docs: documentation for HTTP/2 and HTTP/3 support Co-authored-by: Nicolas Duchon Co-authored-by: Patrick Domack --- README.md | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/README.md b/README.md index 6d918e0..30bf591 100644 --- a/README.md +++ b/README.md @@ -388,6 +388,35 @@ If the default certificate is also missing, nginx-proxy will configure nginx to > > Error code: `SSL_ERROR_INTERNAL_ERROR_ALERT` "TLS error". +### HTTP/2 support + +HTTP/2 is enabled by default and can be disabled if necessary either per-proxied container or globally: + +To disable HTTP/2 for a single proxied container, set the `com.github.nginx-proxy.nginx-proxy.http2.enable` label to `false` on this container. + +To disable HTTP/2 globally set the environment variable `ENABLE_HTTP2` to `false` on the nginx-proxy container. + +More reading on the potential TCP head-of-line blocking issue with HTTP/2: [HTTP/2 Issues](https://www.twilio.com/blog/2017/10/http2-issues.html), [Comparing HTTP/3 vs HTTP/2](https://blog.cloudflare.com/http-3-vs-http-2/) + +### HTTP/3 support + +> **Warning** +> HTTP/3 support [is still considered experimental in nginx](https://www.nginx.com/blog/binary-packages-for-preview-nginx-quic-http3-implementation/) and as such is considered experimental in nginx-proxy too and is disabled by default. [Feedbacks for the HTTP/3 support are welcome in #2271.](https://github.com/nginx-proxy/nginx-proxy/discussions/2271) + +HTTP/3 use the QUIC protocol over UDP (unlike HTTP/1.1 and HTTP/2 which work over TCP), so if you want to use HTTP/3 you'll have to explicitely publish the 443/udp port of the proxy in addition to the 443/tcp port: + +```console +docker run -d -p 80:80 -p 443:443/tcp -p 443:443/udp \ + -v /var/run/docker.sock:/tmp/docker.sock:ro \ + nginxproxy/nginx-proxy +``` + +HTTP/3 can be enabled either per-proxied container or globally: + +To enable HTTP/3 for a single proxied container, set the `com.github.nginx-proxy.nginx-proxy.http3.enable` label to `true` on this container. + +To enable HTTP/3 globally set the environment variable `ENABLE_HTTP3` to `true` on the nginx-proxy container. + ### 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 on directory From c4cb1c3797a5fc2648bb93ea743680432f98be58 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Fri, 8 Dec 2023 00:46:21 +0100 Subject: [PATCH 218/300] test: tests for HTTP/3 Co-authored-by: Nicolas Duchon Co-authored-by: Niek <100143256+SchoNie@users.noreply.github.com> --- test/test_http2/test_http2_global_disabled.py | 8 +++ .../test_http2/test_http2_global_disabled.yml | 15 ++++++ test/test_http3/test_http3_global_disabled.py | 19 +++++++ .../test_http3/test_http3_global_disabled.yml | 15 ++++++ test/test_http3/test_http3_global_enabled.py | 21 ++++++++ test/test_http3/test_http3_global_enabled.yml | 15 ++++++ test/test_http3/test_http3_vhost.py | 49 +++++++++++++++++++ test/test_http3/test_http3_vhost.yml | 33 +++++++++++++ test/test_ssl/test_hsts.py | 8 +++ test/test_ssl/test_hsts.yml | 10 ++++ 10 files changed, 193 insertions(+) create mode 100644 test/test_http2/test_http2_global_disabled.py create mode 100644 test/test_http2/test_http2_global_disabled.yml create mode 100644 test/test_http3/test_http3_global_disabled.py create mode 100644 test/test_http3/test_http3_global_disabled.yml create mode 100644 test/test_http3/test_http3_global_enabled.py create mode 100644 test/test_http3/test_http3_global_enabled.yml create mode 100644 test/test_http3/test_http3_vhost.py create mode 100644 test/test_http3/test_http3_vhost.yml diff --git a/test/test_http2/test_http2_global_disabled.py b/test/test_http2/test_http2_global_disabled.py new file mode 100644 index 0000000..42e102d --- /dev/null +++ b/test/test_http2/test_http2_global_disabled.py @@ -0,0 +1,8 @@ +import pytest +import re + +def test_http2_global_disabled_config(docker_compose, nginxproxy): + conf = nginxproxy.get_conf().decode('ASCII') + r = nginxproxy.get("http://http2-global-disabled.nginx-proxy.tld") + assert r.status_code == 200 + assert not re.search(r"(?s)http2-global-disabled\.nginx-proxy\.tld.*http2 on", conf) diff --git a/test/test_http2/test_http2_global_disabled.yml b/test/test_http2/test_http2_global_disabled.yml new file mode 100644 index 0000000..5dffa19 --- /dev/null +++ b/test/test_http2/test_http2_global_disabled.yml @@ -0,0 +1,15 @@ +services: + http2-global-disabled: + image: web + expose: + - "80" + environment: + WEB_PORTS: 80 + VIRTUAL_HOST: http2-global-disabled.nginx-proxy.tld + + sut: + image: nginxproxy/nginx-proxy:test + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro + environment: + ENABLE_HTTP2: "false" diff --git a/test/test_http3/test_http3_global_disabled.py b/test/test_http3/test_http3_global_disabled.py new file mode 100644 index 0000000..508823e --- /dev/null +++ b/test/test_http3/test_http3_global_disabled.py @@ -0,0 +1,19 @@ +import pytest +import re + + #Python Requests is not able to do native http3 requests. + #We only check for directives which should enable http3. + +def test_http3_global_disabled_ALTSVC_header(docker_compose, nginxproxy): + r = nginxproxy.get("http://http3-global-disabled.nginx-proxy.tld/headers") + assert r.status_code == 200 + assert "Host: http3-global-disabled.nginx-proxy.tld" in r.text + assert not "alt-svc" in r.headers + +def test_http3_global_disabled_config(docker_compose, nginxproxy): + conf = nginxproxy.get_conf().decode('ASCII') + r = nginxproxy.get("http://http3-global-disabled.nginx-proxy.tld") + assert r.status_code == 200 + assert not re.search(r"(?s)listen 443 quic", conf) + assert not re.search(r"(?s)http3 on", conf) + assert not re.search(r"(?s)add_header alt-svc \'h3=\":443\"; ma=86400;\'", conf) diff --git a/test/test_http3/test_http3_global_disabled.yml b/test/test_http3/test_http3_global_disabled.yml new file mode 100644 index 0000000..66530a4 --- /dev/null +++ b/test/test_http3/test_http3_global_disabled.yml @@ -0,0 +1,15 @@ +services: + http3-global-disabled: + image: web + expose: + - "80" + environment: + WEB_PORTS: 80 + VIRTUAL_HOST: http3-global-disabled.nginx-proxy.tld + + sut: + image: nginxproxy/nginx-proxy:test + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro + #environment: + #ENABLE_HTTP3: "false" #Disabled by default diff --git a/test/test_http3/test_http3_global_enabled.py b/test/test_http3/test_http3_global_enabled.py new file mode 100644 index 0000000..c678ab6 --- /dev/null +++ b/test/test_http3/test_http3_global_enabled.py @@ -0,0 +1,21 @@ +import pytest +import re + + #Python Requests is not able to do native http3 requests. + #We only check for directives which should enable http3. + +def test_http3_global_enabled_ALTSVC_header(docker_compose, nginxproxy): + r = nginxproxy.get("http://http3-global-enabled.nginx-proxy.tld/headers") + assert r.status_code == 200 + assert "Host: http3-global-enabled.nginx-proxy.tld" in r.text + assert "alt-svc" in r.headers + assert r.headers["alt-svc"] == 'h3=":443"; ma=86400;' + +def test_http3_global_enabled_config(docker_compose, nginxproxy): + conf = nginxproxy.get_conf().decode('ASCII') + r = nginxproxy.get("http://http3-global-enabled.nginx-proxy.tld") + assert r.status_code == 200 + assert re.search(r"listen 443 quic reuseport\;", conf) + assert re.search(r"(?s)http3-global-enabled\.nginx-proxy\.tld;.*listen 443 quic", conf) + assert re.search(r"(?s)http3-global-enabled\.nginx-proxy\.tld;.*http3 on\;", conf) + assert re.search(r"(?s)http3-global-enabled\.nginx-proxy\.tld;.*add_header alt-svc \'h3=\":443\"; ma=86400;\'", conf) diff --git a/test/test_http3/test_http3_global_enabled.yml b/test/test_http3/test_http3_global_enabled.yml new file mode 100644 index 0000000..0825469 --- /dev/null +++ b/test/test_http3/test_http3_global_enabled.yml @@ -0,0 +1,15 @@ +services: + http3-global-enabled: + image: web + expose: + - "80" + environment: + WEB_PORTS: 80 + VIRTUAL_HOST: http3-global-enabled.nginx-proxy.tld + + sut: + image: nginxproxy/nginx-proxy:test + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro + environment: + ENABLE_HTTP3: "true" diff --git a/test/test_http3/test_http3_vhost.py b/test/test_http3/test_http3_vhost.py new file mode 100644 index 0000000..93a217c --- /dev/null +++ b/test/test_http3/test_http3_vhost.py @@ -0,0 +1,49 @@ +import pytest +import re + + #Python Requests is not able to do native http3 requests. + #We only check for directives which should enable http3. + +def test_http3_vhost_enabled_ALTSVC_header(docker_compose, nginxproxy): + r = nginxproxy.get("http://http3-vhost-enabled.nginx-proxy.tld/headers") + assert r.status_code == 200 + assert "Host: http3-vhost-enabled.nginx-proxy.tld" in r.text + assert "alt-svc" in r.headers + assert r.headers["alt-svc"] == 'h3=":443"; ma=86400;' + +def test_http3_vhost_enabled_config(docker_compose, nginxproxy): + conf = nginxproxy.get_conf().decode('ASCII') + r = nginxproxy.get("http://http3-vhost-enabled.nginx-proxy.tld") + assert r.status_code == 200 + assert re.search(r"listen 443 quic reuseport\;", conf) + assert re.search(r"(?s)http3-vhost-enabled\.nginx-proxy\.tld;.*listen 443 quic", conf) + assert re.search(r"(?s)http3-vhost-enabled\.nginx-proxy\.tld;.*http3 on\;", conf) + assert re.search(r"(?s)http3-vhost-enabled\.nginx-proxy\.tld;.*add_header alt-svc \'h3=\":443\"; ma=86400;\'", conf) + +def test_http3_vhost_disabled_ALTSVC_header(docker_compose, nginxproxy): + r = nginxproxy.get("http://http3-vhost-disabled.nginx-proxy.tld/headers") + assert r.status_code == 200 + assert "Host: http3-vhost-disabled.nginx-proxy.tld" in r.text + assert not "alt-svc" in r.headers + +def test_http3_vhost_disabled_config(docker_compose, nginxproxy): + conf = nginxproxy.get_conf().decode('ASCII') + r = nginxproxy.get("http://http3-vhost-disabled.nginx-proxy.tld") + assert r.status_code == 200 + assert not re.search(r"(?s)http3-vhost-disabled\.nginx-proxy\.tld.*listen 443 quic.*\# http3-vhost-enabled\.nginx-proxy\.tld", conf) + assert not re.search(r"(?s)http3-vhost-disabled\.nginx-proxy\.tld.*http3 on.*\# http3-vhost-enabled\.nginx-proxy\.tld", conf) + assert not re.search(r"(?s)http3-vhost-disabled\.nginx-proxy\.tld;.*add_header alt-svc \'h3=\":443\"; ma=86400;\'.*\# http3-vhost-enabled\.nginx-proxy\.tld", conf) + +def test_http3_vhost_disabledbydefault_ALTSVC_header(docker_compose, nginxproxy): + r = nginxproxy.get("http://http3-vhost-default-disabled.nginx-proxy.tld/headers") + assert r.status_code == 200 + assert "Host: http3-vhost-default-disabled.nginx-proxy.tld" in r.text + assert not "alt-svc" in r.headers + +def test_http3_vhost_disabledbydefault_config(docker_compose, nginxproxy): + conf = nginxproxy.get_conf().decode('ASCII') + r = nginxproxy.get("http://http3-vhost-default-disabled.nginx-proxy.tld") + assert r.status_code == 200 + assert not re.search(r"(?s)http3-vhost-default-disabled\.nginx-proxy\.tld.*listen 443 quic.*\# http3-vhost-disabled\.nginx-proxy\.tld", conf) + assert not re.search(r"(?s)http3-vhost-default-disabled\.nginx-proxy\.tld.*http3 on.*\# http3-vhost-disabled\.nginx-proxy\.tld", conf) + assert not re.search(r"(?s)http3-vhost-default-disabled\.nginx-proxy\.tld;.*add_header alt-svc \'h3=\":443\"; ma=86400;\'.*\# http3-vhost-disabled\.nginx-proxy\.tld", conf) diff --git a/test/test_http3/test_http3_vhost.yml b/test/test_http3/test_http3_vhost.yml new file mode 100644 index 0000000..1d5cdf2 --- /dev/null +++ b/test/test_http3/test_http3_vhost.yml @@ -0,0 +1,33 @@ +services: + http3-vhost-enabled: + image: web + expose: + - "80" + environment: + WEB_PORTS: 80 + VIRTUAL_HOST: http3-vhost-enabled.nginx-proxy.tld + labels: + com.github.nginx-proxy.nginx-proxy.http3.enable: "true" + + http3-vhost-disabled: + image: web + expose: + - "80" + environment: + WEB_PORTS: 80 + VIRTUAL_HOST: http3-vhost-disabled.nginx-proxy.tld + labels: + com.github.nginx-proxy.nginx-proxy.http3.enable: "false" + + http3-vhost-default-disabled: + image: web + expose: + - "80" + environment: + WEB_PORTS: 80 + VIRTUAL_HOST: http3-vhost-default-disabled.nginx-proxy.tld + + sut: + image: nginxproxy/nginx-proxy:test + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro diff --git a/test/test_ssl/test_hsts.py b/test/test_ssl/test_hsts.py index 16dffd2..890c4ad 100644 --- a/test/test_ssl/test_hsts.py +++ b/test/test_ssl/test_hsts.py @@ -31,3 +31,11 @@ def test_web4_HSTS_off_noredirect(docker_compose, nginxproxy): r = nginxproxy.get("https://web4.nginx-proxy.tld/port", allow_redirects=False) assert "answer from port 81\n" in r.text assert "Strict-Transport-Security" not in r.headers + +def test_http3_vhost_enabled_HSTS_default(docker_compose, nginxproxy): + r = nginxproxy.get("https://http3-vhost-enabled.nginx-proxy.tld/port", allow_redirects=False) + assert "answer from port 81\n" in r.text + assert "Strict-Transport-Security" in r.headers + assert "max-age=31536000" == r.headers["Strict-Transport-Security"] + assert "alt-svc" in r.headers + assert r.headers["alt-svc"] == 'h3=":443"; ma=86400;' diff --git a/test/test_ssl/test_hsts.yml b/test/test_ssl/test_hsts.yml index b4af3b6..da3b629 100644 --- a/test/test_ssl/test_hsts.yml +++ b/test/test_ssl/test_hsts.yml @@ -34,6 +34,16 @@ web4: HSTS: "off" HTTPS_METHOD: "noredirect" +web5: + image: web + expose: + - "81" + environment: + WEB_PORTS: "81" + VIRTUAL_HOST: http3-vhost-enabled.nginx-proxy.tld + labels: + com.github.nginx-proxy.nginx-proxy.http3.enable: "true" + sut: image: nginxproxy/nginx-proxy:test volumes: From d37eff83295832dc03e1005ddbac58a317f99496 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 8 Dec 2023 00:32:19 +0000 Subject: [PATCH 219/300] build: bump nginxproxy/docker-gen from 0.10.6 to 0.10.7 Bumps nginxproxy/docker-gen from 0.10.6 to 0.10.7. --- updated-dependencies: - dependency-name: nginxproxy/docker-gen dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Dockerfile | 2 +- Dockerfile.alpine | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 1f77670..5c44047 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM nginxproxy/docker-gen:0.10.6-debian AS docker-gen +FROM nginxproxy/docker-gen:0.10.7-debian AS docker-gen FROM nginxproxy/forego:0.17.2-debian AS forego diff --git a/Dockerfile.alpine b/Dockerfile.alpine index a00b28f..ce2f7a6 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -1,4 +1,4 @@ -FROM nginxproxy/docker-gen:0.10.6 AS docker-gen +FROM nginxproxy/docker-gen:0.10.7 AS docker-gen FROM nginxproxy/forego:0.17.2 AS forego From 099ac04576e0692f90dca8be6ec81c68645565b1 Mon Sep 17 00:00:00 2001 From: patrickdk Date: Wed, 12 Jul 2023 23:44:40 +0200 Subject: [PATCH 220/300] feat: add new SSL policies --- README.md | 2 +- nginx.tmpl | 35 +++++++++++++++++++++++++++++------ 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 30bf591..e21d233 100644 --- a/README.md +++ b/README.md @@ -347,7 +347,7 @@ The default SSL cipher configuration is based on the [Mozilla intermediate profi If you don't require backward compatibility, you can use the [Mozilla modern profile](https://wiki.mozilla.org/Security/Server_Side_TLS#Modern_compatibility) profile instead by including the environment variable `SSL_POLICY=Mozilla-Modern` to the nginx-proxy container or to your container. This profile is compatible with clients back to Firefox 63, Android 10.0, Chrome 70, Edge 75, Java 11, OpenSSL 1.1.1, Opera 57, and Safari 12.1. Note that this profile is **not** compatible with any version of Internet Explorer. -Other policies available through the `SSL_POLICY` environment variable are [`Mozilla-Old`](https://wiki.mozilla.org/Security/Server_Side_TLS#Old_backward_compatibility) and the [AWS ELB Security Policies](https://docs.aws.amazon.com/elasticloadbalancing/latest/classic/elb-security-policy-table.html) `AWS-TLS-1-2-2017-01`, `AWS-TLS-1-1-2017-01`, `AWS-2016-08`, `AWS-2015-05`, `AWS-2015-03` and `AWS-2015-02`. +Other policies available through the `SSL_POLICY` environment variable are [`Mozilla-Old`](https://wiki.mozilla.org/Security/Server_Side_TLS#Old_backward_compatibility) and the [AWS ELB Security Policies](https://docs.aws.amazon.com/elasticloadbalancing/latest/classic/elb-security-policy-table.html) `AWS-FS-1-2-Res-2020-10`, `AWS-FS-1-2-Res-2019-08`, `AWS-FS-1-2-2019-08`, `AWS-FS-1-1-2019-08`, `AWS-FS-2018-06`, `AWS-TLS-1-2-Ext-2018-06`, `AWS-TLS-1-2-2017-01`, `AWS-TLS-1-1-2017-01`, `AWS-2016-08`, `AWS-2015-05`, `AWS-2015-03` and `AWS-2015-02`. Note that the `Mozilla-Old` policy should use a 1024 bits DH key for compatibility but this container provides a 4096 bits key. The [Diffie-Hellman Groups](#diffie-hellman-groups) section details different methods of bypassing this, either globally or per virtual-host. diff --git a/nginx.tmpl b/nginx.tmpl index db2d54b..aa46b2d 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -144,12 +144,11 @@ ssl_protocols TLSv1.3; {{- /* * nginx currently lacks ability to choose ciphers in TLS 1.3 in - * configuration; see https://trac.nginx.org/nginx/ticket/1529. A - * possible workaround can be modify /etc/ssl/openssl.cnf to change - * it globally (see - * https://trac.nginx.org/nginx/ticket/1529#comment:12). Explicitly - * set ngnix default value in order to allow single servers to - * override the global http value. + * configuration, see https://trac.nginx.org/nginx/ticket/1529. + * A possible workaround can be modify /etc/ssl/openssl.cnf to change + * it globally (see https://trac.nginx.org/nginx/ticket/1529#comment:12). + * Explicitly set nginx default value in order to allow single servers + * to override the global http value. */}} ssl_ciphers HIGH:!aNULL:!MD5; ssl_prefer_server_ciphers off; @@ -161,6 +160,30 @@ ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA256:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA'; ssl_prefer_server_ciphers on; + {{- else if eq .ssl_policy "AWS-FS-1-2-Res-2020-10" }} + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384'; + ssl_prefer_server_ciphers on; + {{- else if eq .ssl_policy "AWS-FS-1-2-Res-2019-08" }} + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384'; + ssl_prefer_server_ciphers on; + {{- else if eq .ssl_policy "AWS-FS-1-2-2019-08" }} + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA'; + ssl_prefer_server_ciphers on; + {{- else if eq .ssl_policy "AWS-FS-1-1-2019-08" }} + ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3; + ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA'; + ssl_prefer_server_ciphers on; + {{- else if eq .ssl_policy "AWS-FS-2018-06" }} + ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; + ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA'; + ssl_prefer_server_ciphers on; + {{- else if eq .ssl_policy "AWS-TLS-1-2-Ext-2018-06" }} + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:AES128-GCM-SHA256:AES128-SHA256:AES128-SHA:AES256-GCM-SHA384:AES256-SHA256:AES256-SHA'; + ssl_prefer_server_ciphers on; {{- else if eq .ssl_policy "AWS-TLS-1-2-2017-01" }} ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:AES128-GCM-SHA256:AES128-SHA256:AES256-GCM-SHA384:AES256-SHA256'; From 1535227c783164480cb919c35d16367e5f8b8794 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Wed, 12 Jul 2023 23:57:28 +0200 Subject: [PATCH 221/300] docs: up to date link to AWS ELB SSL policies --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e21d233..2dc1f64 100644 --- a/README.md +++ b/README.md @@ -347,7 +347,7 @@ The default SSL cipher configuration is based on the [Mozilla intermediate profi If you don't require backward compatibility, you can use the [Mozilla modern profile](https://wiki.mozilla.org/Security/Server_Side_TLS#Modern_compatibility) profile instead by including the environment variable `SSL_POLICY=Mozilla-Modern` to the nginx-proxy container or to your container. This profile is compatible with clients back to Firefox 63, Android 10.0, Chrome 70, Edge 75, Java 11, OpenSSL 1.1.1, Opera 57, and Safari 12.1. Note that this profile is **not** compatible with any version of Internet Explorer. -Other policies available through the `SSL_POLICY` environment variable are [`Mozilla-Old`](https://wiki.mozilla.org/Security/Server_Side_TLS#Old_backward_compatibility) and the [AWS ELB Security Policies](https://docs.aws.amazon.com/elasticloadbalancing/latest/classic/elb-security-policy-table.html) `AWS-FS-1-2-Res-2020-10`, `AWS-FS-1-2-Res-2019-08`, `AWS-FS-1-2-2019-08`, `AWS-FS-1-1-2019-08`, `AWS-FS-2018-06`, `AWS-TLS-1-2-Ext-2018-06`, `AWS-TLS-1-2-2017-01`, `AWS-TLS-1-1-2017-01`, `AWS-2016-08`, `AWS-2015-05`, `AWS-2015-03` and `AWS-2015-02`. +Other policies available through the `SSL_POLICY` environment variable are [`Mozilla-Old`](https://wiki.mozilla.org/Security/Server_Side_TLS#Old_backward_compatibility) and the [AWS ELB Security Policies](https://docs.aws.amazon.com/elasticloadbalancing/latest/application/create-https-listener.html#describe-ssl-policies) `AWS-FS-1-2-Res-2020-10`, `AWS-FS-1-2-Res-2019-08`, `AWS-FS-1-2-2019-08`, `AWS-FS-1-1-2019-08`, `AWS-FS-2018-06`, `AWS-TLS-1-2-Ext-2018-06`, `AWS-TLS-1-2-2017-01`, `AWS-TLS-1-1-2017-01`, `AWS-2016-08`, `AWS-2015-05`, `AWS-2015-03` and `AWS-2015-02`. Note that the `Mozilla-Old` policy should use a 1024 bits DH key for compatibility but this container provides a 4096 bits key. The [Diffie-Hellman Groups](#diffie-hellman-groups) section details different methods of bypassing this, either globally or per virtual-host. From 34655618a6923a6d3db6fd8de611b1aff0b8b960 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Fri, 8 Dec 2023 16:43:27 +0100 Subject: [PATCH 222/300] docs: cleanup SSL policies section --- README.md | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 74 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 2dc1f64..3d7ec44 100644 --- a/README.md +++ b/README.md @@ -347,7 +347,80 @@ The default SSL cipher configuration is based on the [Mozilla intermediate profi If you don't require backward compatibility, you can use the [Mozilla modern profile](https://wiki.mozilla.org/Security/Server_Side_TLS#Modern_compatibility) profile instead by including the environment variable `SSL_POLICY=Mozilla-Modern` to the nginx-proxy container or to your container. This profile is compatible with clients back to Firefox 63, Android 10.0, Chrome 70, Edge 75, Java 11, OpenSSL 1.1.1, Opera 57, and Safari 12.1. Note that this profile is **not** compatible with any version of Internet Explorer. -Other policies available through the `SSL_POLICY` environment variable are [`Mozilla-Old`](https://wiki.mozilla.org/Security/Server_Side_TLS#Old_backward_compatibility) and the [AWS ELB Security Policies](https://docs.aws.amazon.com/elasticloadbalancing/latest/application/create-https-listener.html#describe-ssl-policies) `AWS-FS-1-2-Res-2020-10`, `AWS-FS-1-2-Res-2019-08`, `AWS-FS-1-2-2019-08`, `AWS-FS-1-1-2019-08`, `AWS-FS-2018-06`, `AWS-TLS-1-2-Ext-2018-06`, `AWS-TLS-1-2-2017-01`, `AWS-TLS-1-1-2017-01`, `AWS-2016-08`, `AWS-2015-05`, `AWS-2015-03` and `AWS-2015-02`. +Complete list of policies available through the `SSL_POLICY` environment variable, including the [AWS ELB Security Policies](https://docs.aws.amazon.com/elasticloadbalancing/latest/application/create-https-listener.html#describe-ssl-policies) and [AWS Classic ELB security policies](https://docs.aws.amazon.com/fr_fr/elasticloadbalancing/latest/classic/elb-security-policy-table.html): + +
+ Mozilla policies + +
+
+ AWS ELB FS supported policies +
    +
  • + AWS-FS-1-2-Res-2020-10 +
  • +
  • + AWS-FS-1-2-Res-2019-08 +
  • +
  • + AWS-FS-1-2-2019-08 +
  • +
  • + AWS-FS-1-1-2019-08 +
  • +
  • + AWS-FS-2018-06 +
  • +
+
+
+ AWS ELB TLS 1.0 - 1.2 security policies +
    +
  • + AWS-TLS-1-2-Ext-2018-06 +
  • +
  • + AWS-TLS-1-2-2017-01 +
  • +
  • + AWS-TLS-1-1-2017-01 +
  • +
  • + AWS-2016-08 +
  • +
+
+
+ AWS Classic ELB security policies +
    +
  • + AWS-2015-05 +
  • +
  • + AWS-2015-03 +
  • +
  • + AWS-2015-02 +
  • +
+
+
Note that the `Mozilla-Old` policy should use a 1024 bits DH key for compatibility but this container provides a 4096 bits key. The [Diffie-Hellman Groups](#diffie-hellman-groups) section details different methods of bypassing this, either globally or per virtual-host. From 664ba246fd333e8d3ee8a7b59eabc172d6b9ca5d Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Fri, 8 Dec 2023 16:44:26 +0100 Subject: [PATCH 223/300] fix: remove unsupported TLSv1.3 from new AWS SSL policies --- nginx.tmpl | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/nginx.tmpl b/nginx.tmpl index aa46b2d..7ff31ef 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -161,27 +161,27 @@ ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA256:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA'; ssl_prefer_server_ciphers on; {{- else if eq .ssl_policy "AWS-FS-1-2-Res-2020-10" }} - ssl_protocols TLSv1.2 TLSv1.3; + ssl_protocols TLSv1.2; ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384'; ssl_prefer_server_ciphers on; {{- else if eq .ssl_policy "AWS-FS-1-2-Res-2019-08" }} - ssl_protocols TLSv1.2 TLSv1.3; + ssl_protocols TLSv1.2; ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384'; ssl_prefer_server_ciphers on; {{- else if eq .ssl_policy "AWS-FS-1-2-2019-08" }} - ssl_protocols TLSv1.2 TLSv1.3; + ssl_protocols TLSv1.2; ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA'; ssl_prefer_server_ciphers on; {{- else if eq .ssl_policy "AWS-FS-1-1-2019-08" }} - ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3; + ssl_protocols TLSv1.1 TLSv1.2; ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA'; ssl_prefer_server_ciphers on; {{- else if eq .ssl_policy "AWS-FS-2018-06" }} - ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; + ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA'; ssl_prefer_server_ciphers on; {{- else if eq .ssl_policy "AWS-TLS-1-2-Ext-2018-06" }} - ssl_protocols TLSv1.2 TLSv1.3; + ssl_protocols TLSv1.2; ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:AES128-GCM-SHA256:AES128-SHA256:AES128-SHA:AES256-GCM-SHA384:AES256-SHA256:AES256-SHA'; ssl_prefer_server_ciphers on; {{- else if eq .ssl_policy "AWS-TLS-1-2-2017-01" }} From 99aa94aa32023f278c88d24cd14ec6f1e853530a Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Fri, 8 Dec 2023 16:53:27 +0100 Subject: [PATCH 224/300] docs: HTML anchors fix --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 3d7ec44..a984069 100644 --- a/README.md +++ b/README.md @@ -353,17 +353,17 @@ Complete list of policies available through the `SSL_POLICY` environment variabl Mozilla policies
  • - + Mozilla-Modern
  • - + Mozilla-Intermediate
  • - + Mozilla-Old
  • From ec0d908a4482ab3681d93b058889a0d8e3278d29 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Fri, 8 Dec 2023 17:59:26 +0100 Subject: [PATCH 225/300] feat: add AWS TLS 1.3 security policies --- README.md | 26 ++++++++++++++++++++++++++ nginx.tmpl | 40 ++++++++++++++++++++++++++++++++++------ 2 files changed, 60 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index a984069..71c324e 100644 --- a/README.md +++ b/README.md @@ -369,6 +369,32 @@ Complete list of policies available through the `SSL_POLICY` environment variabl
+
+ AWS ELB TLS 1.3 security policies +
    +
  • + AWS-TLS13-1-3-2021-06 +
  • +
  • + AWS-TLS13-1-2-2021-06 +
  • +
  • + AWS-TLS13-1-2-Res-2021-06 +
  • +
  • + AWS-TLS13-1-2-Ext1-2021-06 +
  • +
  • + AWS-TLS13-1-2-Ext2-2021-06 +
  • +
  • + AWS-TLS13-1-1-2021-06 +
  • +
  • + AWS-TLS13-1-0-2021-06 +
  • +
+
AWS ELB FS supported policies
    diff --git a/nginx.tmpl b/nginx.tmpl index 7ff31ef..eb64b6a 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -160,6 +160,34 @@ ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA256:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA'; ssl_prefer_server_ciphers on; + {{- else if eq .ssl_policy "AWS-TLS13-1-3-2021-06" }} + ssl_protocols TLSv1.3; + ssl_ciphers 'TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256'; + ssl_prefer_server_ciphers on; + {{- else if eq .ssl_policy "AWS-TLS13-1-2-2021-06" }} + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers 'TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384'; + ssl_prefer_server_ciphers on; + {{- else if eq .ssl_policy "AWS-TLS13-1-2-Res-2021-06" }} + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers 'TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384'; + ssl_prefer_server_ciphers on; + {{- else if eq .ssl_policy "AWS-TLS13-1-2-Ext1-2021-06" }} + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers 'TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:AES128-GCM-SHA256:AES128-SHA256:AES256-GCM-SHA384:AES256-SHA256'; + ssl_prefer_server_ciphers on; + {{- else if eq .ssl_policy "AWS-TLS13-1-2-Ext2-2021-06" }} + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers 'TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:AES128-GCM-SHA256:AES128-SHA256:AES128-SHA:AES256-GCM-SHA384:AES256-SHA256:AES256-SHA'; + ssl_prefer_server_ciphers on; + {{- else if eq .ssl_policy "AWS-TLS13-1-1-2021-06" }} + ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3; + ssl_ciphers 'TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:AES128-GCM-SHA256:AES128-SHA256:AES128-SHA:AES256-GCM-SHA384:AES256-SHA256:AES256-SHA'; + ssl_prefer_server_ciphers on; + {{- else if eq .ssl_policy "AWS-TLS13-1-0-2021-06" }} + ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; + ssl_ciphers 'TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:AES128-GCM-SHA256:AES128-SHA256:AES128-SHA:AES256-GCM-SHA384:AES256-SHA256:AES256-SHA'; + ssl_prefer_server_ciphers on; {{- else if eq .ssl_policy "AWS-FS-1-2-Res-2020-10" }} ssl_protocols TLSv1.2; ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384'; @@ -185,27 +213,27 @@ ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:AES128-GCM-SHA256:AES128-SHA256:AES128-SHA:AES256-GCM-SHA384:AES256-SHA256:AES256-SHA'; ssl_prefer_server_ciphers on; {{- else if eq .ssl_policy "AWS-TLS-1-2-2017-01" }} - ssl_protocols TLSv1.2 TLSv1.3; + ssl_protocols TLSv1.2; ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:AES128-GCM-SHA256:AES128-SHA256:AES256-GCM-SHA384:AES256-SHA256'; ssl_prefer_server_ciphers on; {{- else if eq .ssl_policy "AWS-TLS-1-1-2017-01" }} - ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3; + ssl_protocols TLSv1.1 TLSv1.2; ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:AES128-GCM-SHA256:AES128-SHA256:AES128-SHA:AES256-GCM-SHA384:AES256-SHA256:AES256-SHA'; ssl_prefer_server_ciphers on; {{- else if eq .ssl_policy "AWS-2016-08" }} - ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; + ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:AES128-GCM-SHA256:AES128-SHA256:AES128-SHA:AES256-GCM-SHA384:AES256-SHA256:AES256-SHA'; ssl_prefer_server_ciphers on; {{- else if eq .ssl_policy "AWS-2015-05" }} - ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; + ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:AES128-GCM-SHA256:AES128-SHA256:AES128-SHA:AES256-GCM-SHA384:AES256-SHA256:AES256-SHA:DES-CBC3-SHA'; ssl_prefer_server_ciphers on; {{- else if eq .ssl_policy "AWS-2015-03" }} - ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; + ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:AES128-GCM-SHA256:AES128-SHA256:AES128-SHA:AES256-GCM-SHA384:AES256-SHA256:AES256-SHA:DHE-DSS-AES128-SHA:DES-CBC3-SHA'; ssl_prefer_server_ciphers on; {{- else if eq .ssl_policy "AWS-2015-02" }} - ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; + ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:AES128-GCM-SHA256:AES128-SHA256:AES128-SHA:AES256-GCM-SHA384:AES256-SHA256:AES256-SHA:DHE-DSS-AES128-SHA'; ssl_prefer_server_ciphers on; {{- end }} From c6868ed6be0b6371067c204f6ec26dcd96a1f2c2 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Fri, 8 Dec 2023 22:06:07 +0100 Subject: [PATCH 226/300] fix: SSL cipher suites / TLSv1.3 --- nginx.tmpl | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/nginx.tmpl b/nginx.tmpl index eb64b6a..75087dc 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -162,31 +162,32 @@ ssl_prefer_server_ciphers on; {{- else if eq .ssl_policy "AWS-TLS13-1-3-2021-06" }} ssl_protocols TLSv1.3; - ssl_ciphers 'TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256'; + ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384; + ssl_conf_command Ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256; ssl_prefer_server_ciphers on; {{- else if eq .ssl_policy "AWS-TLS13-1-2-2021-06" }} ssl_protocols TLSv1.2 TLSv1.3; - ssl_ciphers 'TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384'; + ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384'; ssl_prefer_server_ciphers on; {{- else if eq .ssl_policy "AWS-TLS13-1-2-Res-2021-06" }} ssl_protocols TLSv1.2 TLSv1.3; - ssl_ciphers 'TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384'; + ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384'; ssl_prefer_server_ciphers on; {{- else if eq .ssl_policy "AWS-TLS13-1-2-Ext1-2021-06" }} ssl_protocols TLSv1.2 TLSv1.3; - ssl_ciphers 'TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:AES128-GCM-SHA256:AES128-SHA256:AES256-GCM-SHA384:AES256-SHA256'; + ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:AES128-GCM-SHA256:AES128-SHA256:AES256-GCM-SHA384:AES256-SHA256'; ssl_prefer_server_ciphers on; {{- else if eq .ssl_policy "AWS-TLS13-1-2-Ext2-2021-06" }} ssl_protocols TLSv1.2 TLSv1.3; - ssl_ciphers 'TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:AES128-GCM-SHA256:AES128-SHA256:AES128-SHA:AES256-GCM-SHA384:AES256-SHA256:AES256-SHA'; + ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:AES128-GCM-SHA256:AES128-SHA256:AES128-SHA:AES256-GCM-SHA384:AES256-SHA256:AES256-SHA'; ssl_prefer_server_ciphers on; {{- else if eq .ssl_policy "AWS-TLS13-1-1-2021-06" }} ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3; - ssl_ciphers 'TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:AES128-GCM-SHA256:AES128-SHA256:AES128-SHA:AES256-GCM-SHA384:AES256-SHA256:AES256-SHA'; + ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:AES128-GCM-SHA256:AES128-SHA256:AES128-SHA:AES256-GCM-SHA384:AES256-SHA256:AES256-SHA'; ssl_prefer_server_ciphers on; {{- else if eq .ssl_policy "AWS-TLS13-1-0-2021-06" }} ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; - ssl_ciphers 'TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:AES128-GCM-SHA256:AES128-SHA256:AES128-SHA:AES256-GCM-SHA384:AES256-SHA256:AES256-SHA'; + ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:AES128-GCM-SHA256:AES128-SHA256:AES128-SHA:AES256-GCM-SHA384:AES256-SHA256:AES256-SHA'; ssl_prefer_server_ciphers on; {{- else if eq .ssl_policy "AWS-FS-1-2-Res-2020-10" }} ssl_protocols TLSv1.2; From 4c556290f9ec21e4648ed85a1bb7f89cdcef26c2 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Fri, 8 Dec 2023 22:41:29 +0100 Subject: [PATCH 227/300] fix: enforce TLSv1.3 on Mozilla-Modern SSL policy --- nginx.tmpl | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/nginx.tmpl b/nginx.tmpl index 75087dc..f830fd2 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -142,15 +142,12 @@ {{- define "ssl_policy" }} {{- if eq .ssl_policy "Mozilla-Modern" }} ssl_protocols TLSv1.3; - {{- /* - * nginx currently lacks ability to choose ciphers in TLS 1.3 in - * configuration, see https://trac.nginx.org/nginx/ticket/1529. - * A possible workaround can be modify /etc/ssl/openssl.cnf to change - * it globally (see https://trac.nginx.org/nginx/ticket/1529#comment:12). - * Explicitly set nginx default value in order to allow single servers - * to override the global http value. - */}} - ssl_ciphers HIGH:!aNULL:!MD5; + {{- /* + * This ssl_ciphers directive is not used but necessary to get TLSv1.3 only. + * see https://serverfault.com/questions/1023766/nginx-with-only-tls1-3-cipher-suites + */}} + ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384; + ssl_conf_command Ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256; ssl_prefer_server_ciphers off; {{- else if eq .ssl_policy "Mozilla-Intermediate" }} ssl_protocols TLSv1.2 TLSv1.3; @@ -162,6 +159,10 @@ ssl_prefer_server_ciphers on; {{- else if eq .ssl_policy "AWS-TLS13-1-3-2021-06" }} ssl_protocols TLSv1.3; + {{- /* + * This ssl_ciphers directive is not used but necessary to get TLSv1.3 only. + * see https://serverfault.com/questions/1023766/nginx-with-only-tls1-3-cipher-suites + */}} ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384; ssl_conf_command Ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256; ssl_prefer_server_ciphers on; From c06593bdcb7be07b41cf5c0624155ccdfa87d5ee Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Dec 2023 04:09:41 +0000 Subject: [PATCH 228/300] ci: bump actions/setup-python from 4 to 5 Bumps [actions/setup-python](https://github.com/actions/setup-python) from 4 to 5. - [Release notes](https://github.com/actions/setup-python/releases) - [Commits](https://github.com/actions/setup-python/compare/v4...v5) --- updated-dependencies: - dependency-name: actions/setup-python dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 2d8db92..36e6273 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -26,7 +26,7 @@ jobs: - uses: actions/checkout@v4 - name: Set up Python 3.9 - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: 3.9 From b5cac063058c195e87ed87f8f70e1a56111f7aef Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Mon, 11 Dec 2023 13:54:28 +0100 Subject: [PATCH 229/300] ci: remove python docker-compose --- README.md | 6 +++--- test/README.md | 6 +++--- test/conftest.py | 16 ++++++++-------- test/pytest.sh | 4 ++-- test/requirements/python-requirements.txt | 1 - test/test_wildcard_host.yml | 2 +- 6 files changed, 17 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 71c324e..6ff07f0 100644 --- a/README.md +++ b/README.md @@ -73,7 +73,7 @@ services: ``` ```console -docker-compose up +docker compose up curl -H "Host: whoami.example" localhost ``` @@ -259,10 +259,10 @@ nginx-proxy can also be run as two separate containers using the [nginxproxy/doc You may want to do this to prevent having the docker socket bound to a publicly exposed container service. -You can demo this pattern with docker-compose: +You can demo this pattern with docker compose: ```console -docker-compose --file docker-compose-separate-containers.yml up +docker compose --file docker-compose-separate-containers.yml up curl -H "Host: whoami.example" localhost ``` diff --git a/test/README.md b/test/README.md index 99d16db..5a93e1b 100644 --- a/test/README.md +++ b/test/README.md @@ -48,11 +48,11 @@ This test suite uses [pytest](http://doc.pytest.org/en/latest/). The [conftest.p When using the `docker_compose` fixture in a test, pytest will try to find a yml file named after your test module filename. For instance, if your test module is `test_example.py`, then the `docker_compose` fixture will try to load a `test_example.yml` [docker compose file](https://docs.docker.com/compose/compose-file/). -Once the docker compose file found, the fixture will remove all containers, run `docker-compose up`, and finally your test will be executed. +Once the docker compose file found, the fixture will remove all containers, run `docker compose up`, and finally your test will be executed. -The fixture will run the _docker-compose_ command with the `-f` option to load the given compose file. So you can test your docker compose file syntax by running it yourself with: +The fixture will run the _docker compose_ command with the `-f` option to load the given compose file. So you can test your docker compose file syntax by running it yourself with: - docker-compose -f test_example.yml up -d + docker compose -f test_example.yml up -d In the case you are running pytest from within a docker container, the `docker_compose` fixture will make sure the container running pytest is attached to all docker networks. That way, your test will be able to reach any of them. diff --git a/test/conftest.py b/test/conftest.py index f73b7c0..938be6b 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -301,19 +301,19 @@ def get_nginx_conf_from_container(container): def docker_compose_up(compose_file='docker-compose.yml'): - logging.info(f'docker-compose -f {compose_file} up -d') + logging.info(f'docker compose -f {compose_file} up -d') try: - subprocess.check_output(shlex.split(f'docker-compose -f {compose_file} up -d'), stderr=subprocess.STDOUT) + subprocess.check_output(shlex.split(f'docker compose -f {compose_file} up -d'), stderr=subprocess.STDOUT) except subprocess.CalledProcessError as e: - pytest.fail(f"Error while runninng 'docker-compose -f {compose_file} up -d':\n{e.output}", pytrace=False) + pytest.fail(f"Error while runninng 'docker compose -f {compose_file} up -d':\n{e.output}", pytrace=False) def docker_compose_down(compose_file='docker-compose.yml'): - logging.info(f'docker-compose -f {compose_file} down -v') + logging.info(f'docker compose -f {compose_file} down -v') try: - subprocess.check_output(shlex.split(f'docker-compose -f {compose_file} down -v'), stderr=subprocess.STDOUT) + subprocess.check_output(shlex.split(f'docker compose -f {compose_file} down -v'), stderr=subprocess.STDOUT) except subprocess.CalledProcessError as e: - pytest.fail(f"Error while runninng 'docker-compose -f {compose_file} down -v':\n{e.output}", pytrace=False) + pytest.fail(f"Error while runninng 'docker compose -f {compose_file} down -v':\n{e.output}", pytrace=False) def wait_for_nginxproxy_to_be_ready(): @@ -333,7 +333,7 @@ def wait_for_nginxproxy_to_be_ready(): @pytest.fixture def docker_compose_file(request): - """Fixture naming the docker-compose file to consider. + """Fixture naming the docker compose file to consider. If a YAML file exists with the same name as the test module (with the `.py` extension replaced with `.yml` or `.yaml`), use that. Otherwise, use `docker-compose.yml` in the same directory @@ -354,7 +354,7 @@ def docker_compose_file(request): docker_compose_file = default_file if not os.path.isfile(docker_compose_file): - logging.error("Could not find any docker-compose file named either '{0}.yml', '{0}.yaml' or 'docker-compose.yml'".format(request.module.__name__)) + logging.error("Could not find any docker compose file named either '{0}.yml', '{0}.yaml' or 'docker-compose.yml'".format(request.module.__name__)) logging.debug(f"using docker compose file {docker_compose_file}") return docker_compose_file diff --git a/test/pytest.sh b/test/pytest.sh index 19a8188..9cbe750 100755 --- a/test/pytest.sh +++ b/test/pytest.sh @@ -19,8 +19,8 @@ docker build --pull -t nginx-proxy-tester \ "${TESTDIR}/requirements" \ || exit 1 -# run the nginx-proxy-tester container setting the correct value for the working dir in order for -# docker-compose to work properly when run from within that container. +# run the nginx-proxy-tester container setting the correct value for the working dir +# in order for docker compose to work properly when run from within that container. exec docker run --rm -it --name "nginx-proxy-pytest" \ --volume "/var/run/docker.sock:/var/run/docker.sock" \ --volume "${DIR}:${DIR}" \ diff --git a/test/requirements/python-requirements.txt b/test/requirements/python-requirements.txt index 15182fd..079a74e 100644 --- a/test/requirements/python-requirements.txt +++ b/test/requirements/python-requirements.txt @@ -1,5 +1,4 @@ backoff==2.2.1 -docker-compose==1.29.2 docker==6.1.3 pytest==7.4.3 requests==2.31.0 diff --git a/test/test_wildcard_host.yml b/test/test_wildcard_host.yml index b745e31..cd66873 100644 --- a/test/test_wildcard_host.yml +++ b/test/test_wildcard_host.yml @@ -28,7 +28,7 @@ web4: - "84" environment: WEB_PORTS: "84" - VIRTUAL_HOST: ~^web4\..*\.nginx-proxy\.regexp$$ # we need to double the `$` because of docker-compose variable interpolation + VIRTUAL_HOST: ~^web4\..*\.nginx-proxy\.regexp$$ # we need to double the `$` because of docker compose variable interpolation sut: From 060f09cfce3e7cb8da1722ebdb1300f752e5ef71 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Mon, 11 Dec 2023 14:25:04 +0100 Subject: [PATCH 230/300] ci: ensure all compose files are valid compose v2 + formatting --- docker-compose-separate-containers.yml | 3 +- docker-compose.yml | 3 +- .../test_deleted_cert/docker-compose.yml | 28 ++-- .../docker-compose.yml | 1 - test/test_DOCKER_HOST_unix_socket.yml | 42 +++--- test/test_composev2.yml | 3 +- test/test_custom/test_defaults-location.yml | 57 ++++---- test/test_custom/test_defaults.yml | 3 +- test/test_custom/test_location-per-vhost.yml | 3 +- test/test_custom/test_per-vhost.yml | 3 +- test/test_custom/test_proxy-wide.yml | 3 +- test/test_default-host.yml | 32 +++-- test/test_default-root-none.yml | 3 + test/test_dockergen/test_dockergen_v2.yml | 2 +- test/test_dockergen/test_dockergen_v3.yml | 3 +- test/test_events.yml | 11 +- test/test_fallback.data/custom-fallback.yml | 3 + test/test_fallback.data/nodefault.yml | 6 + test/test_fallback.data/nohttp-on-app.yml | 3 + .../nohttp-with-missing-cert.yml | 4 + test/test_fallback.data/nohttp.yml | 3 + test/test_fallback.data/nohttps-on-app.yml | 3 + test/test_fallback.data/nohttps.yml | 3 + test/test_fallback.data/withdefault.yml | 6 + test/test_headers/test_http.yml | 40 +++--- test/test_headers/test_https.yml | 52 +++---- .../test_http2/test_http2_global_disabled.yml | 2 + .../test_http3/test_http3_global_disabled.yml | 4 +- test/test_http3/test_http3_global_enabled.yml | 2 + test/test_http3/test_http3_vhost.yml | 2 + test/test_http_port.yml | 29 ++-- .../test_internal/test_internal-per-vhost.yml | 42 +++--- .../test_internal/test_internal-per-vpath.yml | 50 +++---- test/test_ipv6.yml | 3 +- test/test_keepalive.yml | 46 +++--- test/test_loadbalancing.yml | 2 + test/test_location-override.yml | 2 + test/test_log_format.yml | 31 ++-- test/test_multiple-hosts.yml | 24 ++-- test/test_multiple-networks.yml | 2 +- ...PORT-single-different-from-single-port.yml | 26 ++-- .../test_multiple-ports/test_VIRTUAL_PORT.yml | 29 ++-- test/test_multiple-ports/test_default-80.yml | 27 ++-- .../test_single-port-not-80.yml | 24 ++-- test/test_nominal.yml | 3 +- test/test_raw-ip-vhost.yml | 4 +- test/test_server-down/test_load-balancing.yml | 55 ++++---- test/test_server-down/test_no-server-down.yml | 25 ++-- test/test_server-down/test_server-down.yml | 27 ++-- test/test_ssl/test_dhparam.yml | 132 +++++++++--------- test/test_ssl/test_hsts.yml | 95 +++++++------ test/test_ssl/test_https_port.yml | 33 +++-- test/test_ssl/test_nohttp.yml | 28 ++-- test/test_ssl/test_nohttps.yml | 26 ++-- test/test_ssl/test_noredirect.yml | 28 ++-- test/test_ssl/test_virtual_path.yml | 48 ++++--- test/test_ssl/test_wildcard.yml | 27 ++-- .../test_default.yml | 30 ++-- .../test_disabled.yml | 34 ++--- .../test_enabled.yml | 34 ++--- .../test_predictable-name.yml | 2 +- test/test_upstream-name/test_sha1-name.yml | 2 +- test/test_vhost-empty-string.yml | 6 + test/test_vhost-in-multiple-networks.yml | 2 +- test/test_virtual-path/test_custom_conf.yml | 87 ++++++------ test/test_virtual-path/test_forwarding.yml | 35 ++--- .../test_location_precedence.yml | 71 +++++----- test/test_virtual-path/test_virtual_paths.yml | 76 +++++----- test/test_wildcard_host.yml | 66 ++++----- 69 files changed, 894 insertions(+), 752 deletions(-) diff --git a/docker-compose-separate-containers.yml b/docker-compose-separate-containers.yml index 4277632..5a64895 100644 --- a/docker-compose-separate-containers.yml +++ b/docker-compose-separate-containers.yml @@ -1,4 +1,5 @@ -version: '2' +version: "2" + services: nginx: image: nginx diff --git a/docker-compose.yml b/docker-compose.yml index 931c364..809d6fa 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,4 +1,5 @@ -version: '2' +version: "2" + services: nginx-proxy: image: nginxproxy/nginx-proxy diff --git a/test/stress_tests/test_deleted_cert/docker-compose.yml b/test/stress_tests/test_deleted_cert/docker-compose.yml index a42abac..a362e44 100644 --- a/test/stress_tests/test_deleted_cert/docker-compose.yml +++ b/test/stress_tests/test_deleted_cert/docker-compose.yml @@ -1,15 +1,17 @@ -web: - image: web - expose: - - "81" - environment: - WEB_PORTS: 81 - VIRTUAL_HOST: web.nginx-proxy +version: "2" +services: + web: + image: web + expose: + - "81" + environment: + WEB_PORTS: 81 + VIRTUAL_HOST: web.nginx-proxy -reverseproxy: - image: nginxproxy/nginx-proxy:test - container_name: reverseproxy - volumes: - - /var/run/docker.sock:/tmp/docker.sock:ro - - ./tmp_certs:/etc/nginx/certs:ro + reverseproxy: + image: nginxproxy/nginx-proxy:test + container_name: reverseproxy + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro + - ./tmp_certs:/etc/nginx/certs:ro diff --git a/test/stress_tests/test_unreachable_network/docker-compose.yml b/test/stress_tests/test_unreachable_network/docker-compose.yml index 9666d29..f90a441 100644 --- a/test/stress_tests/test_unreachable_network/docker-compose.yml +++ b/test/stress_tests/test_unreachable_network/docker-compose.yml @@ -32,4 +32,3 @@ services: environment: WEB_PORTS: 82 VIRTUAL_HOST: webB.nginx-proxy - diff --git a/test/test_DOCKER_HOST_unix_socket.yml b/test/test_DOCKER_HOST_unix_socket.yml index 1563872..caeaa2a 100644 --- a/test/test_DOCKER_HOST_unix_socket.yml +++ b/test/test_DOCKER_HOST_unix_socket.yml @@ -1,23 +1,25 @@ -web1: - image: web - expose: - - "81" - environment: - WEB_PORTS: 81 - VIRTUAL_HOST: web1.nginx-proxy.tld +version: "2" -web2: - image: web - expose: - - "82" - environment: - WEB_PORTS: 82 - VIRTUAL_HOST: web2.nginx-proxy.tld +services: + 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 -sut: - image: nginxproxy/nginx-proxy:test - volumes: - - /var/run/docker.sock:/f00.sock:ro - environment: - DOCKER_HOST: unix:///f00.sock + sut: + image: nginxproxy/nginx-proxy:test + volumes: + - /var/run/docker.sock:/f00.sock:ro + environment: + DOCKER_HOST: unix:///f00.sock diff --git a/test/test_composev2.yml b/test/test_composev2.yml index dff434c..3c36022 100644 --- a/test/test_composev2.yml +++ b/test/test_composev2.yml @@ -1,4 +1,5 @@ -version: '2' +version: "2" + services: nginx-proxy: image: nginxproxy/nginx-proxy:test diff --git a/test/test_custom/test_defaults-location.yml b/test/test_custom/test_defaults-location.yml index 195d232..9a3ab44 100644 --- a/test/test_custom/test_defaults-location.yml +++ b/test/test_custom/test_defaults-location.yml @@ -1,30 +1,33 @@ -nginx-proxy: - 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_bar.conf:/etc/nginx/vhost.d/web3.nginx-proxy.example_location:ro +version: "2" -web1: - image: web - expose: - - "81" - environment: - WEB_PORTS: 81 - VIRTUAL_HOST: web1.nginx-proxy.example +services: + nginx-proxy: + 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_bar.conf:/etc/nginx/vhost.d/web3.nginx-proxy.example_location:ro -web2: - image: web - expose: - - "82" - environment: - WEB_PORTS: 82 - VIRTUAL_HOST: web2.nginx-proxy.example + web1: + image: web + expose: + - "81" + environment: + WEB_PORTS: 81 + VIRTUAL_HOST: web1.nginx-proxy.example -web3: - image: web - expose: - - "83" - environment: - WEB_PORTS: 83 - VIRTUAL_HOST: web3.nginx-proxy.example + web2: + image: web + expose: + - "82" + environment: + WEB_PORTS: 82 + VIRTUAL_HOST: web2.nginx-proxy.example + + web3: + image: web + expose: + - "83" + environment: + WEB_PORTS: 83 + VIRTUAL_HOST: web3.nginx-proxy.example diff --git a/test/test_custom/test_defaults.yml b/test/test_custom/test_defaults.yml index 2983e25..d6a959a 100644 --- a/test/test_custom/test_defaults.yml +++ b/test/test_custom/test_defaults.yml @@ -1,4 +1,5 @@ -version: '2' +version: "2" + services: nginx-proxy: image: nginxproxy/nginx-proxy:test diff --git a/test/test_custom/test_location-per-vhost.yml b/test/test_custom/test_location-per-vhost.yml index 6bf69f9..5294308 100644 --- a/test/test_custom/test_location-per-vhost.yml +++ b/test/test_custom/test_location-per-vhost.yml @@ -1,4 +1,5 @@ -version: '2' +version: "2" + services: nginx-proxy: image: nginxproxy/nginx-proxy:test diff --git a/test/test_custom/test_per-vhost.yml b/test/test_custom/test_per-vhost.yml index e7e50b4..63d33b2 100644 --- a/test/test_custom/test_per-vhost.yml +++ b/test/test_custom/test_per-vhost.yml @@ -1,4 +1,5 @@ -version: '2' +version: "2" + services: nginx-proxy: image: nginxproxy/nginx-proxy:test diff --git a/test/test_custom/test_proxy-wide.yml b/test/test_custom/test_proxy-wide.yml index 0c4a2a0..1322bcd 100644 --- a/test/test_custom/test_proxy-wide.yml +++ b/test/test_custom/test_proxy-wide.yml @@ -1,4 +1,5 @@ -version: '2' +version: "2" + services: nginx-proxy: image: nginxproxy/nginx-proxy:test diff --git a/test/test_default-host.yml b/test/test_default-host.yml index 2cb94d9..405bb08 100644 --- a/test/test_default-host.yml +++ b/test/test_default-host.yml @@ -1,17 +1,19 @@ -# GIVEN a webserver with VIRTUAL_HOST set to web1.tld -web1: - image: web - expose: - - "81" - environment: - WEB_PORTS: 81 - VIRTUAL_HOST: web1.tld +version: "2" +services: + # GIVEN a webserver with VIRTUAL_HOST set to web1.tld + web1: + image: web + expose: + - "81" + environment: + WEB_PORTS: 81 + VIRTUAL_HOST: web1.tld -# WHEN nginx-proxy runs with DEFAULT_HOST set to web1.tld -sut: - image: nginxproxy/nginx-proxy:test - volumes: - - /var/run/docker.sock:/tmp/docker.sock:ro - environment: - DEFAULT_HOST: web1.tld + # WHEN nginx-proxy runs with DEFAULT_HOST set to web1.tld + sut: + image: nginxproxy/nginx-proxy:test + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro + environment: + DEFAULT_HOST: web1.tld diff --git a/test/test_default-root-none.yml b/test/test_default-root-none.yml index 309d2ab..f0172e8 100644 --- a/test/test_default-root-none.yml +++ b/test/test_default-root-none.yml @@ -1,3 +1,5 @@ +version: "2" + services: sut: image: nginxproxy/nginx-proxy:test @@ -5,6 +7,7 @@ services: - /var/run/docker.sock:/tmp/docker.sock:ro environment: DEFAULT_ROOT: none + web: image: web expose: diff --git a/test/test_dockergen/test_dockergen_v2.yml b/test/test_dockergen/test_dockergen_v2.yml index 36ee1c1..f98992f 100644 --- a/test/test_dockergen/test_dockergen_v2.yml +++ b/test/test_dockergen/test_dockergen_v2.yml @@ -1,4 +1,4 @@ -version: '2' +version: "2" services: nginx: diff --git a/test/test_dockergen/test_dockergen_v3.yml b/test/test_dockergen/test_dockergen_v3.yml index 8b0411c..7e4aef8 100644 --- a/test/test_dockergen/test_dockergen_v3.yml +++ b/test/test_dockergen/test_dockergen_v3.yml @@ -1,4 +1,5 @@ -version: '3' +version: "3" + services: nginx: image: nginx diff --git a/test/test_events.yml b/test/test_events.yml index 260529e..ac27e1d 100644 --- a/test/test_events.yml +++ b/test/test_events.yml @@ -1,4 +1,7 @@ -nginxproxy: - image: nginxproxy/nginx-proxy:test - volumes: - - /var/run/docker.sock:/tmp/docker.sock:ro +version: "2" + +services: + nginxproxy: + image: nginxproxy/nginx-proxy:test + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro diff --git a/test/test_fallback.data/custom-fallback.yml b/test/test_fallback.data/custom-fallback.yml index bc44b11..a150441 100644 --- a/test/test_fallback.data/custom-fallback.yml +++ b/test/test_fallback.data/custom-fallback.yml @@ -1,9 +1,12 @@ +version: "2" + services: sut: image: nginxproxy/nginx-proxy:test volumes: - /var/run/docker.sock:/tmp/docker.sock:ro - ./custom-fallback.conf:/etc/nginx/conf.d/zzz-custom-fallback.conf:ro + http-only: image: web expose: diff --git a/test/test_fallback.data/nodefault.yml b/test/test_fallback.data/nodefault.yml index ecd4359..6397a0b 100644 --- a/test/test_fallback.data/nodefault.yml +++ b/test/test_fallback.data/nodefault.yml @@ -1,9 +1,12 @@ +version: "2" + services: sut: image: nginxproxy/nginx-proxy:test volumes: - /var/run/docker.sock:/tmp/docker.sock:ro - ./nodefault.certs:/etc/nginx/certs:ro + https-and-http: image: web expose: @@ -11,6 +14,7 @@ services: environment: WEB_PORTS: "81" VIRTUAL_HOST: https-and-http.nginx-proxy.test + https-only: image: web expose: @@ -19,6 +23,7 @@ services: WEB_PORTS: "82" VIRTUAL_HOST: https-only.nginx-proxy.test HTTPS_METHOD: nohttp + http-only: image: web expose: @@ -27,6 +32,7 @@ services: WEB_PORTS: "83" VIRTUAL_HOST: http-only.nginx-proxy.test HTTPS_METHOD: nohttps + missing-cert: image: web expose: diff --git a/test/test_fallback.data/nohttp-on-app.yml b/test/test_fallback.data/nohttp-on-app.yml index d81c9ca..b6ca82a 100644 --- a/test/test_fallback.data/nohttp-on-app.yml +++ b/test/test_fallback.data/nohttp-on-app.yml @@ -1,3 +1,5 @@ +version: "2" + services: sut: image: nginxproxy/nginx-proxy:test @@ -6,6 +8,7 @@ services: - ./withdefault.certs:/etc/nginx/certs:ro environment: HTTPS_METHOD: redirect + https-only: image: web expose: diff --git a/test/test_fallback.data/nohttp-with-missing-cert.yml b/test/test_fallback.data/nohttp-with-missing-cert.yml index 3593a32..70ece7b 100644 --- a/test/test_fallback.data/nohttp-with-missing-cert.yml +++ b/test/test_fallback.data/nohttp-with-missing-cert.yml @@ -1,3 +1,5 @@ +version: "2" + services: sut: image: nginxproxy/nginx-proxy:test @@ -6,6 +8,7 @@ services: - ./withdefault.certs:/etc/nginx/certs:ro environment: HTTPS_METHOD: nohttp + https-only: image: web expose: @@ -13,6 +16,7 @@ services: environment: WEB_PORTS: "82" VIRTUAL_HOST: https-only.nginx-proxy.test + missing-cert: image: web expose: diff --git a/test/test_fallback.data/nohttp.yml b/test/test_fallback.data/nohttp.yml index 3ed0c0e..9d47d51 100644 --- a/test/test_fallback.data/nohttp.yml +++ b/test/test_fallback.data/nohttp.yml @@ -1,3 +1,5 @@ +version: "2" + services: sut: image: nginxproxy/nginx-proxy:test @@ -6,6 +8,7 @@ services: - ./withdefault.certs:/etc/nginx/certs:ro environment: HTTPS_METHOD: nohttp + https-only: image: web expose: diff --git a/test/test_fallback.data/nohttps-on-app.yml b/test/test_fallback.data/nohttps-on-app.yml index 690d656..966154c 100644 --- a/test/test_fallback.data/nohttps-on-app.yml +++ b/test/test_fallback.data/nohttps-on-app.yml @@ -1,3 +1,5 @@ +version: "2" + services: sut: image: nginxproxy/nginx-proxy:test @@ -5,6 +7,7 @@ services: - /var/run/docker.sock:/tmp/docker.sock:ro environment: HTTPS_METHOD: redirect + http-only: image: web expose: diff --git a/test/test_fallback.data/nohttps.yml b/test/test_fallback.data/nohttps.yml index f07ddf9..c733492 100644 --- a/test/test_fallback.data/nohttps.yml +++ b/test/test_fallback.data/nohttps.yml @@ -1,3 +1,5 @@ +version: "2" + services: sut: image: nginxproxy/nginx-proxy:test @@ -5,6 +7,7 @@ services: - /var/run/docker.sock:/tmp/docker.sock:ro environment: HTTPS_METHOD: nohttps + http-only: image: web expose: diff --git a/test/test_fallback.data/withdefault.yml b/test/test_fallback.data/withdefault.yml index 00f7ee7..46ab126 100644 --- a/test/test_fallback.data/withdefault.yml +++ b/test/test_fallback.data/withdefault.yml @@ -1,9 +1,12 @@ +version: "2" + services: sut: image: nginxproxy/nginx-proxy:test volumes: - /var/run/docker.sock:/tmp/docker.sock:ro - ./withdefault.certs:/etc/nginx/certs:ro + https-and-http: image: web expose: @@ -11,6 +14,7 @@ services: environment: WEB_PORTS: "81" VIRTUAL_HOST: https-and-http.nginx-proxy.test + https-only: image: web expose: @@ -19,6 +23,7 @@ services: WEB_PORTS: "82" VIRTUAL_HOST: https-only.nginx-proxy.test HTTPS_METHOD: nohttp + http-only: image: web expose: @@ -27,6 +32,7 @@ services: WEB_PORTS: "83" VIRTUAL_HOST: http-only.nginx-proxy.test HTTPS_METHOD: nohttps + missing-cert: image: web expose: diff --git a/test/test_headers/test_http.yml b/test/test_headers/test_http.yml index 93795dc..fa59840 100644 --- a/test/test_headers/test_http.yml +++ b/test/test_headers/test_http.yml @@ -1,22 +1,24 @@ -web: - image: web - expose: - - "80" - environment: - WEB_PORTS: 80 - VIRTUAL_HOST: web.nginx-proxy.tld +version: "2" -web-server-tokens-off: - image: web - expose: - - "80" - environment: - WEB_PORTS: 80 - VIRTUAL_HOST: web-server-tokens-off.nginx-proxy.tld - SERVER_TOKENS: "off" +services: + web: + image: web + expose: + - "80" + environment: + WEB_PORTS: 80 + VIRTUAL_HOST: web.nginx-proxy.tld + web-server-tokens-off: + image: web + expose: + - "80" + environment: + WEB_PORTS: 80 + VIRTUAL_HOST: web-server-tokens-off.nginx-proxy.tld + SERVER_TOKENS: "off" -sut: - image: nginxproxy/nginx-proxy:test - volumes: - - /var/run/docker.sock:/tmp/docker.sock:ro + sut: + image: nginxproxy/nginx-proxy:test + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro diff --git a/test/test_headers/test_https.yml b/test/test_headers/test_https.yml index 49dcec4..0300d43 100644 --- a/test/test_headers/test_https.yml +++ b/test/test_headers/test_https.yml @@ -1,28 +1,30 @@ -web: - image: web - expose: - - "80" - environment: - WEB_PORTS: 80 - VIRTUAL_HOST: web.nginx-proxy.tld +version: "2" -web-server-tokens-off: - image: web - expose: - - "80" - environment: - WEB_PORTS: 80 - VIRTUAL_HOST: web-server-tokens-off.nginx-proxy.tld - SERVER_TOKENS: "off" +services: + web: + image: web + expose: + - "80" + environment: + WEB_PORTS: 80 + VIRTUAL_HOST: web.nginx-proxy.tld + web-server-tokens-off: + image: web + expose: + - "80" + environment: + WEB_PORTS: 80 + VIRTUAL_HOST: web-server-tokens-off.nginx-proxy.tld + SERVER_TOKENS: "off" -sut: - image: nginxproxy/nginx-proxy:test - volumes: - - /var/run/docker.sock:/tmp/docker.sock:ro - - ./certs/web.nginx-proxy.tld.crt:/etc/nginx/certs/default.crt:ro - - ./certs/web.nginx-proxy.tld.key:/etc/nginx/certs/default.key:ro - - ./certs/web.nginx-proxy.tld.crt:/etc/nginx/certs/web.nginx-proxy.tld.crt:ro - - ./certs/web.nginx-proxy.tld.key:/etc/nginx/certs/web.nginx-proxy.tld.key:ro - - ./certs/web-server-tokens-off.nginx-proxy.tld.crt:/etc/nginx/certs/web-server-tokens-off.nginx-proxy.tld.crt:ro - - ./certs/web-server-tokens-off.nginx-proxy.tld.key:/etc/nginx/certs/web-server-tokens-off.nginx-proxy.tld.key:ro + sut: + image: nginxproxy/nginx-proxy:test + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro + - ./certs/web.nginx-proxy.tld.crt:/etc/nginx/certs/default.crt:ro + - ./certs/web.nginx-proxy.tld.key:/etc/nginx/certs/default.key:ro + - ./certs/web.nginx-proxy.tld.crt:/etc/nginx/certs/web.nginx-proxy.tld.crt:ro + - ./certs/web.nginx-proxy.tld.key:/etc/nginx/certs/web.nginx-proxy.tld.key:ro + - ./certs/web-server-tokens-off.nginx-proxy.tld.crt:/etc/nginx/certs/web-server-tokens-off.nginx-proxy.tld.crt:ro + - ./certs/web-server-tokens-off.nginx-proxy.tld.key:/etc/nginx/certs/web-server-tokens-off.nginx-proxy.tld.key:ro diff --git a/test/test_http2/test_http2_global_disabled.yml b/test/test_http2/test_http2_global_disabled.yml index 5dffa19..8fd3cde 100644 --- a/test/test_http2/test_http2_global_disabled.yml +++ b/test/test_http2/test_http2_global_disabled.yml @@ -1,3 +1,5 @@ +version: "2" + services: http2-global-disabled: image: web diff --git a/test/test_http3/test_http3_global_disabled.yml b/test/test_http3/test_http3_global_disabled.yml index 66530a4..482a5ea 100644 --- a/test/test_http3/test_http3_global_disabled.yml +++ b/test/test_http3/test_http3_global_disabled.yml @@ -1,3 +1,5 @@ +version: "2" + services: http3-global-disabled: image: web @@ -12,4 +14,4 @@ services: volumes: - /var/run/docker.sock:/tmp/docker.sock:ro #environment: - #ENABLE_HTTP3: "false" #Disabled by default + #ENABLE_HTTP3: "false" #Disabled by default diff --git a/test/test_http3/test_http3_global_enabled.yml b/test/test_http3/test_http3_global_enabled.yml index 0825469..1cd40e0 100644 --- a/test/test_http3/test_http3_global_enabled.yml +++ b/test/test_http3/test_http3_global_enabled.yml @@ -1,3 +1,5 @@ +version: "2" + services: http3-global-enabled: image: web diff --git a/test/test_http3/test_http3_vhost.yml b/test/test_http3/test_http3_vhost.yml index 1d5cdf2..345bb30 100644 --- a/test/test_http3/test_http3_vhost.yml +++ b/test/test_http3/test_http3_vhost.yml @@ -1,3 +1,5 @@ +version: "2" + services: http3-vhost-enabled: image: web diff --git a/test/test_http_port.yml b/test/test_http_port.yml index 72f142f..a346982 100644 --- a/test/test_http_port.yml +++ b/test/test_http_port.yml @@ -1,14 +1,17 @@ -web1: - image: web - expose: - - "81" - environment: - WEB_PORTS: "81" - VIRTUAL_HOST: "*.nginx-proxy.tld" +version: "2" -sut: - image: nginxproxy/nginx-proxy:test - volumes: - - /var/run/docker.sock:/tmp/docker.sock:ro - environment: - HTTP_PORT: 8080 \ No newline at end of file +services: + web1: + image: web + expose: + - "81" + environment: + WEB_PORTS: "81" + VIRTUAL_HOST: "*.nginx-proxy.tld" + + sut: + image: nginxproxy/nginx-proxy:test + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro + environment: + HTTP_PORT: 8080 diff --git a/test/test_internal/test_internal-per-vhost.yml b/test/test_internal/test_internal-per-vhost.yml index 3763723..cc67c22 100644 --- a/test/test_internal/test_internal-per-vhost.yml +++ b/test/test_internal/test_internal-per-vhost.yml @@ -1,23 +1,25 @@ -web1: - image: web - expose: - - "81" - environment: - WEB_PORTS: 81 - VIRTUAL_HOST: web1.nginx-proxy.example - NETWORK_ACCESS: internal +version: "2" -web2: - image: web - expose: - - "82" - environment: - WEB_PORTS: 82 - VIRTUAL_HOST: web2.nginx-proxy.example +services: + web1: + image: web + expose: + - "81" + environment: + WEB_PORTS: 81 + VIRTUAL_HOST: web1.nginx-proxy.example + NETWORK_ACCESS: internal -sut: - image: nginxproxy/nginx-proxy:test - volumes: - - /var/run/docker.sock:/tmp/docker.sock:ro - - ./network_internal.conf:/etc/nginx/network_internal.conf:ro + web2: + image: web + expose: + - "82" + environment: + WEB_PORTS: 82 + VIRTUAL_HOST: web2.nginx-proxy.example + sut: + image: nginxproxy/nginx-proxy:test + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro + - ./network_internal.conf:/etc/nginx/network_internal.conf:ro diff --git a/test/test_internal/test_internal-per-vpath.yml b/test/test_internal/test_internal-per-vpath.yml index 3cc4a05..35e92f0 100644 --- a/test/test_internal/test_internal-per-vpath.yml +++ b/test/test_internal/test_internal-per-vpath.yml @@ -1,27 +1,29 @@ -web1: - image: web - expose: - - "81" - environment: - WEB_PORTS: 81 - VIRTUAL_HOST: nginx-proxy.example - VIRTUAL_PATH: /web1/ - VIRTUAL_DEST: / - NETWORK_ACCESS: internal +version: "2" -web2: - image: web - expose: - - "82" - environment: - WEB_PORTS: 82 - VIRTUAL_HOST: nginx-proxy.example - VIRTUAL_PATH: /web2/ - VIRTUAL_DEST: / +services: + web1: + image: web + expose: + - "81" + environment: + WEB_PORTS: 81 + VIRTUAL_HOST: nginx-proxy.example + VIRTUAL_PATH: /web1/ + VIRTUAL_DEST: / + NETWORK_ACCESS: internal -sut: - image: nginxproxy/nginx-proxy:test - volumes: - - /var/run/docker.sock:/tmp/docker.sock:ro - - ./network_internal.conf:/etc/nginx/network_internal.conf:ro + web2: + image: web + expose: + - "82" + environment: + WEB_PORTS: 82 + VIRTUAL_HOST: nginx-proxy.example + VIRTUAL_PATH: /web2/ + VIRTUAL_DEST: / + sut: + image: nginxproxy/nginx-proxy:test + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro + - ./network_internal.conf:/etc/nginx/network_internal.conf:ro diff --git a/test/test_ipv6.yml b/test/test_ipv6.yml index 4dce515..d5fec9b 100644 --- a/test/test_ipv6.yml +++ b/test/test_ipv6.yml @@ -1,4 +1,4 @@ -version: '2' +version: "2" networks: net1: @@ -28,7 +28,6 @@ services: networks: - net1 - sut: image: nginxproxy/nginx-proxy:test volumes: diff --git a/test/test_keepalive.yml b/test/test_keepalive.yml index 541b69d..62f5b25 100644 --- a/test/test_keepalive.yml +++ b/test/test_keepalive.yml @@ -1,25 +1,27 @@ -keepalive-disabled: - image: web - expose: - - "80" - environment: - WEB_PORTS: 80 - VIRTUAL_HOST: keepalive-disabled.nginx-proxy.test +version: "2" -keepalive-enabled: - image: web - expose: - - "80" - environment: - WEB_PORTS: 80 - VIRTUAL_HOST: keepalive-enabled.nginx-proxy.test - labels: - com.github.nginx-proxy.nginx-proxy.keepalive: "64" +services: + keepalive-disabled: + image: web + expose: + - "80" + environment: + WEB_PORTS: 80 + VIRTUAL_HOST: keepalive-disabled.nginx-proxy.test + keepalive-enabled: + image: web + expose: + - "80" + environment: + WEB_PORTS: 80 + VIRTUAL_HOST: keepalive-enabled.nginx-proxy.test + labels: + com.github.nginx-proxy.nginx-proxy.keepalive: "64" -sut: - image: nginxproxy/nginx-proxy:test - volumes: - - /var/run/docker.sock:/tmp/docker.sock:ro - environment: - HTTPS_METHOD: nohttps + sut: + image: nginxproxy/nginx-proxy:test + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro + environment: + HTTPS_METHOD: nohttps diff --git a/test/test_loadbalancing.yml b/test/test_loadbalancing.yml index b8f42eb..72155fb 100644 --- a/test/test_loadbalancing.yml +++ b/test/test_loadbalancing.yml @@ -1,3 +1,5 @@ +version: "2" + services: loadbalance-hash: image: web diff --git a/test/test_location-override.yml b/test/test_location-override.yml index f36b206..9ba4eb8 100644 --- a/test/test_location-override.yml +++ b/test/test_location-override.yml @@ -1,3 +1,5 @@ +version: "2" + services: sut: image: nginxproxy/nginx-proxy:test diff --git a/test/test_log_format.yml b/test/test_log_format.yml index ef3bbf6..2a32e3d 100644 --- a/test/test_log_format.yml +++ b/test/test_log_format.yml @@ -1,15 +1,18 @@ -web1: - image: web - expose: - - "81" - environment: - WEB_PORTS: 81 - VIRTUAL_HOST: nginx-proxy.test +version: "2" -sut: - container_name: sut - image: nginxproxy/nginx-proxy:test - volumes: - - /var/run/docker.sock:/tmp/docker.sock:ro - environment: - LOG_FORMAT: "$$remote_addr - $$remote_user [$$time_local] \"$$request\" $$status $$body_bytes_sent \"$$http_referer\" \"$$http_user_agent\" request_time=$$request_time $$upstream_response_time" +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: + LOG_FORMAT: '$$remote_addr - $$remote_user [$$time_local] "$$request" $$status $$body_bytes_sent "$$http_referer" "$$http_user_agent" request_time=$$request_time $$upstream_response_time' diff --git a/test/test_multiple-hosts.yml b/test/test_multiple-hosts.yml index b72da83..832aac4 100644 --- a/test/test_multiple-hosts.yml +++ b/test/test_multiple-hosts.yml @@ -1,13 +1,15 @@ -web: - image: web - expose: - - "81" - environment: - WEB_PORTS: 81 - VIRTUAL_HOST: webA.nginx-proxy.tld,webB.nginx-proxy.tld +version: "2" +services: + web: + image: web + expose: + - "81" + environment: + WEB_PORTS: 81 + VIRTUAL_HOST: webA.nginx-proxy.tld,webB.nginx-proxy.tld -sut: - image: nginxproxy/nginx-proxy:test - volumes: - - /var/run/docker.sock:/tmp/docker.sock:ro + sut: + image: nginxproxy/nginx-proxy:test + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro diff --git a/test/test_multiple-networks.yml b/test/test_multiple-networks.yml index 1247cb3..3e34b48 100644 --- a/test/test_multiple-networks.yml +++ b/test/test_multiple-networks.yml @@ -1,4 +1,4 @@ -version: '2' +version: "2" networks: net1: {} diff --git a/test/test_multiple-ports/test_VIRTUAL_PORT-single-different-from-single-port.yml b/test/test_multiple-ports/test_VIRTUAL_PORT-single-different-from-single-port.yml index dff6212..ba58d4e 100644 --- a/test/test_multiple-ports/test_VIRTUAL_PORT-single-different-from-single-port.yml +++ b/test/test_multiple-ports/test_VIRTUAL_PORT-single-different-from-single-port.yml @@ -1,14 +1,16 @@ -web: - image: web - expose: - - "81" - environment: - WEB_PORTS: "81" - VIRTUAL_HOST: "web.nginx-proxy.tld" - VIRTUAL_PORT: "90" +version: "2" +services: + web: + image: web + expose: + - "81" + environment: + WEB_PORTS: "81" + VIRTUAL_HOST: "web.nginx-proxy.tld" + VIRTUAL_PORT: "90" -sut: - image: nginxproxy/nginx-proxy:test - volumes: - - /var/run/docker.sock:/tmp/docker.sock:ro + sut: + image: nginxproxy/nginx-proxy:test + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro diff --git a/test/test_multiple-ports/test_VIRTUAL_PORT.yml b/test/test_multiple-ports/test_VIRTUAL_PORT.yml index 1a3ecaa..ab1af46 100644 --- a/test/test_multiple-ports/test_VIRTUAL_PORT.yml +++ b/test/test_multiple-ports/test_VIRTUAL_PORT.yml @@ -1,14 +1,17 @@ -web: - image: web - expose: - - "80" - - "90" - environment: - WEB_PORTS: "80 90" - VIRTUAL_HOST: "web.nginx-proxy.tld" - VIRTUAL_PORT: 90 +version: "2" -sut: - image: nginxproxy/nginx-proxy:test - volumes: - - /var/run/docker.sock:/tmp/docker.sock:ro +services: + web: + image: web + expose: + - "80" + - "90" + environment: + WEB_PORTS: "80 90" + VIRTUAL_HOST: "web.nginx-proxy.tld" + VIRTUAL_PORT: 90 + + sut: + image: nginxproxy/nginx-proxy:test + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro diff --git a/test/test_multiple-ports/test_default-80.yml b/test/test_multiple-ports/test_default-80.yml index 10047dc..0cfdd7e 100644 --- a/test/test_multiple-ports/test_default-80.yml +++ b/test/test_multiple-ports/test_default-80.yml @@ -1,13 +1,16 @@ -web: - image: web - expose: - - "80" - - "81" - environment: - WEB_PORTS: "80 81" - VIRTUAL_HOST: "web.nginx-proxy.tld" +version: "2" -sut: - image: nginxproxy/nginx-proxy:test - volumes: - - /var/run/docker.sock:/tmp/docker.sock:ro +services: + web: + image: web + expose: + - "80" + - "81" + environment: + WEB_PORTS: "80 81" + VIRTUAL_HOST: "web.nginx-proxy.tld" + + sut: + image: nginxproxy/nginx-proxy:test + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro diff --git a/test/test_multiple-ports/test_single-port-not-80.yml b/test/test_multiple-ports/test_single-port-not-80.yml index 18b3655..eef4e08 100644 --- a/test/test_multiple-ports/test_single-port-not-80.yml +++ b/test/test_multiple-ports/test_single-port-not-80.yml @@ -1,13 +1,15 @@ -web: - image: web - expose: - - "81" - environment: - WEB_PORTS: "81" - VIRTUAL_HOST: "web.nginx-proxy.tld" +version: "2" +services: + web: + image: web + expose: + - "81" + environment: + WEB_PORTS: "81" + VIRTUAL_HOST: "web.nginx-proxy.tld" -sut: - image: nginxproxy/nginx-proxy:test - volumes: - - /var/run/docker.sock:/tmp/docker.sock:ro + sut: + image: nginxproxy/nginx-proxy:test + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro diff --git a/test/test_nominal.yml b/test/test_nominal.yml index fe02034..6067895 100644 --- a/test/test_nominal.yml +++ b/test/test_nominal.yml @@ -1,4 +1,4 @@ -version: '2' +version: "2" networks: net1: @@ -28,7 +28,6 @@ services: networks: - net1 - sut: image: nginxproxy/nginx-proxy:test volumes: diff --git a/test/test_raw-ip-vhost.yml b/test/test_raw-ip-vhost.yml index 066dade..f034bdb 100644 --- a/test/test_raw-ip-vhost.yml +++ b/test/test_raw-ip-vhost.yml @@ -1,4 +1,4 @@ -version: '2' +version: "2" networks: net1: @@ -6,7 +6,7 @@ networks: ipam: config: - subnet: 172.20.0.0/16 - - subnet: fd00::/80 + - subnet: fd00::/80 services: web1: diff --git a/test/test_server-down/test_load-balancing.yml b/test/test_server-down/test_load-balancing.yml index d420072..bde23d6 100644 --- a/test/test_server-down/test_load-balancing.yml +++ b/test/test_server-down/test_load-balancing.yml @@ -1,29 +1,32 @@ -web1: - image: web - expose: - - "81" - environment: - WEB_PORTS: 81 - VIRTUAL_HOST: web.nginx-proxy.tld +version: "2" -web2: - image: web - expose: - - "82" - environment: - WEB_PORTS: 83 - VIRTUAL_HOST: web.nginx-proxy.tld +services: + web1: + image: web + expose: + - "81" + environment: + WEB_PORTS: 81 + VIRTUAL_HOST: web.nginx-proxy.tld -web3: - image: web - expose: - - "83" - environment: - WEB_PORTS: 83 - VIRTUAL_HOST: web.nginx-proxy.tld - net: "none" + web2: + image: web + expose: + - "82" + environment: + WEB_PORTS: 83 + VIRTUAL_HOST: web.nginx-proxy.tld -sut: - image: nginxproxy/nginx-proxy:test - volumes: - - /var/run/docker.sock:/tmp/docker.sock:ro + web3: + image: web + expose: + - "83" + environment: + WEB_PORTS: 83 + VIRTUAL_HOST: web.nginx-proxy.tld + net: "none" + + sut: + image: nginxproxy/nginx-proxy:test + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro diff --git a/test/test_server-down/test_no-server-down.yml b/test/test_server-down/test_no-server-down.yml index b3d4629..cd7e5ac 100644 --- a/test/test_server-down/test_no-server-down.yml +++ b/test/test_server-down/test_no-server-down.yml @@ -1,12 +1,15 @@ -web: - image: web - expose: - - "81" - environment: - WEB_PORTS: 81 - VIRTUAL_HOST: web.nginx-proxy.tld +version: "2" -sut: - image: nginxproxy/nginx-proxy:test - volumes: - - /var/run/docker.sock:/tmp/docker.sock:ro +services: + web: + image: web + expose: + - "81" + environment: + WEB_PORTS: 81 + VIRTUAL_HOST: web.nginx-proxy.tld + + sut: + image: nginxproxy/nginx-proxy:test + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro diff --git a/test/test_server-down/test_server-down.yml b/test/test_server-down/test_server-down.yml index 938d26a..d4d109a 100644 --- a/test/test_server-down/test_server-down.yml +++ b/test/test_server-down/test_server-down.yml @@ -1,13 +1,16 @@ -web: - image: web - expose: - - "81" - environment: - WEB_PORTS: 81 - VIRTUAL_HOST: web.nginx-proxy.tld - net: "none" +version: "2" -sut: - image: nginxproxy/nginx-proxy:test - volumes: - - /var/run/docker.sock:/tmp/docker.sock:ro +services: + web: + image: web + expose: + - "81" + environment: + WEB_PORTS: 81 + VIRTUAL_HOST: web.nginx-proxy.tld + net: "none" + + sut: + image: nginxproxy/nginx-proxy:test + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro diff --git a/test/test_ssl/test_dhparam.yml b/test/test_ssl/test_dhparam.yml index 505ac4c..456b1b3 100644 --- a/test/test_ssl/test_dhparam.yml +++ b/test/test_ssl/test_dhparam.yml @@ -1,73 +1,75 @@ -web5: - image: web - expose: - - "85" - environment: - WEB_PORTS: "85" - VIRTUAL_HOST: "web5.nginx-proxy.tld" +version: "2" -# Intended for testing with `dh-file` container. -# VIRTUAL_HOST is paired with site-specific DH param file. -# DEFAULT_HOST is required to avoid defaulting to web2, -# if not specifying FQDN (`-servername`) in openssl queries. -web2: - image: web - expose: - - "85" - environment: - WEB_PORTS: "85" - VIRTUAL_HOST: "web2.nginx-proxy.tld" +services: + web5: + image: web + expose: + - "85" + environment: + WEB_PORTS: "85" + VIRTUAL_HOST: "web5.nginx-proxy.tld" + # Intended for testing with `dh-file` container. + # VIRTUAL_HOST is paired with site-specific DH param file. + # DEFAULT_HOST is required to avoid defaulting to web2, + # if not specifying FQDN (`-servername`) in openssl queries. + web2: + image: web + expose: + - "85" + environment: + WEB_PORTS: "85" + VIRTUAL_HOST: "web2.nginx-proxy.tld" -# sut - System Under Test -# `docker.sock` required for functionality -# `certs` required to enable HTTPS via template -with_default_group: - container_name: dh-default - image: &img-nginxproxy nginxproxy/nginx-proxy:test - environment: &env-common - - &default-host DEFAULT_HOST=web5.nginx-proxy.tld - volumes: &vols-common - - &docker-sock /var/run/docker.sock:/tmp/docker.sock:ro - - &nginx-certs ./certs:/etc/nginx/certs:ro + # sut - System Under Test + # `docker.sock` required for functionality + # `certs` required to enable HTTPS via template + with_default_group: + container_name: dh-default + image: &img-nginxproxy nginxproxy/nginx-proxy:test + environment: &env-common + - &default-host DEFAULT_HOST=web5.nginx-proxy.tld + volumes: &vols-common + - &docker-sock /var/run/docker.sock:/tmp/docker.sock:ro + - &nginx-certs ./certs:/etc/nginx/certs:ro -with_alternative_group: - container_name: dh-env - environment: - - DHPARAM_BITS=3072 - - *default-host - image: *img-nginxproxy - volumes: *vols-common + with_alternative_group: + container_name: dh-env + environment: + - DHPARAM_BITS=3072 + - *default-host + image: *img-nginxproxy + volumes: *vols-common -with_invalid_group: - container_name: invalid-group-1024 - environment: - - DHPARAM_BITS=1024 - - *default-host - image: *img-nginxproxy - volumes: *vols-common + with_invalid_group: + container_name: invalid-group-1024 + environment: + - DHPARAM_BITS=1024 + - *default-host + image: *img-nginxproxy + volumes: *vols-common -with_custom_file: - container_name: dh-file - image: *img-nginxproxy - environment: *env-common - volumes: - - *docker-sock - - *nginx-certs - - ../../app/dhparam/ffdhe3072.pem:/etc/nginx/dhparam/dhparam.pem:ro + with_custom_file: + container_name: dh-file + image: *img-nginxproxy + environment: *env-common + volumes: + - *docker-sock + - *nginx-certs + - ../../app/dhparam/ffdhe3072.pem:/etc/nginx/dhparam/dhparam.pem:ro -with_skip: - container_name: dh-skip - environment: - - DHPARAM_SKIP=true - - *default-host - image: *img-nginxproxy - volumes: *vols-common + with_skip: + container_name: dh-skip + environment: + - DHPARAM_SKIP=true + - *default-host + image: *img-nginxproxy + volumes: *vols-common -with_skip_backward: - container_name: dh-skip-backward - environment: - - DHPARAM_GENERATION=false - - *default-host - image: *img-nginxproxy - volumes: *vols-common + with_skip_backward: + container_name: dh-skip-backward + environment: + - DHPARAM_GENERATION=false + - *default-host + image: *img-nginxproxy + volumes: *vols-common diff --git a/test/test_ssl/test_hsts.yml b/test/test_ssl/test_hsts.yml index da3b629..b84fb80 100644 --- a/test/test_ssl/test_hsts.yml +++ b/test/test_ssl/test_hsts.yml @@ -1,51 +1,54 @@ -web1: - image: web - expose: - - "81" - environment: - WEB_PORTS: "81" - VIRTUAL_HOST: "web1.nginx-proxy.tld" +version: "2" -web2: - image: web - expose: - - "81" - environment: - WEB_PORTS: "81" - VIRTUAL_HOST: "web2.nginx-proxy.tld" - HSTS: "off" +services: + web1: + image: web + expose: + - "81" + environment: + WEB_PORTS: "81" + VIRTUAL_HOST: "web1.nginx-proxy.tld" -web3: - image: web - expose: - - "81" - environment: - WEB_PORTS: "81" - VIRTUAL_HOST: "web3.nginx-proxy.tld" - HSTS: "max-age=86400; includeSubDomains; preload" + web2: + image: web + expose: + - "81" + environment: + WEB_PORTS: "81" + VIRTUAL_HOST: "web2.nginx-proxy.tld" + HSTS: "off" -web4: - image: web - expose: - - "81" - environment: - WEB_PORTS: "81" - VIRTUAL_HOST: "web4.nginx-proxy.tld" - HSTS: "off" - HTTPS_METHOD: "noredirect" + web3: + image: web + expose: + - "81" + environment: + WEB_PORTS: "81" + VIRTUAL_HOST: "web3.nginx-proxy.tld" + HSTS: "max-age=86400; includeSubDomains; preload" -web5: - image: web - expose: - - "81" - environment: - WEB_PORTS: "81" - VIRTUAL_HOST: http3-vhost-enabled.nginx-proxy.tld - labels: - com.github.nginx-proxy.nginx-proxy.http3.enable: "true" + web4: + image: web + expose: + - "81" + environment: + WEB_PORTS: "81" + VIRTUAL_HOST: "web4.nginx-proxy.tld" + HSTS: "off" + HTTPS_METHOD: "noredirect" -sut: - image: nginxproxy/nginx-proxy:test - volumes: - - /var/run/docker.sock:/tmp/docker.sock:ro - - ./certs:/etc/nginx/certs:ro + web5: + image: web + expose: + - "81" + environment: + WEB_PORTS: "81" + VIRTUAL_HOST: http3-vhost-enabled.nginx-proxy.tld + labels: + com.github.nginx-proxy.nginx-proxy.http3.enable: "true" + + sut: + image: nginxproxy/nginx-proxy:test + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro + - ./certs:/etc/nginx/certs:ro diff --git a/test/test_ssl/test_https_port.yml b/test/test_ssl/test_https_port.yml index 7b674d7..047054a 100644 --- a/test/test_ssl/test_https_port.yml +++ b/test/test_ssl/test_https_port.yml @@ -1,16 +1,19 @@ -web1: - image: web - expose: - - "81" - environment: - WEB_PORTS: "81" - VIRTUAL_HOST: "*.nginx-proxy.tld" +version: "2" -sut: - image: nginxproxy/nginx-proxy:test - volumes: - - /var/run/docker.sock:/tmp/docker.sock:ro - - ./certs:/etc/nginx/certs:ro - environment: - HTTP_PORT: 8080 - HTTPS_PORT: 8443 \ No newline at end of file +services: + web1: + image: web + expose: + - "81" + environment: + WEB_PORTS: "81" + VIRTUAL_HOST: "*.nginx-proxy.tld" + + sut: + image: nginxproxy/nginx-proxy:test + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro + - ./certs:/etc/nginx/certs:ro + environment: + HTTP_PORT: 8080 + HTTPS_PORT: 8443 diff --git a/test/test_ssl/test_nohttp.yml b/test/test_ssl/test_nohttp.yml index 48a7aa3..40b393a 100644 --- a/test/test_ssl/test_nohttp.yml +++ b/test/test_ssl/test_nohttp.yml @@ -1,15 +1,17 @@ -web2: - image: web - expose: - - "82" - environment: - WEB_PORTS: "82" - VIRTUAL_HOST: "web2.nginx-proxy.tld" - HTTPS_METHOD: nohttp +version: "2" +services: + web2: + image: web + expose: + - "82" + environment: + WEB_PORTS: "82" + VIRTUAL_HOST: "web2.nginx-proxy.tld" + HTTPS_METHOD: nohttp -sut: - image: nginxproxy/nginx-proxy:test - volumes: - - /var/run/docker.sock:/tmp/docker.sock:ro - - ./certs:/etc/nginx/certs:ro + sut: + image: nginxproxy/nginx-proxy:test + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro + - ./certs:/etc/nginx/certs:ro diff --git a/test/test_ssl/test_nohttps.yml b/test/test_ssl/test_nohttps.yml index 3f3df19..f2b0757 100644 --- a/test/test_ssl/test_nohttps.yml +++ b/test/test_ssl/test_nohttps.yml @@ -1,14 +1,16 @@ -web: - image: web - expose: - - "83" - environment: - WEB_PORTS: "83" - VIRTUAL_HOST: "web.nginx-proxy.tld" - HTTPS_METHOD: nohttps +version: "2" +services: + web: + image: web + expose: + - "83" + environment: + WEB_PORTS: "83" + VIRTUAL_HOST: "web.nginx-proxy.tld" + HTTPS_METHOD: nohttps -sut: - image: nginxproxy/nginx-proxy:test - volumes: - - /var/run/docker.sock:/tmp/docker.sock:ro + sut: + image: nginxproxy/nginx-proxy:test + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro diff --git a/test/test_ssl/test_noredirect.yml b/test/test_ssl/test_noredirect.yml index ecd93f6..8ee8455 100644 --- a/test/test_ssl/test_noredirect.yml +++ b/test/test_ssl/test_noredirect.yml @@ -1,15 +1,17 @@ -web3: - image: web - expose: - - "83" - environment: - WEB_PORTS: "83" - VIRTUAL_HOST: "web3.nginx-proxy.tld" - HTTPS_METHOD: noredirect +version: "2" +services: + web3: + image: web + expose: + - "83" + environment: + WEB_PORTS: "83" + VIRTUAL_HOST: "web3.nginx-proxy.tld" + HTTPS_METHOD: noredirect -sut: - image: nginxproxy/nginx-proxy:test - volumes: - - /var/run/docker.sock:/tmp/docker.sock:ro - - ./certs:/etc/nginx/certs:ro + sut: + image: nginxproxy/nginx-proxy:test + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro + - ./certs:/etc/nginx/certs:ro diff --git a/test/test_ssl/test_virtual_path.yml b/test/test_ssl/test_virtual_path.yml index 2260321..2494d35 100644 --- a/test/test_ssl/test_virtual_path.yml +++ b/test/test_ssl/test_virtual_path.yml @@ -1,26 +1,28 @@ -web1: - image: web - expose: - - "81" - environment: - WEB_PORTS: "81" - VIRTUAL_HOST: "www.nginx-proxy.tld" - VIRTUAL_PATH: "/web1/" - VIRTUAL_DEST: "/" +version: "2" -web2: - image: web - expose: - - "82" - environment: - WEB_PORTS: "82" - VIRTUAL_HOST: "www.nginx-proxy.tld" - VIRTUAL_PATH: "/web2/" - VIRTUAL_DEST: "/" +services: + web1: + image: web + expose: + - "81" + environment: + WEB_PORTS: "81" + VIRTUAL_HOST: "www.nginx-proxy.tld" + VIRTUAL_PATH: "/web1/" + VIRTUAL_DEST: "/" -sut: - image: nginxproxy/nginx-proxy:test - volumes: - - /var/run/docker.sock:/tmp/docker.sock:ro - - ./certs:/etc/nginx/certs:ro + web2: + image: web + expose: + - "82" + environment: + WEB_PORTS: "82" + VIRTUAL_HOST: "www.nginx-proxy.tld" + VIRTUAL_PATH: "/web2/" + VIRTUAL_DEST: "/" + sut: + image: nginxproxy/nginx-proxy:test + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro + - ./certs:/etc/nginx/certs:ro diff --git a/test/test_ssl/test_wildcard.yml b/test/test_ssl/test_wildcard.yml index e1504ed..ea8c596 100644 --- a/test/test_ssl/test_wildcard.yml +++ b/test/test_ssl/test_wildcard.yml @@ -1,13 +1,16 @@ -web1: - image: web - expose: - - "81" - environment: - WEB_PORTS: "81" - VIRTUAL_HOST: "*.nginx-proxy.tld" +version: "2" -sut: - image: nginxproxy/nginx-proxy:test - volumes: - - /var/run/docker.sock:/tmp/docker.sock:ro - - ./certs:/etc/nginx/certs:ro +services: + web1: + image: web + expose: + - "81" + environment: + WEB_PORTS: "81" + VIRTUAL_HOST: "*.nginx-proxy.tld" + + sut: + image: nginxproxy/nginx-proxy:test + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro + - ./certs:/etc/nginx/certs:ro diff --git a/test/test_trust-downstream-proxy/test_default.yml b/test/test_trust-downstream-proxy/test_default.yml index c420d80..936dbad 100644 --- a/test/test_trust-downstream-proxy/test_default.yml +++ b/test/test_trust-downstream-proxy/test_default.yml @@ -1,16 +1,18 @@ -web: - image: web - expose: - - "80" - environment: - WEB_PORTS: 80 - VIRTUAL_HOST: web.nginx-proxy.tld - HTTPS_METHOD: noredirect +version: "2" +services: + web: + image: web + expose: + - "80" + environment: + WEB_PORTS: 80 + VIRTUAL_HOST: web.nginx-proxy.tld + HTTPS_METHOD: noredirect -sut: - image: nginxproxy/nginx-proxy:test - volumes: - - /var/run/docker.sock:/tmp/docker.sock:ro - - ./certs/web.nginx-proxy.tld.crt:/etc/nginx/certs/web.nginx-proxy.tld.crt:ro - - ./certs/web.nginx-proxy.tld.key:/etc/nginx/certs/web.nginx-proxy.tld.key:ro + sut: + image: nginxproxy/nginx-proxy:test + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro + - ./certs/web.nginx-proxy.tld.crt:/etc/nginx/certs/web.nginx-proxy.tld.crt:ro + - ./certs/web.nginx-proxy.tld.key:/etc/nginx/certs/web.nginx-proxy.tld.key:ro diff --git a/test/test_trust-downstream-proxy/test_disabled.yml b/test/test_trust-downstream-proxy/test_disabled.yml index 860e5f9..9318d63 100644 --- a/test/test_trust-downstream-proxy/test_disabled.yml +++ b/test/test_trust-downstream-proxy/test_disabled.yml @@ -1,18 +1,20 @@ -web: - image: web - expose: - - "80" - environment: - WEB_PORTS: 80 - VIRTUAL_HOST: web.nginx-proxy.tld - HTTPS_METHOD: noredirect +version: "2" +services: + web: + image: web + expose: + - "80" + environment: + WEB_PORTS: 80 + VIRTUAL_HOST: web.nginx-proxy.tld + HTTPS_METHOD: noredirect -sut: - image: nginxproxy/nginx-proxy:test - environment: - TRUST_DOWNSTREAM_PROXY: "false" - volumes: - - /var/run/docker.sock:/tmp/docker.sock:ro - - ./certs/web.nginx-proxy.tld.crt:/etc/nginx/certs/web.nginx-proxy.tld.crt:ro - - ./certs/web.nginx-proxy.tld.key:/etc/nginx/certs/web.nginx-proxy.tld.key:ro + sut: + image: nginxproxy/nginx-proxy:test + environment: + TRUST_DOWNSTREAM_PROXY: "false" + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro + - ./certs/web.nginx-proxy.tld.crt:/etc/nginx/certs/web.nginx-proxy.tld.crt:ro + - ./certs/web.nginx-proxy.tld.key:/etc/nginx/certs/web.nginx-proxy.tld.key:ro diff --git a/test/test_trust-downstream-proxy/test_enabled.yml b/test/test_trust-downstream-proxy/test_enabled.yml index 7b2a8de..9a3e975 100644 --- a/test/test_trust-downstream-proxy/test_enabled.yml +++ b/test/test_trust-downstream-proxy/test_enabled.yml @@ -1,18 +1,20 @@ -web: - image: web - expose: - - "80" - environment: - WEB_PORTS: 80 - VIRTUAL_HOST: web.nginx-proxy.tld - HTTPS_METHOD: noredirect +version: "2" +services: + web: + image: web + expose: + - "80" + environment: + WEB_PORTS: 80 + VIRTUAL_HOST: web.nginx-proxy.tld + HTTPS_METHOD: noredirect -sut: - image: nginxproxy/nginx-proxy:test - environment: - TRUST_DOWNSTREAM_PROXY: "true" - volumes: - - /var/run/docker.sock:/tmp/docker.sock:ro - - ./certs/web.nginx-proxy.tld.crt:/etc/nginx/certs/web.nginx-proxy.tld.crt:ro - - ./certs/web.nginx-proxy.tld.key:/etc/nginx/certs/web.nginx-proxy.tld.key:ro + sut: + image: nginxproxy/nginx-proxy:test + environment: + TRUST_DOWNSTREAM_PROXY: "true" + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro + - ./certs/web.nginx-proxy.tld.crt:/etc/nginx/certs/web.nginx-proxy.tld.crt:ro + - ./certs/web.nginx-proxy.tld.key:/etc/nginx/certs/web.nginx-proxy.tld.key:ro diff --git a/test/test_upstream-name/test_predictable-name.yml b/test/test_upstream-name/test_predictable-name.yml index cd8d250..b5caad0 100644 --- a/test/test_upstream-name/test_predictable-name.yml +++ b/test/test_upstream-name/test_predictable-name.yml @@ -1,4 +1,4 @@ -version: '2' +version: "2" services: web: diff --git a/test/test_upstream-name/test_sha1-name.yml b/test/test_upstream-name/test_sha1-name.yml index 54989ae..b52a5c9 100644 --- a/test/test_upstream-name/test_sha1-name.yml +++ b/test/test_upstream-name/test_sha1-name.yml @@ -1,4 +1,4 @@ -version: '2' +version: "2" services: web: diff --git a/test/test_vhost-empty-string.yml b/test/test_vhost-empty-string.yml index 83dd554..9d2ff52 100644 --- a/test/test_vhost-empty-string.yml +++ b/test/test_vhost-empty-string.yml @@ -1,8 +1,11 @@ +version: "2" + services: sut: image: nginxproxy/nginx-proxy:test volumes: - /var/run/docker.sock:/tmp/docker.sock:ro + web1: image: web expose: @@ -11,6 +14,7 @@ services: WEB_PORTS: "81" # The space is intentional (should be trimmed). VIRTUAL_HOST: " " + web2: image: web expose: @@ -19,6 +23,7 @@ services: WEB_PORTS: "82" # The space is intentional (should be trimmed). VIRTUAL_HOST: "web2.nginx-proxy.test ," + web3: image: web expose: @@ -27,6 +32,7 @@ services: WEB_PORTS: "83" # The space is intentional (should be trimmed). VIRTUAL_HOST: " ,web3.nginx-proxy.test" + web4: image: web expose: diff --git a/test/test_vhost-in-multiple-networks.yml b/test/test_vhost-in-multiple-networks.yml index 280af04..4e9bb3e 100644 --- a/test/test_vhost-in-multiple-networks.yml +++ b/test/test_vhost-in-multiple-networks.yml @@ -1,4 +1,4 @@ -version: '2' +version: "2" networks: net1: {} diff --git a/test/test_virtual-path/test_custom_conf.yml b/test/test_virtual-path/test_custom_conf.yml index 40ab512..2c4d6b9 100644 --- a/test/test_virtual-path/test_custom_conf.yml +++ b/test/test_virtual-path/test_custom_conf.yml @@ -1,48 +1,49 @@ +version: "2" -foo: - image: web - expose: - - "42" - environment: - WEB_PORTS: "42" - VIRTUAL_HOST: "foo.nginx-proxy.test" +services: + foo: + image: web + expose: + - "42" + environment: + WEB_PORTS: "42" + VIRTUAL_HOST: "foo.nginx-proxy.test" -web1: - image: web - expose: - - "81" - environment: - WEB_PORTS: "81" - VIRTUAL_HOST: "nginx-proxy.test" - VIRTUAL_PATH: "/web1/" - VIRTUAL_DEST: "/" + web1: + image: web + expose: + - "81" + environment: + WEB_PORTS: "81" + VIRTUAL_HOST: "nginx-proxy.test" + VIRTUAL_PATH: "/web1/" + VIRTUAL_DEST: "/" -web2: - image: web - expose: - - "82" - environment: - WEB_PORTS: "82" - VIRTUAL_HOST: "nginx-proxy.test" - VIRTUAL_PATH: "/web2/" - VIRTUAL_DEST: "/" + web2: + image: web + expose: + - "82" + environment: + WEB_PORTS: "82" + VIRTUAL_HOST: "nginx-proxy.test" + VIRTUAL_PATH: "/web2/" + VIRTUAL_DEST: "/" -web3: - image: web - expose: - - "83" - environment: - WEB_PORTS: "83" - VIRTUAL_HOST: "nginx-proxy.test" - VIRTUAL_PATH: "~ ^/(web3|alt)/" - -sut: - image: nginxproxy/nginx-proxy:test - environment: - DEFAULT_ROOT: 418 - volumes: - - /var/run/docker.sock:/tmp/docker.sock:ro - - ./foo.conf:/etc/nginx/vhost.d/foo.nginx-proxy.test:ro - - ./bar.conf:/etc/nginx/vhost.d/nginx-proxy.test_918d687a929083edd0c7224ee2293e0e7c062ab4_location:ro - - ./alternate.conf:/etc/nginx/vhost.d/nginx-proxy.test_7fb22b74bbdf907425dbbad18e4462565cada230_location:ro + web3: + image: web + expose: + - "83" + environment: + WEB_PORTS: "83" + VIRTUAL_HOST: "nginx-proxy.test" + VIRTUAL_PATH: "~ ^/(web3|alt)/" + sut: + image: nginxproxy/nginx-proxy:test + environment: + DEFAULT_ROOT: 418 + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro + - ./foo.conf:/etc/nginx/vhost.d/foo.nginx-proxy.test:ro + - ./bar.conf:/etc/nginx/vhost.d/nginx-proxy.test_918d687a929083edd0c7224ee2293e0e7c062ab4_location:ro + - ./alternate.conf:/etc/nginx/vhost.d/nginx-proxy.test_7fb22b74bbdf907425dbbad18e4462565cada230_location:ro diff --git a/test/test_virtual-path/test_forwarding.yml b/test/test_virtual-path/test_forwarding.yml index ee87e8d..9b15c74 100644 --- a/test/test_virtual-path/test_forwarding.yml +++ b/test/test_virtual-path/test_forwarding.yml @@ -1,17 +1,20 @@ -web1: - image: web - expose: - - "81" - environment: - WEB_PORTS: "81" - VIRTUAL_HOST: "www.nginx-proxy.tld" - VIRTUAL_PATH: "/web1/" - VIRTUAL_DEST: "/" +version: "2" -sut: - image: nginxproxy/nginx-proxy:test - volumes: - - /var/run/docker.sock:/tmp/docker.sock:ro - - ./certs:/etc/nginx/certs:ro - environment: - - DEFAULT_ROOT=301 http://$$host/web1$$request_uri +services: + web1: + image: web + expose: + - "81" + environment: + WEB_PORTS: "81" + VIRTUAL_HOST: "www.nginx-proxy.tld" + VIRTUAL_PATH: "/web1/" + VIRTUAL_DEST: "/" + + sut: + image: nginxproxy/nginx-proxy:test + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro + - ./certs:/etc/nginx/certs:ro + environment: + - DEFAULT_ROOT=301 http://$$host/web1$$request_uri diff --git a/test/test_virtual-path/test_location_precedence.yml b/test/test_virtual-path/test_location_precedence.yml index be3248c..a250a1d 100644 --- a/test/test_virtual-path/test_location_precedence.yml +++ b/test/test_virtual-path/test_location_precedence.yml @@ -1,37 +1,40 @@ -web1: - image: web - expose: - - "81" - environment: - WEB_PORTS: "81" - VIRTUAL_HOST: "foo.nginx-proxy.test" - VIRTUAL_PATH: "/web1/" - VIRTUAL_DEST: "/" +version: "2" -web2: - image: web - expose: - - "82" - environment: - WEB_PORTS: "82" - VIRTUAL_HOST: "bar.nginx-proxy.test" - VIRTUAL_PATH: "/web2/" - VIRTUAL_DEST: "/" +services: + web1: + image: web + expose: + - "81" + environment: + WEB_PORTS: "81" + VIRTUAL_HOST: "foo.nginx-proxy.test" + VIRTUAL_PATH: "/web1/" + VIRTUAL_DEST: "/" -web3: - image: web - expose: - - "83" - environment: - WEB_PORTS: "83" - VIRTUAL_HOST: "bar.nginx-proxy.test" - VIRTUAL_PATH: "/web3/" - VIRTUAL_DEST: "/" + web2: + image: web + expose: + - "82" + environment: + WEB_PORTS: "82" + VIRTUAL_HOST: "bar.nginx-proxy.test" + VIRTUAL_PATH: "/web2/" + VIRTUAL_DEST: "/" -sut: - image: nginxproxy/nginx-proxy:test - volumes: - - /var/run/docker.sock:/tmp/docker.sock:ro - - ./default.conf:/etc/nginx/vhost.d/default_location:ro - - ./host.conf:/etc/nginx/vhost.d/bar.nginx-proxy.test_location:ro - - ./path.conf:/etc/nginx/vhost.d/bar.nginx-proxy.test_99f2db0ed8aa95dbb5b87fca79c7eff2ff6bb8bd_location:ro + web3: + image: web + expose: + - "83" + environment: + WEB_PORTS: "83" + VIRTUAL_HOST: "bar.nginx-proxy.test" + VIRTUAL_PATH: "/web3/" + VIRTUAL_DEST: "/" + + sut: + image: nginxproxy/nginx-proxy:test + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro + - ./default.conf:/etc/nginx/vhost.d/default_location:ro + - ./host.conf:/etc/nginx/vhost.d/bar.nginx-proxy.test_location:ro + - ./path.conf:/etc/nginx/vhost.d/bar.nginx-proxy.test_99f2db0ed8aa95dbb5b87fca79c7eff2ff6bb8bd_location:ro diff --git a/test/test_virtual-path/test_virtual_paths.yml b/test/test_virtual-path/test_virtual_paths.yml index 9f6a54f..ac70297 100644 --- a/test/test_virtual-path/test_virtual_paths.yml +++ b/test/test_virtual-path/test_virtual_paths.yml @@ -1,42 +1,44 @@ +version: "2" -foo: - image: web - expose: - - "42" - environment: - WEB_PORTS: "42" - VIRTUAL_HOST: "foo.nginx-proxy.test" +services: + foo: + image: web + expose: + - "42" + environment: + WEB_PORTS: "42" + VIRTUAL_HOST: "foo.nginx-proxy.test" -web1: - image: web - expose: - - "81" - environment: - WEB_PORTS: "81" - VIRTUAL_HOST: "nginx-proxy.test" - VIRTUAL_PATH: "/web1/" - VIRTUAL_DEST: "/" + web1: + image: web + expose: + - "81" + environment: + WEB_PORTS: "81" + VIRTUAL_HOST: "nginx-proxy.test" + VIRTUAL_PATH: "/web1/" + VIRTUAL_DEST: "/" -web2: - image: web - expose: - - "82" - environment: - WEB_PORTS: "82" - VIRTUAL_HOST: "nginx-proxy.test" - VIRTUAL_PATH: "/web2/" - VIRTUAL_DEST: "/" + web2: + image: web + expose: + - "82" + environment: + WEB_PORTS: "82" + VIRTUAL_HOST: "nginx-proxy.test" + VIRTUAL_PATH: "/web2/" + VIRTUAL_DEST: "/" -web3: - image: web - expose: - - "83" - environment: - WEB_PORTS: "83" - VIRTUAL_HOST: "nginx-proxy.test" - VIRTUAL_PATH: "/" + web3: + image: web + expose: + - "83" + environment: + WEB_PORTS: "83" + VIRTUAL_HOST: "nginx-proxy.test" + VIRTUAL_PATH: "/" -sut: - image: nginxproxy/nginx-proxy:test - volumes: - - /var/run/docker.sock:/tmp/docker.sock:ro + sut: + image: nginxproxy/nginx-proxy:test + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro diff --git a/test/test_wildcard_host.yml b/test/test_wildcard_host.yml index cd66873..47e75e4 100644 --- a/test/test_wildcard_host.yml +++ b/test/test_wildcard_host.yml @@ -1,37 +1,39 @@ -web1: - image: web - expose: - - "81" - environment: - WEB_PORTS: "81" - VIRTUAL_HOST: "*.nginx-proxy.test" +version: "2" -web2: - image: web - expose: - - "82" - environment: - WEB_PORTS: "82" - VIRTUAL_HOST: "test.nginx-proxy.*" +services: + web1: + image: web + expose: + - "81" + environment: + WEB_PORTS: "81" + VIRTUAL_HOST: "*.nginx-proxy.test" -web3: - image: web - expose: - - "83" - environment: - WEB_PORTS: "83" - VIRTUAL_HOST: ~^web3\..*\.nginx-proxy\.regexp + web2: + image: web + expose: + - "82" + environment: + WEB_PORTS: "82" + VIRTUAL_HOST: "test.nginx-proxy.*" -web4: - image: web - expose: - - "84" - environment: - WEB_PORTS: "84" - VIRTUAL_HOST: ~^web4\..*\.nginx-proxy\.regexp$$ # we need to double the `$` because of docker compose variable interpolation + web3: + image: web + expose: + - "83" + environment: + WEB_PORTS: "83" + VIRTUAL_HOST: ~^web3\..*\.nginx-proxy\.regexp + web4: + image: web + expose: + - "84" + environment: + WEB_PORTS: "84" + VIRTUAL_HOST: ~^web4\..*\.nginx-proxy\.regexp$$ # we need to double the `$` because of docker compose variable interpolation -sut: - image: nginxproxy/nginx-proxy:test - volumes: - - /var/run/docker.sock:/tmp/docker.sock:ro + sut: + image: nginxproxy/nginx-proxy:test + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro From c4cf0af3732e8f2d9ff5b58fe1e089571eaf7f06 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Mon, 11 Dec 2023 15:06:29 +0100 Subject: [PATCH 231/300] test: fix failing tests --- test/test_events.py | 2 ++ test/test_server-down/test_load-balancing.yml | 2 +- test/test_server-down/test_server-down.yml | 2 +- test/test_ssl/test_dhparam.py | 6 ++++-- test/test_virtual-path/test_virtual_paths.py | 1 + 5 files changed, 9 insertions(+), 4 deletions(-) diff --git a/test/test_events.py b/test/test_events.py index b5da3dd..9b99e93 100644 --- a/test/test_events.py +++ b/test/test_events.py @@ -22,6 +22,7 @@ def web1(docker_compose): }, ports={"81/tcp": None} ) + docker_compose.networks.get("test_default").connect(container) sleep(2) # give it some time to initialize and for docker-gen to detect it yield container try: @@ -46,6 +47,7 @@ def web2(docker_compose): }, ports={"82/tcp": None} ) + docker_compose.networks.get("test_default").connect(container) sleep(2) # give it some time to initialize and for docker-gen to detect it yield container try: diff --git a/test/test_server-down/test_load-balancing.yml b/test/test_server-down/test_load-balancing.yml index bde23d6..2322590 100644 --- a/test/test_server-down/test_load-balancing.yml +++ b/test/test_server-down/test_load-balancing.yml @@ -24,7 +24,7 @@ services: environment: WEB_PORTS: 83 VIRTUAL_HOST: web.nginx-proxy.tld - net: "none" + network_mode: "none" sut: image: nginxproxy/nginx-proxy:test diff --git a/test/test_server-down/test_server-down.yml b/test/test_server-down/test_server-down.yml index d4d109a..98fd30f 100644 --- a/test/test_server-down/test_server-down.yml +++ b/test/test_server-down/test_server-down.yml @@ -8,7 +8,7 @@ services: environment: WEB_PORTS: 81 VIRTUAL_HOST: web.nginx-proxy.tld - net: "none" + network_mode: "none" sut: image: nginxproxy/nginx-proxy:test diff --git a/test/test_ssl/test_dhparam.py b/test/test_ssl/test_dhparam.py index d4d64a3..65dcfae 100644 --- a/test/test_ssl/test_dhparam.py +++ b/test/test_ssl/test_dhparam.py @@ -3,6 +3,7 @@ import subprocess import backoff import docker +import pprint import pytest docker_client = docker.from_env() @@ -60,7 +61,8 @@ def require_openssl(required_version): @require_openssl("1.0.2") def negotiate_cipher(sut_container, additional_params='', grep='Cipher is'): - host = f"{sut_container.attrs['NetworkSettings']['IPAddress']}:443" + sut_container.reload() + host = f"{sut_container.attrs['NetworkSettings']['Networks']['test_ssl_default']['IPAddress']}:443" try: # Enforce TLS 1.2 as newer versions don't support custom dhparam or ciphersuite preference. @@ -77,7 +79,7 @@ def negotiate_cipher(sut_container, additional_params='', grep='Cipher is'): except subprocess.CalledProcessError as e: # Output a more helpful error, the original exception in this case isn't that helpful. # `from None` to ignore undesired output from exception chaining. - raise Exception("Failed to process CLI request:\n" + e.stderr) from None + raise Exception(f"Failed to process CLI request openssl s_client -connect {host} -tls1_2 {additional_params}:\n" + e.stderr) from None # The default `dh_bits` can vary due to configuration. diff --git a/test/test_virtual-path/test_virtual_paths.py b/test/test_virtual-path/test_virtual_paths.py index 115d47f..a91a8dd 100644 --- a/test/test_virtual-path/test_virtual_paths.py +++ b/test/test_virtual-path/test_virtual_paths.py @@ -39,6 +39,7 @@ def web4(docker_compose): }, ports={"84/tcp": None} ) + docker_compose.networks.get("test_virtual-path_default").connect(container) sleep(2) # give it some time to initialize and for docker-gen to detect it yield container try: From c1617a6face74d58a835c1fc9424c2e249382064 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 12 Dec 2023 21:07:53 +0000 Subject: [PATCH 232/300] ci: bump docker from 6.1.3 to 7.0.0 in /test/requirements Bumps [docker](https://github.com/docker/docker-py) from 6.1.3 to 7.0.0. - [Release notes](https://github.com/docker/docker-py/releases) - [Commits](https://github.com/docker/docker-py/compare/6.1.3...7.0.0) --- updated-dependencies: - dependency-name: docker dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- test/requirements/python-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/requirements/python-requirements.txt b/test/requirements/python-requirements.txt index 079a74e..985fc95 100644 --- a/test/requirements/python-requirements.txt +++ b/test/requirements/python-requirements.txt @@ -1,4 +1,4 @@ backoff==2.2.1 -docker==6.1.3 +docker==7.0.0 pytest==7.4.3 requests==2.31.0 From 7d44f98e4fdaff0c80240ee60f86629f990fd95b Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Tue, 12 Dec 2023 22:16:32 +0100 Subject: [PATCH 233/300] test: remove unused import --- test/test_ssl/test_dhparam.py | 1 - 1 file changed, 1 deletion(-) diff --git a/test/test_ssl/test_dhparam.py b/test/test_ssl/test_dhparam.py index 65dcfae..1cbc0ac 100644 --- a/test/test_ssl/test_dhparam.py +++ b/test/test_ssl/test_dhparam.py @@ -3,7 +3,6 @@ import subprocess import backoff import docker -import pprint import pytest docker_client = docker.from_env() From 005488886d6d19168a21329665ed237778ae1fc5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 19 Dec 2023 12:40:22 +0000 Subject: [PATCH 234/300] build: bump nginxproxy/docker-gen from 0.10.7 to 0.11.0 Bumps nginxproxy/docker-gen from 0.10.7 to 0.11.0. --- updated-dependencies: - dependency-name: nginxproxy/docker-gen dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- Dockerfile | 2 +- Dockerfile.alpine | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 5c44047..137b156 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM nginxproxy/docker-gen:0.10.7-debian AS docker-gen +FROM nginxproxy/docker-gen:0.11.0-debian AS docker-gen FROM nginxproxy/forego:0.17.2-debian AS forego diff --git a/Dockerfile.alpine b/Dockerfile.alpine index ce2f7a6..a00a0b5 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -1,4 +1,4 @@ -FROM nginxproxy/docker-gen:0.10.7 AS docker-gen +FROM nginxproxy/docker-gen:0.11.0 AS docker-gen FROM nginxproxy/forego:0.17.2 AS forego From db55ddcab4cc6920f1e5a997a2735c44de665fbf Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Mon, 15 May 2023 22:22:05 +0200 Subject: [PATCH 235/300] ci: use build matrix rather than separate jobs --- .github/workflows/build-publish.yml | 112 +++++++--------------------- Dockerfile => Dockerfile.debian | 0 Makefile | 2 +- 3 files changed, 26 insertions(+), 88 deletions(-) rename Dockerfile => Dockerfile.debian (100%) diff --git a/.github/workflows/build-publish.yml b/.github/workflows/build-publish.yml index 9bd3eaf..be406f6 100644 --- a/.github/workflows/build-publish.yml +++ b/.github/workflows/build-publish.yml @@ -19,8 +19,11 @@ on: - "*.md" jobs: - multiarch-build-debian: - name: Build and publish Debian image + multiarch-build: + name: Build and publish image + strategy: + matrix: + base: [alpine, debian] runs-on: ubuntu-latest steps: - name: Checkout @@ -32,8 +35,12 @@ jobs: id: nginx-proxy_version run: echo "VERSION=$(git describe --tags)" >> "$GITHUB_OUTPUT" - - name: Get Docker tags for Debian based image - id: docker_meta_debian + - name: Retrieve docker-gen version + id: docker-gen_version + run: sed -n -e 's;^FROM nginxproxy/docker-gen:\([0-9.]*\).*;VERSION=\1;p' Dockerfile.${{ matrix.base }} >> "$GITHUB_OUTPUT" + + - name: Get Docker tags + id: docker_meta uses: docker/metadata-action@v5 with: images: | @@ -41,12 +48,17 @@ jobs: nginxproxy/nginx-proxy jwilder/nginx-proxy tags: | - type=semver,pattern={{version}} - type=semver,pattern={{major}}.{{minor}} - type=raw,value=latest,enable={{is_default_branch}} + type=semver,pattern={{version}},enable=${{ matrix.base == 'debian' }} + type=semver,pattern={{major}}.{{minor}},enable=${{ matrix.base == 'debian' }} + type=semver,suffix=-alpine,pattern={{version}},enable=${{ matrix.base == 'alpine' }} + type=semver,suffix=-alpine,pattern={{major}}.{{minor}},enable=${{ matrix.base == 'alpine' }} + type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' && matrix.base == 'debian' }} + type=raw,value=alpine,enable=${{ github.ref == 'refs/heads/main' && matrix.base == 'alpine' }} labels: | org.opencontainers.image.authors=Nicolas Duchon (@buchdag), Jason Wilder org.opencontainers.image.version=${{ steps.nginx-proxy_version.outputs.VERSION }} + flavor: | + latest=false - name: Set up QEMU uses: docker/setup-qemu-action@v3 @@ -67,93 +79,19 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Retrieve docker-gen version - id: docker-gen_version - run: sed -n -e 's;^FROM nginxproxy/docker-gen:\([0-9.]*\).*;VERSION=\1;p' Dockerfile >> "$GITHUB_OUTPUT" - - - name: Build and push the Debian based image - id: docker_build_debian + - name: Build and push the image + id: docker_build uses: docker/build-push-action@v5 with: context: . - file: Dockerfile + file: Dockerfile.${{ matrix.base }} build-args: | NGINX_PROXY_VERSION=${{ steps.nginx-proxy_version.outputs.VERSION }} DOCKER_GEN_VERSION=${{ steps.docker-gen_version.outputs.VERSION }} platforms: linux/amd64,linux/arm64,linux/arm/v7 push: true - tags: ${{ steps.docker_meta_debian.outputs.tags }} - labels: ${{ steps.docker_meta_debian.outputs.labels }} + tags: ${{ steps.docker_meta.outputs.tags }} + labels: ${{ steps.docker_meta.outputs.labels }} - name: Images digests - run: echo ${{ steps.docker_build_debian.outputs.digest }} - - multiarch-build-alpine: - name: Build and publish Alpine image - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Retrieve nginx-proxy version - id: nginx-proxy_version - run: echo "VERSION=$(git describe --tags)" >> "$GITHUB_OUTPUT" - - - name: Get Docker tags for Alpine based image - id: docker_meta_alpine - uses: docker/metadata-action@v5 - with: - images: | - ghcr.io/nginx-proxy/nginx-proxy - nginxproxy/nginx-proxy - jwilder/nginx-proxy - tags: | - type=semver,suffix=-alpine,pattern={{version}} - type=semver,suffix=-alpine,pattern={{major}}.{{minor}} - type=raw,value=alpine,enable={{is_default_branch}} - labels: | - org.opencontainers.image.authors=Nicolas Duchon (@buchdag), Jason Wilder - org.opencontainers.image.version=${{ steps.nginx-proxy_version.outputs.VERSION }} - flavor: latest=false - - - name: Set up QEMU - uses: docker/setup-qemu-action@v3 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - - name: Login to DockerHub - uses: docker/login-action@v3 - with: - username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN }} - - - name: Log in to GitHub Container Registry - uses: docker/login-action@v3 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Retrieve docker-gen version - id: docker-gen_version - run: sed -n -e 's;^FROM nginxproxy/docker-gen:\([0-9.]*\).*;VERSION=\1;p' Dockerfile >> "$GITHUB_OUTPUT" - - - name: Build and push the Alpine based image - id: docker_build_alpine - uses: docker/build-push-action@v5 - with: - context: . - file: Dockerfile.alpine - build-args: | - NGINX_PROXY_VERSION=${{ steps.nginx-proxy_version.outputs.VERSION }} - DOCKER_GEN_VERSION=${{ steps.docker-gen_version.outputs.VERSION }} - platforms: linux/amd64,linux/arm64,linux/arm/v7 - push: true - tags: ${{ steps.docker_meta_alpine.outputs.tags }} - labels: ${{ steps.docker_meta_alpine.outputs.labels }} - - - name: Images digests - run: echo ${{ steps.docker_build_alpine.outputs.digest }} + run: echo ${{ steps.docker_build.outputs.digest }} diff --git a/Dockerfile b/Dockerfile.debian similarity index 100% rename from Dockerfile rename to Dockerfile.debian diff --git a/Makefile b/Makefile index 5e53e36..e735e6a 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ build-webserver: docker build --pull -t web test/requirements/web build-nginx-proxy-test-debian: - docker build --pull --build-arg NGINX_PROXY_VERSION="test" -t nginxproxy/nginx-proxy:test . + docker build --pull --build-arg NGINX_PROXY_VERSION="test" -f Dockerfile.debian -t nginxproxy/nginx-proxy:test . build-nginx-proxy-test-alpine: docker build --pull --build-arg NGINX_PROXY_VERSION="test" -f Dockerfile.alpine -t nginxproxy/nginx-proxy:test . From e2997d9fb9a22bc98d361a35ea6c6029b1d68033 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Mon, 15 May 2023 22:23:58 +0200 Subject: [PATCH 236/300] ci: enable gha caching on docker/build-push-action --- .github/workflows/build-publish.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/build-publish.yml b/.github/workflows/build-publish.yml index be406f6..5c823c9 100644 --- a/.github/workflows/build-publish.yml +++ b/.github/workflows/build-publish.yml @@ -92,6 +92,8 @@ jobs: push: true tags: ${{ steps.docker_meta.outputs.tags }} labels: ${{ steps.docker_meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max - name: Images digests run: echo ${{ steps.docker_build.outputs.digest }} From a2ade38abb111aece48a5c120650a4cdf2a607ac Mon Sep 17 00:00:00 2001 From: Gilles Filippini Date: Tue, 19 Dec 2023 19:20:56 +0100 Subject: [PATCH 237/300] fix #2310 Check the '.Internal' network property, because the .Gateway property is defined for internal networks as well. --- nginx.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nginx.tmpl b/nginx.tmpl index f830fd2..66324ff 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -75,7 +75,7 @@ {{- continue }} {{- end }} {{- range sortObjectsByKeysAsc $.globals.CurrentContainer.Networks "Name" }} - {{- if and . .Gateway }} + {{- if and . .Gateway (not .Internal) }} # container is in host network mode, using {{ .Name }} gateway IP {{- $ip = .Gateway }} {{- break }} From 5d37cab19b9fd94d97902700dc1a2819e9193474 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Tue, 19 Dec 2023 19:26:13 +0100 Subject: [PATCH 238/300] ci: add explicit provenance and enable sbom --- .github/workflows/build-publish.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/build-publish.yml b/.github/workflows/build-publish.yml index 5c823c9..1d47393 100644 --- a/.github/workflows/build-publish.yml +++ b/.github/workflows/build-publish.yml @@ -89,7 +89,9 @@ jobs: NGINX_PROXY_VERSION=${{ steps.nginx-proxy_version.outputs.VERSION }} DOCKER_GEN_VERSION=${{ steps.docker-gen_version.outputs.VERSION }} platforms: linux/amd64,linux/arm64,linux/arm/v7 + sbom: true push: true + provenance: mode=max tags: ${{ steps.docker_meta.outputs.tags }} labels: ${{ steps.docker_meta.outputs.labels }} cache-from: type=gha From 2c3883ca8108a8be9f0453d41fae990f4a75b801 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 19 Dec 2023 19:07:02 +0000 Subject: [PATCH 239/300] build: bump nginxproxy/forego from 0.17.2-debian to 0.17.3-debian Bumps nginxproxy/forego from 0.17.2-debian to 0.17.3-debian. --- updated-dependencies: - dependency-name: nginxproxy/forego 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 a00a0b5..2fb2cda 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -1,6 +1,6 @@ FROM nginxproxy/docker-gen:0.11.0 AS docker-gen -FROM nginxproxy/forego:0.17.2 AS forego +FROM nginxproxy/forego:0.17.3 AS forego # Build the final image FROM nginx:1.25.3-alpine diff --git a/Dockerfile.debian b/Dockerfile.debian index 137b156..2b7801c 100644 --- a/Dockerfile.debian +++ b/Dockerfile.debian @@ -1,6 +1,6 @@ FROM nginxproxy/docker-gen:0.11.0-debian AS docker-gen -FROM nginxproxy/forego:0.17.2-debian AS forego +FROM nginxproxy/forego:0.17.3-debian AS forego # Build the final image FROM nginx:1.25.3 From 980470377a957dee31ff2e533babb42f8c79d495 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Tue, 19 Dec 2023 20:27:13 +0100 Subject: [PATCH 240/300] ci: Docker Hub description update --- .github/workflows/dockerhub-description.yml | 27 +++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 .github/workflows/dockerhub-description.yml diff --git a/.github/workflows/dockerhub-description.yml b/.github/workflows/dockerhub-description.yml new file mode 100644 index 0000000..594e132 --- /dev/null +++ b/.github/workflows/dockerhub-description.yml @@ -0,0 +1,27 @@ +name: Update Docker Hub Description + +on: + push: + branches: + - main + paths: + - README.md + - .github/workflows/dockerhub-description.yml + +jobs: + dockerHubDescription: + name: Update Docker Hub Description + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Docker Hub Description + uses: peter-evans/dockerhub-description@v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN_RWD }} + repository: nginxproxy/nginx-proxy + short-description: ${{ github.event.repository.description }} + enable-url-completion: true From 5d2f51dfe27de9f01c45f96f0b3995941ce919a6 Mon Sep 17 00:00:00 2001 From: Gilles Filippini Date: Tue, 12 Dec 2023 19:24:14 +0100 Subject: [PATCH 241/300] Fix test case assertion depending on python version --- .../wildcard_cert_and_nohttps/test_wildcard_cert_nohttps.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/test_ssl/wildcard_cert_and_nohttps/test_wildcard_cert_nohttps.py b/test/test_ssl/wildcard_cert_and_nohttps/test_wildcard_cert_nohttps.py index 590eafc..4453779 100644 --- a/test/test_ssl/wildcard_cert_and_nohttps/test_wildcard_cert_nohttps.py +++ b/test/test_ssl/wildcard_cert_and_nohttps/test_wildcard_cert_nohttps.py @@ -27,7 +27,8 @@ def test_https_get_served(docker_compose, nginxproxy, subdomain): def test_https_request_to_nohttps_vhost_goes_to_fallback_server(docker_compose, nginxproxy): with pytest.raises( (CertificateError, SSLError) ) as excinfo: nginxproxy.get("https://3.web.nginx-proxy.tld/port") - assert """certificate is not valid for '3.web.nginx-proxy.tld'""" in str(excinfo.value) + assert """certificate is not valid for '3.web.nginx-proxy.tld'""" in str(excinfo.value) or \ + """hostname '3.web.nginx-proxy.tld' doesn't match 'nginx-proxy.tld'""" in str(excinfo.value) r = nginxproxy.get("https://3.web.nginx-proxy.tld/port", verify=False) assert r.status_code == 503 From 9e77e81e7dbd99e1de0d4978233be2e1695a8bf5 Mon Sep 17 00:00:00 2001 From: Gilles Filippini Date: Tue, 19 Dec 2023 21:07:30 +0100 Subject: [PATCH 242/300] Tests: support custom 'docker compose' command Enable overriding default 'docker compose' command with environment variable 'DOCKER_COMPOSE'. This way docker compose v1 is still supported with: $ DOCKER_COMPOSE=docker-compose pytest This is important because people using the Debian packaged docker compose are stuck to v1. --- test/README.md | 3 +++ test/conftest.py | 13 +++++++------ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/test/README.md b/test/README.md index 5a93e1b..056cd37 100644 --- a/test/README.md +++ b/test/README.md @@ -28,6 +28,9 @@ need more verbosity ? pytest -s +Note: By default this test suite relies on Docker Compose v2 with the command `docker compose`. It still supports Docker Compose v1 via the `DOCKER_COMPOSE` environment variable: + + DOCKER_COMPOSE=docker-compose pytest Run one single test module -------------------------- diff --git a/test/conftest.py b/test/conftest.py index 938be6b..7fa269a 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -26,6 +26,7 @@ CA_ROOT_CERTIFICATE = os.path.join(os.path.dirname(__file__), 'certs/ca-root.crt PYTEST_RUNNING_IN_CONTAINER = os.environ.get('PYTEST_RUNNING_IN_CONTAINER') == "1" FORCE_CONTAINER_IPV6 = False # ugly global state to consider containers' IPv6 address instead of IPv4 +DOCKER_COMPOSE = os.environ.get('DOCKER_COMPOSE', 'docker compose') docker_client = docker.from_env() @@ -301,19 +302,19 @@ def get_nginx_conf_from_container(container): def docker_compose_up(compose_file='docker-compose.yml'): - logging.info(f'docker compose -f {compose_file} up -d') + logging.info(f'{DOCKER_COMPOSE} -f {compose_file} up -d') try: - subprocess.check_output(shlex.split(f'docker compose -f {compose_file} up -d'), stderr=subprocess.STDOUT) + subprocess.check_output(shlex.split(f'{DOCKER_COMPOSE} -f {compose_file} up -d'), stderr=subprocess.STDOUT) except subprocess.CalledProcessError as e: - pytest.fail(f"Error while runninng 'docker compose -f {compose_file} up -d':\n{e.output}", pytrace=False) + pytest.fail(f"Error while runninng '{DOCKER_COMPOSE} -f {compose_file} up -d':\n{e.output}", pytrace=False) def docker_compose_down(compose_file='docker-compose.yml'): - logging.info(f'docker compose -f {compose_file} down -v') + logging.info(f'{DOCKER_COMPOSE} -f {compose_file} down -v') try: - subprocess.check_output(shlex.split(f'docker compose -f {compose_file} down -v'), stderr=subprocess.STDOUT) + subprocess.check_output(shlex.split(f'{DOCKER_COMPOSE} -f {compose_file} down -v'), stderr=subprocess.STDOUT) except subprocess.CalledProcessError as e: - pytest.fail(f"Error while runninng 'docker compose -f {compose_file} down -v':\n{e.output}", pytrace=False) + pytest.fail(f"Error while runninng '{DOCKER_COMPOSE} -f {compose_file} down -v':\n{e.output}", pytrace=False) def wait_for_nginxproxy_to_be_ready(): From c338a7cf22f3038c3d87255509f0ff1b1a23b8b9 Mon Sep 17 00:00:00 2001 From: Niek <100143256+SchoNie@users.noreply.github.com> Date: Fri, 22 Dec 2023 14:37:20 +0100 Subject: [PATCH 243/300] Color terminal output --- test/pytest.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/pytest.ini b/test/pytest.ini index 9ca7667..10ef478 100644 --- a/test/pytest.ini +++ b/test/pytest.ini @@ -1,5 +1,5 @@ [pytest] # disable the creation of the `.cache` folders -addopts = -p no:cacheprovider --ignore=requirements --ignore=certs -r s -v +addopts = -p no:cacheprovider --ignore=requirements --ignore=certs --color=yes -v markers = - incremental: mark a test as incremental. \ No newline at end of file + incremental: mark a test as incremental. From 51744959634af2b0bec2a3080b1762d72a82e9c5 Mon Sep 17 00:00:00 2001 From: Niek <100143256+SchoNie@users.noreply.github.com> Date: Fri, 22 Dec 2023 17:19:42 +0100 Subject: [PATCH 244/300] Fix test --- .../test_restart_while_missing_cert.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/test/stress_tests/test_deleted_cert/test_restart_while_missing_cert.py b/test/stress_tests/test_deleted_cert/test_restart_while_missing_cert.py index d7e4cbb..e984685 100644 --- a/test/stress_tests/test_deleted_cert/test_restart_while_missing_cert.py +++ b/test/stress_tests/test_deleted_cert/test_restart_while_missing_cert.py @@ -9,8 +9,6 @@ from requests import ConnectionError script_dir = os.path.dirname(__file__) -pytestmark = pytest.mark.xfail() # TODO delete this marker once those issues are fixed - @pytest.fixture(scope="module", autouse=True) def certs(): """ @@ -45,7 +43,6 @@ def test_https_web_is_200(docker_compose, nginxproxy): assert "answer from port 81\n" in r.text -@pytest.mark.incremental def test_delete_cert_and_restart_reverseproxy(docker_compose): os.remove(join(script_dir, "tmp_certs", "web.nginx-proxy.crt")) docker_compose.containers.get("reverseproxy").restart() @@ -53,20 +50,17 @@ def test_delete_cert_and_restart_reverseproxy(docker_compose): assert "running" == docker_compose.containers.get("reverseproxy").status -@pytest.mark.incremental -def test_unknown_virtual_host_is_still_503(nginxproxy): +def test_unknown_virtual_host_is_still_503(docker_compose, nginxproxy): r = nginxproxy.get("http://foo.nginx-proxy/") assert r.status_code == 503 -@pytest.mark.incremental -def test_http_web_is_now_200(nginxproxy): +def test_http_web_is_now_200(docker_compose, nginxproxy): r = nginxproxy.get("http://web.nginx-proxy/port", allow_redirects=False) assert r.status_code == 200 assert "answer from port 81\n" == r.text -@pytest.mark.incremental def test_https_web_is_now_broken_since_there_is_no_cert(nginxproxy): with pytest.raises(ConnectionError): nginxproxy.get("https://web.nginx-proxy/port") From 33ceec07d82e2671d4bee144931b1811323497c0 Mon Sep 17 00:00:00 2001 From: Niek <100143256+SchoNie@users.noreply.github.com> Date: Fri, 22 Dec 2023 17:50:09 +0100 Subject: [PATCH 245/300] Sleep longer --- .../test_deleted_cert/test_restart_while_missing_cert.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/stress_tests/test_deleted_cert/test_restart_while_missing_cert.py b/test/stress_tests/test_deleted_cert/test_restart_while_missing_cert.py index e984685..7fdfa95 100644 --- a/test/stress_tests/test_deleted_cert/test_restart_while_missing_cert.py +++ b/test/stress_tests/test_deleted_cert/test_restart_while_missing_cert.py @@ -46,7 +46,7 @@ def test_https_web_is_200(docker_compose, nginxproxy): def test_delete_cert_and_restart_reverseproxy(docker_compose): os.remove(join(script_dir, "tmp_certs", "web.nginx-proxy.crt")) docker_compose.containers.get("reverseproxy").restart() - sleep(3) # give time for the container to initialize + sleep(5) # give time for the container to initialize assert "running" == docker_compose.containers.get("reverseproxy").status From a4ced5b8bdc8f9bebc0a3effd7286a60b0a92576 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Sun, 24 Dec 2023 00:15:39 +0100 Subject: [PATCH 246/300] test: revert "Fix test" and "Sleep longer" This reverts commit 51744959634af2b0bec2a3080b1762d72a82e9c5. This reverts commit 33ceec07d82e2671d4bee144931b1811323497c0. --- .../test_restart_while_missing_cert.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/test/stress_tests/test_deleted_cert/test_restart_while_missing_cert.py b/test/stress_tests/test_deleted_cert/test_restart_while_missing_cert.py index 7fdfa95..d7e4cbb 100644 --- a/test/stress_tests/test_deleted_cert/test_restart_while_missing_cert.py +++ b/test/stress_tests/test_deleted_cert/test_restart_while_missing_cert.py @@ -9,6 +9,8 @@ from requests import ConnectionError script_dir = os.path.dirname(__file__) +pytestmark = pytest.mark.xfail() # TODO delete this marker once those issues are fixed + @pytest.fixture(scope="module", autouse=True) def certs(): """ @@ -43,24 +45,28 @@ def test_https_web_is_200(docker_compose, nginxproxy): assert "answer from port 81\n" in r.text +@pytest.mark.incremental def test_delete_cert_and_restart_reverseproxy(docker_compose): os.remove(join(script_dir, "tmp_certs", "web.nginx-proxy.crt")) docker_compose.containers.get("reverseproxy").restart() - sleep(5) # give time for the container to initialize + sleep(3) # give time for the container to initialize assert "running" == docker_compose.containers.get("reverseproxy").status -def test_unknown_virtual_host_is_still_503(docker_compose, nginxproxy): +@pytest.mark.incremental +def test_unknown_virtual_host_is_still_503(nginxproxy): r = nginxproxy.get("http://foo.nginx-proxy/") assert r.status_code == 503 -def test_http_web_is_now_200(docker_compose, nginxproxy): +@pytest.mark.incremental +def test_http_web_is_now_200(nginxproxy): r = nginxproxy.get("http://web.nginx-proxy/port", allow_redirects=False) assert r.status_code == 200 assert "answer from port 81\n" == r.text +@pytest.mark.incremental def test_https_web_is_now_broken_since_there_is_no_cert(nginxproxy): with pytest.raises(ConnectionError): nginxproxy.get("https://web.nginx-proxy/port") From 7f43f0a66b75b184634d96efcd96e79f2d51cc7d Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Sun, 24 Dec 2023 16:14:52 +0100 Subject: [PATCH 247/300] docs: split documentation --- README.md | 762 ++----------------------------------------------- docs/README.md | 728 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 754 insertions(+), 736 deletions(-) create mode 100644 docs/README.md diff --git a/README.md b/README.md index 6ff07f0..48d513f 100644 --- a/README.md +++ b/README.md @@ -15,766 +15,56 @@ See [Automated Nginx Reverse Proxy for Docker](http://jasonwilder.com/blog/2014/ To run it: ```console -docker run -d -p 80:80 -v /var/run/docker.sock:/tmp/docker.sock:ro nginxproxy/nginx-proxy +docker run --detach \ + --name nginx-proxy \ + --publish 80:80 \ + --volume /var/run/docker.sock:/tmp/docker.sock:ro \ + nginxproxy/nginx-proxy:1.4 ``` -Then start any containers you want proxied with an env var `VIRTUAL_HOST=subdomain.youdomain.com` +Then start any containers (here an nginx container) you want proxied with an env var `VIRTUAL_HOST=subdomain.yourdomain.com` ```console -docker run -e VIRTUAL_HOST=foo.bar.com ... +docker run --detach \ + --name your-proxied-app \ + --env VIRTUAL_HOST=foo.bar.com \ + nginx ``` -The containers being proxied must [expose](https://docs.docker.com/engine/reference/run/#expose-incoming-ports) the port to be proxied, either by using the `EXPOSE` directive in their `Dockerfile` or by using the `--expose` flag to `docker run` or `docker create` and be in the same network. By default, if you don't pass the --net flag when your nginx-proxy container is created, it will only be attached to the default bridge network. This means that it will not be able to connect to containers on networks other than bridge. +Provided your DNS is setup to resolve `foo.bar.com` to the host running nginx-proxy, a request to `http://foo.bar.com` will then be routed to a container with the `VIRTUAL_HOST` env var set to `foo.bar.com` (in this case, the **your-proxied-app** container). -Provided your DNS is setup to forward foo.bar.com to the host running nginx-proxy, the request will be routed to a container with the `VIRTUAL_HOST` env var set. +The containers being proxied must : +- [expose](https://docs.docker.com/engine/reference/run/#expose-incoming-ports) the port to be proxied, either by using the `EXPOSE` directive in their `Dockerfile` or by using the `--expose` flag to `docker run` or `docker create`. +- share at least one Docker network with the nginx-proxy container: by default, if you don't pass the `--net` flag when your nginx-proxy container is created, it will only be attached to the default bridge network. This means that it will not be able to connect to containers on networks other than bridge. -Note: providing a port number in `VIRTUAL_HOST` isn't suported, please see [virtual ports](https://github.com/nginx-proxy/nginx-proxy#virtual-ports) or [custom external HTTP/HTTPS ports](https://github.com/nginx-proxy/nginx-proxy#custom-external-httphttps-ports) depending on what you want to achieve. +Note: providing a port number in `VIRTUAL_HOST` isn't suported, please see [virtual ports](https://github.com/nginx-proxy/nginx-proxy/docs#virtual-ports) or [custom external HTTP/HTTPS ports](https://github.com/nginx-proxy/nginx-proxy/docs#custom-external-httphttps-ports) depending on what you want to achieve. ### Image variants The nginx-proxy images are available in two flavors. -#### nginxproxy/nginx-proxy:latest +#### Debian based version -This image uses the debian:buster based nginx image. +This image is based on the nginx:mainline image, itself based on the debian slim image. ```console -docker pull nginxproxy/nginx-proxy:latest +docker pull nginxproxy/nginx-proxy:1.4 ``` -#### nginxproxy/nginx-proxy:alpine +#### Alpine based version (`-alpine` suffix) -This image is based on the nginx:alpine image. Use this image to fully support HTTP/2 (including ALPN required by recent Chrome versions). A valid certificate is required as well (see eg. below "SSL Support using an ACME CA" for more info). +This image is based on the nginx:alpine image. ```console -docker pull nginxproxy/nginx-proxy:alpine +docker pull nginxproxy/nginx-proxy:1.4-alpine ``` -### Docker Compose +#### :warning: a note on `latest` and `alpine`: -```yaml -version: '2' +It is not recommended to use the `latest` (`nginxproxy/nginx-proxy`, `nginxproxy/nginx-proxy:latest`) or `alpine` (`nginxproxy/nginx-proxy:alpine`) tag for production setups. -services: - nginx-proxy: - image: nginxproxy/nginx-proxy - ports: - - "80:80" - volumes: - - /var/run/docker.sock:/tmp/docker.sock:ro +Those tags points to the latest commit in the `main` branch. They do not carry any promise of stability, and using them will probably put your nginx-proxy setup at risk of experiencing uncontrolled updates to non backward compatible versions (or versions with breaking changes). You should always specify the version you want to use explicitly to ensure your setup doesn't break when the image is updated. - whoami: - image: jwilder/whoami - expose: - - "8000" - environment: - - VIRTUAL_HOST=whoami.example - - VIRTUAL_PORT=8000 -``` +### Additional documentation -```console -docker compose up -curl -H "Host: whoami.example" localhost -``` - -Example output: -```console -I'm 5b129ab83266 -``` - -### IPv6 support - -You can activate the IPv6 support for the nginx-proxy container by passing the value `true` to the `ENABLE_IPV6` environment variable: - -```console -docker run -d -p 80:80 -e ENABLE_IPV6=true -v /var/run/docker.sock:/tmp/docker.sock:ro nginxproxy/nginx-proxy -``` - -#### Scoped IPv6 Resolvers - -NginX does not support scoped IPv6 resolvers. In [docker-entrypoint.sh](./docker-entrypoint.sh) the resolvers are parsed from resolv.conf, but any scoped IPv6 addreses will be removed. - -#### IPv6 NAT - -By default, docker uses IPv6-to-IPv4 NAT. This means all client connections from IPv6 addresses will show docker's internal IPv4 host address. To see true IPv6 client IP addresses, you must [enable IPv6](https://docs.docker.com/config/daemon/ipv6/) and use [ipv6nat](https://github.com/robbertkl/docker-ipv6nat). You must also disable the userland proxy by adding `"userland-proxy": false` to `/etc/docker/daemon.json` and restarting the daemon. - -### Multiple Hosts - -If you need to support multiple virtual hosts for a container, you can separate each entry with commas. For example, `foo.bar.com,baz.bar.com,bar.com` and each host will be setup the same. - -### Virtual Ports - -When your container exposes only one port, nginx-proxy will default to this port, else to port 80. - -If you need to specify a different port, you can set a `VIRTUAL_PORT` env var to select a different one. This variable cannot be set to more than one port. - -For each host defined into `VIRTUAL_HOST`, the associated virtual port is retrieved by order of precedence: -1. From the `VIRTUAL_PORT` environment variable -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 - -### Wildcard Hosts - -You can also use wildcards at the beginning and the end of host name, like `*.bar.com` or `foo.bar.*`. Or even a regular expression, which can be very useful in conjunction with a wildcard DNS service like [nip.io](https://nip.io) or [sslip.io](https://sslip.io), using `~^foo\.bar\..*\.nip\.io` will match `foo.bar.127.0.0.1.nip.io`, `foo.bar.10.0.2.2.nip.io` and all other given IPs. More information about this topic can be found in the nginx documentation about [`server_names`](http://nginx.org/en/docs/http/server_names.html). - -### Path-based Routing - -You can have multiple containers proxied by the same `VIRTUAL_HOST` by adding a `VIRTUAL_PATH` environment variable containing the absolute path to where the container should be mounted. For example with `VIRTUAL_HOST=foo.example.com` and `VIRTUAL_PATH=/api/v2/service`, then requests to http://foo.example.com/api/v2/service will be routed to the container. If you wish to have a container serve the root while other containers serve other paths, give the root container a `VIRTUAL_PATH` of `/`. Unmatched paths will be served by the container at `/` or will return the default nginx error page if no container has been assigned `/`. -It is also possible to specify multiple paths with regex locations like `VIRTUAL_PATH=~^/(app1|alternative1)/`. For further details see the nginx documentation on location blocks. This is not compatible with `VIRTUAL_DEST`. - -The full request URI will be forwarded to the serving container in the `X-Original-URI` header. - -**NOTE**: Your application needs to be able to generate links starting with `VIRTUAL_PATH`. This can be achieved by it being natively on this path or having an option to prepend this path. The application does not need to expect this path in the request. - -#### VIRTUAL_DEST - -This environment variable can be used to rewrite the `VIRTUAL_PATH` part of the requested URL to proxied application. The default value is empty (off). -Make sure that your settings won't result in the slash missing or being doubled. Both these versions can cause troubles. - -If the application runs natively on this sub-path or has a setting to do so, `VIRTUAL_DEST` should not be set or empty. -If the requests are expected to not contain a sub-path and the generated links contain the sub-path, `VIRTUAL_DEST=/` should be used. - -```console -$ docker run -d -e VIRTUAL_HOST=example.tld -e VIRTUAL_PATH=/app1/ -e VIRTUAL_DEST=/ --name app1 app -``` - -In this example, the incoming request `http://example.tld/app1/foo` will be proxied as `http://app1/foo` instead of `http://app1/app1/foo`. - -#### 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 filename of the previous example would be `example.tld_8610f6c344b4096614eab6e09d58885349f42faf_location`. - -#### DEFAULT_ROOT - -This environment variable of the nginx proxy container can be used to customize the return error page if no matching path is found. Furthermore it is possible to use anything which is compatible with the `return` statement of nginx. - -Exception: If this is set to the string `none`, no default `location /` directive will be generated. This makes it possible for you to provide your own `location /` directive in your [`/etc/nginx/vhost.d/VIRTUAL_HOST`](#per-virtual_host) or [`/etc/nginx/vhost.d/default`](#per-virtual_host-default-configuration) files. - -If unspecified, `DEFAULT_ROOT` defaults to `404`. - -Examples (YAML syntax): - - * `DEFAULT_ROOT: "none"` prevents `nginx-proxy` from generating a default `location /` directive. - * `DEFAULT_ROOT: "418"` returns a 418 error page instead of the normal 404 one. - * `DEFAULT_ROOT: "301 https://github.com/nginx-proxy/nginx-proxy/blob/main/README.md"` redirects the client to this documentation. - -Nginx variables such as `$scheme`, `$host`, and `$request_uri` can be used. However, care must be taken to make sure the `$` signs are escaped properly. For example, if you want to use `301 $scheme://$host/myapp1$request_uri` you should use: - -* Bash: `DEFAULT_ROOT='301 $scheme://$host/myapp1$request_uri'` -* Docker Compose yaml: `- DEFAULT_ROOT: 301 $$scheme://$$host/myapp1$$request_uri` - - -### Multiple Networks - -With the addition of [overlay networking](https://docs.docker.com/engine/userguide/networking/get-started-overlay/) in Docker 1.9, your `nginx-proxy` container may need to connect to backend containers on multiple networks. By default, if you don't pass the `--net` flag when your `nginx-proxy` container is created, it will only be attached to the default `bridge` network. This means that it will not be able to connect to containers on networks other than `bridge`. - -If you want your `nginx-proxy` container to be attached to a different network, you must pass the `--net=my-network` option in your `docker create` or `docker run` command. At the time of this writing, only a single network can be specified at container creation time. To attach to other networks, you can use the `docker network connect` command after your container is created: - -```console -docker run -d -p 80:80 -v /var/run/docker.sock:/tmp/docker.sock:ro \ - --name my-nginx-proxy --net my-network nginxproxy/nginx-proxy -docker network connect my-other-network my-nginx-proxy -``` - -In this example, the `my-nginx-proxy` container will be connected to `my-network` and `my-other-network` and will be able to proxy to other containers attached to those networks. - -### Host networking - -`nginx-proxy` is compatible with containers using Docker's [host networking](https://docs.docker.com/network/host/), both with the proxy connected to one or more [bridge network](https://docs.docker.com/network/bridge/) (default or user created) or running in host network mode itself. - -Proxyed containers running in host network mode **must** use the [`VIRTUAL_PORT`](#virtual-ports) environment variable, as this is the only way for `nginx-proxy` to get the correct port (or a port at all) for those containers. - -### Custom external HTTP/HTTPS ports - -If you want to use `nginx-proxy` with different external ports that the default ones of `80` for `HTTP` traffic and `443` for `HTTPS` traffic, you'll have to use the environment variable(s) `HTTP_PORT` and/or `HTTPS_PORT` in addition to the changes to the Docker port mapping. If you change the `HTTPS` port, the redirect for `HTTPS` traffic will also be configured to redirect to the custom port. Typical usage, here with the custom ports `1080` and `10443`: - -```console -docker run -d -p 1080:1080 -p 10443:10443 -e HTTP_PORT=1080 -e HTTPS_PORT=10443 -v /var/run/docker.sock:/tmp/docker.sock:ro nginxproxy/nginx-proxy -``` - -### Internet vs. Local Network Access - -If you allow traffic from the public internet to access your `nginx-proxy` container, you may want to restrict some containers to the internal network only, so they cannot be accessed from the public internet. On containers that should be restricted to the internal network, you should set the environment variable `NETWORK_ACCESS=internal`. By default, the *internal* network is defined as `127.0.0.0/8, 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16`. To change the list of networks considered internal, mount a file on the `nginx-proxy` at `/etc/nginx/network_internal.conf` with these contents, edited to suit your needs: - -```Nginx -# These networks are considered "internal" -allow 127.0.0.0/8; -allow 10.0.0.0/8; -allow 192.168.0.0/16; -allow 172.16.0.0/12; - -# Traffic from all other networks will be rejected -deny all; -``` - -When internal-only access is enabled, external clients will be denied with an `HTTP 403 Forbidden` - -> If there is a load-balancer / reverse proxy in front of `nginx-proxy` that hides the client IP (example: AWS Application/Elastic Load Balancer), you will need to use the nginx `realip` module (already installed) to extract the client's IP from the HTTP request headers. Please see the [nginx realip module configuration](http://nginx.org/en/docs/http/ngx_http_realip_module.html) for more details. This configuration can be added to a new config file and mounted in `/etc/nginx/conf.d/`. - -### SSL Backends - -If you would like the reverse proxy to connect to your backend using HTTPS instead of HTTP, set `VIRTUAL_PROTO=https` on the backend container. - -> Note: If you use `VIRTUAL_PROTO=https` and your backend container exposes port 80 and 443, `nginx-proxy` will use HTTPS on port 80. This is almost certainly not what you want, so you should also include `VIRTUAL_PORT=443`. - -### uWSGI Backends - -If you would like to connect to uWSGI backend, set `VIRTUAL_PROTO=uwsgi` on the backend container. Your backend container should then listen on a port rather than a socket and expose that port. - -### FastCGI Backends - -If you would like to connect to FastCGI backend, set `VIRTUAL_PROTO=fastcgi` on the backend container. Your backend container should then listen on a port rather than a socket and expose that port. - -### FastCGI File Root Directory - -If you use fastcgi,you can set `VIRTUAL_ROOT=xxx` for your root directory - -### Custom log format - -If you want to use a custom log format, you can set `LOG_FORMAT=xxx` on the proxy container. - -With docker compose take care to escape the `$` character with `$$` to avoid variable interpolation. Example: `$remote_addr` becomes `$$remote_addr`. - -### Default Host - -To set the default host for nginx use the env var `DEFAULT_HOST=foo.bar.com` for example - -```console -docker run -d -p 80:80 -e DEFAULT_HOST=foo.bar.com -v /var/run/docker.sock:/tmp/docker.sock:ro nginxproxy/nginx-proxy -``` - -nginx-proxy will then redirect all requests to a container where `VIRTUAL_HOST` is set to `DEFAULT_HOST`, if they don't match any (other) `VIRTUAL_HOST`. Using the example above requests without matching `VIRTUAL_HOST` will be redirected to a plain nginx instance after running the following command: - -```console -docker run -d -e VIRTUAL_HOST=foo.bar.com nginx -``` - -### Separate Containers - -nginx-proxy can also be run as two separate containers using the [nginxproxy/docker-gen](https://hub.docker.com/r/nginxproxy/docker-gen) image and the official [nginx](https://registry.hub.docker.com/_/nginx/) image. - -You may want to do this to prevent having the docker socket bound to a publicly exposed container service. - -You can demo this pattern with docker compose: - -```console -docker compose --file docker-compose-separate-containers.yml up -curl -H "Host: whoami.example" localhost -``` - -Example output: -```console -I'm 5b129ab83266 -``` - -To run nginx proxy as a separate container you'll need to have [nginx.tmpl](https://github.com/nginx-proxy/nginx-proxy/blob/main/nginx.tmpl) on your host system. - -First start nginx with a volume: - - -```console -docker run -d -p 80:80 --name nginx -v /tmp/nginx:/etc/nginx/conf.d -t nginx -``` - -Then start the docker-gen container with the shared volume and template: - -```console -docker run --volumes-from nginx \ - -v /var/run/docker.sock:/tmp/docker.sock:ro \ - -v $(pwd):/etc/docker-gen/templates \ - -t nginxproxy/docker-gen -notify-sighup nginx -watch /etc/docker-gen/templates/nginx.tmpl /etc/nginx/conf.d/default.conf -``` - -Finally, start your containers with `VIRTUAL_HOST` environment variables. - -```console -docker run -e VIRTUAL_HOST=foo.bar.com ... -``` - -### SSL Support using an ACME CA - -[acme-companion](https://github.com/nginx-proxy/acme-companion) is a lightweight companion container for the nginx-proxy. It allows the automated creation/renewal of SSL certificates using the ACME protocol. - -### SSL Support - -SSL is supported using single host, wildcard and SNI certificates using naming conventions for certificates or optionally specifying a cert name (for SNI) as an environment variable. - -To enable SSL: - -```console -docker run -d -p 80:80 -p 443:443 -v /path/to/certs:/etc/nginx/certs -v /var/run/docker.sock:/tmp/docker.sock:ro nginxproxy/nginx-proxy -``` - -The contents of `/path/to/certs` should contain the certificates and private keys for any virtual hosts in use. The certificate and keys should be named after the virtual host with a `.crt` and `.key` extension. For example, a container with `VIRTUAL_HOST=foo.bar.com` should have a `foo.bar.com.crt` and `foo.bar.com.key` file in the certs directory. - -If you are running the container in a virtualized environment (Hyper-V, VirtualBox, etc...), /path/to/certs must exist in that environment or be made accessible to that environment. By default, Docker is not able to mount directories on the host machine to containers running in a virtual machine. - -#### 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. - -To use custom `dhparam.pem` files per-virtual-host, the files should be named after the virtual host with a `dhparam` suffix and `.pem` extension. For example, a container with `VIRTUAL_HOST=foo.bar.com` should have a `foo.bar.com.dhparam.pem` file in the `/etc/nginx/certs` directory. - -> COMPATIBILITY WARNING: The default generated `dhparam.pem` key is 4096 bits for A+ security. Some older clients (like Java 6 and 7) do not support DH keys with over 1024 bits. In order to support these clients, you must provide your own `dhparam.pem`. - -In the separate container setup, no pre-generated key will be available and neither the [nginxproxy/docker-gen](https://hub.docker.com/r/nginxproxy/docker-gen) image, nor the offical [nginx](https://registry.hub.docker.com/_/nginx/) image will provide one. If you still want A+ security in a separate container setup, you should mount an RFC7919 DH key file to the nginx container at `/etc/nginx/dhparam/dhparam.pem`. - -Set `DHPARAM_SKIP` environment variable to `true` to disable using default Diffie-Hellman parameters. The default value is `false`. - -```console -docker run -e DHPARAM_SKIP=true .... -``` - -#### Wildcard Certificates - -Wildcard certificates and keys should be named after the domain name with a `.crt` and `.key` extension. For example `VIRTUAL_HOST=foo.bar.com` would use cert name `bar.com.crt` and `bar.com.key`. - -#### SNI - -If your certificate(s) supports multiple domain names, you can start a container with `CERT_NAME=` to identify the certificate to be used. For example, a certificate for `*.foo.com` and `*.bar.com` could be named `shared.crt` and `shared.key`. A container running with `VIRTUAL_HOST=foo.bar.com` and `CERT_NAME=shared` will then use this shared cert. - -#### OCSP Stapling - -To enable OCSP Stapling for a domain, `nginx-proxy` looks for a PEM certificate containing the trusted CA certificate chain at `/etc/nginx/certs/.chain.pem`, where `` is the domain name in the `VIRTUAL_HOST` directive. The format of this file is a concatenation of the public PEM CA certificates starting with the intermediate CA most near the SSL certificate, down to the root CA. This is often referred to as the "SSL Certificate Chain". If found, this filename is passed to the NGINX [`ssl_trusted_certificate` directive](http://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_trusted_certificate) and OCSP Stapling is enabled. - -#### How SSL Support Works - -The default SSL cipher configuration is based on the [Mozilla intermediate profile](https://wiki.mozilla.org/Security/Server_Side_TLS#Intermediate_compatibility_.28recommended.29) version 5.0 which should provide compatibility with clients back to Firefox 27, Android 4.4.2, Chrome 31, Edge, IE 11 on Windows 7, Java 8u31, OpenSSL 1.0.1, Opera 20, and Safari 9. Note that the DES-based TLS ciphers were removed for security. The configuration also enables HSTS, PFS, OCSP stapling and SSL session caches. Currently TLS 1.2 and 1.3 are supported. - -If you don't require backward compatibility, you can use the [Mozilla modern profile](https://wiki.mozilla.org/Security/Server_Side_TLS#Modern_compatibility) profile instead by including the environment variable `SSL_POLICY=Mozilla-Modern` to the nginx-proxy container or to your container. This profile is compatible with clients back to Firefox 63, Android 10.0, Chrome 70, Edge 75, Java 11, OpenSSL 1.1.1, Opera 57, and Safari 12.1. Note that this profile is **not** compatible with any version of Internet Explorer. - -Complete list of policies available through the `SSL_POLICY` environment variable, including the [AWS ELB Security Policies](https://docs.aws.amazon.com/elasticloadbalancing/latest/application/create-https-listener.html#describe-ssl-policies) and [AWS Classic ELB security policies](https://docs.aws.amazon.com/fr_fr/elasticloadbalancing/latest/classic/elb-security-policy-table.html): - -
    - Mozilla policies - -
    -
    - AWS ELB TLS 1.3 security policies -
      -
    • - AWS-TLS13-1-3-2021-06 -
    • -
    • - AWS-TLS13-1-2-2021-06 -
    • -
    • - AWS-TLS13-1-2-Res-2021-06 -
    • -
    • - AWS-TLS13-1-2-Ext1-2021-06 -
    • -
    • - AWS-TLS13-1-2-Ext2-2021-06 -
    • -
    • - AWS-TLS13-1-1-2021-06 -
    • -
    • - AWS-TLS13-1-0-2021-06 -
    • -
    -
    -
    - AWS ELB FS supported policies -
      -
    • - AWS-FS-1-2-Res-2020-10 -
    • -
    • - AWS-FS-1-2-Res-2019-08 -
    • -
    • - AWS-FS-1-2-2019-08 -
    • -
    • - AWS-FS-1-1-2019-08 -
    • -
    • - AWS-FS-2018-06 -
    • -
    -
    -
    - AWS ELB TLS 1.0 - 1.2 security policies -
      -
    • - AWS-TLS-1-2-Ext-2018-06 -
    • -
    • - AWS-TLS-1-2-2017-01 -
    • -
    • - AWS-TLS-1-1-2017-01 -
    • -
    • - AWS-2016-08 -
    • -
    -
    -
    - AWS Classic ELB security policies -
      -
    • - AWS-2015-05 -
    • -
    • - AWS-2015-03 -
    • -
    • - AWS-2015-02 -
    • -
    -
    -
    - -Note that the `Mozilla-Old` policy should use a 1024 bits DH key for compatibility but this container provides a 4096 bits key. The [Diffie-Hellman Groups](#diffie-hellman-groups) section details different methods of bypassing this, either globally or per virtual-host. - -The default behavior for the proxy when port 80 and 443 are exposed is as follows: - -* If a virtual host has a usable cert, port 80 will redirect to 443 for that virtual host so that HTTPS is always preferred when available. -* If the virtual host does not have a usable cert, but `default.crt` and `default.key` exist, those will be used as the virtual host's certificate and the client browser will receive a 500 error. -* If the virtual host does not have a usable cert, and `default.crt` and `default.key` do not exist, TLS negotiation will fail (see [Missing Certificate](#missing-certificate) below). - -To serve traffic in both SSL and non-SSL modes without redirecting to SSL, you can include the environment variable `HTTPS_METHOD=noredirect` (the default is `HTTPS_METHOD=redirect`). You can also disable the non-SSL site entirely with `HTTPS_METHOD=nohttp`, or disable the HTTPS site with `HTTPS_METHOD=nohttps`. `HTTPS_METHOD` can be specified on each container for which you want to override the default behavior or on the proxy container to set it globally. If `HTTPS_METHOD=noredirect` is used, Strict Transport Security (HSTS) is disabled to prevent HTTPS users from being redirected by the client. If you cannot get to the HTTP site after changing this setting, your browser has probably cached the HSTS policy and is automatically redirecting you back to HTTPS. You will need to clear your browser's HSTS cache or use an incognito window / different browser. - -By default, [HTTP Strict Transport Security (HSTS)](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security) is enabled with `max-age=31536000` for HTTPS sites. You can disable HSTS with the environment variable `HSTS=off` or use a custom HSTS configuration like `HSTS=max-age=31536000; includeSubDomains; preload`. - -*WARNING*: HSTS will force your users to visit the HTTPS version of your site for the `max-age` time - even if they type in `http://` manually. The only way to get to an HTTP site after receiving an HSTS response is to clear your browser's HSTS cache. - -#### Missing Certificate - -If HTTPS is enabled for a virtual host but its certificate is missing, nginx-proxy will configure nginx to use the default certificate (`default.crt` with `default.key`) and return a 500 error. - -If the default certificate is also missing, nginx-proxy will configure nginx to accept HTTPS connections but fail the TLS negotiation. Client browsers will render a TLS error page. As of March 2023, web browsers display the following error messages: - - * Chrome: - - > This site can't provide a secure connection - > - > example.test sent an invalid response. - > - > Try running Connectivity Diagnostics. - > - > `ERR_SSL_PROTOCOL_ERROR` - - * Firefox: - - > Secure Connection Failed - > - > An error occurred during a connection to example.test. - > Peer reports it experienced an internal error. - > - > Error code: `SSL_ERROR_INTERNAL_ERROR_ALERT` "TLS error". - -### HTTP/2 support - -HTTP/2 is enabled by default and can be disabled if necessary either per-proxied container or globally: - -To disable HTTP/2 for a single proxied container, set the `com.github.nginx-proxy.nginx-proxy.http2.enable` label to `false` on this container. - -To disable HTTP/2 globally set the environment variable `ENABLE_HTTP2` to `false` on the nginx-proxy container. - -More reading on the potential TCP head-of-line blocking issue with HTTP/2: [HTTP/2 Issues](https://www.twilio.com/blog/2017/10/http2-issues.html), [Comparing HTTP/3 vs HTTP/2](https://blog.cloudflare.com/http-3-vs-http-2/) - -### HTTP/3 support - -> **Warning** -> HTTP/3 support [is still considered experimental in nginx](https://www.nginx.com/blog/binary-packages-for-preview-nginx-quic-http3-implementation/) and as such is considered experimental in nginx-proxy too and is disabled by default. [Feedbacks for the HTTP/3 support are welcome in #2271.](https://github.com/nginx-proxy/nginx-proxy/discussions/2271) - -HTTP/3 use the QUIC protocol over UDP (unlike HTTP/1.1 and HTTP/2 which work over TCP), so if you want to use HTTP/3 you'll have to explicitely publish the 443/udp port of the proxy in addition to the 443/tcp port: - -```console -docker run -d -p 80:80 -p 443:443/tcp -p 443:443/udp \ - -v /var/run/docker.sock:/tmp/docker.sock:ro \ - nginxproxy/nginx-proxy -``` - -HTTP/3 can be enabled either per-proxied container or globally: - -To enable HTTP/3 for a single proxied container, set the `com.github.nginx-proxy.nginx-proxy.http3.enable` label to `true` on this container. - -To enable HTTP/3 globally set the environment variable `ENABLE_HTTP3` to `true` on the nginx-proxy container. - -### 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 on directory -/etc/nginx/htpasswd/$VIRTUAL_HOST - -```console -docker run -d -p 80:80 -p 443:443 \ - -v /path/to/htpasswd:/etc/nginx/htpasswd \ - -v /path/to/certs:/etc/nginx/certs \ - -v /var/run/docker.sock:/tmp/docker.sock:ro \ - nginxproxy/nginx-proxy -``` - -You'll need apache2-utils on the machine where you plan to create the htpasswd file. Follow these [instructions](http://httpd.apache.org/docs/2.2/programs/htpasswd.html) - -### Upstream (Backend) Server HTTP Load Balancing Support - -> **Warning** -> This feature is experimental. The behavior may change (or the feature may be removed entirely) without warning in a future release, even if the release is not a new major version. If you use this feature, or if you would like to use this feature but you require changes to it first, please [provide feedback in #2195](https://github.com/nginx-proxy/nginx-proxy/discussions/2195). Once we have collected enough feedback we will promote this feature to officially supported. - -If you have multiple containers with the same `VIRTUAL_HOST` and `VIRTUAL_PATH` settings, nginx will spread the load across all of them. To change the load balancing algorithm from nginx's default (round-robin), set the `com.github.nginx-proxy.nginx-proxy.loadbalance` label on one or more of your application containers to the desired load balancing directive. See the [`ngx_http_upstream_module` documentation](https://nginx.org/en/docs/http/ngx_http_upstream_module.html) for available directives. - -> **Note** -> * Don't forget the terminating semicolon (`;`). -> * If you are using Docker Compose, remember to escape any dollar sign (`$`) characters (`$` becomes `$$`). - -Docker Compose example: - -```yaml -services: - nginx-proxy: - image: nginxproxy/nginx-proxy - ports: - - "80:80" - volumes: - - /var/run/docker.sock:/tmp/docker.sock:ro - environment: - HTTPS_METHOD: nohttps - myapp: - image: jwilder/whoami - expose: - - "8000" - environment: - VIRTUAL_HOST: myapp.example - VIRTUAL_PORT: "8000" - labels: - com.github.nginx-proxy.nginx-proxy.loadbalance: "hash $$remote_addr;" - deploy: - replicas: 4 -``` - -### Upstream (Backend) Server HTTP Keep-Alive Support - -> **Warning** -> This feature is experimental. The behavior may change (or the feature may be removed entirely) without warning in a future release, even if the release is not a new major version. If you use this feature, or if you would like to use this feature but you require changes to it first, please [provide feedback in #2194](https://github.com/nginx-proxy/nginx-proxy/discussions/2194). Once we have collected enough feedback we will promote this feature to officially supported. - -To enable HTTP keep-alive between `nginx-proxy` and a backend server, set the `com.github.nginx-proxy.nginx-proxy.keepalive` label on the server's container to the desired maximum number of idle connections. See the [nginx keepalive documentation](https://nginx.org/en/docs/http/ngx_http_upstream_module.html#keepalive) and the [Docker label documentation](https://docs.docker.com/config/labels-custom-metadata/) for details. - -### Headers - -By default, `nginx-proxy` forwards all incoming request headers from the client to the backend server unmodified, with the following exceptions: - - * `Connection`: Set to `upgrade` if the client sets the `Upgrade` header, otherwise set to `close`. (Keep-alive between `nginx-proxy` and the backend server is not supported.) - * `Proxy`: Always removed if present. This prevents attackers from using the so-called [httpoxy attack](http://httpoxy.org). There is no legitimate reason for a client to send this header, and there are many vulnerable languages / platforms (`CVE-2016-5385`, `CVE-2016-5386`, `CVE-2016-5387`, `CVE-2016-5388`, `CVE-2016-1000109`, `CVE-2016-1000110`, `CERT-VU#797896`). - * `X-Real-IP`: Set to the client's IP address. - * `X-Forwarded-For`: The client's IP address is appended to the value provided by the client. (If the client did not provide this header, it is set to the client's IP address.) - * `X-Forwarded-Host`: If the client did not provide this header or if the `TRUST_DOWNSTREAM_PROXY` environment variable is set to `false` (see below), this is set to the value of the `Host` header provided by the client. Otherwise, the header is forwarded to the backend server unmodified. - * `X-Forwarded-Proto`: If the client did not provide this header or if the `TRUST_DOWNSTREAM_PROXY` environment variable is set to `false` (see below), this is set to `http` for plain HTTP connections and `https` for TLS connections. Otherwise, the header is forwarded to the backend server unmodified. - * `X-Forwarded-Ssl`: Set to `on` if the `X-Forwarded-Proto` header sent to the backend server is `https`, otherwise set to `off`. - * `X-Forwarded-Port`: If the client did not provide this header or if the `TRUST_DOWNSTREAM_PROXY` environment variable is set to `false` (see below), this is set to the port of the server that accepted the client's request. Otherwise, the header is forwarded to the backend server unmodified. - * `X-Original-URI`: Set to the original request URI. - -#### Trusting Downstream Proxy Headers - -For legacy compatibility reasons, `nginx-proxy` forwards any client-supplied `X-Forwarded-Proto` (which affects the value of `X-Forwarded-Ssl`), `X-Forwarded-Host`, and `X-Forwarded-Port` headers unchecked and unmodified. To prevent malicious clients from spoofing the protocol, hostname, or port that is perceived by your backend server, you are encouraged to set the `TRUST_DOWNSTREAM_PROXY` value to `false` if: - - * you do not operate a second reverse proxy downstream of `nginx-proxy`, or - * you do operate a second reverse proxy downstream of `nginx-proxy` but that proxy forwards those headers unchecked from untrusted clients. - -The default for `TRUST_DOWNSTREAM_PROXY` may change to `false` in a future version of `nginx-proxy`. If you require it to be enabled, you are encouraged to explicitly set it to `true` to avoid compatibility problems when upgrading. - -### Custom Nginx Configuration - -If you need to configure Nginx beyond what is possible using environment variables, you can provide custom configuration files on either a proxy-wide or per-`VIRTUAL_HOST` basis. - -#### Replacing default proxy settings - -If you want to replace the default proxy settings for the nginx container, add a configuration file at `/etc/nginx/proxy.conf`. A file with the default settings would look like this: - -```Nginx -# HTTP 1.1 support -proxy_http_version 1.1; -proxy_buffering off; -proxy_set_header Host $http_host; -proxy_set_header Upgrade $http_upgrade; -proxy_set_header Connection $proxy_connection; -proxy_set_header X-Real-IP $remote_addr; -proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; -proxy_set_header X-Forwarded-Host $proxy_x_forwarded_host; -proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto; -proxy_set_header X-Forwarded-Ssl $proxy_x_forwarded_ssl; -proxy_set_header X-Forwarded-Port $proxy_x_forwarded_port; -proxy_set_header X-Original-URI $request_uri; - -# Mitigate httpoxy attack (see README for details) -proxy_set_header Proxy ""; -``` - -***NOTE***: If you provide this file it will replace the defaults; you may want to check the .tmpl file to make sure you have all of the needed options. - -#### Proxy-wide - -To add settings on a proxy-wide basis, add your configuration file under `/etc/nginx/conf.d` using a name ending in `.conf`. - -This can be done in a derived image by creating the file in a `RUN` command or by `COPY`ing the file into `conf.d`: - -```Dockerfile -FROM nginxproxy/nginx-proxy -RUN { \ - echo 'server_tokens off;'; \ - echo 'client_max_body_size 100m;'; \ - } > /etc/nginx/conf.d/my_proxy.conf -``` - -Or it can be done by mounting in your custom configuration in your `docker run` command: - -```console -docker run -d -p 80:80 -p 443:443 -v /path/to/my_proxy.conf:/etc/nginx/conf.d/my_proxy.conf:ro -v /var/run/docker.sock:/tmp/docker.sock:ro nginxproxy/nginx-proxy -``` - -#### 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`. - -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. - -For example, if you have a virtual host named `app.example.com`, you could provide a custom configuration for that host as follows: - -```console -docker run -d -p 80:80 -p 443:443 -v /path/to/vhost.d:/etc/nginx/vhost.d:ro -v /var/run/docker.sock:/tmp/docker.sock:ro nginxproxy/nginx-proxy -{ echo 'server_tokens off;'; echo 'client_max_body_size 100m;'; } > /path/to/vhost.d/app.example.com -``` - -If you are using multiple hostnames for a single container (e.g. `VIRTUAL_HOST=example.com,www.example.com`), the virtual host configuration file must exist for each hostname. If you would like to use the same configuration for multiple virtual host names, you can use a symlink: - -```console -{ echo 'server_tokens off;'; echo 'client_max_body_size 100m;'; } > /path/to/vhost.d/www.example.com -ln -s /path/to/vhost.d/www.example.com /path/to/vhost.d/example.com -``` - -#### Per-VIRTUAL_HOST default configuration - -If you want most of your virtual hosts to use a default single configuration and then override on a few specific ones, add those settings to the `/etc/nginx/vhost.d/default` file. This file will be used on any virtual host which does not have a `/etc/nginx/vhost.d/{VIRTUAL_HOST}` file associated with it. - -#### 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`. - -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: - -```console -docker run -d -p 80:80 -p 443:443 -v /path/to/vhost.d:/etc/nginx/vhost.d:ro -v /var/run/docker.sock:/tmp/docker.sock:ro nginxproxy/nginx-proxy -{ echo 'proxy_cache my-cache;'; echo 'proxy_cache_valid 200 302 60m;'; echo 'proxy_cache_valid 404 1m;' } > /path/to/vhost.d/app.example.com_location -``` - -If you are using multiple hostnames for a single container (e.g. `VIRTUAL_HOST=example.com,www.example.com`), the virtual host configuration file must exist for each hostname. If you would like to use the same configuration for multiple virtual host names, you can use a symlink: - -```console -{ echo 'proxy_cache my-cache;'; echo 'proxy_cache_valid 200 302 60m;'; echo 'proxy_cache_valid 404 1m;' } > /path/to/vhost.d/app.example.com_location -ln -s /path/to/vhost.d/www.example.com /path/to/vhost.d/example.com -``` - -#### Per-VIRTUAL_HOST location default configuration - -If you want most of your virtual hosts to use a default single `location` block configuration and then override on a few specific ones, add those settings to the `/etc/nginx/vhost.d/default_location` file. This file will be used on any virtual host which does not have a `/etc/nginx/vhost.d/{VIRTUAL_HOST}_location` file associated with it. - -#### Overriding `location` blocks - -The `${VIRTUAL_HOST}_${PATH_HASH}_location`, `${VIRTUAL_HOST}_location`, and `default_location` files documented above make it possible to *augment* the generated [`location` block(s)](https://nginx.org/en/docs/http/ngx_http_core_module.html#location) in a virtual host. In some circumstances, you may need to *completely override* the `location` block for a particular combination of virtual host and path. To do this, create a file whose name follows this pattern: - -``` -/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). - -For convenience, the `_${PATH_HASH}` part can be omitted if the path is `/`: - -``` -/etc/nginx/vhost.d/${VIRTUAL_HOST}_location_override -``` - -When an override file exists, the `location` block that is normally created by `nginx-proxy` is not generated. Instead, the override file is included via the [nginx `include` directive](https://nginx.org/en/docs/ngx_core_module.html#include). - -You are responsible for providing a suitable `location` block in your override file as required for your service. By default, `nginx-proxy` uses the `VIRTUAL_HOST` name as the upstream name for your application's Docker container; see [here](#unhashed-vs-sha1-upstream-names) for details. As an example, if your container has a `VIRTUAL_HOST` value of `app.example.com`, then to override the location block for `/` you would create a file named `/etc/nginx/vhost.d/app.example.com_location_override` that contains something like this: - -``` -location / { - proxy_pass http://app.example.com; -} -``` - -#### Per-VIRTUAL_HOST `server_tokens` configuration -Per virtual-host `servers_tokens` directive can be configured by passing appropriate value to the `SERVER_TOKENS` environment variable. Please see the [nginx http_core module configuration](https://nginx.org/en/docs/http/ngx_http_core_module.html#server_tokens) for more details. - -### Unhashed vs SHA1 upstream names - -By default the nginx configuration `upstream` blocks will use this block's corresponding hostname as a predictable name. However, this can cause issues in some setups (see [this issue](https://github.com/nginx-proxy/nginx-proxy/issues/1162)). In those cases you might want to switch to SHA1 names for the `upstream` blocks by setting the `SHA1_UPSTREAM_NAME` environment variable to `true` on the nginx-proxy container. - -Please note that using regular expressions in `VIRTUAL_HOST` will always result in a corresponding `upstream` block with an SHA1 name. - -### Troubleshooting - -If you can't access your `VIRTUAL_HOST`, inspect the generated nginx configuration: - -```console -docker exec nginx -T -``` - -Pay attention to the `upstream` definition blocks, which should look like this: - -```Nginx -# foo.example.com -upstream foo.example.com { - ## Can be connected with "my_network" network - # Exposed ports: [{ tcp } { tcp } ...] - # Default virtual port: - # VIRTUAL_PORT: - # foo - server 172.18.0.9:; - # Fallback entry - server 127.0.0.1 down; -} -``` - -The effective `Port` is retrieved by order of precedence: -1. From the `VIRTUAL_PORT` environment variable -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 - -### Contributing - -Before submitting pull requests or issues, please check github to make sure an existing issue or pull request is not already open. - -#### Running Tests Locally - -To run tests, you just need to run the command below: - -```console -make test -``` - -This commands run tests on two variants of the nginx-proxy docker image: Debian and Alpine. - -You can run the tests for each of these images with their respective commands: - -```console -make test-debian -make test-alpine -``` - -You can learn more about how the test suite works and how to write new tests in the [test/README.md](test/README.md) file. +Please check the [docs section](https://github.com/nginx-proxy/nginx-proxy/tree/main/docs). diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..5162054 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,728 @@ +### Docker Compose + +```yaml +version: '2' + +services: + nginx-proxy: + image: nginxproxy/nginx-proxy + ports: + - "80:80" + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro + + whoami: + image: jwilder/whoami + expose: + - "8000" + environment: + - VIRTUAL_HOST=whoami.example + - VIRTUAL_PORT=8000 +``` + +```console +docker compose up +curl -H "Host: whoami.example" localhost +``` + +Example output: +```console +I'm 5b129ab83266 +``` + +### IPv6 support + +You can activate the IPv6 support for the nginx-proxy container by passing the value `true` to the `ENABLE_IPV6` environment variable: + +```console +docker run -d -p 80:80 -e ENABLE_IPV6=true -v /var/run/docker.sock:/tmp/docker.sock:ro nginxproxy/nginx-proxy +``` + +#### Scoped IPv6 Resolvers + +NginX does not support scoped IPv6 resolvers. In [docker-entrypoint.sh](https://github.com/nginx-proxy/nginx-proxy/tree/main/docker-entrypoint.sh) the resolvers are parsed from resolv.conf, but any scoped IPv6 addreses will be removed. + +#### IPv6 NAT + +By default, docker uses IPv6-to-IPv4 NAT. This means all client connections from IPv6 addresses will show docker's internal IPv4 host address. To see true IPv6 client IP addresses, you must [enable IPv6](https://docs.docker.com/config/daemon/ipv6/) and use [ipv6nat](https://github.com/robbertkl/docker-ipv6nat). You must also disable the userland proxy by adding `"userland-proxy": false` to `/etc/docker/daemon.json` and restarting the daemon. + +### Multiple Hosts + +If you need to support multiple virtual hosts for a container, you can separate each entry with commas. For example, `foo.bar.com,baz.bar.com,bar.com` and each host will be setup the same. + +### Virtual Ports + +When your container exposes only one port, nginx-proxy will default to this port, else to port 80. + +If you need to specify a different port, you can set a `VIRTUAL_PORT` env var to select a different one. This variable cannot be set to more than one port. + +For each host defined into `VIRTUAL_HOST`, the associated virtual port is retrieved by order of precedence: +1. From the `VIRTUAL_PORT` environment variable +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 + +### Wildcard Hosts + +You can also use wildcards at the beginning and the end of host name, like `*.bar.com` or `foo.bar.*`. Or even a regular expression, which can be very useful in conjunction with a wildcard DNS service like [nip.io](https://nip.io) or [sslip.io](https://sslip.io), using `~^foo\.bar\..*\.nip\.io` will match `foo.bar.127.0.0.1.nip.io`, `foo.bar.10.0.2.2.nip.io` and all other given IPs. More information about this topic can be found in the nginx documentation about [`server_names`](http://nginx.org/en/docs/http/server_names.html). + +### Path-based Routing + +You can have multiple containers proxied by the same `VIRTUAL_HOST` by adding a `VIRTUAL_PATH` environment variable containing the absolute path to where the container should be mounted. For example with `VIRTUAL_HOST=foo.example.com` and `VIRTUAL_PATH=/api/v2/service`, then requests to http://foo.example.com/api/v2/service will be routed to the container. If you wish to have a container serve the root while other containers serve other paths, give the root container a `VIRTUAL_PATH` of `/`. Unmatched paths will be served by the container at `/` or will return the default nginx error page if no container has been assigned `/`. +It is also possible to specify multiple paths with regex locations like `VIRTUAL_PATH=~^/(app1|alternative1)/`. For further details see the nginx documentation on location blocks. This is not compatible with `VIRTUAL_DEST`. + +The full request URI will be forwarded to the serving container in the `X-Original-URI` header. + +**NOTE**: Your application needs to be able to generate links starting with `VIRTUAL_PATH`. This can be achieved by it being natively on this path or having an option to prepend this path. The application does not need to expect this path in the request. + +#### VIRTUAL_DEST + +This environment variable can be used to rewrite the `VIRTUAL_PATH` part of the requested URL to proxied application. The default value is empty (off). +Make sure that your settings won't result in the slash missing or being doubled. Both these versions can cause troubles. + +If the application runs natively on this sub-path or has a setting to do so, `VIRTUAL_DEST` should not be set or empty. +If the requests are expected to not contain a sub-path and the generated links contain the sub-path, `VIRTUAL_DEST=/` should be used. + +```console +$ docker run -d -e VIRTUAL_HOST=example.tld -e VIRTUAL_PATH=/app1/ -e VIRTUAL_DEST=/ --name app1 app +``` + +In this example, the incoming request `http://example.tld/app1/foo` will be proxied as `http://app1/foo` instead of `http://app1/app1/foo`. + +#### 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 filename of the previous example would be `example.tld_8610f6c344b4096614eab6e09d58885349f42faf_location`. + +#### DEFAULT_ROOT + +This environment variable of the nginx proxy container can be used to customize the return error page if no matching path is found. Furthermore it is possible to use anything which is compatible with the `return` statement of nginx. + +Exception: If this is set to the string `none`, no default `location /` directive will be generated. This makes it possible for you to provide your own `location /` directive in your [`/etc/nginx/vhost.d/VIRTUAL_HOST`](#per-virtual_host) or [`/etc/nginx/vhost.d/default`](#per-virtual_host-default-configuration) files. + +If unspecified, `DEFAULT_ROOT` defaults to `404`. + +Examples (YAML syntax): + + * `DEFAULT_ROOT: "none"` prevents `nginx-proxy` from generating a default `location /` directive. + * `DEFAULT_ROOT: "418"` returns a 418 error page instead of the normal 404 one. + * `DEFAULT_ROOT: "301 https://github.com/nginx-proxy/nginx-proxy/blob/main/README.md"` redirects the client to this documentation. + +Nginx variables such as `$scheme`, `$host`, and `$request_uri` can be used. However, care must be taken to make sure the `$` signs are escaped properly. For example, if you want to use `301 $scheme://$host/myapp1$request_uri` you should use: + +* Bash: `DEFAULT_ROOT='301 $scheme://$host/myapp1$request_uri'` +* Docker Compose yaml: `- DEFAULT_ROOT: 301 $$scheme://$$host/myapp1$$request_uri` + + +### Multiple Networks + +With the addition of [overlay networking](https://docs.docker.com/engine/userguide/networking/get-started-overlay/) in Docker 1.9, your `nginx-proxy` container may need to connect to backend containers on multiple networks. By default, if you don't pass the `--net` flag when your `nginx-proxy` container is created, it will only be attached to the default `bridge` network. This means that it will not be able to connect to containers on networks other than `bridge`. + +If you want your `nginx-proxy` container to be attached to a different network, you must pass the `--net=my-network` option in your `docker create` or `docker run` command. At the time of this writing, only a single network can be specified at container creation time. To attach to other networks, you can use the `docker network connect` command after your container is created: + +```console +docker run -d -p 80:80 -v /var/run/docker.sock:/tmp/docker.sock:ro \ + --name my-nginx-proxy --net my-network nginxproxy/nginx-proxy +docker network connect my-other-network my-nginx-proxy +``` + +In this example, the `my-nginx-proxy` container will be connected to `my-network` and `my-other-network` and will be able to proxy to other containers attached to those networks. + +### Host networking + +`nginx-proxy` is compatible with containers using Docker's [host networking](https://docs.docker.com/network/host/), both with the proxy connected to one or more [bridge network](https://docs.docker.com/network/bridge/) (default or user created) or running in host network mode itself. + +Proxyed containers running in host network mode **must** use the [`VIRTUAL_PORT`](#virtual-ports) environment variable, as this is the only way for `nginx-proxy` to get the correct port (or a port at all) for those containers. + +### Custom external HTTP/HTTPS ports + +If you want to use `nginx-proxy` with different external ports that the default ones of `80` for `HTTP` traffic and `443` for `HTTPS` traffic, you'll have to use the environment variable(s) `HTTP_PORT` and/or `HTTPS_PORT` in addition to the changes to the Docker port mapping. If you change the `HTTPS` port, the redirect for `HTTPS` traffic will also be configured to redirect to the custom port. Typical usage, here with the custom ports `1080` and `10443`: + +```console +docker run -d -p 1080:1080 -p 10443:10443 -e HTTP_PORT=1080 -e HTTPS_PORT=10443 -v /var/run/docker.sock:/tmp/docker.sock:ro nginxproxy/nginx-proxy +``` + +### Internet vs. Local Network Access + +If you allow traffic from the public internet to access your `nginx-proxy` container, you may want to restrict some containers to the internal network only, so they cannot be accessed from the public internet. On containers that should be restricted to the internal network, you should set the environment variable `NETWORK_ACCESS=internal`. By default, the *internal* network is defined as `127.0.0.0/8, 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16`. To change the list of networks considered internal, mount a file on the `nginx-proxy` at `/etc/nginx/network_internal.conf` with these contents, edited to suit your needs: + +```Nginx +# These networks are considered "internal" +allow 127.0.0.0/8; +allow 10.0.0.0/8; +allow 192.168.0.0/16; +allow 172.16.0.0/12; + +# Traffic from all other networks will be rejected +deny all; +``` + +When internal-only access is enabled, external clients will be denied with an `HTTP 403 Forbidden` + +> If there is a load-balancer / reverse proxy in front of `nginx-proxy` that hides the client IP (example: AWS Application/Elastic Load Balancer), you will need to use the nginx `realip` module (already installed) to extract the client's IP from the HTTP request headers. Please see the [nginx realip module configuration](http://nginx.org/en/docs/http/ngx_http_realip_module.html) for more details. This configuration can be added to a new config file and mounted in `/etc/nginx/conf.d/`. + +### SSL Backends + +If you would like the reverse proxy to connect to your backend using HTTPS instead of HTTP, set `VIRTUAL_PROTO=https` on the backend container. + +> Note: If you use `VIRTUAL_PROTO=https` and your backend container exposes port 80 and 443, `nginx-proxy` will use HTTPS on port 80. This is almost certainly not what you want, so you should also include `VIRTUAL_PORT=443`. + +### uWSGI Backends + +If you would like to connect to uWSGI backend, set `VIRTUAL_PROTO=uwsgi` on the backend container. Your backend container should then listen on a port rather than a socket and expose that port. + +### FastCGI Backends + +If you would like to connect to FastCGI backend, set `VIRTUAL_PROTO=fastcgi` on the backend container. Your backend container should then listen on a port rather than a socket and expose that port. + +### FastCGI File Root Directory + +If you use fastcgi,you can set `VIRTUAL_ROOT=xxx` for your root directory + +### Custom log format + +If you want to use a custom log format, you can set `LOG_FORMAT=xxx` on the proxy container. + +With docker compose take care to escape the `$` character with `$$` to avoid variable interpolation. Example: `$remote_addr` becomes `$$remote_addr`. + +### Default Host + +To set the default host for nginx use the env var `DEFAULT_HOST=foo.bar.com` for example + +```console +docker run -d -p 80:80 -e DEFAULT_HOST=foo.bar.com -v /var/run/docker.sock:/tmp/docker.sock:ro nginxproxy/nginx-proxy +``` + +nginx-proxy will then redirect all requests to a container where `VIRTUAL_HOST` is set to `DEFAULT_HOST`, if they don't match any (other) `VIRTUAL_HOST`. Using the example above requests without matching `VIRTUAL_HOST` will be redirected to a plain nginx instance after running the following command: + +```console +docker run -d -e VIRTUAL_HOST=foo.bar.com nginx +``` + +### Separate Containers + +nginx-proxy can also be run as two separate containers using the [nginxproxy/docker-gen](https://hub.docker.com/r/nginxproxy/docker-gen) image and the official [nginx](https://registry.hub.docker.com/_/nginx/) image. + +You may want to do this to prevent having the docker socket bound to a publicly exposed container service. + +You can demo this pattern with docker compose: + +```console +docker compose --file docker-compose-separate-containers.yml up +curl -H "Host: whoami.example" localhost +``` + +Example output: +```console +I'm 5b129ab83266 +``` + +To run nginx proxy as a separate container you'll need to have [nginx.tmpl](https://github.com/nginx-proxy/nginx-proxy/blob/main/nginx.tmpl) on your host system. + +First start nginx with a volume: + + +```console +docker run -d -p 80:80 --name nginx -v /tmp/nginx:/etc/nginx/conf.d -t nginx +``` + +Then start the docker-gen container with the shared volume and template: + +```console +docker run --volumes-from nginx \ + -v /var/run/docker.sock:/tmp/docker.sock:ro \ + -v $(pwd):/etc/docker-gen/templates \ + -t nginxproxy/docker-gen -notify-sighup nginx -watch /etc/docker-gen/templates/nginx.tmpl /etc/nginx/conf.d/default.conf +``` + +Finally, start your containers with `VIRTUAL_HOST` environment variables. + +```console +docker run -e VIRTUAL_HOST=foo.bar.com ... +``` + +### SSL Support using an ACME CA + +[acme-companion](https://github.com/nginx-proxy/acme-companion) is a lightweight companion container for the nginx-proxy. It allows the automated creation/renewal of SSL certificates using the ACME protocol. + +### SSL Support + +SSL is supported using single host, wildcard and SNI certificates using naming conventions for certificates or optionally specifying a cert name (for SNI) as an environment variable. + +To enable SSL: + +```console +docker run -d -p 80:80 -p 443:443 -v /path/to/certs:/etc/nginx/certs -v /var/run/docker.sock:/tmp/docker.sock:ro nginxproxy/nginx-proxy +``` + +The contents of `/path/to/certs` should contain the certificates and private keys for any virtual hosts in use. The certificate and keys should be named after the virtual host with a `.crt` and `.key` extension. For example, a container with `VIRTUAL_HOST=foo.bar.com` should have a `foo.bar.com.crt` and `foo.bar.com.key` file in the certs directory. + +If you are running the container in a virtualized environment (Hyper-V, VirtualBox, etc...), /path/to/certs must exist in that environment or be made accessible to that environment. By default, Docker is not able to mount directories on the host machine to containers running in a virtual machine. + +#### 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. + +To use custom `dhparam.pem` files per-virtual-host, the files should be named after the virtual host with a `dhparam` suffix and `.pem` extension. For example, a container with `VIRTUAL_HOST=foo.bar.com` should have a `foo.bar.com.dhparam.pem` file in the `/etc/nginx/certs` directory. + +> COMPATIBILITY WARNING: The default generated `dhparam.pem` key is 4096 bits for A+ security. Some older clients (like Java 6 and 7) do not support DH keys with over 1024 bits. In order to support these clients, you must provide your own `dhparam.pem`. + +In the separate container setup, no pre-generated key will be available and neither the [nginxproxy/docker-gen](https://hub.docker.com/r/nginxproxy/docker-gen) image, nor the offical [nginx](https://registry.hub.docker.com/_/nginx/) image will provide one. If you still want A+ security in a separate container setup, you should mount an RFC7919 DH key file to the nginx container at `/etc/nginx/dhparam/dhparam.pem`. + +Set `DHPARAM_SKIP` environment variable to `true` to disable using default Diffie-Hellman parameters. The default value is `false`. + +```console +docker run -e DHPARAM_SKIP=true .... +``` + +#### Wildcard Certificates + +Wildcard certificates and keys should be named after the domain name with a `.crt` and `.key` extension. For example `VIRTUAL_HOST=foo.bar.com` would use cert name `bar.com.crt` and `bar.com.key`. + +#### SNI + +If your certificate(s) supports multiple domain names, you can start a container with `CERT_NAME=` to identify the certificate to be used. For example, a certificate for `*.foo.com` and `*.bar.com` could be named `shared.crt` and `shared.key`. A container running with `VIRTUAL_HOST=foo.bar.com` and `CERT_NAME=shared` will then use this shared cert. + +#### OCSP Stapling + +To enable OCSP Stapling for a domain, `nginx-proxy` looks for a PEM certificate containing the trusted CA certificate chain at `/etc/nginx/certs/.chain.pem`, where `` is the domain name in the `VIRTUAL_HOST` directive. The format of this file is a concatenation of the public PEM CA certificates starting with the intermediate CA most near the SSL certificate, down to the root CA. This is often referred to as the "SSL Certificate Chain". If found, this filename is passed to the NGINX [`ssl_trusted_certificate` directive](http://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_trusted_certificate) and OCSP Stapling is enabled. + +#### How SSL Support Works + +The default SSL cipher configuration is based on the [Mozilla intermediate profile](https://wiki.mozilla.org/Security/Server_Side_TLS#Intermediate_compatibility_.28recommended.29) version 5.0 which should provide compatibility with clients back to Firefox 27, Android 4.4.2, Chrome 31, Edge, IE 11 on Windows 7, Java 8u31, OpenSSL 1.0.1, Opera 20, and Safari 9. Note that the DES-based TLS ciphers were removed for security. The configuration also enables HSTS, PFS, OCSP stapling and SSL session caches. Currently TLS 1.2 and 1.3 are supported. + +If you don't require backward compatibility, you can use the [Mozilla modern profile](https://wiki.mozilla.org/Security/Server_Side_TLS#Modern_compatibility) profile instead by including the environment variable `SSL_POLICY=Mozilla-Modern` to the nginx-proxy container or to your container. This profile is compatible with clients back to Firefox 63, Android 10.0, Chrome 70, Edge 75, Java 11, OpenSSL 1.1.1, Opera 57, and Safari 12.1. Note that this profile is **not** compatible with any version of Internet Explorer. + +Complete list of policies available through the `SSL_POLICY` environment variable, including the [AWS ELB Security Policies](https://docs.aws.amazon.com/elasticloadbalancing/latest/application/create-https-listener.html#describe-ssl-policies) and [AWS Classic ELB security policies](https://docs.aws.amazon.com/fr_fr/elasticloadbalancing/latest/classic/elb-security-policy-table.html): + +
    + Mozilla policies + +
    +
    + AWS ELB TLS 1.3 security policies +
      +
    • + AWS-TLS13-1-3-2021-06 +
    • +
    • + AWS-TLS13-1-2-2021-06 +
    • +
    • + AWS-TLS13-1-2-Res-2021-06 +
    • +
    • + AWS-TLS13-1-2-Ext1-2021-06 +
    • +
    • + AWS-TLS13-1-2-Ext2-2021-06 +
    • +
    • + AWS-TLS13-1-1-2021-06 +
    • +
    • + AWS-TLS13-1-0-2021-06 +
    • +
    +
    +
    + AWS ELB FS supported policies +
      +
    • + AWS-FS-1-2-Res-2020-10 +
    • +
    • + AWS-FS-1-2-Res-2019-08 +
    • +
    • + AWS-FS-1-2-2019-08 +
    • +
    • + AWS-FS-1-1-2019-08 +
    • +
    • + AWS-FS-2018-06 +
    • +
    +
    +
    + AWS ELB TLS 1.0 - 1.2 security policies +
      +
    • + AWS-TLS-1-2-Ext-2018-06 +
    • +
    • + AWS-TLS-1-2-2017-01 +
    • +
    • + AWS-TLS-1-1-2017-01 +
    • +
    • + AWS-2016-08 +
    • +
    +
    +
    + AWS Classic ELB security policies +
      +
    • + AWS-2015-05 +
    • +
    • + AWS-2015-03 +
    • +
    • + AWS-2015-02 +
    • +
    +
    +
    + +Note that the `Mozilla-Old` policy should use a 1024 bits DH key for compatibility but this container provides a 4096 bits key. The [Diffie-Hellman Groups](#diffie-hellman-groups) section details different methods of bypassing this, either globally or per virtual-host. + +The default behavior for the proxy when port 80 and 443 are exposed is as follows: + +* If a virtual host has a usable cert, port 80 will redirect to 443 for that virtual host so that HTTPS is always preferred when available. +* If the virtual host does not have a usable cert, but `default.crt` and `default.key` exist, those will be used as the virtual host's certificate and the client browser will receive a 500 error. +* If the virtual host does not have a usable cert, and `default.crt` and `default.key` do not exist, TLS negotiation will fail (see [Missing Certificate](#missing-certificate) below). + +To serve traffic in both SSL and non-SSL modes without redirecting to SSL, you can include the environment variable `HTTPS_METHOD=noredirect` (the default is `HTTPS_METHOD=redirect`). You can also disable the non-SSL site entirely with `HTTPS_METHOD=nohttp`, or disable the HTTPS site with `HTTPS_METHOD=nohttps`. `HTTPS_METHOD` can be specified on each container for which you want to override the default behavior or on the proxy container to set it globally. If `HTTPS_METHOD=noredirect` is used, Strict Transport Security (HSTS) is disabled to prevent HTTPS users from being redirected by the client. If you cannot get to the HTTP site after changing this setting, your browser has probably cached the HSTS policy and is automatically redirecting you back to HTTPS. You will need to clear your browser's HSTS cache or use an incognito window / different browser. + +By default, [HTTP Strict Transport Security (HSTS)](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security) is enabled with `max-age=31536000` for HTTPS sites. You can disable HSTS with the environment variable `HSTS=off` or use a custom HSTS configuration like `HSTS=max-age=31536000; includeSubDomains; preload`. + +*WARNING*: HSTS will force your users to visit the HTTPS version of your site for the `max-age` time - even if they type in `http://` manually. The only way to get to an HTTP site after receiving an HSTS response is to clear your browser's HSTS cache. + +#### Missing Certificate + +If HTTPS is enabled for a virtual host but its certificate is missing, nginx-proxy will configure nginx to use the default certificate (`default.crt` with `default.key`) and return a 500 error. + +If the default certificate is also missing, nginx-proxy will configure nginx to accept HTTPS connections but fail the TLS negotiation. Client browsers will render a TLS error page. As of March 2023, web browsers display the following error messages: + + * Chrome: + + > This site can't provide a secure connection + > + > example.test sent an invalid response. + > + > Try running Connectivity Diagnostics. + > + > `ERR_SSL_PROTOCOL_ERROR` + + * Firefox: + + > Secure Connection Failed + > + > An error occurred during a connection to example.test. + > Peer reports it experienced an internal error. + > + > Error code: `SSL_ERROR_INTERNAL_ERROR_ALERT` "TLS error". + +### HTTP/2 support + +HTTP/2 is enabled by default and can be disabled if necessary either per-proxied container or globally: + +To disable HTTP/2 for a single proxied container, set the `com.github.nginx-proxy.nginx-proxy.http2.enable` label to `false` on this container. + +To disable HTTP/2 globally set the environment variable `ENABLE_HTTP2` to `false` on the nginx-proxy container. + +More reading on the potential TCP head-of-line blocking issue with HTTP/2: [HTTP/2 Issues](https://www.twilio.com/blog/2017/10/http2-issues.html), [Comparing HTTP/3 vs HTTP/2](https://blog.cloudflare.com/http-3-vs-http-2/) + +### HTTP/3 support + +> **Warning** +> HTTP/3 support [is still considered experimental in nginx](https://www.nginx.com/blog/binary-packages-for-preview-nginx-quic-http3-implementation/) and as such is considered experimental in nginx-proxy too and is disabled by default. [Feedbacks for the HTTP/3 support are welcome in #2271.](https://github.com/nginx-proxy/nginx-proxy/discussions/2271) + +HTTP/3 use the QUIC protocol over UDP (unlike HTTP/1.1 and HTTP/2 which work over TCP), so if you want to use HTTP/3 you'll have to explicitely publish the 443/udp port of the proxy in addition to the 443/tcp port: + +```console +docker run -d -p 80:80 -p 443:443/tcp -p 443:443/udp \ + -v /var/run/docker.sock:/tmp/docker.sock:ro \ + nginxproxy/nginx-proxy +``` + +HTTP/3 can be enabled either per-proxied container or globally: + +To enable HTTP/3 for a single proxied container, set the `com.github.nginx-proxy.nginx-proxy.http3.enable` label to `true` on this container. + +To enable HTTP/3 globally set the environment variable `ENABLE_HTTP3` to `true` on the nginx-proxy container. + +### 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 on directory +/etc/nginx/htpasswd/$VIRTUAL_HOST + +```console +docker run -d -p 80:80 -p 443:443 \ + -v /path/to/htpasswd:/etc/nginx/htpasswd \ + -v /path/to/certs:/etc/nginx/certs \ + -v /var/run/docker.sock:/tmp/docker.sock:ro \ + nginxproxy/nginx-proxy +``` + +You'll need apache2-utils on the machine where you plan to create the htpasswd file. Follow these [instructions](http://httpd.apache.org/docs/2.2/programs/htpasswd.html) + +### Upstream (Backend) Server HTTP Load Balancing Support + +> **Warning** +> This feature is experimental. The behavior may change (or the feature may be removed entirely) without warning in a future release, even if the release is not a new major version. If you use this feature, or if you would like to use this feature but you require changes to it first, please [provide feedback in #2195](https://github.com/nginx-proxy/nginx-proxy/discussions/2195). Once we have collected enough feedback we will promote this feature to officially supported. + +If you have multiple containers with the same `VIRTUAL_HOST` and `VIRTUAL_PATH` settings, nginx will spread the load across all of them. To change the load balancing algorithm from nginx's default (round-robin), set the `com.github.nginx-proxy.nginx-proxy.loadbalance` label on one or more of your application containers to the desired load balancing directive. See the [`ngx_http_upstream_module` documentation](https://nginx.org/en/docs/http/ngx_http_upstream_module.html) for available directives. + +> **Note** +> * Don't forget the terminating semicolon (`;`). +> * If you are using Docker Compose, remember to escape any dollar sign (`$`) characters (`$` becomes `$$`). + +Docker Compose example: + +```yaml +services: + nginx-proxy: + image: nginxproxy/nginx-proxy + ports: + - "80:80" + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro + environment: + HTTPS_METHOD: nohttps + myapp: + image: jwilder/whoami + expose: + - "8000" + environment: + VIRTUAL_HOST: myapp.example + VIRTUAL_PORT: "8000" + labels: + com.github.nginx-proxy.nginx-proxy.loadbalance: "hash $$remote_addr;" + deploy: + replicas: 4 +``` + +### Upstream (Backend) Server HTTP Keep-Alive Support + +> **Warning** +> This feature is experimental. The behavior may change (or the feature may be removed entirely) without warning in a future release, even if the release is not a new major version. If you use this feature, or if you would like to use this feature but you require changes to it first, please [provide feedback in #2194](https://github.com/nginx-proxy/nginx-proxy/discussions/2194). Once we have collected enough feedback we will promote this feature to officially supported. + +To enable HTTP keep-alive between `nginx-proxy` and a backend server, set the `com.github.nginx-proxy.nginx-proxy.keepalive` label on the server's container to the desired maximum number of idle connections. See the [nginx keepalive documentation](https://nginx.org/en/docs/http/ngx_http_upstream_module.html#keepalive) and the [Docker label documentation](https://docs.docker.com/config/labels-custom-metadata/) for details. + +### Headers + +By default, `nginx-proxy` forwards all incoming request headers from the client to the backend server unmodified, with the following exceptions: + + * `Connection`: Set to `upgrade` if the client sets the `Upgrade` header, otherwise set to `close`. (Keep-alive between `nginx-proxy` and the backend server is not supported.) + * `Proxy`: Always removed if present. This prevents attackers from using the so-called [httpoxy attack](http://httpoxy.org). There is no legitimate reason for a client to send this header, and there are many vulnerable languages / platforms (`CVE-2016-5385`, `CVE-2016-5386`, `CVE-2016-5387`, `CVE-2016-5388`, `CVE-2016-1000109`, `CVE-2016-1000110`, `CERT-VU#797896`). + * `X-Real-IP`: Set to the client's IP address. + * `X-Forwarded-For`: The client's IP address is appended to the value provided by the client. (If the client did not provide this header, it is set to the client's IP address.) + * `X-Forwarded-Host`: If the client did not provide this header or if the `TRUST_DOWNSTREAM_PROXY` environment variable is set to `false` (see below), this is set to the value of the `Host` header provided by the client. Otherwise, the header is forwarded to the backend server unmodified. + * `X-Forwarded-Proto`: If the client did not provide this header or if the `TRUST_DOWNSTREAM_PROXY` environment variable is set to `false` (see below), this is set to `http` for plain HTTP connections and `https` for TLS connections. Otherwise, the header is forwarded to the backend server unmodified. + * `X-Forwarded-Ssl`: Set to `on` if the `X-Forwarded-Proto` header sent to the backend server is `https`, otherwise set to `off`. + * `X-Forwarded-Port`: If the client did not provide this header or if the `TRUST_DOWNSTREAM_PROXY` environment variable is set to `false` (see below), this is set to the port of the server that accepted the client's request. Otherwise, the header is forwarded to the backend server unmodified. + * `X-Original-URI`: Set to the original request URI. + +#### Trusting Downstream Proxy Headers + +For legacy compatibility reasons, `nginx-proxy` forwards any client-supplied `X-Forwarded-Proto` (which affects the value of `X-Forwarded-Ssl`), `X-Forwarded-Host`, and `X-Forwarded-Port` headers unchecked and unmodified. To prevent malicious clients from spoofing the protocol, hostname, or port that is perceived by your backend server, you are encouraged to set the `TRUST_DOWNSTREAM_PROXY` value to `false` if: + + * you do not operate a second reverse proxy downstream of `nginx-proxy`, or + * you do operate a second reverse proxy downstream of `nginx-proxy` but that proxy forwards those headers unchecked from untrusted clients. + +The default for `TRUST_DOWNSTREAM_PROXY` may change to `false` in a future version of `nginx-proxy`. If you require it to be enabled, you are encouraged to explicitly set it to `true` to avoid compatibility problems when upgrading. + +### Custom Nginx Configuration + +If you need to configure Nginx beyond what is possible using environment variables, you can provide custom configuration files on either a proxy-wide or per-`VIRTUAL_HOST` basis. + +#### Replacing default proxy settings + +If you want to replace the default proxy settings for the nginx container, add a configuration file at `/etc/nginx/proxy.conf`. A file with the default settings would look like this: + +```Nginx +# HTTP 1.1 support +proxy_http_version 1.1; +proxy_buffering off; +proxy_set_header Host $http_host; +proxy_set_header Upgrade $http_upgrade; +proxy_set_header Connection $proxy_connection; +proxy_set_header X-Real-IP $remote_addr; +proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; +proxy_set_header X-Forwarded-Host $proxy_x_forwarded_host; +proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto; +proxy_set_header X-Forwarded-Ssl $proxy_x_forwarded_ssl; +proxy_set_header X-Forwarded-Port $proxy_x_forwarded_port; +proxy_set_header X-Original-URI $request_uri; + +# Mitigate httpoxy attack (see README for details) +proxy_set_header Proxy ""; +``` + +***NOTE***: If you provide this file it will replace the defaults; you may want to check the .tmpl file to make sure you have all of the needed options. + +#### Proxy-wide + +To add settings on a proxy-wide basis, add your configuration file under `/etc/nginx/conf.d` using a name ending in `.conf`. + +This can be done in a derived image by creating the file in a `RUN` command or by `COPY`ing the file into `conf.d`: + +```Dockerfile +FROM nginxproxy/nginx-proxy +RUN { \ + echo 'server_tokens off;'; \ + echo 'client_max_body_size 100m;'; \ + } > /etc/nginx/conf.d/my_proxy.conf +``` + +Or it can be done by mounting in your custom configuration in your `docker run` command: + +```console +docker run -d -p 80:80 -p 443:443 -v /path/to/my_proxy.conf:/etc/nginx/conf.d/my_proxy.conf:ro -v /var/run/docker.sock:/tmp/docker.sock:ro nginxproxy/nginx-proxy +``` + +#### 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`. + +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. + +For example, if you have a virtual host named `app.example.com`, you could provide a custom configuration for that host as follows: + +```console +docker run -d -p 80:80 -p 443:443 -v /path/to/vhost.d:/etc/nginx/vhost.d:ro -v /var/run/docker.sock:/tmp/docker.sock:ro nginxproxy/nginx-proxy +{ echo 'server_tokens off;'; echo 'client_max_body_size 100m;'; } > /path/to/vhost.d/app.example.com +``` + +If you are using multiple hostnames for a single container (e.g. `VIRTUAL_HOST=example.com,www.example.com`), the virtual host configuration file must exist for each hostname. If you would like to use the same configuration for multiple virtual host names, you can use a symlink: + +```console +{ echo 'server_tokens off;'; echo 'client_max_body_size 100m;'; } > /path/to/vhost.d/www.example.com +ln -s /path/to/vhost.d/www.example.com /path/to/vhost.d/example.com +``` + +#### Per-VIRTUAL_HOST default configuration + +If you want most of your virtual hosts to use a default single configuration and then override on a few specific ones, add those settings to the `/etc/nginx/vhost.d/default` file. This file will be used on any virtual host which does not have a `/etc/nginx/vhost.d/{VIRTUAL_HOST}` file associated with it. + +#### 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`. + +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: + +```console +docker run -d -p 80:80 -p 443:443 -v /path/to/vhost.d:/etc/nginx/vhost.d:ro -v /var/run/docker.sock:/tmp/docker.sock:ro nginxproxy/nginx-proxy +{ echo 'proxy_cache my-cache;'; echo 'proxy_cache_valid 200 302 60m;'; echo 'proxy_cache_valid 404 1m;' } > /path/to/vhost.d/app.example.com_location +``` + +If you are using multiple hostnames for a single container (e.g. `VIRTUAL_HOST=example.com,www.example.com`), the virtual host configuration file must exist for each hostname. If you would like to use the same configuration for multiple virtual host names, you can use a symlink: + +```console +{ echo 'proxy_cache my-cache;'; echo 'proxy_cache_valid 200 302 60m;'; echo 'proxy_cache_valid 404 1m;' } > /path/to/vhost.d/app.example.com_location +ln -s /path/to/vhost.d/www.example.com /path/to/vhost.d/example.com +``` + +#### Per-VIRTUAL_HOST location default configuration + +If you want most of your virtual hosts to use a default single `location` block configuration and then override on a few specific ones, add those settings to the `/etc/nginx/vhost.d/default_location` file. This file will be used on any virtual host which does not have a `/etc/nginx/vhost.d/{VIRTUAL_HOST}_location` file associated with it. + +#### Overriding `location` blocks + +The `${VIRTUAL_HOST}_${PATH_HASH}_location`, `${VIRTUAL_HOST}_location`, and `default_location` files documented above make it possible to *augment* the generated [`location` block(s)](https://nginx.org/en/docs/http/ngx_http_core_module.html#location) in a virtual host. In some circumstances, you may need to *completely override* the `location` block for a particular combination of virtual host and path. To do this, create a file whose name follows this pattern: + +``` +/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). + +For convenience, the `_${PATH_HASH}` part can be omitted if the path is `/`: + +``` +/etc/nginx/vhost.d/${VIRTUAL_HOST}_location_override +``` + +When an override file exists, the `location` block that is normally created by `nginx-proxy` is not generated. Instead, the override file is included via the [nginx `include` directive](https://nginx.org/en/docs/ngx_core_module.html#include). + +You are responsible for providing a suitable `location` block in your override file as required for your service. By default, `nginx-proxy` uses the `VIRTUAL_HOST` name as the upstream name for your application's Docker container; see [here](#unhashed-vs-sha1-upstream-names) for details. As an example, if your container has a `VIRTUAL_HOST` value of `app.example.com`, then to override the location block for `/` you would create a file named `/etc/nginx/vhost.d/app.example.com_location_override` that contains something like this: + +``` +location / { + proxy_pass http://app.example.com; +} +``` + +#### Per-VIRTUAL_HOST `server_tokens` configuration +Per virtual-host `servers_tokens` directive can be configured by passing appropriate value to the `SERVER_TOKENS` environment variable. Please see the [nginx http_core module configuration](https://nginx.org/en/docs/http/ngx_http_core_module.html#server_tokens) for more details. + +### Unhashed vs SHA1 upstream names + +By default the nginx configuration `upstream` blocks will use this block's corresponding hostname as a predictable name. However, this can cause issues in some setups (see [this issue](https://github.com/nginx-proxy/nginx-proxy/issues/1162)). In those cases you might want to switch to SHA1 names for the `upstream` blocks by setting the `SHA1_UPSTREAM_NAME` environment variable to `true` on the nginx-proxy container. + +Please note that using regular expressions in `VIRTUAL_HOST` will always result in a corresponding `upstream` block with an SHA1 name. + +### Troubleshooting + +If you can't access your `VIRTUAL_HOST`, inspect the generated nginx configuration: + +```console +docker exec nginx -T +``` + +Pay attention to the `upstream` definition blocks, which should look like this: + +```Nginx +# foo.example.com +upstream foo.example.com { + ## Can be connected with "my_network" network + # Exposed ports: [{ tcp } { tcp } ...] + # Default virtual port: + # VIRTUAL_PORT: + # foo + server 172.18.0.9:; + # Fallback entry + server 127.0.0.1 down; +} +``` + +The effective `Port` is retrieved by order of precedence: +1. From the `VIRTUAL_PORT` environment variable +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 + +### Contributing + +Before submitting pull requests or issues, please check github to make sure an existing issue or pull request is not already open. + +#### Running Tests Locally + +To run tests, you just need to run the command below: + +```console +make test +``` + +This commands run tests on two variants of the nginx-proxy docker image: Debian and Alpine. + +You can run the tests for each of these images with their respective commands: + +```console +make test-debian +make test-alpine +``` + +You can learn more about how the test suite works and how to write new tests in the [test/README.md](https://github.com/nginx-proxy/nginx-proxy/tree/main/test/README.md) file. From 4a8aa5db671a470f044e4c787bd28bf389afe62a Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Mon, 25 Dec 2023 11:27:22 +0100 Subject: [PATCH 248/300] docs: fix two links in updated README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 48d513f..edb3bb2 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ The containers being proxied must : - [expose](https://docs.docker.com/engine/reference/run/#expose-incoming-ports) the port to be proxied, either by using the `EXPOSE` directive in their `Dockerfile` or by using the `--expose` flag to `docker run` or `docker create`. - share at least one Docker network with the nginx-proxy container: by default, if you don't pass the `--net` flag when your nginx-proxy container is created, it will only be attached to the default bridge network. This means that it will not be able to connect to containers on networks other than bridge. -Note: providing a port number in `VIRTUAL_HOST` isn't suported, please see [virtual ports](https://github.com/nginx-proxy/nginx-proxy/docs#virtual-ports) or [custom external HTTP/HTTPS ports](https://github.com/nginx-proxy/nginx-proxy/docs#custom-external-httphttps-ports) depending on what you want to achieve. +Note: providing a port number in `VIRTUAL_HOST` isn't suported, please see [virtual ports](https://github.com/nginx-proxy/nginx-proxy/tree/main/docs#virtual-ports) or [custom external HTTP/HTTPS ports](https://github.com/nginx-proxy/nginx-proxy/tree/main/docs#custom-external-httphttps-ports) depending on what you want to achieve. ### Image variants From 5c1db95551e5a5ac8ef412df082b042da54453ce Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Mon, 25 Dec 2023 17:27:34 +0100 Subject: [PATCH 249/300] feat: enable proxy_buffering --- docs/README.md | 1 - nginx.tmpl | 1 - 2 files changed, 2 deletions(-) diff --git a/docs/README.md b/docs/README.md index 5162054..b2f87c4 100644 --- a/docs/README.md +++ b/docs/README.md @@ -556,7 +556,6 @@ If you want to replace the default proxy settings for the nginx container, add a ```Nginx # HTTP 1.1 support proxy_http_version 1.1; -proxy_buffering off; proxy_set_header Host $http_host; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $proxy_connection; diff --git a/nginx.tmpl b/nginx.tmpl index 66324ff..08606b9 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -402,7 +402,6 @@ include /etc/nginx/proxy.conf; {{- else }} # HTTP 1.1 support proxy_http_version 1.1; -proxy_buffering off; proxy_set_header Host $host; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $proxy_connection; From de4cb3d2b06171825e0df97414e1c3ac80e1cc73 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Mon, 25 Dec 2023 19:16:10 +0100 Subject: [PATCH 250/300] refactor: move nginx daemon off to procfile --- Dockerfile.alpine | 3 +-- Dockerfile.debian | 3 +-- app/Procfile | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/Dockerfile.alpine b/Dockerfile.alpine index 2fb2cda..b94f067 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -21,8 +21,7 @@ RUN apk add --no-cache --virtual .run-deps \ && update-ca-certificates # Configure Nginx -RUN echo "daemon off;" >> /etc/nginx/nginx.conf \ - && sed -i 's/worker_processes 1/worker_processes auto/' /etc/nginx/nginx.conf \ +RUN sed -i 's/worker_processes 1/worker_processes auto/' /etc/nginx/nginx.conf \ && sed -i 's/worker_connections 1024/worker_connections 10240/' /etc/nginx/nginx.conf \ && mkdir -p '/etc/nginx/dhparam' diff --git a/Dockerfile.debian b/Dockerfile.debian index 2b7801c..99e16d9 100644 --- a/Dockerfile.debian +++ b/Dockerfile.debian @@ -20,8 +20,7 @@ RUN apt-get update \ && rm -r /var/lib/apt/lists/* # Configure Nginx -RUN echo "daemon off;" >> /etc/nginx/nginx.conf \ - && sed -i 's/worker_processes 1/worker_processes auto/' /etc/nginx/nginx.conf \ +RUN sed -i 's/worker_processes 1/worker_processes auto/' /etc/nginx/nginx.conf \ && sed -i 's/worker_connections 1024/worker_connections 10240/' /etc/nginx/nginx.conf \ && mkdir -p '/etc/nginx/dhparam' diff --git a/app/Procfile b/app/Procfile index 29fe166..f23e0f4 100644 --- a/app/Procfile +++ b/app/Procfile @@ -1,2 +1,2 @@ dockergen: docker-gen -watch -notify "nginx -s reload" /app/nginx.tmpl /etc/nginx/conf.d/default.conf -nginx: nginx +nginx: nginx -g "daemon off;" From 758b43a5b2c71501b7683f094be97eb8755a0a51 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Mon, 25 Dec 2023 19:18:00 +0100 Subject: [PATCH 251/300] refactor: remove unneeded nginx.conf modification the upstream nginx.conf already has "worker_processes auto;" --- Dockerfile.alpine | 3 +-- Dockerfile.debian | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/Dockerfile.alpine b/Dockerfile.alpine index b94f067..f402e05 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -21,8 +21,7 @@ RUN apk add --no-cache --virtual .run-deps \ && update-ca-certificates # Configure Nginx -RUN sed -i 's/worker_processes 1/worker_processes auto/' /etc/nginx/nginx.conf \ - && sed -i 's/worker_connections 1024/worker_connections 10240/' /etc/nginx/nginx.conf \ +RUN sed -i 's/worker_connections 1024/worker_connections 10240/' /etc/nginx/nginx.conf \ && mkdir -p '/etc/nginx/dhparam' # Install Forego + docker-gen diff --git a/Dockerfile.debian b/Dockerfile.debian index 99e16d9..e13f324 100644 --- a/Dockerfile.debian +++ b/Dockerfile.debian @@ -20,8 +20,7 @@ RUN apt-get update \ && rm -r /var/lib/apt/lists/* # Configure Nginx -RUN sed -i 's/worker_processes 1/worker_processes auto/' /etc/nginx/nginx.conf \ - && sed -i 's/worker_connections 1024/worker_connections 10240/' /etc/nginx/nginx.conf \ +RUN sed -i 's/worker_connections 1024/worker_connections 10240/' /etc/nginx/nginx.conf \ && mkdir -p '/etc/nginx/dhparam' # Install Forego + docker-gen From eb9fca85cf50f0d42a7dcd0741e26d3c3674c414 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Mon, 25 Dec 2023 19:19:57 +0100 Subject: [PATCH 252/300] refactor: remove already present or unneeded dependencies --- Dockerfile.alpine | 6 +----- Dockerfile.debian | 6 ------ 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/Dockerfile.alpine b/Dockerfile.alpine index f402e05..864aed5 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -14,11 +14,7 @@ ENV NGINX_PROXY_VERSION=${NGINX_PROXY_VERSION} \ DOCKER_HOST=unix:///tmp/docker.sock # Install dependencies -RUN apk add --no-cache --virtual .run-deps \ - bash \ - ca-certificates \ - openssl \ - && update-ca-certificates +RUN apk add --no-cache --virtual .run-deps bash # Configure Nginx RUN sed -i 's/worker_connections 1024/worker_connections 10240/' /etc/nginx/nginx.conf \ diff --git a/Dockerfile.debian b/Dockerfile.debian index e13f324..69114bc 100644 --- a/Dockerfile.debian +++ b/Dockerfile.debian @@ -13,12 +13,6 @@ ENV NGINX_PROXY_VERSION=${NGINX_PROXY_VERSION} \ DOCKER_GEN_VERSION=${DOCKER_GEN_VERSION} \ DOCKER_HOST=unix:///tmp/docker.sock -# Install/update certificates -RUN apt-get update \ - && apt-get install -y -q --no-install-recommends ca-certificates \ - && apt-get clean \ - && rm -r /var/lib/apt/lists/* - # Configure Nginx RUN sed -i 's/worker_connections 1024/worker_connections 10240/' /etc/nginx/nginx.conf \ && mkdir -p '/etc/nginx/dhparam' From 051c8a510576e70f841f6a07e8ff236df4730d55 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 25 Dec 2023 19:45:00 +0000 Subject: [PATCH 253/300] build: bump nginxproxy/docker-gen from 0.11.0-debian to 0.11.1-debian Bumps nginxproxy/docker-gen from 0.11.0-debian to 0.11.1-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 864aed5..3234807 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -1,4 +1,4 @@ -FROM nginxproxy/docker-gen:0.11.0 AS docker-gen +FROM nginxproxy/docker-gen:0.11.1 AS docker-gen FROM nginxproxy/forego:0.17.3 AS forego diff --git a/Dockerfile.debian b/Dockerfile.debian index 69114bc..b170653 100644 --- a/Dockerfile.debian +++ b/Dockerfile.debian @@ -1,4 +1,4 @@ -FROM nginxproxy/docker-gen:0.11.0-debian AS docker-gen +FROM nginxproxy/docker-gen:0.11.1-debian AS docker-gen FROM nginxproxy/forego:0.17.3-debian AS forego From 47ee75d7800eeaa9a151fb24e53ab79ca1430373 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 25 Dec 2023 20:12:56 +0000 Subject: [PATCH 254/300] build: bump nginxproxy/forego from 0.17.3-debian to 0.18.1-debian Bumps nginxproxy/forego from 0.17.3-debian to 0.18.1-debian. --- updated-dependencies: - dependency-name: nginxproxy/forego dependency-type: direct:production update-type: version-update:semver-minor ... 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 3234807..ffdd52c 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -1,6 +1,6 @@ FROM nginxproxy/docker-gen:0.11.1 AS docker-gen -FROM nginxproxy/forego:0.17.3 AS forego +FROM nginxproxy/forego:0.18.1 AS forego # Build the final image FROM nginx:1.25.3-alpine diff --git a/Dockerfile.debian b/Dockerfile.debian index b170653..2d767fe 100644 --- a/Dockerfile.debian +++ b/Dockerfile.debian @@ -1,6 +1,6 @@ FROM nginxproxy/docker-gen:0.11.1-debian AS docker-gen -FROM nginxproxy/forego:0.17.3-debian AS forego +FROM nginxproxy/forego:0.18.1-debian AS forego # Build the final image FROM nginx:1.25.3 From beeb80732aba685cd4534facbe4d5477acf8350b Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Mon, 25 Dec 2023 21:19:02 +0100 Subject: [PATCH 255/300] docs: mention color disabling --- docs/README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/docs/README.md b/docs/README.md index b2f87c4..f59d2aa 100644 --- a/docs/README.md +++ b/docs/README.md @@ -674,6 +674,18 @@ By default the nginx configuration `upstream` blocks will use this block's corre Please note that using regular expressions in `VIRTUAL_HOST` will always result in a corresponding `upstream` block with an SHA1 name. +### Disabling colors in the log output + +To remove colors from the log output, set the [`NO_COLOR` environment variable to any value other than an empty string](https://no-color.org/) on the nginx-proxy container. + +```console +docker run --detach \ + --publish 80:80 \ + --env NO_COLOR=1 \ + --volume /var/run/docker.sock:/tmp/docker.sock:ro \ + nginxproxy/nginx-proxy +``` + ### Troubleshooting If you can't access your `VIRTUAL_HOST`, inspect the generated nginx configuration: From 26db13387e26385639f9394c58b2bb4c116bc037 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Tue, 26 Dec 2023 17:58:24 +0100 Subject: [PATCH 256/300] refactor: explicitely default keepalive to disabled --- nginx.tmpl | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/nginx.tmpl b/nginx.tmpl index 08606b9..b7a3b9a 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -249,7 +249,7 @@ {{- if exists $override }} include {{ $override }}; {{- else }} - {{- $keepalive := first (keys (groupByLabel .Containers "com.github.nginx-proxy.nginx-proxy.keepalive")) }} + {{- $keepalive := coalesce (first (keys (groupByLabel .Containers "com.github.nginx-proxy.nginx-proxy.keepalive"))) "disabled" }} location {{ .Path }} { {{- if eq .NetworkTag "internal" }} # Only allow traffic from internal clients @@ -263,14 +263,14 @@ root {{ trim .VhostRoot }}; include fastcgi_params; fastcgi_pass {{ trim .Upstream }}; - {{- if $keepalive }} + {{- if ne $keepalive "disabled" }} fastcgi_keep_conn on; {{- end }} {{- else if eq .Proto "grpc" }} grpc_pass {{ trim .Proto }}://{{ trim .Upstream }}; {{- else }} proxy_pass {{ trim .Proto }}://{{ trim .Upstream }}{{ trim .Dest }}; - set $upstream_keepalive {{ if $keepalive }}true{{ else }}false{{ end }}; + set $upstream_keepalive {{ if ne $keepalive "disabled" }}true{{ else }}false{{ end }}; {{- end }} {{- if (exists (printf "/etc/nginx/htpasswd/%s" .Host)) }} @@ -315,8 +315,8 @@ upstream {{ .Upstream }} { # Fallback entry server 127.0.0.1 down; {{- end }} - {{- $keepalive := first (keys (groupByLabel .Containers "com.github.nginx-proxy.nginx-proxy.keepalive")) }} - {{- if $keepalive }} + {{- $keepalive := coalesce (first (keys (groupByLabel .Containers "com.github.nginx-proxy.nginx-proxy.keepalive"))) "disabled" }} + {{- if ne $keepalive "disabled" }} keepalive {{ $keepalive }}; {{- end }} } From 7ce72d59a98522ae1c99258ee7ec37fd8fec19d0 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Tue, 26 Dec 2023 18:18:00 +0100 Subject: [PATCH 257/300] feat: add auto keepalive setting --- nginx.tmpl | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/nginx.tmpl b/nginx.tmpl index b7a3b9a..9477928 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -292,6 +292,7 @@ {{- define "upstream" }} upstream {{ .Upstream }} { {{- $server_found := false }} + {{- $servers := 0 }} {{- $loadbalance := first (keys (groupByLabel .Containers "com.github.nginx-proxy.nginx-proxy.loadbalance")) }} {{- if $loadbalance }} # From the container's loadbalance label: @@ -307,6 +308,7 @@ upstream {{ .Upstream }} { {{- $port := $args.port }} {{- if $ip }} {{- $server_found = true }} + {{- $servers = add1 $servers }} server {{ $ip }}:{{ $port }}; {{- end }} {{- end }} @@ -316,8 +318,12 @@ upstream {{ .Upstream }} { server 127.0.0.1 down; {{- end }} {{- $keepalive := coalesce (first (keys (groupByLabel .Containers "com.github.nginx-proxy.nginx-proxy.keepalive"))) "disabled" }} - {{- if ne $keepalive "disabled" }} + {{- if and (ne $keepalive "disabled") (gt $servers 0) }} + {{- if eq $keepalive "auto" }} + keepalive {{ mul $servers 2 }}; + {{- else }} keepalive {{ $keepalive }}; + {{- end }} {{- end }} } {{- end }} From d56e8f1d8a6851520c2e7cf3a9e722ec13aaa0eb Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Tue, 26 Dec 2023 18:43:05 +0100 Subject: [PATCH 258/300] refactor: $server_found and $servers aren't both needed --- nginx.tmpl | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/nginx.tmpl b/nginx.tmpl index 9477928..e187a0f 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -291,7 +291,6 @@ {{- define "upstream" }} upstream {{ .Upstream }} { - {{- $server_found := false }} {{- $servers := 0 }} {{- $loadbalance := first (keys (groupByLabel .Containers "com.github.nginx-proxy.nginx-proxy.loadbalance")) }} {{- if $loadbalance }} @@ -307,13 +306,12 @@ upstream {{ .Upstream }} { {{- template "container_port" $args }} {{- $port := $args.port }} {{- if $ip }} - {{- $server_found = true }} {{- $servers = add1 $servers }} server {{ $ip }}:{{ $port }}; {{- end }} {{- end }} {{- /* nginx-proxy/nginx-proxy#1105 */}} - {{- if not $server_found }} + {{- if lt $servers 1 }} # Fallback entry server 127.0.0.1 down; {{- end }} From 443ee5202c25972a97f535089155c90de1be6b7e Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Tue, 26 Dec 2023 18:52:43 +0100 Subject: [PATCH 259/300] test: do we get desired number of idle keepalive connections --- test/test_keepalive.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/test_keepalive.py b/test/test_keepalive.py index b5b8353..2f78c3a 100644 --- a/test/test_keepalive.py +++ b/test/test_keepalive.py @@ -20,6 +20,9 @@ def test_keepalive_disabled_other_headers_ok(docker_compose, nginxproxy): assert re.search(fr'(?m)^(?i:X-Real-IP): ', r.text) def test_keepalive_enabled(docker_compose, nginxproxy): + conf = nginxproxy.get_conf().decode('ASCII') + assert re.search(r"keepalive 64\;", conf) + r = nginxproxy.get("http://keepalive-enabled.nginx-proxy.test/headers") assert r.status_code == 200 assert not re.search(fr'(?m)^(?i:Connection):', r.text) From 2aa35aa6371895affa0c90afe191a4f823cfcb42 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Tue, 26 Dec 2023 19:07:09 +0100 Subject: [PATCH 260/300] tests: keepalive auto setting --- test/test_keepalive.py | 8 ++++++++ test/test_keepalive.yml | 13 +++++++++++++ 2 files changed, 21 insertions(+) diff --git a/test/test_keepalive.py b/test/test_keepalive.py index 2f78c3a..c007cf1 100644 --- a/test/test_keepalive.py +++ b/test/test_keepalive.py @@ -27,6 +27,14 @@ def test_keepalive_enabled(docker_compose, nginxproxy): assert r.status_code == 200 assert not re.search(fr'(?m)^(?i:Connection):', r.text) +def test_keepalive_auto_enabled(docker_compose, nginxproxy): + conf = nginxproxy.get_conf().decode('ASCII') + assert re.search(r"keepalive 8\;", conf) + + r = nginxproxy.get("http://keepalive-auto.nginx-proxy.test/headers") + assert r.status_code == 200 + assert not re.search(fr'(?m)^(?i:Connection):', r.text) + def test_keepalive_enabled_other_headers_ok(docker_compose, nginxproxy): """See the docstring for the disabled case above.""" r = nginxproxy.get("http://keepalive-enabled.nginx-proxy.test/headers") diff --git a/test/test_keepalive.yml b/test/test_keepalive.yml index 62f5b25..6da66f0 100644 --- a/test/test_keepalive.yml +++ b/test/test_keepalive.yml @@ -18,6 +18,19 @@ services: VIRTUAL_HOST: keepalive-enabled.nginx-proxy.test labels: com.github.nginx-proxy.nginx-proxy.keepalive: "64" + + keepalive-auto: + image: web + deploy: + mode: replicated + replicas: 4 + expose: + - "80" + environment: + WEB_PORTS: 80 + VIRTUAL_HOST: keepalive-auto.nginx-proxy.test + labels: + com.github.nginx-proxy.nginx-proxy.keepalive: "auto" sut: image: nginxproxy/nginx-proxy:test From d12689cd52021ac28a1cb045fe8e9e430bb4f364 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Tue, 26 Dec 2023 19:10:42 +0100 Subject: [PATCH 261/300] docs: keepalive auto setting --- docs/README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index f59d2aa..431fe60 100644 --- a/docs/README.md +++ b/docs/README.md @@ -520,7 +520,9 @@ services: > **Warning** > This feature is experimental. The behavior may change (or the feature may be removed entirely) without warning in a future release, even if the release is not a new major version. If you use this feature, or if you would like to use this feature but you require changes to it first, please [provide feedback in #2194](https://github.com/nginx-proxy/nginx-proxy/discussions/2194). Once we have collected enough feedback we will promote this feature to officially supported. -To enable HTTP keep-alive between `nginx-proxy` and a backend server, set the `com.github.nginx-proxy.nginx-proxy.keepalive` label on the server's container to the desired maximum number of idle connections. See the [nginx keepalive documentation](https://nginx.org/en/docs/http/ngx_http_upstream_module.html#keepalive) and the [Docker label documentation](https://docs.docker.com/config/labels-custom-metadata/) for details. +To enable HTTP keep-alive between `nginx-proxy` and backend server(s), set the `com.github.nginx-proxy.nginx-proxy.keepalive` label on the server's container either to `auto` or to the desired maximum number of idle connections. The `auto` setting will dynamically set the maximum number of idle connections to twice the number of servers listed in the corresponding `upstream{}` block, [per nginx recommendation](https://www.nginx.com/blog/avoiding-top-10-nginx-configuration-mistakes/#no-keepalives). + +See the [nginx keepalive documentation](https://nginx.org/en/docs/http/ngx_http_upstream_module.html#keepalive) and the [Docker label documentation](https://docs.docker.com/config/labels-custom-metadata/) for details. ### Headers From e2bd0d63654c012b4e06d8952cdd383b75b32f81 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Jan 2024 04:39:54 +0000 Subject: [PATCH 262/300] ci: bump pytest from 7.4.3 to 7.4.4 in /test/requirements Bumps [pytest](https://github.com/pytest-dev/pytest) from 7.4.3 to 7.4.4. - [Release notes](https://github.com/pytest-dev/pytest/releases) - [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst) - [Commits](https://github.com/pytest-dev/pytest/compare/7.4.3...7.4.4) --- updated-dependencies: - dependency-name: pytest dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- test/requirements/python-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/requirements/python-requirements.txt b/test/requirements/python-requirements.txt index 985fc95..d503342 100644 --- a/test/requirements/python-requirements.txt +++ b/test/requirements/python-requirements.txt @@ -1,4 +1,4 @@ backoff==2.2.1 docker==7.0.0 -pytest==7.4.3 +pytest==7.4.4 requests==2.31.0 From 1433daed4da51558b43363190da7ee34b5f59531 Mon Sep 17 00:00:00 2001 From: Niek <100143256+SchoNie@users.noreply.github.com> Date: Fri, 5 Jan 2024 14:32:11 +0100 Subject: [PATCH 263/300] Install docker dependencies in nginx-proxy-tester image --- .../Dockerfile-nginx-proxy-tester | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/test/requirements/Dockerfile-nginx-proxy-tester b/test/requirements/Dockerfile-nginx-proxy-tester index 36984fe..1af4a16 100644 --- a/test/requirements/Dockerfile-nginx-proxy-tester +++ b/test/requirements/Dockerfile-nginx-proxy-tester @@ -5,5 +5,32 @@ ENV PYTEST_RUNNING_IN_CONTAINER=1 COPY python-requirements.txt /requirements.txt RUN pip install -r /requirements.txt +# Add Docker's official GPG key +RUN apt-get update \ + && apt-get install -y \ + ca-certificates \ + curl \ + gnupg \ + && install -m 0755 -d /etc/apt/keyrings \ + && curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg \ + && chmod a+r /etc/apt/keyrings/docker.gpg + +# Add the Docker repository to Apt sources +RUN echo \ + "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian \ + $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \ + tee /etc/apt/sources.list.d/docker.list > /dev/null + +# Install docker-ce-cli and docker-compose-plugin requirements for Pytest docker_compose fixture +RUN apt-get update \ + && apt-get install -y --no-install-recommends \ + docker-ce-cli \ + docker-compose-plugin \ + && apt-get clean \ + && rm -r /var/lib/apt/lists/* + +# Check if docker compose is available +RUN docker compose version + WORKDIR /test ENTRYPOINT ["pytest"] From 329b69fe76e02219be48e6d03a21671432094606 Mon Sep 17 00:00:00 2001 From: Niek <100143256+SchoNie@users.noreply.github.com> Date: Fri, 5 Jan 2024 14:33:05 +0100 Subject: [PATCH 264/300] Update test readme --- test/README.md | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/test/README.md b/test/README.md index 056cd37..07a29d2 100644 --- a/test/README.md +++ b/test/README.md @@ -4,12 +4,10 @@ Nginx proxy test suite Install requirements -------------------- -You need [python 3.9](https://www.python.org/) and [pip](https://pip.pypa.io/en/stable/installing/) installed. Then run the commands: +You need [Docker Compose v2](https://docs.docker.com/compose/install/linux/), [python 3.9](https://www.python.org/) and [pip](https://pip.pypa.io/en/stable/installation/) installed. Then run the commands: pip install -r requirements/python-requirements.txt - - Prepare the nginx-proxy test image ---------------------------------- @@ -37,6 +35,16 @@ Run one single test module pytest test_nominal.py +Run the test suite from a Docker container +------------------------------------------ + +If you cannot (or don't want to) install pytest and its requirements on your computer. You can use the nginx-proxy-tester docker image to run the test suite from a Docker container. + + make test-debian + +or if you want to test the alpine flavor: + + make test-alpine Write a test module ------------------- From 63411b240743027120608abea3fb71487eb2289e Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Wed, 10 Jan 2024 17:00:47 +0100 Subject: [PATCH 265/300] build: add the openssl cli back to the alpine image --- Dockerfile.alpine | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile.alpine b/Dockerfile.alpine index ffdd52c..e4ec6d6 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -14,7 +14,7 @@ ENV NGINX_PROXY_VERSION=${NGINX_PROXY_VERSION} \ DOCKER_HOST=unix:///tmp/docker.sock # Install dependencies -RUN apk add --no-cache --virtual .run-deps bash +RUN apk add --no-cache --virtual .run-deps bash openssl # Configure Nginx RUN sed -i 's/worker_connections 1024/worker_connections 10240/' /etc/nginx/nginx.conf \ From bfe9e0ac1dce62bfe049ddd5c5acc55a62e55fbc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Jan 2024 04:35:11 +0000 Subject: [PATCH 266/300] ci: bump peter-evans/dockerhub-description from 3 to 4 Bumps [peter-evans/dockerhub-description](https://github.com/peter-evans/dockerhub-description) from 3 to 4. - [Release notes](https://github.com/peter-evans/dockerhub-description/releases) - [Commits](https://github.com/peter-evans/dockerhub-description/compare/v3...v4) --- updated-dependencies: - dependency-name: peter-evans/dockerhub-description dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/dockerhub-description.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dockerhub-description.yml b/.github/workflows/dockerhub-description.yml index 594e132..4be8cc2 100644 --- a/.github/workflows/dockerhub-description.yml +++ b/.github/workflows/dockerhub-description.yml @@ -18,7 +18,7 @@ jobs: uses: actions/checkout@v4 - name: Docker Hub Description - uses: peter-evans/dockerhub-description@v3 + uses: peter-evans/dockerhub-description@v4 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN_RWD }} From af5acae58a858f75ee638bb6053da293213dd2c3 Mon Sep 17 00:00:00 2001 From: Yan Song Liu Date: Thu, 1 Feb 2024 14:42:15 +0800 Subject: [PATCH 267/300] Add s390x support Add s390x support Signed-off-by: Yan Song Liu --- .github/workflows/build-publish.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-publish.yml b/.github/workflows/build-publish.yml index 1d47393..6aeb9f5 100644 --- a/.github/workflows/build-publish.yml +++ b/.github/workflows/build-publish.yml @@ -88,7 +88,7 @@ jobs: build-args: | NGINX_PROXY_VERSION=${{ steps.nginx-proxy_version.outputs.VERSION }} DOCKER_GEN_VERSION=${{ steps.docker-gen_version.outputs.VERSION }} - platforms: linux/amd64,linux/arm64,linux/arm/v7 + platforms: linux/amd64,linux/arm64,linux/s390x,linux/arm/v7 sbom: true push: true provenance: mode=max From 5d10467c4264436235c06404334cfb951d00facc Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Sat, 10 Feb 2024 13:56:38 +0100 Subject: [PATCH 268/300] fix: set worker_rlimit_nofile to (worker_connections x 2) --- Dockerfile.alpine | 6 ++++-- Dockerfile.debian | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/Dockerfile.alpine b/Dockerfile.alpine index e4ec6d6..d19359c 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -17,8 +17,10 @@ ENV NGINX_PROXY_VERSION=${NGINX_PROXY_VERSION} \ RUN apk add --no-cache --virtual .run-deps bash openssl # Configure Nginx -RUN sed -i 's/worker_connections 1024/worker_connections 10240/' /etc/nginx/nginx.conf \ - && mkdir -p '/etc/nginx/dhparam' +RUN sed -i 's/worker_connections.*;$/worker_connections 10240;/' /etc/nginx/nginx.conf \ + && sed -i -e '/^\}$/{s//\}\nworker_rlimit_nofile 20480;/;:a' -e '$!N;$!ba' -e '}' /etc/nginx/nginx.conf \ + && mkdir -p '/etc/nginx/dhparam' \ + && mkdir -p '/etc/nginx/certs' # Install Forego + docker-gen COPY --from=forego /usr/local/bin/forego /usr/local/bin/forego diff --git a/Dockerfile.debian b/Dockerfile.debian index 2d767fe..1cb73d2 100644 --- a/Dockerfile.debian +++ b/Dockerfile.debian @@ -14,8 +14,10 @@ ENV NGINX_PROXY_VERSION=${NGINX_PROXY_VERSION} \ DOCKER_HOST=unix:///tmp/docker.sock # Configure Nginx -RUN sed -i 's/worker_connections 1024/worker_connections 10240/' /etc/nginx/nginx.conf \ - && mkdir -p '/etc/nginx/dhparam' +RUN sed -i 's/worker_connections.*;$/worker_connections 10240;/' /etc/nginx/nginx.conf \ + && sed -i -e '/^\}$/{s//\}\nworker_rlimit_nofile 20480;/;:a' -e '$!N;$!ba' -e '}' /etc/nginx/nginx.conf \ + && mkdir -p '/etc/nginx/dhparam' \ + && mkdir -p '/etc/nginx/certs' # Install Forego + docker-gen COPY --from=forego /usr/local/bin/forego /usr/local/bin/forego From 40a347bfae4541ab92b534f2b37ea92de641f350 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Sat, 10 Feb 2024 15:23:35 +0100 Subject: [PATCH 269/300] fix: add non standard port to Host header --- nginx.tmpl | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/nginx.tmpl b/nginx.tmpl index a0be212..f9fff01 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -347,6 +347,13 @@ map $http_x_forwarded_port $proxy_x_forwarded_port { '' $server_port; } +# Include the port in the Host header sent to the container if it is non-standard +map $server_port $host_port { + default :$server_port; + 80 ''; + 443 ''; +} + # If the request from the downstream client has an "Upgrade:" header (set to any # non-empty value), pass "Connection: upgrade" to the upstream (backend) server. # Otherwise, the value for the "Connection" header depends on whether the user @@ -408,7 +415,7 @@ include /etc/nginx/proxy.conf; {{- else }} # HTTP 1.1 support proxy_http_version 1.1; -proxy_set_header Host $host; +proxy_set_header Host $host$host_port; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $proxy_connection; proxy_set_header X-Real-IP $remote_addr; From fa23c11edba63e7b4689b99521cafdc115c3cde3 Mon Sep 17 00:00:00 2001 From: jmformenti Date: Sat, 10 Feb 2024 16:24:00 +0100 Subject: [PATCH 270/300] feat: define basic auth for virtual path --- docs/README.md | 3 +++ nginx.tmpl | 5 ++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index 431fe60..32d432c 100644 --- a/docs/README.md +++ b/docs/README.md @@ -479,6 +479,9 @@ docker run -d -p 80:80 -p 443:443 \ You'll need apache2-utils on the machine where you plan to create the htpasswd file. Follow these [instructions](http://httpd.apache.org/docs/2.2/programs/htpasswd.html) +If you want to define basic authentication for a `VIRTUAL_PATH`, you have to create a file named as /etc/ngingx/htpasswd/${VIRTUAL_HOST}_${VIRTUAL_PATH_SHA1} +(where $VIRTUAL_PATH_SHA1 is the SHA1 hash for the virtual path, you can use any SHA1 online generator to calculate it). + ### Upstream (Backend) Server HTTP Load Balancing Support > **Warning** diff --git a/nginx.tmpl b/nginx.tmpl index f9fff01..8b8b12e 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -275,7 +275,10 @@ set $upstream_keepalive {{ if ne $keepalive "disabled" }}true{{ else }}false{{ end }}; {{- end }} - {{- if (exists (printf "/etc/nginx/htpasswd/%s" .Host)) }} + {{- if (exists (printf "/etc/nginx/htpasswd/%s_%s" .Host (sha1 .Path) )) }} + 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_user_file {{ (printf "/etc/nginx/htpasswd/%s" .Host) }}; {{- end }} From de9809a9e57bef9f2025a382ce7baa040b9cab30 Mon Sep 17 00:00:00 2001 From: Denis Arh Date: Tue, 14 Mar 2023 12:11:33 +0100 Subject: [PATCH 271/300] Add more control over log_format config directive Introduces 3 new environmental variables: - `LOG_FORMAT` - `LOG_FORMAT_ESCAPE` - `LOG_JSON` `LOG_FORMAT` and `LOG_FORMAT_ESCAPE` default to standard values. When `LOG_JSON` is set, defaults are changed to: `{"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"}`and `json`. See `nginx.tmpl` and https://nginx.org/en/docs/http/ngx_http_log_module.html#log_format for details --- nginx.tmpl | 19 ++++++++++++++++++- test/test_log_json.py | 14 ++++++++++++++ test/test_log_json.yml | 15 +++++++++++++++ test/test_log_json_format.py | 16 ++++++++++++++++ test/test_log_json_format.yml | 15 +++++++++++++++ 5 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 test/test_log_json.py create mode 100644 test/test_log_json.yml create mode 100644 test/test_log_json_format.py create mode 100644 test/test_log_json_format.yml diff --git a/nginx.tmpl b/nginx.tmpl index 8b8b12e..5405e7e 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -402,7 +402,24 @@ map $proxy_x_forwarded_proto $proxy_x_forwarded_ssl { gzip_types text/plain text/css application/javascript application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript; -log_format vhost '{{ or $globals.Env.LOG_FORMAT "$host $remote_addr - $remote_user [$time_local] \"$request\" $status $body_bytes_sent \"$http_referer\" \"$http_user_agent\" \"$upstream_addr\"" }}'; + +{{- /* See https://nginx.org/en/docs/http/ngx_http_log_module.html#log_format for details and variables + * 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"`) }} + +{{- if $globals.Env.LOG_JSON }} +{{- /* LOG_JSON is a shorthand + * that sets logging defaults to JSON format + */}} +# 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"}`) }} +{{- end }} + +log_format vhost {{ $logEscape }} '{{ or $globals.Env.LOG_FORMAT $logFormat }}'; access_log off; diff --git a/test/test_log_json.py b/test/test_log_json.py new file mode 100644 index 0000000..1a04b22 --- /dev/null +++ b/test/test_log_json.py @@ -0,0 +1,14 @@ +import pytest + +def test_log_json(docker_compose, nginxproxy): + log_conf = [line for line in nginxproxy.get_conf().decode('ASCII').splitlines() if "log_format vhost escape=" in line] + assert "{\"time_local\":\"$time_iso8601\"," in log_conf[0] + + 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 "{\"time_local\":" in line] + assert "GET /port" in docker_logs[0] diff --git a/test/test_log_json.yml b/test/test_log_json.yml new file mode 100644 index 0000000..7740191 --- /dev/null +++ b/test/test_log_json.yml @@ -0,0 +1,15 @@ +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: + LOG_JSON: 1 diff --git a/test/test_log_json_format.py b/test/test_log_json_format.py new file mode 100644 index 0000000..56cfdea --- /dev/null +++ b/test/test_log_json_format.py @@ -0,0 +1,16 @@ +import pytest + +def test_log_json_format(docker_compose, nginxproxy): + log_conf = [line for line in nginxproxy.get_conf().decode('ASCII').splitlines() if "log_format vhost escape=" in line] + assert "{\"time_local\":\"$time_iso8601\"," in log_conf[0] + + 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 "{\"time_local\":" in line] + assert "GET /port" in docker_logs[0] + + diff --git a/test/test_log_json_format.yml b/test/test_log_json_format.yml new file mode 100644 index 0000000..caf20a7 --- /dev/null +++ b/test/test_log_json_format.yml @@ -0,0 +1,15 @@ +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: + LOG_FORMAT: '{"time_local":"$$time_iso8601","remote_addr":"$$remote_addr","request":"$$request","upstream_addr":"$$upstream_addr"}' From 8aefce916f2b5c6dcf8f6130fe73348ee49306aa Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Sat, 10 Feb 2024 18:02:42 +0100 Subject: [PATCH 272/300] tests: fix the json log test compose files --- test/test_log_json.yml | 31 +++++++++++++++++-------------- test/test_log_json_format.yml | 31 +++++++++++++++++-------------- 2 files changed, 34 insertions(+), 28 deletions(-) diff --git a/test/test_log_json.yml b/test/test_log_json.yml index 7740191..2e6fefd 100644 --- a/test/test_log_json.yml +++ b/test/test_log_json.yml @@ -1,15 +1,18 @@ -web1: - image: web - expose: - - "81" - environment: - WEB_PORTS: 81 - VIRTUAL_HOST: nginx-proxy.test +version: "2" -sut: - container_name: sut - image: nginxproxy/nginx-proxy:test - volumes: - - /var/run/docker.sock:/tmp/docker.sock:ro - environment: - LOG_JSON: 1 +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: + LOG_JSON: 1 diff --git a/test/test_log_json_format.yml b/test/test_log_json_format.yml index caf20a7..5e01e92 100644 --- a/test/test_log_json_format.yml +++ b/test/test_log_json_format.yml @@ -1,15 +1,18 @@ -web1: - image: web - expose: - - "81" - environment: - WEB_PORTS: 81 - VIRTUAL_HOST: nginx-proxy.test +version: "2" -sut: - container_name: sut - image: nginxproxy/nginx-proxy:test - volumes: - - /var/run/docker.sock:/tmp/docker.sock:ro - environment: - LOG_FORMAT: '{"time_local":"$$time_iso8601","remote_addr":"$$remote_addr","request":"$$request","upstream_addr":"$$upstream_addr"}' +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: + LOG_FORMAT: '{"time_local":"$$time_iso8601","remote_addr":"$$remote_addr","request":"$$request","upstream_addr":"$$upstream_addr"}' From 76778cebb17d24629a0aea3c13565d111f64d939 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Sat, 10 Feb 2024 17:54:14 +0100 Subject: [PATCH 273/300] refactor: parse LOG_JSON as boolean + avoid unnecessary backticks --- nginx.tmpl | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/nginx.tmpl b/nginx.tmpl index 5405e7e..c72c1c7 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -407,16 +407,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 := 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"` }} -{{- if $globals.Env.LOG_JSON }} -{{- /* LOG_JSON is a shorthand - * that sets logging defaults to JSON format - */}} +{{- if parseBool (or $globals.Env.LOG_JSON "false") }} + {{- /* LOG_JSON is a shorthand + * that sets logging defaults to JSON format + */}} # 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 = 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"}` }} {{- end }} log_format vhost {{ $logEscape }} '{{ or $globals.Env.LOG_FORMAT $logFormat }}'; From 62f55b4428a1133e5f44a75dde310271fef28c60 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Sat, 10 Feb 2024 19:03:13 +0100 Subject: [PATCH 274/300] docs: add logging documentation --- docs/README.md | 65 +++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 51 insertions(+), 14 deletions(-) diff --git a/docs/README.md b/docs/README.md index 32d432c..e381b7f 100644 --- a/docs/README.md +++ b/docs/README.md @@ -181,12 +181,61 @@ If you would like to connect to FastCGI backend, set `VIRTUAL_PROTO=fastcgi` on If you use fastcgi,you can set `VIRTUAL_ROOT=xxx` for your root directory -### Custom log format +### Logging -If you want to use a custom log format, you can set `LOG_FORMAT=xxx` on the proxy container. +The default nginx access log format is + +``` +$host $remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" "$upstream_addr" +``` + +#### Custom log format + +If you want to use a custom access log format, you can set `LOG_FORMAT=xxx` on the proxy container. With docker compose take care to escape the `$` character with `$$` to avoid variable interpolation. Example: `$remote_addr` becomes `$$remote_addr`. +#### JSON log format + +If you want access logs in JSON format, you can set `LOG_JSON=true`. This will correctly set the escape character to `json` and the log format to : + +```json +{ + "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" +} +``` + +#### Log format escaping + +If you want to manually set nginx `log_format`'s `escape`, set the `LOG_FORMAT_ESCAPE` variable to [a value supported by nginx](https://nginx.org/en/docs/http/ngx_http_log_module.html#log_format). + +#### Disable access logs + +To disable nginx access logs entirely, set the `DISABLE_ACCESS_LOGS` environment variable to any value. + +#### Disabling colors in the container log output + +To remove colors from the container log output, set the [`NO_COLOR` environment variable to any value other than an empty string](https://no-color.org/) on the nginx-proxy container. + +```console +docker run --detach \ + --publish 80:80 \ + --env NO_COLOR=1 \ + --volume /var/run/docker.sock:/tmp/docker.sock:ro \ + nginxproxy/nginx-proxy +``` + ### Default Host To set the default host for nginx use the env var `DEFAULT_HOST=foo.bar.com` for example @@ -679,18 +728,6 @@ By default the nginx configuration `upstream` blocks will use this block's corre Please note that using regular expressions in `VIRTUAL_HOST` will always result in a corresponding `upstream` block with an SHA1 name. -### Disabling colors in the log output - -To remove colors from the log output, set the [`NO_COLOR` environment variable to any value other than an empty string](https://no-color.org/) on the nginx-proxy container. - -```console -docker run --detach \ - --publish 80:80 \ - --env NO_COLOR=1 \ - --volume /var/run/docker.sock:/tmp/docker.sock:ro \ - nginxproxy/nginx-proxy -``` - ### Troubleshooting If you can't access your `VIRTUAL_HOST`, inspect the generated nginx configuration: From 25883ac05fd3ba2ca0efcad2d45200ac62fb5f6b Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Sat, 10 Feb 2024 19:04:56 +0100 Subject: [PATCH 275/300] style: remove extra blank lines --- test/test_log_json_format.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/test_log_json_format.py b/test/test_log_json_format.py index 56cfdea..2d158cb 100644 --- a/test/test_log_json_format.py +++ b/test/test_log_json_format.py @@ -12,5 +12,3 @@ def test_log_json_format(docker_compose, nginxproxy): docker_logs = docker_logs.decode("utf-8").splitlines() docker_logs = [line for line in docker_logs if "{\"time_local\":" in line] assert "GET /port" in docker_logs[0] - - From 3a193827025aeaa4d8c77e79003522b11eca5adf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 10 Feb 2024 18:16:49 +0000 Subject: [PATCH 276/300] build: bump nginxproxy/docker-gen from 0.11.1-debian to 0.11.2-debian Bumps nginxproxy/docker-gen from 0.11.1-debian to 0.11.2-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 d19359c..1a1c8bf 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -1,4 +1,4 @@ -FROM nginxproxy/docker-gen:0.11.1 AS docker-gen +FROM nginxproxy/docker-gen:0.11.2 AS docker-gen FROM nginxproxy/forego:0.18.1 AS forego diff --git a/Dockerfile.debian b/Dockerfile.debian index 1cb73d2..a8c26bc 100644 --- a/Dockerfile.debian +++ b/Dockerfile.debian @@ -1,4 +1,4 @@ -FROM nginxproxy/docker-gen:0.11.1-debian AS docker-gen +FROM nginxproxy/docker-gen:0.11.2-debian AS docker-gen FROM nginxproxy/forego:0.18.1-debian AS forego From cb59c2447035288660a84bbc455c8443a41a3848 Mon Sep 17 00:00:00 2001 From: Niek <100143256+SchoNie@users.noreply.github.com> Date: Tue, 13 Feb 2024 15:24:37 +0100 Subject: [PATCH 277/300] tests non standard port Host header --- test/test_http_port.py | 7 ++++++- test/test_ssl/test_https_port.py | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/test/test_http_port.py b/test/test_http_port.py index 26302c5..0bd6bb4 100644 --- a/test/test_http_port.py +++ b/test/test_http_port.py @@ -5,4 +5,9 @@ import pytest def test_web1_http_custom_port(docker_compose, nginxproxy, subdomain): r = nginxproxy.get("http://%s.nginx-proxy.tld:8080/port" % subdomain, allow_redirects=False) assert r.status_code == 200 - assert "answer from port 81\n" in r.text \ No newline at end of file + assert "answer from port 81\n" in r.text + +def test_nonstandardport_Host_header(docker_compose, nginxproxy): + r = nginxproxy.get("http://web.nginx-proxy.tld:8080/headers") + assert r.status_code == 200 + assert "Host: web.nginx-proxy.tld:8080" in r.text diff --git a/test/test_ssl/test_https_port.py b/test/test_ssl/test_https_port.py index 214d4d9..27a42ef 100644 --- a/test/test_ssl/test_https_port.py +++ b/test/test_ssl/test_https_port.py @@ -11,4 +11,9 @@ def test_web1_http_redirects_to_https(docker_compose, nginxproxy, subdomain): def test_web1_https_is_forwarded(docker_compose, nginxproxy, subdomain): r = nginxproxy.get("https://%s.nginx-proxy.tld:8443/port" % subdomain, allow_redirects=False) assert r.status_code == 200 - assert "answer from port 81\n" in r.text \ No newline at end of file + assert "answer from port 81\n" in r.text + +def test_nonstandardport_Host_header(docker_compose, nginxproxy): + r = nginxproxy.get("https://web.nginx-proxy.tld:8443/headers") + assert r.status_code == 200 + assert "Host: web.nginx-proxy.tld:8443" in r.text From 1aef017df2dac59659ed2fb1402e181091141959 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 15 Feb 2024 04:46:02 +0000 Subject: [PATCH 278/300] build: bump nginx from 1.25.3 to 1.25.4 Bumps nginx from 1.25.3 to 1.25.4. --- updated-dependencies: - dependency-name: nginx 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 1a1c8bf..362e708 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -3,7 +3,7 @@ FROM nginxproxy/docker-gen:0.11.2 AS docker-gen FROM nginxproxy/forego:0.18.1 AS forego # Build the final image -FROM nginx:1.25.3-alpine +FROM nginx:1.25.4-alpine ARG NGINX_PROXY_VERSION # Add DOCKER_GEN_VERSION environment variable because diff --git a/Dockerfile.debian b/Dockerfile.debian index a8c26bc..726c863 100644 --- a/Dockerfile.debian +++ b/Dockerfile.debian @@ -3,7 +3,7 @@ FROM nginxproxy/docker-gen:0.11.2-debian AS docker-gen FROM nginxproxy/forego:0.18.1-debian AS forego # Build the final image -FROM nginx:1.25.3 +FROM nginx:1.25.4 ARG NGINX_PROXY_VERSION # Add DOCKER_GEN_VERSION environment variable because From d9b1751f9763e8d29e166f61c7c8966a52d3e129 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Thu, 15 Feb 2024 08:40:46 +0100 Subject: [PATCH 279/300] build: update docs and tests with nginx 1.25.4 --- README.md | 2 +- test/certs/create_server_certificate.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index edb3bb2..de2cdfb 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ [![Test](https://github.com/nginx-proxy/nginx-proxy/actions/workflows/test.yml/badge.svg)](https://github.com/nginx-proxy/nginx-proxy/actions/workflows/test.yml) [![GitHub release](https://img.shields.io/github/v/release/nginx-proxy/nginx-proxy)](https://github.com/nginx-proxy/nginx-proxy/releases) -![nginx 1.25.3](https://img.shields.io/badge/nginx-1.25.3-brightgreen.svg) +![nginx 1.25.4](https://img.shields.io/badge/nginx-1.25.4-brightgreen.svg) [![Docker Image Size](https://img.shields.io/docker/image-size/nginxproxy/nginx-proxy?sort=semver)](https://hub.docker.com/r/nginxproxy/nginx-proxy "Click to view the image on Docker Hub") [![Docker stars](https://img.shields.io/docker/stars/nginxproxy/nginx-proxy.svg)](https://hub.docker.com/r/nginxproxy/nginx-proxy 'DockerHub') [![Docker pulls](https://img.shields.io/docker/pulls/nginxproxy/nginx-proxy.svg)](https://hub.docker.com/r/nginxproxy/nginx-proxy 'DockerHub') diff --git a/test/certs/create_server_certificate.sh b/test/certs/create_server_certificate.sh index 0789a22..b8625db 100755 --- a/test/certs/create_server_certificate.sh +++ b/test/certs/create_server_certificate.sh @@ -24,7 +24,7 @@ fi # Create a nginx container (which conveniently provides the `openssl` command) ############################################################################### -CONTAINER=$(docker run -d -v $DIR:/work -w /work -e SAN="$ALTERNATE_DOMAINS" nginx:1.25.3) +CONTAINER=$(docker run -d -v $DIR:/work -w /work -e SAN="$ALTERNATE_DOMAINS" nginx:1.25.4) # Configure openssl docker exec $CONTAINER bash -c ' mkdir -p /ca/{certs,crl,private,newcerts} 2>/dev/null From 5583b385cb858e1f28ef00b2123465e2b9499e90 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Thu, 15 Feb 2024 08:41:11 +0100 Subject: [PATCH 280/300] style: docs linting --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index de2cdfb..46d1d61 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,8 @@ [![GitHub release](https://img.shields.io/github/v/release/nginx-proxy/nginx-proxy)](https://github.com/nginx-proxy/nginx-proxy/releases) ![nginx 1.25.4](https://img.shields.io/badge/nginx-1.25.4-brightgreen.svg) [![Docker Image Size](https://img.shields.io/docker/image-size/nginxproxy/nginx-proxy?sort=semver)](https://hub.docker.com/r/nginxproxy/nginx-proxy "Click to view the image on Docker Hub") -[![Docker stars](https://img.shields.io/docker/stars/nginxproxy/nginx-proxy.svg)](https://hub.docker.com/r/nginxproxy/nginx-proxy 'DockerHub') -[![Docker pulls](https://img.shields.io/docker/pulls/nginxproxy/nginx-proxy.svg)](https://hub.docker.com/r/nginxproxy/nginx-proxy 'DockerHub') - +[![Docker stars](https://img.shields.io/docker/stars/nginxproxy/nginx-proxy.svg)](https://hub.docker.com/r/nginxproxy/nginx-proxy "DockerHub") +[![Docker pulls](https://img.shields.io/docker/pulls/nginxproxy/nginx-proxy.svg)](https://hub.docker.com/r/nginxproxy/nginx-proxy "DockerHub") nginx-proxy sets up a container running nginx and [docker-gen](https://github.com/nginx-proxy/docker-gen). docker-gen generates reverse proxy configs for nginx and reloads nginx when containers are started and stopped. @@ -34,6 +33,7 @@ docker run --detach \ Provided your DNS is setup to resolve `foo.bar.com` to the host running nginx-proxy, a request to `http://foo.bar.com` will then be routed to a container with the `VIRTUAL_HOST` env var set to `foo.bar.com` (in this case, the **your-proxied-app** container). The containers being proxied must : + - [expose](https://docs.docker.com/engine/reference/run/#expose-incoming-ports) the port to be proxied, either by using the `EXPOSE` directive in their `Dockerfile` or by using the `--expose` flag to `docker run` or `docker create`. - share at least one Docker network with the nginx-proxy container: by default, if you don't pass the `--net` flag when your nginx-proxy container is created, it will only be attached to the default bridge network. This means that it will not be able to connect to containers on networks other than bridge. From e75c2dfb792f4baa5901a6714fbf2075f0ca675e Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Thu, 15 Feb 2024 09:50:12 +0100 Subject: [PATCH 281/300] build: revert nginx to 1.25.3 (#2396) * Revert "build: update docs and tests with nginx 1.25.4" This reverts commit d9b1751f9763e8d29e166f61c7c8966a52d3e129. * Revert "build: bump nginx from 1.25.3 to 1.25.4" This reverts commit 1aef017df2dac59659ed2fb1402e181091141959. --- Dockerfile.alpine | 2 +- Dockerfile.debian | 2 +- README.md | 2 +- test/certs/create_server_certificate.sh | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Dockerfile.alpine b/Dockerfile.alpine index 362e708..1a1c8bf 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -3,7 +3,7 @@ FROM nginxproxy/docker-gen:0.11.2 AS docker-gen FROM nginxproxy/forego:0.18.1 AS forego # Build the final image -FROM nginx:1.25.4-alpine +FROM nginx:1.25.3-alpine ARG NGINX_PROXY_VERSION # Add DOCKER_GEN_VERSION environment variable because diff --git a/Dockerfile.debian b/Dockerfile.debian index 726c863..a8c26bc 100644 --- a/Dockerfile.debian +++ b/Dockerfile.debian @@ -3,7 +3,7 @@ FROM nginxproxy/docker-gen:0.11.2-debian AS docker-gen FROM nginxproxy/forego:0.18.1-debian AS forego # Build the final image -FROM nginx:1.25.4 +FROM nginx:1.25.3 ARG NGINX_PROXY_VERSION # Add DOCKER_GEN_VERSION environment variable because diff --git a/README.md b/README.md index 46d1d61..c2b9a7d 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ [![Test](https://github.com/nginx-proxy/nginx-proxy/actions/workflows/test.yml/badge.svg)](https://github.com/nginx-proxy/nginx-proxy/actions/workflows/test.yml) [![GitHub release](https://img.shields.io/github/v/release/nginx-proxy/nginx-proxy)](https://github.com/nginx-proxy/nginx-proxy/releases) -![nginx 1.25.4](https://img.shields.io/badge/nginx-1.25.4-brightgreen.svg) +![nginx 1.25.3](https://img.shields.io/badge/nginx-1.25.3-brightgreen.svg) [![Docker Image Size](https://img.shields.io/docker/image-size/nginxproxy/nginx-proxy?sort=semver)](https://hub.docker.com/r/nginxproxy/nginx-proxy "Click to view the image on Docker Hub") [![Docker stars](https://img.shields.io/docker/stars/nginxproxy/nginx-proxy.svg)](https://hub.docker.com/r/nginxproxy/nginx-proxy "DockerHub") [![Docker pulls](https://img.shields.io/docker/pulls/nginxproxy/nginx-proxy.svg)](https://hub.docker.com/r/nginxproxy/nginx-proxy "DockerHub") diff --git a/test/certs/create_server_certificate.sh b/test/certs/create_server_certificate.sh index b8625db..0789a22 100755 --- a/test/certs/create_server_certificate.sh +++ b/test/certs/create_server_certificate.sh @@ -24,7 +24,7 @@ fi # Create a nginx container (which conveniently provides the `openssl` command) ############################################################################### -CONTAINER=$(docker run -d -v $DIR:/work -w /work -e SAN="$ALTERNATE_DOMAINS" nginx:1.25.4) +CONTAINER=$(docker run -d -v $DIR:/work -w /work -e SAN="$ALTERNATE_DOMAINS" nginx:1.25.3) # Configure openssl docker exec $CONTAINER bash -c ' mkdir -p /ca/{certs,crl,private,newcerts} 2>/dev/null From 2eaf6891727bce3b04839a153601883f83e3bdb0 Mon Sep 17 00:00:00 2001 From: Man Kim Date: Thu, 15 Feb 2024 14:37:21 -0800 Subject: [PATCH 282/300] fix typo README.md ngingx to nginx --- docs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index e381b7f..9e26be5 100644 --- a/docs/README.md +++ b/docs/README.md @@ -528,7 +528,7 @@ docker run -d -p 80:80 -p 443:443 \ You'll need apache2-utils on the machine where you plan to create the htpasswd file. Follow these [instructions](http://httpd.apache.org/docs/2.2/programs/htpasswd.html) -If you want to define basic authentication for a `VIRTUAL_PATH`, you have to create a file named as /etc/ngingx/htpasswd/${VIRTUAL_HOST}_${VIRTUAL_PATH_SHA1} +If you want to define basic authentication for a `VIRTUAL_PATH`, you have to create a file named as /etc/nginx/htpasswd/${VIRTUAL_HOST}_${VIRTUAL_PATH_SHA1} (where $VIRTUAL_PATH_SHA1 is the SHA1 hash for the virtual path, you can use any SHA1 online generator to calculate it). ### Upstream (Backend) Server HTTP Load Balancing Support From 29168655cf0897385218ded9b69936948bf8e3d1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 16 Feb 2024 04:25:16 +0000 Subject: [PATCH 283/300] build: bump nginx from 1.25.3 to 1.25.4 Bumps nginx from 1.25.3 to 1.25.4. --- updated-dependencies: - dependency-name: nginx 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 1a1c8bf..362e708 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -3,7 +3,7 @@ FROM nginxproxy/docker-gen:0.11.2 AS docker-gen FROM nginxproxy/forego:0.18.1 AS forego # Build the final image -FROM nginx:1.25.3-alpine +FROM nginx:1.25.4-alpine ARG NGINX_PROXY_VERSION # Add DOCKER_GEN_VERSION environment variable because diff --git a/Dockerfile.debian b/Dockerfile.debian index a8c26bc..726c863 100644 --- a/Dockerfile.debian +++ b/Dockerfile.debian @@ -3,7 +3,7 @@ FROM nginxproxy/docker-gen:0.11.2-debian AS docker-gen FROM nginxproxy/forego:0.18.1-debian AS forego # Build the final image -FROM nginx:1.25.3 +FROM nginx:1.25.4 ARG NGINX_PROXY_VERSION # Add DOCKER_GEN_VERSION environment variable because From a2a441e1dbc0e7871f4bf392a78a95798d67f02a Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Sun, 18 Feb 2024 10:08:23 +0100 Subject: [PATCH 284/300] docs: update nginx badge --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c2b9a7d..46d1d61 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ [![Test](https://github.com/nginx-proxy/nginx-proxy/actions/workflows/test.yml/badge.svg)](https://github.com/nginx-proxy/nginx-proxy/actions/workflows/test.yml) [![GitHub release](https://img.shields.io/github/v/release/nginx-proxy/nginx-proxy)](https://github.com/nginx-proxy/nginx-proxy/releases) -![nginx 1.25.3](https://img.shields.io/badge/nginx-1.25.3-brightgreen.svg) +![nginx 1.25.4](https://img.shields.io/badge/nginx-1.25.4-brightgreen.svg) [![Docker Image Size](https://img.shields.io/docker/image-size/nginxproxy/nginx-proxy?sort=semver)](https://hub.docker.com/r/nginxproxy/nginx-proxy "Click to view the image on Docker Hub") [![Docker stars](https://img.shields.io/docker/stars/nginxproxy/nginx-proxy.svg)](https://hub.docker.com/r/nginxproxy/nginx-proxy "DockerHub") [![Docker pulls](https://img.shields.io/docker/pulls/nginxproxy/nginx-proxy.svg)](https://hub.docker.com/r/nginxproxy/nginx-proxy "DockerHub") From 0dd4f7a8a8dc62d5d81da3ed2bde8ba40075562e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 19 Feb 2024 04:53:15 +0000 Subject: [PATCH 285/300] ci: bump pytest from 7.4.4 to 8.0.1 in /test/requirements Bumps [pytest](https://github.com/pytest-dev/pytest) from 7.4.4 to 8.0.1. - [Release notes](https://github.com/pytest-dev/pytest/releases) - [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst) - [Commits](https://github.com/pytest-dev/pytest/compare/7.4.4...8.0.1) --- updated-dependencies: - dependency-name: pytest dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- test/requirements/python-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/requirements/python-requirements.txt b/test/requirements/python-requirements.txt index d503342..140b431 100644 --- a/test/requirements/python-requirements.txt +++ b/test/requirements/python-requirements.txt @@ -1,4 +1,4 @@ backoff==2.2.1 docker==7.0.0 -pytest==7.4.4 +pytest==8.0.1 requests==2.31.0 From 50750bea5396e564c1e6262d921a0e295fa99086 Mon Sep 17 00:00:00 2001 From: Niek <100143256+SchoNie@users.noreply.github.com> Date: Mon, 19 Feb 2024 12:21:02 +0100 Subject: [PATCH 286/300] highlight variables similar to other in readme --- docs/README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/README.md b/docs/README.md index 9e26be5..09deae6 100644 --- a/docs/README.md +++ b/docs/README.md @@ -515,8 +515,8 @@ To enable HTTP/3 globally set the environment variable `ENABLE_HTTP3` to `true` ### 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 on directory -/etc/nginx/htpasswd/$VIRTUAL_HOST +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 +`/etc/nginx/htpasswd/{$VIRTUAL_HOST}` ```console docker run -d -p 80:80 -p 443:443 \ @@ -526,10 +526,10 @@ docker run -d -p 80:80 -p 443:443 \ nginxproxy/nginx-proxy ``` -You'll need apache2-utils on the machine where you plan to create the htpasswd file. Follow these [instructions](http://httpd.apache.org/docs/2.2/programs/htpasswd.html) +If you want to define basic authentication for a `VIRTUAL_PATH`, you have to create a file named as `/etc/nginx/htpasswd/${VIRTUAL_HOST}_${VIRTUAL_PATH_SHA1}` +(where `$VIRTUAL_PATH_SHA1` is the SHA1 hash for the virtual path, you can use any SHA1 online generator to calculate it). -If you want to define basic authentication for a `VIRTUAL_PATH`, you have to create a file named as /etc/nginx/htpasswd/${VIRTUAL_HOST}_${VIRTUAL_PATH_SHA1} -(where $VIRTUAL_PATH_SHA1 is the SHA1 hash for the virtual path, you can use any SHA1 online generator to calculate it). +You'll need apache2-utils on the machine where you plan to create the htpasswd file. Follow these [instructions](http://httpd.apache.org/docs/programs/htpasswd.html) ### Upstream (Backend) Server HTTP Load Balancing Support From d4438b5a09e477880c8b09428e5c2ea73e126149 Mon Sep 17 00:00:00 2001 From: Niek <100143256+SchoNie@users.noreply.github.com> Date: Mon, 19 Feb 2024 12:23:19 +0100 Subject: [PATCH 287/300] prevent double slash --- nginx.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nginx.tmpl b/nginx.tmpl index c72c1c7..783c643 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -276,7 +276,7 @@ {{- end }} {{- if (exists (printf "/etc/nginx/htpasswd/%s_%s" .Host (sha1 .Path) )) }} - auth_basic "Restricted {{ .Host }}/{{ .Path }}"; + 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 }}"; From 4464269c51184b2f2a076b7c99a507c1471362e6 Mon Sep 17 00:00:00 2001 From: Niek <100143256+SchoNie@users.noreply.github.com> Date: Mon, 19 Feb 2024 17:11:31 +0100 Subject: [PATCH 288/300] remove obsolete stress-test --- test/stress_tests/test_deleted_cert/README.md | 5 -- .../certs/web.nginx-proxy.crt | 70 ------------------ .../certs/web.nginx-proxy.key | 27 ------- .../test_deleted_cert/docker-compose.yml | 17 ----- .../test_restart_while_missing_cert.py | 72 ------------------- .../test_deleted_cert/tmp_certs/.gitignore | 2 - 6 files changed, 193 deletions(-) delete mode 100644 test/stress_tests/test_deleted_cert/README.md delete mode 100644 test/stress_tests/test_deleted_cert/certs/web.nginx-proxy.crt delete mode 100644 test/stress_tests/test_deleted_cert/certs/web.nginx-proxy.key delete mode 100644 test/stress_tests/test_deleted_cert/docker-compose.yml delete mode 100644 test/stress_tests/test_deleted_cert/test_restart_while_missing_cert.py delete mode 100644 test/stress_tests/test_deleted_cert/tmp_certs/.gitignore diff --git a/test/stress_tests/test_deleted_cert/README.md b/test/stress_tests/test_deleted_cert/README.md deleted file mode 100644 index 9fac0b9..0000000 --- a/test/stress_tests/test_deleted_cert/README.md +++ /dev/null @@ -1,5 +0,0 @@ -Test the behavior of nginx-proxy when restarted after deleting a certificate file is was using. - -1. nginx-proxy is created with a virtual host having a certificate -1. while nginx-proxy is running, the certificate file is deleted -1. nginx-proxy is then restarted (without removing the container) diff --git a/test/stress_tests/test_deleted_cert/certs/web.nginx-proxy.crt b/test/stress_tests/test_deleted_cert/certs/web.nginx-proxy.crt deleted file mode 100644 index 2c92efe..0000000 --- a/test/stress_tests/test_deleted_cert/certs/web.nginx-proxy.crt +++ /dev/null @@ -1,70 +0,0 @@ -Certificate: - Data: - Version: 3 (0x2) - Serial Number: 4096 (0x1000) - Signature Algorithm: sha256WithRSAEncryption - Issuer: O=nginx-proxy test suite, CN=www.nginx-proxy.tld - Validity - Not Before: Feb 17 23:20:54 2017 GMT - Not After : Jul 5 23:20:54 2044 GMT - Subject: CN=web.nginx-proxy - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - Public-Key: (2048 bit) - Modulus: - 00:b6:27:63:a5:c6:e8:f4:7a:94:0e:cc:a2:62:76: - 6d:5d:33:6f:cf:19:fc:e7:e5:bb:0e:0e:d0:7c:4f: - 73:4c:48:2b:17:d1:4d:d5:9f:42:08:73:84:54:8c: - 86:d2:c5:da:59:01:3f:42:22:e0:36:f0:dc:ab:de: - 0a:bd:26:2b:22:13:87:a6:1f:23:ef:0e:99:27:8b: - 15:4a:1b:ef:93:c9:6b:91:de:a0:02:0c:62:bb:cc: - 56:37:e8:25:92:c3:1f:f1:69:d8:7c:a8:33:e0:89: - ce:14:67:a0:39:77:88:91:e6:a3:07:97:90:22:88: - d0:79:18:63:fb:6f:7e:ee:2b:42:7e:23:f5:e7:da: - e9:ee:6a:fa:96:65:9f:e1:2b:15:49:c8:cd:2d:ce: - 86:4f:2c:2a:67:79:bf:41:30:14:cc:f6:0f:14:74: - 9e:b6:d3:d0:3b:f0:1b:b8:e8:19:2a:fd:d6:fd:dc: - 4b:4e:65:7d:9b:bf:37:7e:2d:35:22:2e:74:90:ce: - 41:35:3d:41:a0:99:db:97:1f:bf:3e:18:3c:48:fb: - da:df:c6:4e:4e:b9:67:b8:10:d5:a5:13:03:c4:b7: - 65:e7:aa:f0:14:4b:d3:4d:ea:fe:8f:69:cf:50:21: - 63:27:cf:9e:4c:67:15:7b:3f:3b:da:cb:17:80:61: - 1e:25 - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Subject Alternative Name: - DNS:web.nginx-proxy - Signature Algorithm: sha256WithRSAEncryption - 09:31:be:db:4e:b0:b6:68:da:ae:5b:16:51:29:fc:9f:61:b6: - 5a:2f:3c:35:ef:67:76:97:b0:34:4e:3b:b4:d6:88:19:4f:84: - 2e:73:d3:c0:3a:4c:41:54:6c:bb:67:89:67:ad:25:55:d7:d4: - 80:fe:a7:3f:3d:9e:f1:34:96:d8:da:5a:78:51:c0:63:f1:52: - 29:35:55:f4:7d:70:1c:d3:96:62:7f:64:86:81:52:27:c4:c6: - 10:13:c6:73:56:4d:32:d0:b3:c3:c8:2c:25:83:e4:2b:1d:d4: - 74:30:e5:85:af:2d:b6:a5:6b:fe:5d:d3:3c:00:58:94:f4:6a: - f5:a6:1d:cf:f9:ed:d5:27:ed:13:24:b2:4f:2b:f3:b8:e4:af: - 0c:1d:fe:e0:6a:01:5e:a2:44:ff:3e:96:fa:6c:39:a3:51:37: - f3:72:55:d8:2d:29:6e:de:95:b9:d8:e3:1e:65:a5:9c:0d:79: - 2d:39:ab:c7:ac:16:b6:a5:71:4b:35:a4:6c:72:47:1b:72:9c: - 67:58:c1:fc:f6:7f:a7:73:50:7b:d6:27:57:74:a1:31:38:a7: - 31:e3:b9:d4:c9:45:33:ec:ed:16:cf:c5:bd:d0:03:b1:45:3f: - 68:0d:91:5c:26:4e:37:05:74:ed:3e:75:5e:ca:5e:ee:e2:51: - 4b:da:08:99 ------BEGIN CERTIFICATE----- -MIIC8zCCAdugAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwPzEfMB0GA1UECgwWbmdp -bngtcHJveHkgdGVzdCBzdWl0ZTEcMBoGA1UEAwwTd3d3Lm5naW54LXByb3h5LnRs -ZDAeFw0xNzAyMTcyMzIwNTRaFw00NDA3MDUyMzIwNTRaMBoxGDAWBgNVBAMMD3dl -Yi5uZ2lueC1wcm94eTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALYn -Y6XG6PR6lA7MomJ2bV0zb88Z/Ofluw4O0HxPc0xIKxfRTdWfQghzhFSMhtLF2lkB -P0Ii4Dbw3KveCr0mKyITh6YfI+8OmSeLFUob75PJa5HeoAIMYrvMVjfoJZLDH/Fp -2HyoM+CJzhRnoDl3iJHmoweXkCKI0HkYY/tvfu4rQn4j9efa6e5q+pZln+ErFUnI -zS3Ohk8sKmd5v0EwFMz2DxR0nrbT0DvwG7joGSr91v3cS05lfZu/N34tNSIudJDO -QTU9QaCZ25cfvz4YPEj72t/GTk65Z7gQ1aUTA8S3Zeeq8BRL003q/o9pz1AhYyfP -nkxnFXs/O9rLF4BhHiUCAwEAAaMeMBwwGgYDVR0RBBMwEYIPd2ViLm5naW54LXBy -b3h5MA0GCSqGSIb3DQEBCwUAA4IBAQAJMb7bTrC2aNquWxZRKfyfYbZaLzw172d2 -l7A0Tju01ogZT4Quc9PAOkxBVGy7Z4lnrSVV19SA/qc/PZ7xNJbY2lp4UcBj8VIp -NVX0fXAc05Zif2SGgVInxMYQE8ZzVk0y0LPDyCwlg+QrHdR0MOWFry22pWv+XdM8 -AFiU9Gr1ph3P+e3VJ+0TJLJPK/O45K8MHf7gagFeokT/Ppb6bDmjUTfzclXYLSlu -3pW52OMeZaWcDXktOavHrBa2pXFLNaRsckcbcpxnWMH89n+nc1B71idXdKExOKcx -47nUyUUz7O0Wz8W90AOxRT9oDZFcJk43BXTtPnVeyl7u4lFL2giZ ------END CERTIFICATE----- diff --git a/test/stress_tests/test_deleted_cert/certs/web.nginx-proxy.key b/test/stress_tests/test_deleted_cert/certs/web.nginx-proxy.key deleted file mode 100644 index dca1c99..0000000 --- a/test/stress_tests/test_deleted_cert/certs/web.nginx-proxy.key +++ /dev/null @@ -1,27 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEowIBAAKCAQEAtidjpcbo9HqUDsyiYnZtXTNvzxn85+W7Dg7QfE9zTEgrF9FN -1Z9CCHOEVIyG0sXaWQE/QiLgNvDcq94KvSYrIhOHph8j7w6ZJ4sVShvvk8lrkd6g -Agxiu8xWN+glksMf8WnYfKgz4InOFGegOXeIkeajB5eQIojQeRhj+29+7itCfiP1 -59rp7mr6lmWf4SsVScjNLc6GTywqZ3m/QTAUzPYPFHSettPQO/AbuOgZKv3W/dxL -TmV9m783fi01Ii50kM5BNT1BoJnblx+/Phg8SPva38ZOTrlnuBDVpRMDxLdl56rw -FEvTTer+j2nPUCFjJ8+eTGcVez872ssXgGEeJQIDAQABAoIBAGQCMFW+ZfyEqHGP -rMA+oUEAkqy0agSwPwky3QjDXlxNa0uCYSeebtTRB6CcHxHuCzm+04puN4gyqhW6 -rU64fAoTivCMPGBuNWxekmvD9r+/YM4P2u4E+th9EgFT9f0kII+dO30FpKXtQzY0 -xuWGWXcxl+T9M+eiEkPKPmq4BoqgTDo5ty7qDv0ZqksGotKFmdYbtSvgBAueJdwu -VWJvenI9F42ExBRKOW1aldiRiaYBCLiCVPKJtOg9iuOP9RHUL1SE8xy5I5mm78g3 -a13ji3BNq3yS+VhGjQ7zDy1V1jGupLoJw4I7OThu8hy+B8Vt8EN/iqakufOkjlTN -xTJ33CkCgYEA5Iymg0NTjWk6aEkFa9pERjfUWqdVp9sWSpFFZZgi55n7LOx6ohi3 -vuLim3is/gYfK2kU/kHGZZLPnT0Rdx0MbOB4XK0CAUlqtUd0IyO4jMZ06g4/kn3N -e2jLdCCIBoEQuLk4ELxj2mHsLQhEvDrg7nzU2WpTHHhvJbIbDWOAxhsCgYEAzAgv -rKpanF+QDf4yeKHxAj2rrwRksTw4Pe7ZK/bog/i+HIVDA70vMapqftHbual/IRrB -JL7hxskoJ/h9c1w4xkWDjqkSKz8/Ihr4dyPfWyGINWbx/rarT/m5MU5SarScoK7o -Xgb25x+W+61rtI+2JhVRGO86+JiAeT4LkAX88L8CgYAwHHug/jdEeXZWJakCfzwI -HBCT1M3vO+uBXvtg25ndb0i0uENIhDOJ93EEkW65Osis9r34mBgPocwaqZRXosHO -2aH8wF6/rpjL+HK2QvrCh7Rs4Pr494qeA/1wQLjhxaGjgToQK9hJTHvPLwJpLWvU -SGr2Ka+9Oo0LPmb7dorRKQKBgQCLsNcjOodLJMp2KiHYIdfmlt6itzlRd09yZ8Nc -rHHJWVagJEUbnD1hnbHIHlp3pSqbObwfMmlWNoc9xo3tm6hrZ1CJLgx4e5b3/Ms8 -ltznge/F0DPDFsH3wZwfu+YFlJ7gDKCfL9l/qEsxCS0CtJobPOEHV1NivNbJK8ey -1ca19QKBgDTdMOUsobAmDEkPQIpxfK1iqYAB7hpRLi79OOhLp23NKeyRNu8FH9fo -G3DZ4xUi6hP2bwiYugMXDyLKfvxbsXwQC84kGF8j+bGazKNhHqEC1OpYwmaTB3kg -qL9cHbjWySeRdIsRY/eWmiKjUwmiO54eAe1HWUdcsuz8yM3xf636 ------END RSA PRIVATE KEY----- diff --git a/test/stress_tests/test_deleted_cert/docker-compose.yml b/test/stress_tests/test_deleted_cert/docker-compose.yml deleted file mode 100644 index a362e44..0000000 --- a/test/stress_tests/test_deleted_cert/docker-compose.yml +++ /dev/null @@ -1,17 +0,0 @@ -version: "2" - -services: - web: - image: web - expose: - - "81" - environment: - WEB_PORTS: 81 - VIRTUAL_HOST: web.nginx-proxy - - reverseproxy: - image: nginxproxy/nginx-proxy:test - container_name: reverseproxy - volumes: - - /var/run/docker.sock:/tmp/docker.sock:ro - - ./tmp_certs:/etc/nginx/certs:ro diff --git a/test/stress_tests/test_deleted_cert/test_restart_while_missing_cert.py b/test/stress_tests/test_deleted_cert/test_restart_while_missing_cert.py deleted file mode 100644 index d7e4cbb..0000000 --- a/test/stress_tests/test_deleted_cert/test_restart_while_missing_cert.py +++ /dev/null @@ -1,72 +0,0 @@ -import logging -import os -from os.path import join, isfile -from shutil import copy -from time import sleep - -import pytest -from requests import ConnectionError - -script_dir = os.path.dirname(__file__) - -pytestmark = pytest.mark.xfail() # TODO delete this marker once those issues are fixed - -@pytest.fixture(scope="module", autouse=True) -def certs(): - """ - pytest fixture that provides cert and key files into the tmp_certs directory - """ - file_names = ("web.nginx-proxy.crt", "web.nginx-proxy.key") - logging.info("copying server cert and key files into tmp_certs") - for f_name in file_names: - copy(join(script_dir, "certs", f_name), join(script_dir, "tmp_certs")) - yield - logging.info("cleaning up the tmp_cert directory") - for f_name in file_names: - if isfile(join(script_dir, "tmp_certs", f_name)): - os.remove(join(script_dir, "tmp_certs", f_name)) - -############################################################################### - - -def test_unknown_virtual_host_is_503(docker_compose, nginxproxy): - r = nginxproxy.get("http://foo.nginx-proxy/") - assert r.status_code == 503 - - -def test_http_web_is_301(docker_compose, nginxproxy): - r = nginxproxy.get("http://web.nginx-proxy/port", allow_redirects=False) - assert r.status_code == 301 - - -def test_https_web_is_200(docker_compose, nginxproxy): - r = nginxproxy.get("https://web.nginx-proxy/port") - assert r.status_code == 200 - assert "answer from port 81\n" in r.text - - -@pytest.mark.incremental -def test_delete_cert_and_restart_reverseproxy(docker_compose): - os.remove(join(script_dir, "tmp_certs", "web.nginx-proxy.crt")) - docker_compose.containers.get("reverseproxy").restart() - sleep(3) # give time for the container to initialize - assert "running" == docker_compose.containers.get("reverseproxy").status - - -@pytest.mark.incremental -def test_unknown_virtual_host_is_still_503(nginxproxy): - r = nginxproxy.get("http://foo.nginx-proxy/") - assert r.status_code == 503 - - -@pytest.mark.incremental -def test_http_web_is_now_200(nginxproxy): - r = nginxproxy.get("http://web.nginx-proxy/port", allow_redirects=False) - assert r.status_code == 200 - assert "answer from port 81\n" == r.text - - -@pytest.mark.incremental -def test_https_web_is_now_broken_since_there_is_no_cert(nginxproxy): - with pytest.raises(ConnectionError): - nginxproxy.get("https://web.nginx-proxy/port") diff --git a/test/stress_tests/test_deleted_cert/tmp_certs/.gitignore b/test/stress_tests/test_deleted_cert/tmp_certs/.gitignore deleted file mode 100644 index c96a04f..0000000 --- a/test/stress_tests/test_deleted_cert/tmp_certs/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -* -!.gitignore \ No newline at end of file From a9f8a9c32ab83dd3b763495ad110d0cc4c964f5f Mon Sep 17 00:00:00 2001 From: Niek <100143256+SchoNie@users.noreply.github.com> Date: Mon, 19 Feb 2024 17:15:58 +0100 Subject: [PATCH 289/300] htpasswd tests --- .../htpasswd/htpasswd.nginx-proxy.tld | 1 + ...d_8d960560c82f4e6c8b1b0f03eb30a1afd00e5696 | 1 + .../test_htpasswd_virtual_host.py | 13 +++++++++++++ .../test_htpasswd_virtual_host.yml | 17 +++++++++++++++++ .../test_htpasswd_virtual_path.py | 12 ++++++++++++ .../test_htpasswd_virtual_path.yml | 19 +++++++++++++++++++ 6 files changed, 63 insertions(+) create mode 100644 test/test_htpasswd/htpasswd/htpasswd.nginx-proxy.tld create mode 100644 test/test_htpasswd/htpasswd/htpasswd.nginx-proxy.tld_8d960560c82f4e6c8b1b0f03eb30a1afd00e5696 create mode 100644 test/test_htpasswd/test_htpasswd_virtual_host.py create mode 100644 test/test_htpasswd/test_htpasswd_virtual_host.yml create mode 100644 test/test_htpasswd/test_htpasswd_virtual_path.py create mode 100644 test/test_htpasswd/test_htpasswd_virtual_path.yml diff --git a/test/test_htpasswd/htpasswd/htpasswd.nginx-proxy.tld b/test/test_htpasswd/htpasswd/htpasswd.nginx-proxy.tld new file mode 100644 index 0000000..336275a --- /dev/null +++ b/test/test_htpasswd/htpasswd/htpasswd.nginx-proxy.tld @@ -0,0 +1 @@ +vhost:$2a$13$/aPYmoK0mmgyAI4TpKdFY.6441Ugo39MdXjhpm.Pp6D15rbz9tvz. diff --git a/test/test_htpasswd/htpasswd/htpasswd.nginx-proxy.tld_8d960560c82f4e6c8b1b0f03eb30a1afd00e5696 b/test/test_htpasswd/htpasswd/htpasswd.nginx-proxy.tld_8d960560c82f4e6c8b1b0f03eb30a1afd00e5696 new file mode 100644 index 0000000..9816a83 --- /dev/null +++ b/test/test_htpasswd/htpasswd/htpasswd.nginx-proxy.tld_8d960560c82f4e6c8b1b0f03eb30a1afd00e5696 @@ -0,0 +1 @@ +vpath:$2a$13$/aPYmoK0mmgyAI4TpKdFY.6441Ugo39MdXjhpm.Pp6D15rbz9tvz. diff --git a/test/test_htpasswd/test_htpasswd_virtual_host.py b/test/test_htpasswd/test_htpasswd_virtual_host.py new file mode 100644 index 0000000..aff3a62 --- /dev/null +++ b/test/test_htpasswd/test_htpasswd_virtual_host.py @@ -0,0 +1,13 @@ +import pytest + +def test_htpasswd_virtual_host_is_restricted(docker_compose, nginxproxy): + r = nginxproxy.get("http://htpasswd.nginx-proxy.tld/port") + assert r.status_code == 401 + assert "WWW-Authenticate" in r.headers + assert r.headers["WWW-Authenticate"] == 'Basic realm="Restricted htpasswd.nginx-proxy.tld"' + + +def test_htpasswd_virtual_host_basic_auth(docker_compose, nginxproxy): + r = nginxproxy.get("http://htpasswd.nginx-proxy.tld/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_virtual_host.yml b/test/test_htpasswd/test_htpasswd_virtual_host.yml new file mode 100644 index 0000000..b3f15df --- /dev/null +++ b/test/test_htpasswd/test_htpasswd_virtual_host.yml @@ -0,0 +1,17 @@ +version: "2" + +services: + web: + image: web + expose: + - "80" + environment: + WEB_PORTS: 80 + VIRTUAL_HOST: htpasswd.nginx-proxy.tld + + sut: + container_name: sut + image: nginxproxy/nginx-proxy:test + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro + - ./htpasswd:/etc/nginx/htpasswd:ro diff --git a/test/test_htpasswd/test_htpasswd_virtual_path.py b/test/test_htpasswd/test_htpasswd_virtual_path.py new file mode 100644 index 0000000..262b314 --- /dev/null +++ b/test/test_htpasswd/test_htpasswd_virtual_path.py @@ -0,0 +1,12 @@ +import pytest + +def test_htpasswd_virtual_path_is_restricted(docker_compose, nginxproxy): + r = nginxproxy.get("http://htpasswd.nginx-proxy.tld/foo/port") + assert r.status_code == 401 + assert "WWW-Authenticate" in r.headers + assert r.headers["WWW-Authenticate"] == 'Basic realm="Restricted htpasswd.nginx-proxy.tld/foo/"' + +def test_htpasswd_virtual_path_basic_auth(docker_compose, nginxproxy): + r = nginxproxy.get("http://htpasswd.nginx-proxy.tld/foo/port", auth=("vpath", "password")) + assert r.status_code == 200 + assert r.text == "answer from port 80\n" diff --git a/test/test_htpasswd/test_htpasswd_virtual_path.yml b/test/test_htpasswd/test_htpasswd_virtual_path.yml new file mode 100644 index 0000000..ffe1a08 --- /dev/null +++ b/test/test_htpasswd/test_htpasswd_virtual_path.yml @@ -0,0 +1,19 @@ +version: "2" + +services: + web: + image: web + expose: + - "80" + environment: + WEB_PORTS: 80 + VIRTUAL_HOST: htpasswd.nginx-proxy.tld + VIRTUAL_PATH: /foo/ + VIRTUAL_DEST: / + + sut: + container_name: sut + image: nginxproxy/nginx-proxy:test + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro + - ./htpasswd:/etc/nginx/htpasswd:ro From 8c95ed1cc0f45d266b6b64163929894e20cb9b83 Mon Sep 17 00:00:00 2001 From: Michael Bianco Date: Thu, 22 Feb 2024 05:59:51 -0700 Subject: [PATCH 290/300] docs: add comment about host network to compose example --- docker-compose.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docker-compose.yml b/docker-compose.yml index 809d6fa..a261ffc 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -9,6 +9,9 @@ services: volumes: - /var/run/docker.sock:/tmp/docker.sock:ro + # if you want to proxy based on host ports, you'll want to use the host network + # network_mode: "host" + whoami: image: jwilder/whoami environment: From 4d9d0676301a611a1fc0d2de9c9bf37335f7f68f Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Sat, 24 Feb 2024 20:02:58 +0100 Subject: [PATCH 291/300] refactor: refactor virtual hosts --- nginx.tmpl | 167 +++++++++++++++++++++++++---------------------------- 1 file changed, 80 insertions(+), 87 deletions(-) diff --git a/nginx.tmpl b/nginx.tmpl index 783c643..09277db 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -450,33 +450,62 @@ proxy_set_header X-Original-URI $request_uri; proxy_set_header Proxy ""; {{- end }} -{{- /* - * Precompute some information about each vhost. This is done early because - * the creation of fallback servers depends on DEFAULT_HOST, HTTPS_METHOD, - * and whether there are any missing certs. - */}} -{{- range $vhost, $containers := groupByMulti $globals.containers "Env.VIRTUAL_HOST" "," }} - {{- $vhost := trim $vhost }} - {{- if not $vhost }} +{{- /* Precompute some information about each vhost. */}} +{{- range $hostname, $containers := groupByMulti $globals.containers "Env.VIRTUAL_HOST" "," }} + {{- $hostname := trim $hostname }} + {{- if not $hostname }} {{- /* Ignore containers with VIRTUAL_HOST set to the empty string. */}} {{- continue }} {{- end }} + {{- $certName := first (groupByKeys $containers "Env.CERT_NAME") }} - {{- $vhostCert := closest (dir "/etc/nginx/certs") (printf "%s.crt" $vhost) }} + {{- $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)) }} - {{- $default := eq $globals.Env.DEFAULT_HOST $vhost }} + + {{- $default := eq $globals.Env.DEFAULT_HOST $hostname }} {{- $https_method := or (first (groupByKeys $containers "Env.HTTPS_METHOD")) $globals.Env.HTTPS_METHOD "redirect" }} - {{- $http3 := parseBool (or (first (keys (groupByLabel $containers "com.github.nginx-proxy.nginx-proxy.http3.enable"))) $globals.Env.ENABLE_HTTP3 "false")}} - {{- $_ := set $globals.vhosts $vhost (dict + {{- $http2_enabled := parseBool (or (first (keys (groupByLabel $containers "com.github.nginx-proxy.nginx-proxy.http2.enable"))) $globals.Env.ENABLE_HTTP2 "true")}} + {{- $http3_enabled := parseBool (or (first (keys (groupByLabel $containers "com.github.nginx-proxy.nginx-proxy.http3.enable"))) $globals.Env.ENABLE_HTTP3 "false")}} + + {{- $is_regexp := hasPrefix "~" $hostname }} + {{- $upstream_name := when (or $is_regexp $globals.sha1_upstream_name) (sha1 $hostname) $hostname }} + + {{- /* Get the SERVER_TOKENS defined by containers w/ the same vhost, falling back to "". */}} + {{- $server_tokens := trim (or (first (groupByKeys $containers "Env.SERVER_TOKENS")) "") }} + + {{- /* Get the SSL_POLICY defined by containers w/ the same vhost, falling back to empty string (use default). */}} + {{- $ssl_policy := or (first (groupByKeys $containers "Env.SSL_POLICY")) "" }} + + {{- /* Get the HSTS defined by containers w/ the same vhost, falling back to "max-age=31536000". */}} + {{- $hsts := or (first (groupByKeys $containers "Env.HSTS")) (or $globals.Env.HSTS "max-age=31536000") }} + + {{- /* Get the VIRTUAL_ROOT By containers w/ use fastcgi root */}} + {{- $vhost_root := or (first (groupByKeys $containers "Env.VIRTUAL_ROOT")) "/var/www/public" }} + + + {{- $paths := groupBy $containers "Env.VIRTUAL_PATH" }} + {{- $has_virtual_paths := gt (len $paths) 0}} + {{- if not $has_virtual_paths }} + {{- $paths = dict "/" $containers }} + {{- end }} + + {{- $_ := set $globals.vhosts $hostname (dict "cert" $cert "cert_ok" $cert_ok - "containers" $containers "default" $default + "has_virtual_paths" $has_virtual_paths + "hsts" $hsts "https_method" $https_method - "http3" $http3 + "http2_enabled" $http2_enabled + "http3_enabled" $http3_enabled + "paths" $paths + "server_tokens" $server_tokens + "ssl_policy" $ssl_policy + "upstream_name" $upstream_name + "vhost_root" $vhost_root ) }} {{- end }} @@ -499,7 +528,7 @@ proxy_set_header Proxy ""; {{- $https_exists := false }} {{- $default_http_exists := false }} {{- $default_https_exists := false }} - {{- $http3 := false }} + {{- $http3_enabled := false }} {{- range $vhost := $globals.vhosts }} {{- $http := or (ne $vhost.https_method "nohttp") (not $vhost.cert_ok) }} {{- $https := ne $vhost.https_method "nohttps" }} @@ -507,7 +536,7 @@ proxy_set_header Proxy ""; {{- $https_exists = or $https_exists $https }} {{- $default_http_exists = or $default_http_exists (and $http $vhost.default) }} {{- $default_https_exists = or $default_https_exists (and $https $vhost.default) }} - {{- $http3 = or $http3 $vhost.http3 }} + {{- $http3_enabled = or $http3_enabled $vhost.http3_enabled }} {{- end }} {{- $fallback_http := and $http_exists (not $default_http_exists) }} {{- $fallback_https := and $https_exists (not $default_https_exists) }} @@ -537,7 +566,7 @@ server { {{- if $globals.enable_ipv6 }} listen [::]:{{ $globals.external_https_port }} ssl; {{- /* Do not add `default_server` (see comment above). */}} {{- end }} - {{- if $http3 }} + {{- if $http3_enabled }} http3 on; listen {{ $globals.external_https_port }} quic reuseport; {{- /* Do not add `default_server` (see comment above). */}} {{- if $globals.enable_ipv6 }} @@ -567,60 +596,24 @@ server { {{- end }} {{- end }} -{{- range $host, $vhost := $globals.vhosts }} - {{- $cert := $vhost.cert }} - {{- $cert_ok := $vhost.cert_ok }} - {{- $containers := $vhost.containers }} +{{- range $hostname, $vhost := $globals.vhosts }} {{- $default_server := when $vhost.default "default_server" "" }} - {{- $https_method := $vhost.https_method }} - {{- $http2 := parseBool (or (first (keys (groupByLabel $containers "com.github.nginx-proxy.nginx-proxy.http2.enable"))) $globals.Env.ENABLE_HTTP2 "true")}} - {{- $http3 := parseBool (or (first (keys (groupByLabel $containers "com.github.nginx-proxy.nginx-proxy.http3.enable"))) $globals.Env.ENABLE_HTTP3 "false")}} - {{- $is_regexp := hasPrefix "~" $host }} - {{- $upstream_name := when (or $is_regexp $globals.sha1_upstream_name) (sha1 $host) $host }} - - {{- $paths := groupBy $containers "Env.VIRTUAL_PATH" }} - {{- $nPaths := len $paths }} - {{- if eq $nPaths 0 }} - {{- $paths = dict "/" $containers }} - {{- end }} - - {{- range $path, $containers := $paths }} - {{- $upstream := $upstream_name }} - {{- if gt $nPaths 0 }} + {{- range $path, $containers := $vhost.paths }} + {{- $upstream := $vhost.upstream_name }} + {{- if $vhost.has_virtual_paths }} {{- $sum := sha1 $path }} {{- $upstream = printf "%s-%s" $upstream $sum }} {{- end }} -# {{ $host }}{{ $path }} +# {{ $hostname }}{{ $path }} {{ template "upstream" (dict "globals" $globals "Upstream" $upstream "Containers" $containers) }} {{- end }} - {{- /* - * Get the SERVER_TOKENS defined by containers w/ the same vhost, - * falling back to "". - */}} - {{- $server_tokens := trim (or (first (groupByKeys $containers "Env.SERVER_TOKENS")) "") }} - - {{- /* - * Get the SSL_POLICY defined by containers w/ the same vhost, falling - * back to empty string (use default). - */}} - {{- $ssl_policy := or (first (groupByKeys $containers "Env.SSL_POLICY")) "" }} - - {{- /* - * Get the HSTS defined by containers w/ the same vhost, falling back to - * "max-age=31536000". - */}} - {{- $hsts := or (first (groupByKeys $containers "Env.HSTS")) (or $globals.Env.HSTS "max-age=31536000") }} - - {{- /* Get the VIRTUAL_ROOT By containers w/ use fastcgi root */}} - {{- $vhost_root := or (first (groupByKeys $containers "Env.VIRTUAL_ROOT")) "/var/www/public" }} - - {{- if and $cert_ok (eq $https_method "redirect") }} + {{- if and $vhost.cert_ok (eq $vhost.https_method "redirect") }} server { - server_name {{ $host }}; - {{- if $server_tokens }} - server_tokens {{ $server_tokens }}; + server_name {{ $hostname }}; + {{- if $vhost.server_tokens }} + server_tokens {{ $vhost.server_tokens }}; {{- end }} {{ $globals.access_log }} listen {{ $globals.external_http_port }} {{ $default_server }}; @@ -649,27 +642,27 @@ server { {{- end }} server { - server_name {{ $host }}; - {{- if $server_tokens }} - server_tokens {{ $server_tokens }}; + server_name {{ $hostname }}; + {{- if $vhost.server_tokens }} + server_tokens {{ $vhost.server_tokens }}; {{- end }} {{ $globals.access_log }} - {{- if $http2 }} + {{- if $vhost.http2_enabled }} http2 on; {{- end }} - {{- if or (eq $https_method "nohttps") (not $cert_ok) (eq $https_method "noredirect") }} + {{- if or (eq $vhost.https_method "nohttps") (not $vhost.cert_ok) (eq $vhost.https_method "noredirect") }} listen {{ $globals.external_http_port }} {{ $default_server }}; {{- if $globals.enable_ipv6 }} listen [::]:{{ $globals.external_http_port }} {{ $default_server }}; {{- end }} {{- end }} - {{- if ne $https_method "nohttps" }} + {{- 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 }}; {{- end }} - {{- if $http3 }} + {{- 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 }}; @@ -678,30 +671,30 @@ server { {{- end }} {{- end }} - {{- if $cert_ok }} - {{- template "ssl_policy" (dict "ssl_policy" $ssl_policy) }} + {{- if $vhost.cert_ok }} + {{- template "ssl_policy" (dict "ssl_policy" $vhost.ssl_policy) }} ssl_session_timeout 5m; ssl_session_cache shared:SSL:50m; ssl_session_tickets off; - ssl_certificate /etc/nginx/certs/{{ (printf "%s.crt" $cert) }}; - ssl_certificate_key /etc/nginx/certs/{{ (printf "%s.key" $cert) }}; + ssl_certificate /etc/nginx/certs/{{ (printf "%s.crt" $vhost.cert) }}; + ssl_certificate_key /etc/nginx/certs/{{ (printf "%s.key" $vhost.cert) }}; - {{- if (exists (printf "/etc/nginx/certs/%s.dhparam.pem" $cert)) }} - ssl_dhparam {{ printf "/etc/nginx/certs/%s.dhparam.pem" $cert }}; + {{- if (exists (printf "/etc/nginx/certs/%s.dhparam.pem" $vhost.cert)) }} + ssl_dhparam {{ printf "/etc/nginx/certs/%s.dhparam.pem" $vhost.cert }}; {{- end }} - {{- if (exists (printf "/etc/nginx/certs/%s.chain.pem" $cert)) }} + {{- if (exists (printf "/etc/nginx/certs/%s.chain.pem" $vhost.cert)) }} ssl_stapling on; ssl_stapling_verify on; - ssl_trusted_certificate {{ printf "/etc/nginx/certs/%s.chain.pem" $cert }}; + ssl_trusted_certificate {{ printf "/etc/nginx/certs/%s.chain.pem" $vhost.cert }}; {{- end }} - {{- if (not (or (eq $https_method "noredirect") (eq $hsts "off"))) }} + {{- if (not (or (eq $vhost.https_method "noredirect") (eq $vhost.hsts "off"))) }} set $sts_header ""; if ($https) { - set $sts_header "{{ trim $hsts }}"; + set $sts_header "{{ trim $vhost.hsts }}"; } add_header Strict-Transport-Security $sts_header always; {{- end }} @@ -735,13 +728,13 @@ server { {{- end }} {{- end }} - {{- if (exists (printf "/etc/nginx/vhost.d/%s" $host)) }} - include {{ printf "/etc/nginx/vhost.d/%s" $host }}; + {{- if (exists (printf "/etc/nginx/vhost.d/%s" $hostname)) }} + include {{ printf "/etc/nginx/vhost.d/%s" $hostname }}; {{- else if (exists "/etc/nginx/vhost.d/default") }} include /etc/nginx/vhost.d/default; {{- end }} - {{- range $path, $containers := $paths }} + {{- range $path, $containers := $vhost.paths }} {{- /* * Get the VIRTUAL_PROTO defined by containers w/ the same * vhost-vpath, falling back to "http". @@ -753,9 +746,9 @@ server { * falling back to "external". */}} {{- $network_tag := or (first (groupByKeys $containers "Env.NETWORK_ACCESS")) "external" }} - {{- $upstream := $upstream_name }} + {{- $upstream := $vhost.upstream_name }} {{- $dest := "" }} - {{- if gt $nPaths 0 }} + {{- if $vhost.has_virtual_paths }} {{- $sum := sha1 $path }} {{- $upstream = printf "%s-%s" $upstream $sum }} {{- $dest = (or (first (groupByKeys $containers "Env.VIRTUAL_DEST")) "") }} @@ -764,14 +757,14 @@ server { "Path" $path "Proto" $proto "Upstream" $upstream - "Host" $host - "VhostRoot" $vhost_root + "Host" $hostname + "VhostRoot" $vhost.vhost_root "Dest" $dest "NetworkTag" $network_tag "Containers" $containers ) }} {{- end }} - {{- if and (not (contains $paths "/")) (ne $globals.default_root_response "none")}} + {{- if and (not (contains $vhost.paths "/")) (ne $globals.default_root_response "none")}} location / { return {{ $globals.default_root_response }}; } From e97be612721160ddac7593684dace5c60f2fd2be Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Sat, 24 Feb 2024 21:43:26 +0100 Subject: [PATCH 292/300] refactor: refactor virtual paths --- nginx.tmpl | 72 +++++++++++++++++++++++++++--------------------------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/nginx.tmpl b/nginx.tmpl index 09277db..f8ac809 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -486,17 +486,40 @@ proxy_set_header Proxy ""; {{- $vhost_root := or (first (groupByKeys $containers "Env.VIRTUAL_ROOT")) "/var/www/public" }} - {{- $paths := groupBy $containers "Env.VIRTUAL_PATH" }} - {{- $has_virtual_paths := gt (len $paths) 0}} + {{- $tmp_paths := groupBy $containers "Env.VIRTUAL_PATH" }} + {{- $has_virtual_paths := gt (len $tmp_paths) 0}} {{- if not $has_virtual_paths }} - {{- $paths = dict "/" $containers }} + {{- $tmp_paths = dict "/" $containers }} + {{- end }} + + {{ $paths := dict }} + + {{- range $path, $containers := $tmp_paths }} + {{- /* Get the VIRTUAL_PROTO defined by containers w/ the same vhost-vpath, falling back to "http". */}} + {{- $proto := trim (or (first (groupByKeys $containers "Env.VIRTUAL_PROTO")) "http") }} + {{- /* Get the NETWORK_ACCESS defined by codontainers w/ the same vhost, falling back to "external". */}} + {{- $network_tag := or (first (groupByKeys $containers "Env.NETWORK_ACCESS")) "external" }} + + {{- $upstream := $upstream_name }} + {{- $dest := "" }} + {{- if $has_virtual_paths }} + {{- $sum := sha1 $path }} + {{- $upstream = printf "%s-%s" $upstream $sum }} + {{- $dest = (or (first (groupByKeys $containers "Env.VIRTUAL_DEST")) "") }} + {{- end }} + {{- $_ := set $paths $path (dict + "containers" $containers + "dest" $dest + "proto" $proto + "network_tag" $network_tag + "upstream" $upstream + ) }} {{- end }} {{- $_ := set $globals.vhosts $hostname (dict "cert" $cert "cert_ok" $cert_ok "default" $default - "has_virtual_paths" $has_virtual_paths "hsts" $hsts "https_method" $https_method "http2_enabled" $http2_enabled @@ -504,7 +527,6 @@ proxy_set_header Proxy ""; "paths" $paths "server_tokens" $server_tokens "ssl_policy" $ssl_policy - "upstream_name" $upstream_name "vhost_root" $vhost_root ) }} {{- end }} @@ -599,14 +621,9 @@ server { {{- range $hostname, $vhost := $globals.vhosts }} {{- $default_server := when $vhost.default "default_server" "" }} - {{- range $path, $containers := $vhost.paths }} - {{- $upstream := $vhost.upstream_name }} - {{- if $vhost.has_virtual_paths }} - {{- $sum := sha1 $path }} - {{- $upstream = printf "%s-%s" $upstream $sum }} - {{- end }} + {{- range $path, $vpath := $vhost.paths }} # {{ $hostname }}{{ $path }} -{{ template "upstream" (dict "globals" $globals "Upstream" $upstream "Containers" $containers) }} + {{ template "upstream" (dict "globals" $globals "Upstream" $vpath.upstream "Containers" $vpath.containers) }} {{- end }} {{- if and $vhost.cert_ok (eq $vhost.https_method "redirect") }} @@ -734,36 +751,19 @@ server { include /etc/nginx/vhost.d/default; {{- end }} - {{- range $path, $containers := $vhost.paths }} - {{- /* - * Get the VIRTUAL_PROTO defined by containers w/ the same - * vhost-vpath, falling back to "http". - */}} - {{- $proto := trim (or (first (groupByKeys $containers "Env.VIRTUAL_PROTO")) "http") }} - - {{- /* - * Get the NETWORK_ACCESS defined by containers w/ the same vhost, - * falling back to "external". - */}} - {{- $network_tag := or (first (groupByKeys $containers "Env.NETWORK_ACCESS")) "external" }} - {{- $upstream := $vhost.upstream_name }} - {{- $dest := "" }} - {{- if $vhost.has_virtual_paths }} - {{- $sum := sha1 $path }} - {{- $upstream = printf "%s-%s" $upstream $sum }} - {{- $dest = (or (first (groupByKeys $containers "Env.VIRTUAL_DEST")) "") }} - {{- end }} + {{- range $path, $vpath := $vhost.paths }} {{- template "location" (dict "Path" $path - "Proto" $proto - "Upstream" $upstream + "Proto" $vpath.proto + "Upstream" $vpath.upstream "Host" $hostname "VhostRoot" $vhost.vhost_root - "Dest" $dest - "NetworkTag" $network_tag - "Containers" $containers + "Dest" $vpath.dest + "NetworkTag" $vpath.network_tag + "Containers" $vpath.containers ) }} {{- end }} + {{- if and (not (contains $vhost.paths "/")) (ne $globals.default_root_response "none")}} location / { return {{ $globals.default_root_response }}; From d588c96dff8f7e5c650da64cff3117cefdbb4d89 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 25 Feb 2024 10:42:38 +0000 Subject: [PATCH 293/300] build: bump nginxproxy/docker-gen from 0.11.2-debian to 0.12.0-debian Bumps nginxproxy/docker-gen from 0.11.2-debian to 0.12.0-debian. --- updated-dependencies: - dependency-name: nginxproxy/docker-gen dependency-type: direct:production update-type: version-update:semver-minor ... 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 362e708..6d55042 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -1,4 +1,4 @@ -FROM nginxproxy/docker-gen:0.11.2 AS docker-gen +FROM nginxproxy/docker-gen:0.12.0 AS docker-gen FROM nginxproxy/forego:0.18.1 AS forego diff --git a/Dockerfile.debian b/Dockerfile.debian index 726c863..b304bc6 100644 --- a/Dockerfile.debian +++ b/Dockerfile.debian @@ -1,4 +1,4 @@ -FROM nginxproxy/docker-gen:0.11.2-debian AS docker-gen +FROM nginxproxy/docker-gen:0.12.0-debian AS docker-gen FROM nginxproxy/forego:0.18.1-debian AS forego From 2a5521625dac930ac156709f7414e3fdd924668d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 26 Feb 2024 04:49:11 +0000 Subject: [PATCH 294/300] ci: bump pytest from 8.0.1 to 8.0.2 in /test/requirements Bumps [pytest](https://github.com/pytest-dev/pytest) from 8.0.1 to 8.0.2. - [Release notes](https://github.com/pytest-dev/pytest/releases) - [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst) - [Commits](https://github.com/pytest-dev/pytest/compare/8.0.1...8.0.2) --- updated-dependencies: - dependency-name: pytest dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- test/requirements/python-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/requirements/python-requirements.txt b/test/requirements/python-requirements.txt index 140b431..dbd5fde 100644 --- a/test/requirements/python-requirements.txt +++ b/test/requirements/python-requirements.txt @@ -1,4 +1,4 @@ backoff==2.2.1 docker==7.0.0 -pytest==8.0.1 +pytest==8.0.2 requests==2.31.0 From 418f1a3cd0bc89ae864933e859078938d98c1fc7 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Tue, 27 Feb 2024 13:20:39 +0100 Subject: [PATCH 295/300] fix: don't re-assign variable Co-authored-by: pini-gh --- nginx.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nginx.tmpl b/nginx.tmpl index f8ac809..6c570ed 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -452,7 +452,7 @@ proxy_set_header Proxy ""; {{- /* Precompute some information about each vhost. */}} {{- range $hostname, $containers := groupByMulti $globals.containers "Env.VIRTUAL_HOST" "," }} - {{- $hostname := trim $hostname }} + {{- $hostname = trim $hostname }} {{- if not $hostname }} {{- /* Ignore containers with VIRTUAL_HOST set to the empty string. */}} {{- continue }} From b09575297dec6a4a92d8693a043cbdd2fc8a1470 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Tue, 27 Feb 2024 13:27:11 +0100 Subject: [PATCH 296/300] docs: typo in comments Co-authored-by: Niek <100143256+SchoNie@users.noreply.github.com> --- nginx.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nginx.tmpl b/nginx.tmpl index 6c570ed..acaecff 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -497,7 +497,7 @@ proxy_set_header Proxy ""; {{- range $path, $containers := $tmp_paths }} {{- /* Get the VIRTUAL_PROTO defined by containers w/ the same vhost-vpath, falling back to "http". */}} {{- $proto := trim (or (first (groupByKeys $containers "Env.VIRTUAL_PROTO")) "http") }} - {{- /* Get the NETWORK_ACCESS defined by codontainers w/ the same vhost, falling back to "external". */}} + {{- /* Get the NETWORK_ACCESS defined by containers w/ the same vhost, falling back to "external". */}} {{- $network_tag := or (first (groupByKeys $containers "Env.NETWORK_ACCESS")) "external" }} {{- $upstream := $upstream_name }} From 12e1360fc3cc1fd3c1f9ddd6a26bdf7a7066f325 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Mar 2024 04:52:02 +0000 Subject: [PATCH 297/300] ci: bump pytest from 8.0.2 to 8.1.0 in /test/requirements Bumps [pytest](https://github.com/pytest-dev/pytest) from 8.0.2 to 8.1.0. - [Release notes](https://github.com/pytest-dev/pytest/releases) - [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst) - [Commits](https://github.com/pytest-dev/pytest/compare/8.0.2...8.1.0) --- updated-dependencies: - dependency-name: pytest dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- test/requirements/python-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/requirements/python-requirements.txt b/test/requirements/python-requirements.txt index dbd5fde..9523494 100644 --- a/test/requirements/python-requirements.txt +++ b/test/requirements/python-requirements.txt @@ -1,4 +1,4 @@ backoff==2.2.1 docker==7.0.0 -pytest==8.0.2 +pytest==8.1.0 requests==2.31.0 From 45770e04bd482847f7872b1d76c222e5c36295cf Mon Sep 17 00:00:00 2001 From: Gilles Filippini Date: Sat, 9 Mar 2024 11:24:50 +0100 Subject: [PATCH 298/300] refactor: add 'ports' dict to the data structure Nothing changes for the legacy syntax, but adding this level to the data structure enables advanced port configuration. --- nginx.tmpl | 136 ++++++++++++++++++++++++++++++++++------------------- 1 file changed, 87 insertions(+), 49 deletions(-) diff --git a/nginx.tmpl b/nginx.tmpl index acaecff..fefb07f 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -128,7 +128,7 @@ # exposed ports:{{ range sortObjectsByKeysAsc $.container.Addresses "Port" }} {{ .Port }}/{{ .Proto }}{{ else }} (none){{ end }} {{- $default_port := when (eq (len $.container.Addresses) 1) (first $.container.Addresses).Port "80" }} # default port: {{ $default_port }} - {{- $port := or $.container.Env.VIRTUAL_PORT $default_port }} + {{- $port := when (eq $.port "legacy") (or $.container.Env.VIRTUAL_PORT $default_port) $.port }} # using port: {{ $port }} {{- $addr_obj := where $.container.Addresses "Port" $port | first }} {{- if and $addr_obj $addr_obj.HostPort }} @@ -242,6 +242,7 @@ {{- end }} {{- define "location" }} + {{- $vpath := .VPath }} {{- $override := printf "/etc/nginx/vhost.d/%s_%s_location_override" .Host (sha1 .Path) }} {{- if and (eq .Path "/") (not (exists $override)) }} {{- $override = printf "/etc/nginx/vhost.d/%s_location_override" .Host }} @@ -249,29 +250,32 @@ {{- if exists $override }} include {{ $override }}; {{- else }} - {{- $keepalive := coalesce (first (keys (groupByLabel .Containers "com.github.nginx-proxy.nginx-proxy.keepalive"))) "disabled" }} + {{- $keepalive := $vpath.keepalive }} location {{ .Path }} { - {{- if eq .NetworkTag "internal" }} + {{- if eq $vpath.network_tag "internal" }} # Only allow traffic from internal clients include /etc/nginx/network_internal.conf; {{- end }} - {{- if eq .Proto "uwsgi" }} + {{ $proto := $vpath.proto }} + {{ $upstream := $vpath.upstream }} + {{ $dest := $vpath.dest }} + {{- if eq $proto "uwsgi" }} include uwsgi_params; - uwsgi_pass {{ trim .Proto }}://{{ trim .Upstream }}; - {{- else if eq .Proto "fastcgi" }} + uwsgi_pass {{ trim $proto }}://{{ trim $upstream }}; + {{- else if eq $proto "fastcgi" }} root {{ trim .VhostRoot }}; include fastcgi_params; - fastcgi_pass {{ trim .Upstream }}; + fastcgi_pass {{ trim $upstream }}; {{- if ne $keepalive "disabled" }} fastcgi_keep_conn on; {{- end }} - {{- else if eq .Proto "grpc" }} - grpc_pass {{ trim .Proto }}://{{ trim .Upstream }}; - {{- else if eq .Proto "grpcs" }} - grpc_pass {{ trim .Proto }}://{{ trim .Upstream }}; + {{- else if eq $proto "grpc" }} + grpc_pass {{ trim $proto }}://{{ trim $upstream }}; + {{- else if eq $proto "grpcs" }} + grpc_pass {{ trim $proto }}://{{ trim $upstream }}; {{- else }} - proxy_pass {{ trim .Proto }}://{{ trim .Upstream }}{{ trim .Dest }}; + proxy_pass {{ trim $proto }}://{{ trim $upstream }}{{ trim $dest }}; set $upstream_keepalive {{ if ne $keepalive "disabled" }}true{{ else }}false{{ end }}; {{- end }} @@ -295,24 +299,27 @@ {{- end }} {{- define "upstream" }} -upstream {{ .Upstream }} { + {{- $path := .Path }} + {{- $vpath := .VPath }} +upstream {{ $vpath.upstream }} { {{- $servers := 0 }} - {{- $loadbalance := first (keys (groupByLabel .Containers "com.github.nginx-proxy.nginx-proxy.loadbalance")) }} + {{- $loadbalance := $vpath.loadbalance }} {{- if $loadbalance }} # From the container's loadbalance label: {{ $loadbalance }} {{- end }} - {{- range $container := .Containers }} + {{- range $port, $containers := $vpath.ports }} + {{- range $container := $containers }} # Container: {{ $container.Name }} - {{- $args := dict "globals" $.globals "container" $container }} - {{- template "container_ip" $args }} - {{- $ip := $args.ip }} - {{- $args := dict "container" $container }} - {{- template "container_port" $args }} - {{- $port := $args.port }} - {{- if $ip }} - {{- $servers = add1 $servers }} - server {{ $ip }}:{{ $port }}; + {{- $args := dict "globals" $.globals "container" $container }} + {{- template "container_ip" $args }} + {{- $ip := $args.ip }} + {{- $args = dict "container" $container "path" $path "port" $port }} + {{- template "container_port" $args }} + {{- if $ip }} + {{- $servers = add1 $servers }} + server {{ $ip }}:{{ $args.port }}; + {{- end }} {{- end }} {{- end }} {{- /* nginx-proxy/nginx-proxy#1105 */}} @@ -320,7 +327,7 @@ upstream {{ .Upstream }} { # Fallback entry server 127.0.0.1 down; {{- end }} - {{- $keepalive := coalesce (first (keys (groupByLabel .Containers "com.github.nginx-proxy.nginx-proxy.keepalive"))) "disabled" }} + {{- $keepalive := $vpath.keepalive }} {{- if and (ne $keepalive "disabled") (gt $servers 0) }} {{- if eq $keepalive "auto" }} keepalive {{ mul $servers 2 }}; @@ -331,6 +338,49 @@ upstream {{ .Upstream }} { } {{- end }} +{{- /* + * Template used as a function to collect virtual path properties from + * the given containers. These properties are "returned" by storing their + * values into the provided dot dict. + * + * The provided dot dict is expected to have the following entries: + * - "Containers": List of container's RuntimeContainer struct. + * - "Upstream_name" + * - "Has_virtual_paths": boolean + * - "Path" + * + * The return values will be added to the dot dict with keys: + * - "dest" + * - "proto" + * - "network_tag" + * - "upstream" + * - "loadbalance" + * - "keepalive" + */}} +{{- define "get_path_info" }} + {{- /* Get the VIRTUAL_PROTO defined by containers w/ the same vhost-vpath, falling back to "http". */}} + {{- $proto := trim (or (first (groupByKeys $.Containers "Env.VIRTUAL_PROTO")) "http") }} + {{- /* Get the NETWORK_ACCESS defined by containers w/ the same vhost, falling back to "external". */}} + {{- $network_tag := or (first (groupByKeys $.Containers "Env.NETWORK_ACCESS")) "external" }} + + {{- $loadbalance := first (keys (groupByLabel $.Containers "com.github.nginx-proxy.nginx-proxy.loadbalance")) }} + {{- $keepalive := coalesce (first (keys (groupByLabel $.Containers "com.github.nginx-proxy.nginx-proxy.keepalive"))) "disabled" }} + + {{- $upstream := $.Upstream_name }} + {{- $dest := "" }} + {{- if $.Has_virtual_paths }} + {{- $sum := sha1 $.Path }} + {{- $upstream = printf "%s-%s" $upstream $sum }} + {{- $dest = or (first (groupByKeys $.Containers "Env.VIRTUAL_DEST")) "" }} + {{- end }} + {{- $_ := set $ "proto" $proto }} + {{- $_ := set $ "network_tag" $network_tag }} + {{- $_ := set $ "upstream" $upstream }} + {{- $_ := set $ "dest" $dest }} + {{- $_ := set $ "loadbalance" $loadbalance }} + {{- $_ := set $ "keepalive" $keepalive }} +{{- 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 { @@ -492,27 +542,19 @@ proxy_set_header Proxy ""; {{- $tmp_paths = dict "/" $containers }} {{- end }} - {{ $paths := dict }} + {{- $paths := dict }} {{- range $path, $containers := $tmp_paths }} - {{- /* Get the VIRTUAL_PROTO defined by containers w/ the same vhost-vpath, falling back to "http". */}} - {{- $proto := trim (or (first (groupByKeys $containers "Env.VIRTUAL_PROTO")) "http") }} - {{- /* Get the NETWORK_ACCESS defined by containers w/ the same vhost, falling back to "external". */}} - {{- $network_tag := or (first (groupByKeys $containers "Env.NETWORK_ACCESS")) "external" }} - - {{- $upstream := $upstream_name }} - {{- $dest := "" }} - {{- if $has_virtual_paths }} - {{- $sum := sha1 $path }} - {{- $upstream = printf "%s-%s" $upstream $sum }} - {{- $dest = (or (first (groupByKeys $containers "Env.VIRTUAL_DEST")) "") }} - {{- end }} + {{- $args := dict "Containers" $containers "Path" $path "Upstream_name" $upstream_name "Has_virtual_paths" $has_virtual_paths }} + {{- template "get_path_info" $args }} {{- $_ := set $paths $path (dict - "containers" $containers - "dest" $dest - "proto" $proto - "network_tag" $network_tag - "upstream" $upstream + "ports" (dict "legacy" $containers) + "dest" $args.dest + "proto" $args.proto + "network_tag" $args.network_tag + "upstream" $args.upstream + "loadbalance" $args.loadbalance + "keepalive" $args.keepalive ) }} {{- end }} @@ -623,7 +665,7 @@ server { {{- range $path, $vpath := $vhost.paths }} # {{ $hostname }}{{ $path }} - {{ template "upstream" (dict "globals" $globals "Upstream" $vpath.upstream "Containers" $vpath.containers) }} + {{ template "upstream" (dict "globals" $globals "Path" $path "VPath" $vpath) }} {{- end }} {{- if and $vhost.cert_ok (eq $vhost.https_method "redirect") }} @@ -754,13 +796,9 @@ server { {{- range $path, $vpath := $vhost.paths }} {{- template "location" (dict "Path" $path - "Proto" $vpath.proto - "Upstream" $vpath.upstream "Host" $hostname "VhostRoot" $vhost.vhost_root - "Dest" $vpath.dest - "NetworkTag" $vpath.network_tag - "Containers" $vpath.containers + "VPath" $vpath ) }} {{- end }} From 6441daf25b0645c3a3f170847e7620fcb8298be5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Mar 2024 04:19:22 +0000 Subject: [PATCH 299/300] ci: bump pytest from 8.1.0 to 8.1.1 in /test/requirements Bumps [pytest](https://github.com/pytest-dev/pytest) from 8.1.0 to 8.1.1. - [Release notes](https://github.com/pytest-dev/pytest/releases) - [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst) - [Commits](https://github.com/pytest-dev/pytest/compare/8.1.0...8.1.1) --- updated-dependencies: - dependency-name: pytest dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- test/requirements/python-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/requirements/python-requirements.txt b/test/requirements/python-requirements.txt index 9523494..d3bcc2b 100644 --- a/test/requirements/python-requirements.txt +++ b/test/requirements/python-requirements.txt @@ -1,4 +1,4 @@ backoff==2.2.1 docker==7.0.0 -pytest==8.1.0 +pytest==8.1.1 requests==2.31.0 From 16b84ea1b540f82a56ebd42c276018c52940aedc Mon Sep 17 00:00:00 2001 From: Huge Date: Tue, 12 Mar 2024 14:23:56 +0100 Subject: [PATCH 300/300] Update README.md to use 1.5 version and link DockerHub --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 46d1d61..c2eb347 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ docker run --detach \ --name nginx-proxy \ --publish 80:80 \ --volume /var/run/docker.sock:/tmp/docker.sock:ro \ - nginxproxy/nginx-proxy:1.4 + nginxproxy/nginx-proxy:1.5 ``` Then start any containers (here an nginx container) you want proxied with an env var `VIRTUAL_HOST=subdomain.yourdomain.com` @@ -48,7 +48,7 @@ The nginx-proxy images are available in two flavors. This image is based on the nginx:mainline image, itself based on the debian slim image. ```console -docker pull nginxproxy/nginx-proxy:1.4 +docker pull nginxproxy/nginx-proxy:1.5 ``` #### Alpine based version (`-alpine` suffix) @@ -56,14 +56,14 @@ docker pull nginxproxy/nginx-proxy:1.4 This image is based on the nginx:alpine image. ```console -docker pull nginxproxy/nginx-proxy:1.4-alpine +docker pull nginxproxy/nginx-proxy:1.5-alpine ``` #### :warning: a note on `latest` and `alpine`: It is not recommended to use the `latest` (`nginxproxy/nginx-proxy`, `nginxproxy/nginx-proxy:latest`) or `alpine` (`nginxproxy/nginx-proxy:alpine`) tag for production setups. -Those tags points to the latest commit in the `main` branch. They do not carry any promise of stability, and using them will probably put your nginx-proxy setup at risk of experiencing uncontrolled updates to non backward compatible versions (or versions with breaking changes). You should always specify the version you want to use explicitly to ensure your setup doesn't break when the image is updated. +[Those tags point](https://hub.docker.com/r/nginxproxy/nginx-proxy/tags) to the latest commit in the `main` branch. They do not carry any promise of stability, and using them will probably put your nginx-proxy setup at risk of experiencing uncontrolled updates to non backward compatible versions (or versions with breaking changes). You should always specify the version you want to use explicitly to ensure your setup doesn't break when the image is updated. ### Additional documentation