From a3fbaa59909c81d14ce7c29bdf1555bb5f4537bc Mon Sep 17 00:00:00 2001 From: Thomas LEVEIL Date: Tue, 21 Feb 2017 01:01:00 +0100 Subject: [PATCH 01/46] TESTS: add directory for tests featuring scenarios trying to make nginx-proxy fail --- test/stress_tests/README.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 test/stress_tests/README.md diff --git a/test/stress_tests/README.md b/test/stress_tests/README.md new file mode 100644 index 0000000..ca20cc1 --- /dev/null +++ b/test/stress_tests/README.md @@ -0,0 +1 @@ +This directory contains tests that showcase scenarios known to break the expected behavior of nginx-proxy. \ No newline at end of file From e25c78b00ad36c96b864dde2fef73a16e76482db Mon Sep 17 00:00:00 2001 From: Thomas LEVEIL Date: Tue, 21 Feb 2017 01:04:50 +0100 Subject: [PATCH 02/46] TESTS: add pytest `incremental` marker to mark tests as expected to fail if previous test failed see http://stackoverflow.com/a/12579625/107049 --- test/conftest.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/test/conftest.py b/test/conftest.py index fcff6ea..43f83bb 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -445,6 +445,18 @@ def pytest_runtest_logreport(report): report.longrepr.addsection('nginx-proxy conf', get_nginx_conf_from_container(container)) +# Py.test `incremental` marker, see http://stackoverflow.com/a/12579625/107049 +def pytest_runtest_makereport(item, call): + if "incremental" in item.keywords: + if call.excinfo is not None: + parent = item.parent + parent._previousfailed = item + + +def pytest_runtest_setup(item): + previousfailed = getattr(item.parent, "_previousfailed", None) + if previousfailed is not None: + pytest.xfail("previous test failed (%s)" % previousfailed.name) ############################################################################### # From 6dfc3f3f7026982570ea5f9e6d67414bd94da920 Mon Sep 17 00:00:00 2001 From: Thomas LEVEIL Date: Tue, 21 Feb 2017 01:05:42 +0100 Subject: [PATCH 03/46] TESTS: add stress test when a certificate file is missing --- 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 | 73 +++++++++++++++++++ .../test_deleted_cert/tmp_certs/.gitignore | 2 + 6 files changed, 194 insertions(+) create mode 100644 test/stress_tests/test_deleted_cert/README.md create mode 100644 test/stress_tests/test_deleted_cert/certs/web.nginx-proxy.crt create mode 100644 test/stress_tests/test_deleted_cert/certs/web.nginx-proxy.key create mode 100644 test/stress_tests/test_deleted_cert/docker-compose.yml create mode 100644 test/stress_tests/test_deleted_cert/test_restart_while_missing_cert.py create 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 new file mode 100644 index 0000000..9fac0b9 --- /dev/null +++ b/test/stress_tests/test_deleted_cert/README.md @@ -0,0 +1,5 @@ +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 new file mode 100644 index 0000000..2c92efe --- /dev/null +++ b/test/stress_tests/test_deleted_cert/certs/web.nginx-proxy.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 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 new file mode 100644 index 0000000..dca1c99 --- /dev/null +++ b/test/stress_tests/test_deleted_cert/certs/web.nginx-proxy.key @@ -0,0 +1,27 @@ +-----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 new file mode 100644 index 0000000..06a61b9 --- /dev/null +++ b/test/stress_tests/test_deleted_cert/docker-compose.yml @@ -0,0 +1,17 @@ +web: + image: web + expose: + - "81" + environment: + WEB_PORTS: 81 + VIRTUAL_HOST: web.nginx-proxy + + +reverseproxy: + image: jwilder/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 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 new file mode 100644 index 0000000..2b74acd --- /dev/null +++ b/test/stress_tests/test_deleted_cert/test_restart_while_missing_cert.py @@ -0,0 +1,73 @@ +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.yield_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 new file mode 100644 index 0000000..c96a04f --- /dev/null +++ b/test/stress_tests/test_deleted_cert/tmp_certs/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore \ No newline at end of file From de2f057c10b1c18a323283910c293699e48143db Mon Sep 17 00:00:00 2001 From: Thomas LEVEIL Date: Tue, 21 Feb 2017 01:55:52 +0100 Subject: [PATCH 04/46] TESTS: add test for unreachable container resulting in an empty `upstream {}` block in the generated nginx config file --- .../test_unreachable_network/README.md | 59 +++++++++++++++++++ .../docker-compose.yml | 35 +++++++++++ .../test_unreachable_net.py | 35 +++++++++++ 3 files changed, 129 insertions(+) create mode 100644 test/stress_tests/test_unreachable_network/README.md create mode 100644 test/stress_tests/test_unreachable_network/docker-compose.yml create mode 100644 test/stress_tests/test_unreachable_network/test_unreachable_net.py diff --git a/test/stress_tests/test_unreachable_network/README.md b/test/stress_tests/test_unreachable_network/README.md new file mode 100644 index 0000000..aa09c4d --- /dev/null +++ b/test/stress_tests/test_unreachable_network/README.md @@ -0,0 +1,59 @@ +# nginx-proxy template is not considered when a container is not reachable + +Having a container with the `VIRTUAL_HOST` environment variable set but on a network not reachable from the nginx-proxy container will result in nginx-proxy serving the default nginx welcome page for all requests. + +Furthermore, if the nginx-proxy in such state is restarted, the nginx process will crash and the container stops. + +In the generated nginx config file, we can notice the presence of an empty `upstream {}` block. + +This can be fixed by merging [PR-585](https://github.com/jwilder/nginx-proxy/pull/585). + +## How to reproduce + +1. a first web container is created on network `netA` +1. a second web container is created on network `netB` +1. nginx-proxy is created with access to `netA` only + + +## Erratic behavior + +- nginx serves the default welcome page for all requests to `/` and error 404 for any other path +- nginx-container crash on restart + +Log shows: + +``` +webB_1 | starting a web server listening on port 82 +webA_1 | starting a web server listening on port 81 +reverseproxy | forego | starting dockergen.1 on port 5000 +reverseproxy | forego | starting nginx.1 on port 5100 +reverseproxy | dockergen.1 | 2017/02/20 01:10:24 Generated '/etc/nginx/conf.d/default.conf' from 3 containers +reverseproxy | dockergen.1 | 2017/02/20 01:10:24 Running 'nginx -s reload' +reverseproxy | dockergen.1 | 2017/02/20 01:10:24 Error running notify command: nginx -s reload, exit status 1 +reverseproxy | dockergen.1 | 2017/02/20 01:10:24 Watching docker events +reverseproxy | dockergen.1 | 2017/02/20 01:10:24 Contents of /etc/nginx/conf.d/default.conf did not change. Skipping notification 'nginx -s reload' +reverseproxy | reverseproxy | forego | starting dockergen.1 on port 5000 <---- nginx-proxy container restarted +reverseproxy | forego | starting nginx.1 on port 5100 +reverseproxy | dockergen.1 | 2017/02/20 01:10:24 Generated '/etc/nginx/conf.d/default.conf' from 3 containers +reverseproxy | dockergen.1 | 2017/02/20 01:10:24 Running 'nginx -s reload' +reverseproxy | dockergen.1 | 2017/02/20 01:10:24 Error running notify command: nginx -s reload, exit status 1 +reverseproxy | dockergen.1 | 2017/02/20 01:10:24 Watching docker events +reverseproxy | dockergen.1 | 2017/02/20 01:10:24 Contents of /etc/nginx/conf.d/default.conf did not change. Skipping notification 'nginx -s reload' +reverseproxy | forego | starting dockergen.1 on port 5000 +reverseproxy | forego | starting nginx.1 on port 5100 +reverseproxy | nginx.1 | 2017/02/20 01:11:02 [emerg] 17#17: no servers are inside upstream in /etc/nginx/conf.d/default.conf:64 +reverseproxy | forego | starting nginx.1 on port 5200 +reverseproxy | forego | sending SIGTERM to nginx.1 +reverseproxy | forego | sending SIGTERM to dockergen.1 +reverseproxy exited with code 0 +reverseproxy exited with code 0 + +``` + +## Expected behavior + +- no default nginx welcome page should be served +- nginx is able to forward requests to containers of `netA` +- nginx respond with error 503 for unknown virtual hosts +- nginx is not able to forward requests to containers of `netB` and responds with an error +- nginx should survive restarts diff --git a/test/stress_tests/test_unreachable_network/docker-compose.yml b/test/stress_tests/test_unreachable_network/docker-compose.yml new file mode 100644 index 0000000..0ca4f99 --- /dev/null +++ b/test/stress_tests/test_unreachable_network/docker-compose.yml @@ -0,0 +1,35 @@ +version: "2" + +networks: + netA: + netB: + +services: + reverseproxy: + container_name: reverseproxy + networks: + - netA + image: jwilder/nginx-proxy:test + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro + + webA: + networks: + - netA + image: web + expose: + - 81 + environment: + WEB_PORTS: 81 + VIRTUAL_HOST: webA.nginx-proxy + + webB: + networks: + - netB + image: web + expose: + - 82 + environment: + WEB_PORTS: 82 + VIRTUAL_HOST: webB.nginx-proxy + diff --git a/test/stress_tests/test_unreachable_network/test_unreachable_net.py b/test/stress_tests/test_unreachable_network/test_unreachable_net.py new file mode 100644 index 0000000..dbcfb14 --- /dev/null +++ b/test/stress_tests/test_unreachable_network/test_unreachable_net.py @@ -0,0 +1,35 @@ +from time import sleep + +import pytest +import requests + +pytestmark = pytest.mark.xfail() # TODO delete this marker once #585 is merged + + +def test_default_nginx_welcome_page_should_not_be_served(docker_compose, nginxproxy): + r = nginxproxy.get("http://whatever.nginx-proxy/", allow_redirects=False) + assert "Welcome to nginx!" not in r.text + + +def test_unknown_virtual_host_is_503(docker_compose, nginxproxy): + r = nginxproxy.get("http://unknown.nginx-proxy/", allow_redirects=False) + assert r.status_code == 503 + + +def test_http_web_a_is_forwarded(docker_compose, nginxproxy): + r = nginxproxy.get("http://webA.nginx-proxy/port", allow_redirects=False) + assert r.status_code == 200 + assert "answer from port 81\n" == r.text + + +def test_http_web_b_gets_an_error(docker_compose, nginxproxy): + r = nginxproxy.get("http://webB.nginx-proxy/", allow_redirects=False) + assert "Welcome to nginx!" not in r.text + with pytest.raises(requests.exceptions.HTTPError): + r.raise_for_status() + + +def test_reverseproxy_survive_restart(docker_compose): + docker_compose.containers.get("reverseproxy").restart() + sleep(2) # give time for the container to initialize + assert docker_compose.containers.get("reverseproxy").status == "running" From 4b22ccdc81248969e007d295a4bf989bd5170065 Mon Sep 17 00:00:00 2001 From: Pan Teparak Date: Sun, 27 Aug 2017 04:40:35 +0700 Subject: [PATCH 05/46] Add ability to opt-out dh param auto generation --- docker-entrypoint.sh | 3 ++- generate-dhparam.sh | 6 ++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh index 2afd5bf..ed0750f 100755 --- a/docker-entrypoint.sh +++ b/docker-entrypoint.sh @@ -16,7 +16,8 @@ fi # Generate dhparam file if required # Note: if $DHPARAM_BITS is not defined, generate-dhparam.sh will use 2048 as a default -/app/generate-dhparam.sh $DHPARAM_BITS +# Note2: if $GENERATE_DHPARAM is set to false in environment variable, dh param generator will skip completely +/app/generate-dhparam.sh $DHPARAM_BITS $GENERATE_DHPARAM # Compute the DNS resolvers for use in the templates export RESOLVERS=$(awk '$1 == "nameserver" {print $2}' ORS=' ' /etc/resolv.conf | sed 's/ *$//g') diff --git a/generate-dhparam.sh b/generate-dhparam.sh index 3fdc77c..67319a4 100755 --- a/generate-dhparam.sh +++ b/generate-dhparam.sh @@ -2,6 +2,7 @@ # The first argument is the bit depth of the dhparam, or 2048 if unspecified DHPARAM_BITS=${1:-2048} +GENERATE_DHPARAM=${2:-true} # If a dhparam file is not available, use the pre-generated one and generate a new one in the background. # Note that /etc/nginx/dhparam is a volume, so this dhparam will persist restarts. @@ -25,6 +26,11 @@ if [[ -f $DHPARAM_FILE ]]; then fi fi +if [[ $GENERATE_DHPARAM =~ ^[Ff][Aa][Ll][Ss][Ee]$ ]]; then + echo "Skipping Diffie-Hellman parameters generation and Ignoring pre-generated dhparam.pem" + exit 0 +fi + cat >&2 <<-EOT WARNING: $DHPARAM_FILE was not found. A pre-generated dhparam.pem will be used for now while a new one is being generated in the background. Once the new dhparam.pem is in place, nginx will be reloaded. From 09271a333ae8be4f3bee6ddf54dc2c0876ab0e91 Mon Sep 17 00:00:00 2001 From: Pan Teparak Date: Sun, 27 Aug 2017 04:40:47 +0700 Subject: [PATCH 06/46] Update Readme --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 639289c..91229c4 100644 --- a/README.md +++ b/README.md @@ -152,6 +152,10 @@ Finally, start your containers with `VIRTUAL_HOST` environment variables. [letsencrypt-nginx-proxy-companion](https://github.com/JrCs/docker-letsencrypt-nginx-proxy-companion) is a lightweight companion container for the nginx-proxy. It allow the creation/renewal of Let's Encrypt certificates automatically. +Set `GENERATE_DHPARAM` environment variable to `false` to disabled Diffie-Hellman parameters completely. This will also ignore auto-generation made by `nginx-proxy`. +The default value is `true` + + $ docker run -e GENERATE_DHPARAM=false .... ### SSL Support SSL is supported using single host, wildcard and SNI certificates using naming conventions for @@ -359,4 +363,4 @@ If your system has the `make` command, you can automate those tasks by calling: make test -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. +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. \ No newline at end of file From a3b1d5b7ab6788c4d1d4fc62a841cf1e0c9b2774 Mon Sep 17 00:00:00 2001 From: Pan Teparak Date: Sun, 27 Aug 2017 13:19:29 +0700 Subject: [PATCH 07/46] Trigger Build From 3156b97f3a70d164384c248d265a67cd796982a8 Mon Sep 17 00:00:00 2001 From: Patrick Date: Wed, 13 Sep 2017 12:37:06 +0200 Subject: [PATCH 08/46] Fallback if container has no IP Sometimes containers will not be assigned an IP (after reboot or due to misconfiguration). This leads to an incorrect "server down;" line in default.conf and crashes nginx. @therealgambo provided a fix for this: https://github.com/jwilder/nginx-proxy/issues/845 --- nginx.tmpl | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/nginx.tmpl b/nginx.tmpl index 3c26a9c..ad9295c 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -13,8 +13,13 @@ {{ end }} {{ else if .Network }} # {{ .Container.Name }} - server {{ .Network.IP }} down; + {{ if .Network.IP }} + server {{ .Network.IP }} down; + {{ else }} + server 127.0.0.1 down; + {{ end }} {{ end }} + {{ end }} # If we receive X-Forwarded-Proto, pass it through; otherwise, pass along the From 31d2ed172b2f306e0662b6d84caf486f10866089 Mon Sep 17 00:00:00 2001 From: Pan Teparak Date: Sun, 24 Sep 2017 15:13:24 +0700 Subject: [PATCH 09/46] Change ENV variable from GENERATE_DHPARAM to DHPARAM_GENERATION --- docker-entrypoint.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh index ed0750f..ea10d4e 100755 --- a/docker-entrypoint.sh +++ b/docker-entrypoint.sh @@ -16,8 +16,8 @@ fi # Generate dhparam file if required # Note: if $DHPARAM_BITS is not defined, generate-dhparam.sh will use 2048 as a default -# Note2: if $GENERATE_DHPARAM is set to false in environment variable, dh param generator will skip completely -/app/generate-dhparam.sh $DHPARAM_BITS $GENERATE_DHPARAM +# Note2: if $DHPARAM_GENERATION is set to false in environment variable, dh param generator will skip completely +/app/generate-dhparam.sh $DHPARAM_BITS $DHPARAM_GENERATION # Compute the DNS resolvers for use in the templates export RESOLVERS=$(awk '$1 == "nameserver" {print $2}' ORS=' ' /etc/resolv.conf | sed 's/ *$//g') From 92379d8131191fc2787df07a1d9938f4973fe753 Mon Sep 17 00:00:00 2001 From: Pan Teparak Date: Sun, 24 Sep 2017 15:15:00 +0700 Subject: [PATCH 10/46] Update Readme --- README.md | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 91229c4..fa90955 100644 --- a/README.md +++ b/README.md @@ -150,12 +150,12 @@ Finally, start your containers with `VIRTUAL_HOST` environment variables. $ docker run -e VIRTUAL_HOST=foo.bar.com ... ### SSL Support using letsencrypt -[letsencrypt-nginx-proxy-companion](https://github.com/JrCs/docker-letsencrypt-nginx-proxy-companion) is a lightweight companion container for the nginx-proxy. It allow the creation/renewal of Let's Encrypt certificates automatically. +[letsencrypt-nginx-proxy-companion](https://github.com/JrCs/docker-letsencrypt-nginx-proxy-companion) is a lightweight companion container for the nginx-proxy. It allow the creation/renewal of Let's Encrypt certificates automatically. -Set `GENERATE_DHPARAM` environment variable to `false` to disabled Diffie-Hellman parameters completely. This will also ignore auto-generation made by `nginx-proxy`. +Set `DHPARAM_GENERATION` environment variable to `false` to disabled Diffie-Hellman parameters completely. This will also ignore auto-generation made by `nginx-proxy`. The default value is `true` - $ docker run -e GENERATE_DHPARAM=false .... + $ docker run -e DHPARAM_GENERATION=false .... ### SSL Support SSL is supported using single host, wildcard and SNI certificates using naming conventions for @@ -187,7 +187,7 @@ at startup. Since it can take minutes to generate a new `dhparam.pem`, it is do background. Once generation is complete, the `dhparams.pem` is saved on a persistent volume and nginx is reloaded. This generation process only occurs the first time you start `nginx-proxy`. -> COMPATIBILITY WARNING: The default generated `dhparam.pem` key is 2048 bits for A+ security. Some +> COMPATIBILITY WARNING: The default generated `dhparam.pem` key is 2048 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 either provide your own `dhparam.pem`, or tell `nginx-proxy` to generate a 1024-bit > key on startup by passing `-e DHPARAM_BITS=1024`. @@ -210,7 +210,7 @@ The SSL cipher configuration is based on the [Mozilla nginx intermediate profile should provide compatibility with clients back to Firefox 1, Chrome 1, IE 7, Opera 5, Safari 1, Windows XP IE8, Android 2.3, Java 7. 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.0, 1.1 and 1.2 -are supported. TLS 1.0 is deprecated but its end of life is not until June 30, 2018. It is being +are supported. TLS 1.0 is deprecated but its end of life is not until June 30, 2018. It is being included because the following browsers will stop working when it is removed: Chrome < 22, Firefox < 27, IE < 11, Safari < 7, iOS < 5, Android Browser < 5. @@ -227,12 +227,12 @@ a 500. 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` must be specified on each container for which you want to -override the default behavior. 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 +disable the non-SSL site entirely with `HTTPS_METHOD=nohttp`, or disable the HTTPS site with +`HTTPS_METHOD=nohttps`. `HTTPS_METHOD` must be specified on each container for which you want to +override the default behavior. 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. ### Basic Authentication Support @@ -348,7 +348,7 @@ Before submitting pull requests or issues, please check github to make sure an e To run tests, you need to prepare the docker image to test which must be tagged `jwilder/nginx-proxy:test`: docker build -t jwilder/nginx-proxy:test . # build the Debian variant image - + and call the [test/pytest.sh](test/pytest.sh) script. Then build the Alpine variant of the image: @@ -361,6 +361,6 @@ and call the [test/pytest.sh](test/pytest.sh) script again. If your system has the `make` command, you can automate those tasks by calling: make test - -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. \ No newline at end of file + +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. From ea98780960a3966e22abfcbdc7efa86eebdf2b10 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Fri, 27 Oct 2017 10:09:32 +0200 Subject: [PATCH 11/46] Enable optional mozilla modern profile --- nginx.tmpl | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/nginx.tmpl b/nginx.tmpl index 28f745a..8ae9a10 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -158,6 +158,9 @@ upstream {{ $upstream_name }} { {{/* Get the HTTPS_METHOD defined by containers w/ the same vhost, falling back to "redirect" */}} {{ $https_method := or (first (groupByKeys $containers "Env.HTTPS_METHOD")) "redirect" }} +{{/* Get the MODERN_SSL defined by containers w/ the same vhost, falling back to "false" */}} +{{ $modern_ssl := or (first (groupByKeys $containers "Env.MODERN_SSL")) "false" }} + {{/* Get the VIRTUAL_ROOT By containers w/ use fastcgi root */}} {{ $vhost_root := or (first (groupByKeys $containers "Env.VIRTUAL_ROOT")) "/var/www/public" }} @@ -204,8 +207,13 @@ server { include /etc/nginx/network_internal.conf; {{ end }} + {{ if eq $modern_ssl "true" }} + ssl_protocols TLSv1.2; + ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256; + {{ else }} ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:!DSS'; + {{ end }} ssl_prefer_server_ciphers on; ssl_session_timeout 5m; @@ -215,7 +223,7 @@ 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 (and (ne $modern_ssl "true") (exists (printf "/etc/nginx/certs/%s.dhparam.pem" $cert))) }} ssl_dhparam {{ printf "/etc/nginx/certs/%s.dhparam.pem" $cert }}; {{ end }} From 56fb58cc6f3f8541d3fe07ef33883a1af3291652 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Fri, 27 Oct 2017 10:10:00 +0200 Subject: [PATCH 12/46] Update doc for mozilla modern profile --- README.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 91052d4..181b5cb 100644 --- a/README.md +++ b/README.md @@ -238,14 +238,19 @@ and `CERT_NAME=shared` will then use this shared cert. #### How SSL Support Works -The SSL cipher configuration is based on the [Mozilla nginx intermediate profile](https://wiki.mozilla.org/Security/Server_Side_TLS#Nginx) which +The default SSL cipher configuration is based on the [Mozilla intermediate profile](https://wiki.mozilla.org/Security/Server_Side_TLS#Intermediate_compatibility_.28default.29) which should provide compatibility with clients back to Firefox 1, Chrome 1, IE 7, Opera 5, Safari 1, Windows XP IE8, Android 2.3, Java 7. 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.0, 1.1 and 1.2 -are supported. TLS 1.0 is deprecated but its end of life is not until June 30, 2018. It is being +are supported. TLS 1.0 is deprecated but its end of life is not until June 30, 2018. It is being included because the following browsers will stop working when it is removed: Chrome < 22, Firefox < 27, IE < 11, Safari < 7, iOS < 5, Android Browser < 5. +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 `MODERN_SSL=true` to your container. +This profile is compatible with clients back to Firefox 27, Chrome 30, IE 11 on Windows 7, +Edge, Opera 17, Safari 9, Android 5.0, and Java 8. + 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 From bf16afc66540b8a4eb2337776991c6a78f230dd4 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Thu, 16 Nov 2017 23:34:42 +0100 Subject: [PATCH 13/46] Use enumerable SSL_POLICY instead of bool --- nginx.tmpl | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/nginx.tmpl b/nginx.tmpl index 69b0a6e..30c08b9 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -158,8 +158,8 @@ upstream {{ $upstream_name }} { {{/* Get the HTTPS_METHOD defined by containers w/ the same vhost, falling back to "redirect" */}} {{ $https_method := or (first (groupByKeys $containers "Env.HTTPS_METHOD")) "redirect" }} -{{/* Get the MODERN_SSL defined by containers w/ the same vhost, falling back to "false" */}} -{{ $modern_ssl := or (first (groupByKeys $containers "Env.MODERN_SSL")) "false" }} +{{/* Get the SSL_POLICY defined by containers w/ the same vhost, falling back to "Mozilla-Intermediate" */}} +{{ $ssl_policy := or (first (groupByKeys $containers "Env.SSL_POLICY")) "Mozilla-Intermediate" }} {{/* Get the HSTS defined by containers w/ the same vhost, falling back to "max-age=31536000" */}} {{ $hsts := or (first (groupByKeys $containers "Env.HSTS")) "max-age=31536000" }} @@ -210,12 +210,33 @@ server { include /etc/nginx/network_internal.conf; {{ end }} - {{ if eq $modern_ssl "true" }} + {{ if eq $ssl_policy "Mozilla-Modern" }} ssl_protocols TLSv1.2; - ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256; - {{ else }} + ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256'; + {{ else if eq $ssl_policy "Mozilla-Intermediate" }} ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:!DSS'; + {{ else if eq $ssl_policy "Mozilla-Old" }} + ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2; + ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:ECDHE-RSA-DES-CBC3-SHA:ECDHE-ECDSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:DES-CBC3-SHA:HIGH:SEED:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!RSAPSK:!aDH:!aECDH:!EDH-DSS-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA:!SRP'; + {{ else if eq $ssl_policy "AWS-TLS-1-2-2017-01" }} + 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'; + {{ else if eq $ssl_policy "AWS-TLS-1-1-2017-01" }} + 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'; + {{ else if eq $ssl_policy "AWS-2016-08" }} + 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'; + {{ else if eq $ssl_policy "AWS-2015-05" }} + 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'; + {{ else if eq $ssl_policy "AWS-2015-03" }} + 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'; + {{ else if eq $ssl_policy "AWS-2015-02" }} + 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'; {{ end }} ssl_prefer_server_ciphers on; @@ -226,7 +247,7 @@ server { ssl_certificate /etc/nginx/certs/{{ (printf "%s.crt" $cert) }}; ssl_certificate_key /etc/nginx/certs/{{ (printf "%s.key" $cert) }}; - {{ if (and (ne $modern_ssl "true") (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 }} From 35f092ca304b93b24aa928c04cd873eaeda5c764 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Fri, 17 Nov 2017 09:00:54 +0100 Subject: [PATCH 14/46] Update doc with SSL_POLICY values --- README.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a729d5f..c44bf80 100644 --- a/README.md +++ b/README.md @@ -247,10 +247,18 @@ included because the following browsers will stop working when it is removed: Ch IE < 11, Safari < 7, iOS < 5, Android Browser < 5. 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 `MODERN_SSL=true` to your container. +profile instead by including the environment variable `SSL_POLICY=Mozilla-Modern` to your container. This profile is compatible with clients back to Firefox 27, Chrome 30, IE 11 on Windows 7, Edge, Opera 17, Safari 9, Android 5.0, and Java 8. +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`. + +Note that the `Mozilla-Old` policy should use a 1024 bits DH key for compatibility but this container generates +a 2048 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 container has a usable cert, port 80 will redirect to 443 for that container so that HTTPS From 6e9dc343cdcd3fd3e4091bac4a4eb5c542c549fb Mon Sep 17 00:00:00 2001 From: Sy Doveton Date: Sun, 19 Nov 2017 11:35:30 +0000 Subject: [PATCH 15/46] Changed the SSL stapling cert extension to pem from crt. SSL stapling was not working due to the incorrect file extension. --- nginx.tmpl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nginx.tmpl b/nginx.tmpl index 5147fee..ea6bec5 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -222,10 +222,10 @@ server { ssl_dhparam {{ printf "/etc/nginx/certs/%s.dhparam.pem" $cert }}; {{ end }} - {{ if (exists (printf "/etc/nginx/certs/%s.chain.crt" $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.crt" $cert }}; + ssl_trusted_certificate {{ printf "/etc/nginx/certs/%s.chain.pem" $cert }}; {{ end }} {{ if (and (ne $https_method "noredirect") (ne $hsts "off")) }} From 1eac894902f787ce4defca35d1c3b8487698b649 Mon Sep 17 00:00:00 2001 From: mouhamed Date: Tue, 9 Jan 2018 21:12:37 +0100 Subject: [PATCH 16/46] Remove duplicate --- nginx.tmpl | 3 --- 1 file changed, 3 deletions(-) diff --git a/nginx.tmpl b/nginx.tmpl index 30c08b9..18a60d0 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -152,9 +152,6 @@ upstream {{ $upstream_name }} { {{/* 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 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")) "redirect" }} From 32d42ffee720eb4bd848a00b46b630429c40516d Mon Sep 17 00:00:00 2001 From: Jason Wilder Date: Sun, 14 Jan 2018 15:28:46 -0700 Subject: [PATCH 17/46] Update docker-gen to 0.7.4 --- Dockerfile | 2 +- Dockerfile.alpine | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 149fb90..60f3b5b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -18,7 +18,7 @@ RUN echo "daemon off;" >> /etc/nginx/nginx.conf \ ADD https://github.com/jwilder/forego/releases/download/v0.16.1/forego /usr/local/bin/forego RUN chmod u+x /usr/local/bin/forego -ENV DOCKER_GEN_VERSION 0.7.3 +ENV DOCKER_GEN_VERSION 0.7.4 RUN wget https://github.com/jwilder/docker-gen/releases/download/$DOCKER_GEN_VERSION/docker-gen-linux-amd64-$DOCKER_GEN_VERSION.tar.gz \ && tar -C /usr/local/bin -xvzf docker-gen-linux-amd64-$DOCKER_GEN_VERSION.tar.gz \ diff --git a/Dockerfile.alpine b/Dockerfile.alpine index fce6aae..7089fd8 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -15,7 +15,7 @@ RUN echo "daemon off;" >> /etc/nginx/nginx.conf \ ADD https://github.com/jwilder/forego/releases/download/v0.16.1/forego /usr/local/bin/forego RUN chmod u+x /usr/local/bin/forego -ENV DOCKER_GEN_VERSION 0.7.3 +ENV DOCKER_GEN_VERSION 0.7.4 RUN wget --quiet https://github.com/jwilder/docker-gen/releases/download/$DOCKER_GEN_VERSION/docker-gen-alpine-linux-amd64-$DOCKER_GEN_VERSION.tar.gz \ && tar -C /usr/local/bin -xvzf docker-gen-alpine-linux-amd64-$DOCKER_GEN_VERSION.tar.gz \ From 7a769a6a22ac2ea28d084c11bb25b48881234b28 Mon Sep 17 00:00:00 2001 From: b1f6c1c4 Date: Tue, 20 Feb 2018 17:59:52 +0800 Subject: [PATCH 18/46] Add HSTS header regardless of status code See nginx [doc](http://nginx.org/en/docs/http/ngx_http_headers_module.html#add_header) and [blog](https://www.nginx.com/blog/http-strict-transport-security-hsts-and-nginx/). --- nginx.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nginx.tmpl b/nginx.tmpl index 726c74b..bbb9b37 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -260,7 +260,7 @@ server { {{ end }} {{ if (and (ne $https_method "noredirect") (ne $hsts "off")) }} - add_header Strict-Transport-Security "{{ trim $hsts }}"; + add_header Strict-Transport-Security "{{ trim $hsts }}" always; {{ end }} {{ if (exists (printf "/etc/nginx/vhost.d/%s" $host)) }} From 2f8ebe8d45af63e445c7266068d235e04460239b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20D=C3=B6ring?= Date: Wed, 7 Mar 2018 22:36:05 +0100 Subject: [PATCH 19/46] Enable NETWORK_ACCESS feature for alpine version This PR fixes a missing line in the alpine version. - Fixes #1076 - See #842 --- Dockerfile.alpine | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Dockerfile.alpine b/Dockerfile.alpine index fce6aae..18a486c 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -21,6 +21,8 @@ RUN wget --quiet https://github.com/jwilder/docker-gen/releases/download/$DOCKER && tar -C /usr/local/bin -xvzf docker-gen-alpine-linux-amd64-$DOCKER_GEN_VERSION.tar.gz \ && rm /docker-gen-alpine-linux-amd64-$DOCKER_GEN_VERSION.tar.gz +COPY network_internal.conf /etc/nginx/ + COPY . /app/ WORKDIR /app/ From 37714fa4f873fa7d0ca3e67d17bd4a4f4cd31396 Mon Sep 17 00:00:00 2001 From: Sergei Filippov Date: Fri, 9 Mar 2018 10:48:14 +1300 Subject: [PATCH 20/46] Grammar Police Tiny grammatical fix. --- nginx.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nginx.tmpl b/nginx.tmpl index 726c74b..6bf19d5 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -130,7 +130,7 @@ upstream {{ $upstream_name }} { {{ 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 connect with "{{ $containerNetwork.Name }}" network + ## Can be connected with "{{ $containerNetwork.Name }}" network {{/* If only 1 port exposed, use that */}} {{ if eq $addrLen 1 }} From b61c84192960d937a5e5b517264efe9653f8f899 Mon Sep 17 00:00:00 2001 From: Harald Wellmann Date: Thu, 22 Mar 2018 10:56:41 +0100 Subject: [PATCH 21/46] do not create an empty upstream entry for a container from an invisible Docker network --- nginx.tmpl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/nginx.tmpl b/nginx.tmpl index 6bf19d5..1d1d4b6 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -142,6 +142,9 @@ upstream {{ $upstream_name }} { {{ $address := where $container.Addresses "Port" $port | first }} {{ template "upstream" (dict "Container" $container "Address" $address "Network" $containerNetwork) }} {{ end }} + {{ else }} + # Cannot connect to network of this container + server 127.0.0.1 down; {{ end }} {{ end }} {{ end }} From 5266553e1bcb8bdcf47218d8a3c3d95e3272595c Mon Sep 17 00:00:00 2001 From: Jason Wilder Date: Fri, 23 Mar 2018 21:07:43 -0600 Subject: [PATCH 22/46] Add issue template/q&a links --- .github/ISSUE_TEMPLATE.md | 14 ++++++++++++++ README.md | 4 ++++ 2 files changed, 18 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE.md diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 0000000..cfaa367 --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,14 @@ +# !!!PLEASE READ!!! + +## Questions + +If you have a question, DO NOT SUBMIT a new issue. Please ask the question on the Q&A Group: https://groups.google.com/forum/#!forum/nginx-proxy + +## Bugs or Features + +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. + +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. + +Thanks, +Jason diff --git a/README.md b/README.md index c44bf80..72185c4 100644 --- a/README.md +++ b/README.md @@ -416,3 +416,7 @@ If your system has the `make` command, you can automate those tasks by calling: 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. + +### Need help? + +If you have questions on how to use the image, please ask them on the [Q&A Group](https://groups.google.com/forum/#!forum/nginx-proxy) From f8cd4483aca804ef0608d3b0a3b057f213d9518e Mon Sep 17 00:00:00 2001 From: Jason Wilder Date: Sun, 14 Jan 2018 15:29:16 -0700 Subject: [PATCH 23/46] Update version to 0.7.0 --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index c44bf80..d44ec82 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,4 @@ +![latest 0.7.0](https://img.shields.io/badge/latest-0.7.0-green.svg?style=flat) ![nginx 1.13](https://img.shields.io/badge/nginx-1.13-brightgreen.svg) ![License MIT](https://img.shields.io/badge/license-MIT-blue.svg) [![Build Status](https://travis-ci.org/jwilder/nginx-proxy.svg?branch=master)](https://travis-ci.org/jwilder/nginx-proxy) [![](https://img.shields.io/docker/stars/jwilder/nginx-proxy.svg)](https://hub.docker.com/r/jwilder/nginx-proxy 'DockerHub') [![](https://img.shields.io/docker/pulls/jwilder/nginx-proxy.svg)](https://hub.docker.com/r/jwilder/nginx-proxy 'DockerHub') From c1ae91364c25a9722f19e66e5360eddf61642b8a Mon Sep 17 00:00:00 2001 From: Steve Kamerman Date: Mon, 26 Mar 2018 14:57:50 -0400 Subject: [PATCH 24/46] Added endpoint to allow testing alternate response codes --- test/requirements/web/webserver.py | 37 ++++++++++++++++++------------ 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/test/requirements/web/webserver.py b/test/requirements/web/webserver.py index 305c207..9334657 100755 --- a/test/requirements/web/webserver.py +++ b/test/requirements/web/webserver.py @@ -1,28 +1,35 @@ #!/usr/bin/env python3 -import os, sys +import os, sys, re import http.server import socketserver - class Handler(http.server.SimpleHTTPRequestHandler): def do_GET(self): - - self.send_response(200) + + response_body = "" + response_code = 200 + + if self.path == "/headers": + response_body += self.headers.as_string() + elif self.path == "/port": + response_body += "answer from port %s\n" % PORT + elif re.match("/status/(\d+)", self.path): + result = re.match("/status/(\d+)", self.path) + response_code = int(result.group(1)) + response_body += "answer with response code %s\n" % response_code + elif self.path == "/": + response_body += "I'm %s\n" % os.environ['HOSTNAME'] + else: + response_body += "No route for this path!\n" + response_code = 404 + + self.send_response(response_code) self.send_header("Content-Type", "text/plain") self.end_headers() - if self.path == "/headers": - self.wfile.write(self.headers.as_string().encode()) - elif self.path == "/port": - response = "answer from port %s\n" % PORT - self.wfile.write(response.encode()) - elif self.path == "/": - response = "I'm %s\n" % os.environ['HOSTNAME'] - self.wfile.write(response.encode()) - else: - self.wfile.write("No route for this path!\n".encode()) - + if (len(response_body)): + self.wfile.write(response_body.encode()) if __name__ == '__main__': PORT = int(sys.argv[1]) From 3590c1bae00df9a00f0d258282668b36d0380eef Mon Sep 17 00:00:00 2001 From: Steve Kamerman Date: Mon, 26 Mar 2018 14:58:06 -0400 Subject: [PATCH 25/46] Added regression test to ensure HSTS works for errors --- test/test_ssl/test_hsts.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/test_ssl/test_hsts.py b/test/test_ssl/test_hsts.py index 180f274..554d79a 100644 --- a/test/test_ssl/test_hsts.py +++ b/test/test_ssl/test_hsts.py @@ -7,6 +7,13 @@ def test_web1_HSTS_default(docker_compose, nginxproxy): assert "Strict-Transport-Security" in r.headers assert "max-age=31536000" == r.headers["Strict-Transport-Security"] +# Regression test to ensure HSTS is enabled even when the upstream sends an error in response +# Issue #1073 https://github.com/jwilder/nginx-proxy/pull/1073 +def test_web1_HSTS_error(docker_compose, nginxproxy): + r = nginxproxy.get("https://web1.nginx-proxy.tld/status/500", allow_redirects=False) + assert "Strict-Transport-Security" in r.headers + assert "max-age=31536000" == r.headers["Strict-Transport-Security"] + def test_web2_HSTS_off(docker_compose, nginxproxy): r = nginxproxy.get("https://web2.nginx-proxy.tld/port", allow_redirects=False) assert "answer from port 81\n" in r.text From d7e939dc27ce5feeca3a9efce0e94264f6b7db52 Mon Sep 17 00:00:00 2001 From: Steve Kamerman Date: Wed, 28 Mar 2018 11:43:41 -0400 Subject: [PATCH 26/46] Added info on enabling OCSP Stapling --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index 18d65bc..054b4d1 100644 --- a/README.md +++ b/README.md @@ -237,6 +237,15 @@ to identify the certificate to be used. For example, a certificate for `*.foo.c 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_.28default.29) which From 1c7ccc473f9be71981e9c05a9869212318132c7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=80=90=E5=B0=8F=E5=BF=83?= Date: Fri, 30 Mar 2018 09:47:57 +0800 Subject: [PATCH 27/46] fix fastcgi bug --- nginx.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nginx.tmpl b/nginx.tmpl index bdb2de8..5df0dd8 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -278,7 +278,7 @@ server { uwsgi_pass {{ trim $proto }}://{{ trim $upstream_name }}; {{ else if eq $proto "fastcgi" }} root {{ trim $vhost_root }}; - include fastcgi.conf; + include fastcgi_params; fastcgi_pass {{ trim $upstream_name }}; {{ else }} proxy_pass {{ trim $proto }}://{{ trim $upstream_name }}; From 59aa78a4a6914f35b0ccbb6d1b77112cb1dabb83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=80=90=E5=B0=8F=E5=BF=83?= Date: Tue, 17 Apr 2018 21:52:58 +0800 Subject: [PATCH 28/46] fix fastcgi bug --- nginx.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nginx.tmpl b/nginx.tmpl index 5df0dd8..674be5c 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -325,7 +325,7 @@ server { uwsgi_pass {{ trim $proto }}://{{ trim $upstream_name }}; {{ else if eq $proto "fastcgi" }} root {{ trim $vhost_root }}; - include fastcgi.conf; + include fastcgi_params; fastcgi_pass {{ trim $upstream_name }}; {{ else }} proxy_pass {{ trim $proto }}://{{ trim $upstream_name }}; From c417813df916789fa29a83c3e31f196777e718d3 Mon Sep 17 00:00:00 2001 From: Steve Kamerman Date: Sun, 22 Apr 2018 16:03:43 -0400 Subject: [PATCH 29/46] Fixed out-of-scope variable --- test/conftest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/conftest.py b/test/conftest.py index 43f83bb..54c3b08 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -257,7 +257,7 @@ def get_nginx_conf_from_container(container): strm, stat = container.get_archive('/etc/nginx/conf.d/default.conf') with tarfile.open(fileobj=StringIO(strm.read())) as tf: conffile = tf.extractfile('default.conf') - return conffile.read() + return conffile.read() def docker_compose_up(compose_file='docker-compose.yml'): From 9be2624d094a16b9a1d648888f29264713da48fd Mon Sep 17 00:00:00 2001 From: Steve Kamerman Date: Sun, 22 Apr 2018 16:08:29 -0400 Subject: [PATCH 30/46] Increased dependency versions to get around pip internal problem --- test/conftest.py | 4 ++-- test/requirements/python-requirements.txt | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/test/conftest.py b/test/conftest.py index 54c3b08..6bd172a 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -469,5 +469,5 @@ try: except docker.errors.ImageNotFound: pytest.exit("The docker image 'jwilder/nginx-proxy:test' is missing") -if docker.__version__ != "2.0.2": - pytest.exit("This test suite is meant to work with the python docker module v2.0.2") +if docker.__version__ != "2.1.0": + pytest.exit("This test suite is meant to work with the python docker module v2.1.0") diff --git a/test/requirements/python-requirements.txt b/test/requirements/python-requirements.txt index e868e14..ba95455 100644 --- a/test/requirements/python-requirements.txt +++ b/test/requirements/python-requirements.txt @@ -1,5 +1,5 @@ backoff==1.3.2 -docker-compose==1.11.1 -docker==2.0.2 +docker-compose==1.11.2 +docker==2.1.0 pytest==3.0.5 -requests==2.11.1 \ No newline at end of file +requests==2.11.1 From af266c0b83e1b769fd9d90a3fa34a982fec051b2 Mon Sep 17 00:00:00 2001 From: Steve Kamerman Date: Sun, 22 Apr 2018 16:43:00 -0400 Subject: [PATCH 31/46] Remove old docker.list to avoid getting unstable Docker version --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 268e275..7a1c66f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,8 @@ env: - TEST_TARGET: test-alpine before_install: - - sudo apt-get remove docker docker-engine + - sudo apt-get -y remove docker docker-engine docker-ce + - sudo rm /etc/apt/sources.list.d/docker.list - curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - - sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" - sudo apt-get update From 4e6900e8720e35c32e0e48d7404b0ed98e45fc93 Mon Sep 17 00:00:00 2001 From: Steve Kamerman Date: Sat, 21 Apr 2018 19:50:37 -0400 Subject: [PATCH 32/46] Added TLSv1.3 support --- nginx.tmpl | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/nginx.tmpl b/nginx.tmpl index 39e38f7..d861050 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -216,31 +216,31 @@ server { {{ end }} {{ if eq $ssl_policy "Mozilla-Modern" }} - ssl_protocols TLSv1.2; + ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256'; {{ else if eq $ssl_policy "Mozilla-Intermediate" }} - ssl_protocols TLSv1 TLSv1.1 TLSv1.2; + ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:!DSS'; {{ else if eq $ssl_policy "Mozilla-Old" }} - ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2; + ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:ECDHE-RSA-DES-CBC3-SHA:ECDHE-ECDSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:DES-CBC3-SHA:HIGH:SEED:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!RSAPSK:!aDH:!aECDH:!EDH-DSS-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA:!SRP'; {{ else if eq $ssl_policy "AWS-TLS-1-2-2017-01" }} - ssl_protocols TLSv1.2; + 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'; {{ else if eq $ssl_policy "AWS-TLS-1-1-2017-01" }} - ssl_protocols TLSv1.1 TLSv1.2; + 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'; {{ else if eq $ssl_policy "AWS-2016-08" }} - ssl_protocols TLSv1 TLSv1.1 TLSv1.2; + 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'; {{ else if eq $ssl_policy "AWS-2015-05" }} - ssl_protocols TLSv1 TLSv1.1 TLSv1.2; + 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'; {{ else if eq $ssl_policy "AWS-2015-03" }} - ssl_protocols TLSv1 TLSv1.1 TLSv1.2; + 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'; {{ else if eq $ssl_policy "AWS-2015-02" }} - ssl_protocols TLSv1 TLSv1.1 TLSv1.2; + 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'; {{ end }} From cb2b0e2bd33d85cb16ac11e144d6b6f4fc38f5a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Do=CC=88ring?= Date: Wed, 6 Jun 2018 00:56:47 +0200 Subject: [PATCH 33/46] Upgrade to nginx 1.14 stable --- 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 60f3b5b..295c06b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM nginx:1.13 +FROM nginx:1.14 LABEL maintainer="Jason Wilder mail@jasonwilder.com" # Install wget and install/updates certificates diff --git a/Dockerfile.alpine b/Dockerfile.alpine index c65f88c..ba93de7 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -1,4 +1,4 @@ -FROM nginx:1.13-alpine +FROM nginx:1.14-alpine LABEL maintainer="Jason Wilder mail@jasonwilder.com" # Install wget and install/updates certificates diff --git a/README.md b/README.md index 054b4d1..5c83548 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ ![latest 0.7.0](https://img.shields.io/badge/latest-0.7.0-green.svg?style=flat) -![nginx 1.13](https://img.shields.io/badge/nginx-1.13-brightgreen.svg) ![License MIT](https://img.shields.io/badge/license-MIT-blue.svg) [![Build Status](https://travis-ci.org/jwilder/nginx-proxy.svg?branch=master)](https://travis-ci.org/jwilder/nginx-proxy) [![](https://img.shields.io/docker/stars/jwilder/nginx-proxy.svg)](https://hub.docker.com/r/jwilder/nginx-proxy 'DockerHub') [![](https://img.shields.io/docker/pulls/jwilder/nginx-proxy.svg)](https://hub.docker.com/r/jwilder/nginx-proxy 'DockerHub') +![nginx 1.14](https://img.shields.io/badge/nginx-1.14-brightgreen.svg) ![License MIT](https://img.shields.io/badge/license-MIT-blue.svg) [![Build Status](https://travis-ci.org/jwilder/nginx-proxy.svg?branch=master)](https://travis-ci.org/jwilder/nginx-proxy) [![](https://img.shields.io/docker/stars/jwilder/nginx-proxy.svg)](https://hub.docker.com/r/jwilder/nginx-proxy 'DockerHub') [![](https://img.shields.io/docker/pulls/jwilder/nginx-proxy.svg)](https://hub.docker.com/r/jwilder/nginx-proxy 'DockerHub') nginx-proxy sets up a container running nginx and [docker-gen][1]. docker-gen generates reverse proxy configs for nginx and reloads nginx when containers are started and stopped. diff --git a/test/certs/create_server_certificate.sh b/test/certs/create_server_certificate.sh index bffc27e..7473552 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.13) +CONTAINER=$(docker run -d -v $DIR:/work -w /work -e SAN="$ALTERNATE_DOMAINS" nginx:1.14) # Configure openssl docker exec $CONTAINER bash -c ' mkdir -p /ca/{certs,crl,private,newcerts} 2>/dev/null From 936e57a6de5a3e12043ab51492bf795537afe4f2 Mon Sep 17 00:00:00 2001 From: Steve Kamerman Date: Mon, 26 Mar 2018 13:27:30 -0400 Subject: [PATCH 34/46] Fixed #1080, can't disable HSTS with noredirect --- nginx.tmpl | 4 ++-- test/test_ssl/test_hsts.py | 7 +++++++ test/test_ssl/test_hsts.yml | 10 ++++++++++ 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/nginx.tmpl b/nginx.tmpl index d861050..a9fc479 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -19,7 +19,7 @@ server 127.0.0.1 down; {{ end }} {{ end }} - + {{ end }} # If we receive X-Forwarded-Proto, pass it through; otherwise, pass along the @@ -262,7 +262,7 @@ server { ssl_trusted_certificate {{ printf "/etc/nginx/certs/%s.chain.pem" $cert }}; {{ end }} - {{ if (and (ne $https_method "noredirect") (ne $hsts "off")) }} + {{ if (not (or (eq $https_method "noredirect") (eq $hsts "off"))) }} add_header Strict-Transport-Security "{{ trim $hsts }}" always; {{ end }} diff --git a/test/test_ssl/test_hsts.py b/test/test_ssl/test_hsts.py index 554d79a..12bbcc4 100644 --- a/test/test_ssl/test_hsts.py +++ b/test/test_ssl/test_hsts.py @@ -24,3 +24,10 @@ def test_web3_HSTS_custom(docker_compose, nginxproxy): assert "answer from port 81\n" in r.text assert "Strict-Transport-Security" in r.headers assert "max-age=86400; includeSubDomains; preload" == r.headers["Strict-Transport-Security"] + +# Regression test for issue 1080 +# https://github.com/jwilder/nginx-proxy/issues/1080 +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 diff --git a/test/test_ssl/test_hsts.yml b/test/test_ssl/test_hsts.yml index 5c04cf0..f6f39a7 100644 --- a/test/test_ssl/test_hsts.yml +++ b/test/test_ssl/test_hsts.yml @@ -24,6 +24,16 @@ web3: VIRTUAL_HOST: "web3.nginx-proxy.tld" HSTS: "max-age=86400; includeSubDomains; preload" +web4: + image: web + expose: + - "81" + environment: + WEB_PORTS: "81" + VIRTUAL_HOST: "web4.nginx-proxy.tld" + HSTS: "off" + HTTPS_METHOD: "noredirect" + sut: image: jwilder/nginx-proxy:test volumes: From 58c1fe360687a3a005ff9eae23ac3b6c4c4c3123 Mon Sep 17 00:00:00 2001 From: Gpkfr Date: Fri, 9 Nov 2018 15:26:01 +0100 Subject: [PATCH 35/46] Upgrade to nginx 1.14.1 stable version --- 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 295c06b..45a09e3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM nginx:1.14 +FROM nginx:1.14.1 LABEL maintainer="Jason Wilder mail@jasonwilder.com" # Install wget and install/updates certificates diff --git a/Dockerfile.alpine b/Dockerfile.alpine index ba93de7..23459a3 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -1,4 +1,4 @@ -FROM nginx:1.14-alpine +FROM nginx:1.14.1-alpine LABEL maintainer="Jason Wilder mail@jasonwilder.com" # Install wget and install/updates certificates diff --git a/README.md b/README.md index 5c83548..a6504cd 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ ![latest 0.7.0](https://img.shields.io/badge/latest-0.7.0-green.svg?style=flat) -![nginx 1.14](https://img.shields.io/badge/nginx-1.14-brightgreen.svg) ![License MIT](https://img.shields.io/badge/license-MIT-blue.svg) [![Build Status](https://travis-ci.org/jwilder/nginx-proxy.svg?branch=master)](https://travis-ci.org/jwilder/nginx-proxy) [![](https://img.shields.io/docker/stars/jwilder/nginx-proxy.svg)](https://hub.docker.com/r/jwilder/nginx-proxy 'DockerHub') [![](https://img.shields.io/docker/pulls/jwilder/nginx-proxy.svg)](https://hub.docker.com/r/jwilder/nginx-proxy 'DockerHub') +![nginx 1.14.1](https://img.shields.io/badge/nginx-1.14-brightgreen.svg) ![License MIT](https://img.shields.io/badge/license-MIT-blue.svg) [![Build Status](https://travis-ci.org/jwilder/nginx-proxy.svg?branch=master)](https://travis-ci.org/jwilder/nginx-proxy) [![](https://img.shields.io/docker/stars/jwilder/nginx-proxy.svg)](https://hub.docker.com/r/jwilder/nginx-proxy 'DockerHub') [![](https://img.shields.io/docker/pulls/jwilder/nginx-proxy.svg)](https://hub.docker.com/r/jwilder/nginx-proxy 'DockerHub') nginx-proxy sets up a container running nginx and [docker-gen][1]. docker-gen generates reverse proxy configs for nginx and reloads nginx when containers are started and stopped. diff --git a/test/certs/create_server_certificate.sh b/test/certs/create_server_certificate.sh index 7473552..ae51280 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.14) +CONTAINER=$(docker run -d -v $DIR:/work -w /work -e SAN="$ALTERNATE_DOMAINS" nginx:1.14.1) # Configure openssl docker exec $CONTAINER bash -c ' mkdir -p /ca/{certs,crl,private,newcerts} 2>/dev/null From 6a1a518fec5507ba1115468e1e70dc410ed53b2f Mon Sep 17 00:00:00 2001 From: Kenichi HIROSE Date: Tue, 18 Dec 2018 14:05:17 +0000 Subject: [PATCH 36/46] Fix empty dhparam.pem --- generate-dhparam.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/generate-dhparam.sh b/generate-dhparam.sh index 3fdc77c..27b6432 100755 --- a/generate-dhparam.sh +++ b/generate-dhparam.sh @@ -37,7 +37,8 @@ touch $GEN_LOCKFILE # Generate a new dhparam in the background in a low priority and reload nginx when finished (grep removes the progress indicator). ( ( - nice -n +5 openssl dhparam -out $DHPARAM_FILE $DHPARAM_BITS 2>&1 \ + nice -n +5 openssl dhparam -out $DHPARAM_FILE.tmp $DHPARAM_BITS 2>&1 \ + && mv $DHPARAM_FILE.tmp $DHPARAM_FILE \ && echo "dhparam generation complete, reloading nginx" \ && nginx -s reload ) | grep -vE '^[\.+]+' From ad4117803690042e446aa7f7b25d25bebecf843a Mon Sep 17 00:00:00 2001 From: Steve Kamerman Date: Mon, 4 Feb 2019 15:15:04 -0500 Subject: [PATCH 37/46] Fixed tests that are now failing due to the dhparam clearing command beating the nginx startup. This is fixed permanently in #1213, but this PR fixes the test so as not to rely on the dhparam autogen, which is tested elsewhere. --- test/test_ssl/wildcard_cert_and_nohttps/docker-compose.yml | 3 ++- .../wildcard_cert_and_nohttps/test_wildcard_cert_nohttps.py | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/test/test_ssl/wildcard_cert_and_nohttps/docker-compose.yml b/test/test_ssl/wildcard_cert_and_nohttps/docker-compose.yml index bffffc1..20cd1b2 100644 --- a/test/test_ssl/wildcard_cert_and_nohttps/docker-compose.yml +++ b/test/test_ssl/wildcard_cert_and_nohttps/docker-compose.yml @@ -7,6 +7,7 @@ services: volumes: - /var/run/docker.sock:/tmp/docker.sock:ro - ./certs:/etc/nginx/certs:ro + - ../../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro web1: image: web @@ -30,4 +31,4 @@ services: environment: WEB_PORTS: "83" VIRTUAL_HOST: "3.web.nginx-proxy.tld" - HTTPS_METHOD: nohttps \ No newline at end of file + HTTPS_METHOD: nohttps 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 de4b298..2808dee 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 @@ -11,6 +11,7 @@ from requests.exceptions import SSLError def test_http_redirects_to_https(docker_compose, nginxproxy, subdomain, should_redirect_to_https): r = nginxproxy.get("http://%s.web.nginx-proxy.tld/port" % subdomain) if should_redirect_to_https: + assert len(r.history) > 0 assert r.history[0].is_redirect assert r.history[0].headers.get("Location") == "https://%s.web.nginx-proxy.tld/port" % subdomain assert "answer from port 8%s\n" % subdomain == r.text From afa2dc53c7e431e86961d1b03d811338ae0a7c9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Pomyka=C5=82a?= Date: Sat, 23 Mar 2019 12:23:12 +0100 Subject: [PATCH 38/46] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f27c467..f873ddd 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ Then start any containers you want proxied with an env var `VIRTUAL_HOST=subdoma $ docker run -e VIRTUAL_HOST=foo.bar.com ... -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`. +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 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. From 16169a0f74d2191049cbce807dc072eb4f546ee3 Mon Sep 17 00:00:00 2001 From: Jiazhen Xie Date: Wed, 7 Aug 2019 17:32:52 +0100 Subject: [PATCH 39/46] Use nginx latest version --- Dockerfile | 2 +- Dockerfile.alpine | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 45a09e3..fc977c1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM nginx:1.14.1 +FROM nginx:1.17.2 LABEL maintainer="Jason Wilder mail@jasonwilder.com" # Install wget and install/updates certificates diff --git a/Dockerfile.alpine b/Dockerfile.alpine index 23459a3..e4c486a 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -1,4 +1,4 @@ -FROM nginx:1.14.1-alpine +FROM nginx:1.17.2-alpine LABEL maintainer="Jason Wilder mail@jasonwilder.com" # Install wget and install/updates certificates From 23823c4b21a7d56d88229be311a1a1339dd91aba Mon Sep 17 00:00:00 2001 From: Jiazhen Xie Date: Wed, 7 Aug 2019 17:33:02 +0100 Subject: [PATCH 40/46] Fix the test --- test/test_ssl/test_dhparam.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_ssl/test_dhparam.py b/test/test_ssl/test_dhparam.py index fd60217..40339a1 100644 --- a/test/test_ssl/test_dhparam.py +++ b/test/test_ssl/test_dhparam.py @@ -90,4 +90,4 @@ def test_web5_dhparam_is_used(docker_compose): host = "%s:443" % sut_container.attrs["NetworkSettings"]["IPAddress"] r = subprocess.check_output( "echo '' | openssl s_client -connect %s -cipher 'EDH' | grep 'Server Temp Key'" % host, shell=True) - assert "Server Temp Key: DH, 2048 bits\n" == r + assert "Server Temp Key: X25519, 253 bits\n" == r From a4cc2686280b130d42f4e562afa57cb500c751f7 Mon Sep 17 00:00:00 2001 From: Lorenzo Cameroni Date: Sun, 18 Aug 2019 11:20:05 +0200 Subject: [PATCH 41/46] Use nginx 1.17.3 --- Dockerfile | 2 +- Dockerfile.alpine | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index fc977c1..0a1616b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM nginx:1.17.2 +FROM nginx:1.17.3 LABEL maintainer="Jason Wilder mail@jasonwilder.com" # Install wget and install/updates certificates diff --git a/Dockerfile.alpine b/Dockerfile.alpine index e4c486a..03877c8 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -1,4 +1,4 @@ -FROM nginx:1.17.2-alpine +FROM nginx:1.17.3-alpine LABEL maintainer="Jason Wilder mail@jasonwilder.com" # Install wget and install/updates certificates From 26e764950f02417b759e20290c6c1bbc1eb59e54 Mon Sep 17 00:00:00 2001 From: Lorenzo Cameroni Date: Thu, 29 Aug 2019 22:14:14 +0200 Subject: [PATCH 42/46] Update ssl configuration --- README.md | 18 ++++++------ nginx.tmpl | 81 +++++++++++++++++++++++++++++++++--------------------- 2 files changed, 58 insertions(+), 41 deletions(-) diff --git a/README.md b/README.md index f27c467..daa5875 100644 --- a/README.md +++ b/README.md @@ -252,18 +252,16 @@ 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_.28default.29) which -should provide compatibility with clients back to Firefox 1, Chrome 1, IE 7, Opera 5, Safari 1, -Windows XP IE8, Android 2.3, Java 7. 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.0, 1.1 and 1.2 -are supported. TLS 1.0 is deprecated but its end of life is not until June 30, 2018. It is being -included because the following browsers will stop working when it is removed: Chrome < 22, Firefox < 27, -IE < 11, Safari < 7, iOS < 5, Android Browser < 5. +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 your container. -This profile is compatible with clients back to Firefox 27, Chrome 30, IE 11 on Windows 7, -Edge, Opera 17, Safari 9, Android 5.0, and Java 8. +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) diff --git a/nginx.tmpl b/nginx.tmpl index a9fc479..ee286fe 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -22,6 +22,48 @@ {{ end }} +{{ define "ssl_policy" }} + {{ if eq .ssl_policy "Mozilla-Modern" }} + ssl_protocols TLSv1.3; + {{/* ssl_ciphers is undefined in the Mozilla-Modern policy /*}} + {{/* 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 }} + # 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 { @@ -65,6 +107,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" */}} +{{ $ssl_policy := or ($.Env.SSL_POLICY) "Mozilla-Intermediate" }} +{{ template "ssl_policy" (dict "ssl_policy" $ssl_policy) }} + {{ if $.Env.RESOLVERS }} resolver {{ $.Env.RESOLVERS }}; {{ end }} @@ -109,6 +155,7 @@ server { access_log /var/log/nginx/access.log vhost; 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; @@ -163,8 +210,8 @@ upstream {{ $upstream_name }} { {{/* Get the HTTPS_METHOD defined by containers w/ the same vhost, falling back to "redirect" */}} {{ $https_method := or (first (groupByKeys $containers "Env.HTTPS_METHOD")) "redirect" }} -{{/* Get the SSL_POLICY defined by containers w/ the same vhost, falling back to "Mozilla-Intermediate" */}} -{{ $ssl_policy := or (first (groupByKeys $containers "Env.SSL_POLICY")) "Mozilla-Intermediate" }} +{{/* 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")) "max-age=31536000" }} @@ -215,36 +262,8 @@ server { include /etc/nginx/network_internal.conf; {{ end }} - {{ if eq $ssl_policy "Mozilla-Modern" }} - ssl_protocols TLSv1.2 TLSv1.3; - ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256'; - {{ else if eq $ssl_policy "Mozilla-Intermediate" }} - ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; - ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:!DSS'; - {{ else if eq $ssl_policy "Mozilla-Old" }} - ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; - ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:ECDHE-RSA-DES-CBC3-SHA:ECDHE-ECDSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:DES-CBC3-SHA:HIGH:SEED:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!RSAPSK:!aDH:!aECDH:!EDH-DSS-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA:!SRP'; - {{ 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'; - {{ 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'; - {{ 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'; - {{ 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'; - {{ 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'; - {{ 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'; - {{ end }} + {{ template "ssl_policy" (dict "ssl_policy" $ssl_policy) }} - ssl_prefer_server_ciphers on; ssl_session_timeout 5m; ssl_session_cache shared:SSL:50m; ssl_session_tickets off; From ede9f9ec25c561f1aad301b3fddabff83e79f4ff Mon Sep 17 00:00:00 2001 From: Lorenzo Cameroni Date: Thu, 29 Aug 2019 22:59:43 +0200 Subject: [PATCH 43/46] README.md: fix version in nginx banner --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f27c467..9ae7404 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ ![latest 0.7.0](https://img.shields.io/badge/latest-0.7.0-green.svg?style=flat) -![nginx 1.14.1](https://img.shields.io/badge/nginx-1.14-brightgreen.svg) ![License MIT](https://img.shields.io/badge/license-MIT-blue.svg) [![Build Status](https://travis-ci.org/jwilder/nginx-proxy.svg?branch=master)](https://travis-ci.org/jwilder/nginx-proxy) [![](https://img.shields.io/docker/stars/jwilder/nginx-proxy.svg)](https://hub.docker.com/r/jwilder/nginx-proxy 'DockerHub') [![](https://img.shields.io/docker/pulls/jwilder/nginx-proxy.svg)](https://hub.docker.com/r/jwilder/nginx-proxy 'DockerHub') +![nginx 1.17.3](https://img.shields.io/badge/nginx-1.17.3-brightgreen.svg) ![License MIT](https://img.shields.io/badge/license-MIT-blue.svg) [![Build Status](https://travis-ci.org/jwilder/nginx-proxy.svg?branch=master)](https://travis-ci.org/jwilder/nginx-proxy) [![](https://img.shields.io/docker/stars/jwilder/nginx-proxy.svg)](https://hub.docker.com/r/jwilder/nginx-proxy 'DockerHub') [![](https://img.shields.io/docker/pulls/jwilder/nginx-proxy.svg)](https://hub.docker.com/r/jwilder/nginx-proxy 'DockerHub') nginx-proxy sets up a container running nginx and [docker-gen][1]. docker-gen generates reverse proxy configs for nginx and reloads nginx when containers are started and stopped. From d8c04f666ffa34da32f5e7df19bd7143966d8513 Mon Sep 17 00:00:00 2001 From: Dick Visser Date: Mon, 9 Sep 2019 07:22:58 +0200 Subject: [PATCH 44/46] Typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f27c467..b909345 100644 --- a/README.md +++ b/README.md @@ -181,7 +181,7 @@ Finally, start your containers with `VIRTUAL_HOST` environment variables. $ docker run -e VIRTUAL_HOST=foo.bar.com ... ### SSL Support using letsencrypt -[letsencrypt-nginx-proxy-companion](https://github.com/JrCs/docker-letsencrypt-nginx-proxy-companion) is a lightweight companion container for the nginx-proxy. It allow the creation/renewal of Let's Encrypt certificates automatically. +[letsencrypt-nginx-proxy-companion](https://github.com/JrCs/docker-letsencrypt-nginx-proxy-companion) is a lightweight companion container for the nginx-proxy. It allows the creation/renewal of Let's Encrypt certificates automatically. Set `DHPARAM_GENERATION` environment variable to `false` to disabled Diffie-Hellman parameters completely. This will also ignore auto-generation made by `nginx-proxy`. The default value is `true` From eba7d8af7756455de45d36dec85aaeea0657998f Mon Sep 17 00:00:00 2001 From: came88 Date: Mon, 9 Sep 2019 12:45:20 +0200 Subject: [PATCH 45/46] Fix comment about Mozilla Modern Policy and TLS1.3 Thanks to @deAtog for pointing it out --- nginx.tmpl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/nginx.tmpl b/nginx.tmpl index ee286fe..a59cd54 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -25,7 +25,8 @@ {{ define "ssl_policy" }} {{ if eq .ssl_policy "Mozilla-Modern" }} ssl_protocols TLSv1.3; - {{/* ssl_ciphers is undefined in the Mozilla-Modern policy /*}} + {{/* 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 cf911d950a37f33d98bc93109bb5144e8547a2f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Do=CC=88ring?= Date: Fri, 8 Nov 2019 14:11:17 +0100 Subject: [PATCH 46/46] Upgrade to 1.17.5 closes #1337, resolves #1355 --- Dockerfile | 2 +- Dockerfile.alpine | 2 +- README.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index 0a1616b..0a8fdef 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM nginx:1.17.3 +FROM nginx:1.17.5 LABEL maintainer="Jason Wilder mail@jasonwilder.com" # Install wget and install/updates certificates diff --git a/Dockerfile.alpine b/Dockerfile.alpine index 03877c8..33b4793 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -1,4 +1,4 @@ -FROM nginx:1.17.3-alpine +FROM nginx:1.17.5-alpine LABEL maintainer="Jason Wilder mail@jasonwilder.com" # Install wget and install/updates certificates diff --git a/README.md b/README.md index 92aee31..ad8678a 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ ![latest 0.7.0](https://img.shields.io/badge/latest-0.7.0-green.svg?style=flat) -![nginx 1.17.3](https://img.shields.io/badge/nginx-1.17.3-brightgreen.svg) ![License MIT](https://img.shields.io/badge/license-MIT-blue.svg) [![Build Status](https://travis-ci.org/jwilder/nginx-proxy.svg?branch=master)](https://travis-ci.org/jwilder/nginx-proxy) [![](https://img.shields.io/docker/stars/jwilder/nginx-proxy.svg)](https://hub.docker.com/r/jwilder/nginx-proxy 'DockerHub') [![](https://img.shields.io/docker/pulls/jwilder/nginx-proxy.svg)](https://hub.docker.com/r/jwilder/nginx-proxy 'DockerHub') +![nginx 1.17.5](https://img.shields.io/badge/nginx-1.17.5-brightgreen.svg) ![License MIT](https://img.shields.io/badge/license-MIT-blue.svg) [![Build Status](https://travis-ci.org/jwilder/nginx-proxy.svg?branch=master)](https://travis-ci.org/jwilder/nginx-proxy) [![](https://img.shields.io/docker/stars/jwilder/nginx-proxy.svg)](https://hub.docker.com/r/jwilder/nginx-proxy 'DockerHub') [![](https://img.shields.io/docker/pulls/jwilder/nginx-proxy.svg)](https://hub.docker.com/r/jwilder/nginx-proxy 'DockerHub') nginx-proxy sets up a container running nginx and [docker-gen][1]. docker-gen generates reverse proxy configs for nginx and reloads nginx when containers are started and stopped.