From 8aa00fcea2588eb39565b030c706068a21f9ee33 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Wed, 16 Mar 2022 00:59:03 -0400 Subject: [PATCH] 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