From 0b1e9e56e1f01c60c78688bab37e6d05c3b80b83 Mon Sep 17 00:00:00 2001 From: Steve Kamerman Date: Thu, 29 Sep 2016 16:47:47 -0400 Subject: [PATCH 01/76] Issue #535 Added default 2048-bit dhparam.pem file --- Dockerfile | 7 ++++--- README.md | 6 ++++-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/Dockerfile b/Dockerfile index 6d5ce9b..ad9a159 100644 --- a/Dockerfile +++ b/Dockerfile @@ -9,9 +9,10 @@ RUN apt-get update \ && apt-get clean \ && rm -r /var/lib/apt/lists/* -# Configure Nginx and apply fix for very long server names -RUN echo "daemon off;" >> /etc/nginx/nginx.conf \ - && sed -i 's/^http {/&\n server_names_hash_bucket_size 128;/g' /etc/nginx/nginx.conf +# Generate dhparam.pem, configure Nginx, apply fix for very long server names +RUN openssl dhparam -out /etc/nginx/dhparam.pem 2048 \ + && echo "daemon off;" >> /etc/nginx/nginx.conf \ + && sed -i 's|^http {|&\n server_names_hash_bucket_size 128; ssl_dhparam /etc/nginx/dhparam.pem;|g' /etc/nginx/nginx.conf # Install Forego ADD https://github.com/jwilder/forego/releases/download/v0.16.1/forego /usr/local/bin/forego diff --git a/README.md b/README.md index 52ab6e4..0a7593d 100644 --- a/README.md +++ b/README.md @@ -142,9 +142,11 @@ hosts in use. The certificate and keys should be named after the virtual host w #### Diffie-Hellman Groups -If you have Diffie-Hellman groups enabled, the files should be named after the virtual host with a +Diffie-Hellman groups are enabled by default, with a pregenerated key in `/etc/nginx/dhparam.pem`. +You can mount a different `dhparam.pem` file at that location to override the default cert. +To use custom `dhparam.pem` files per-virtual-host, the files should be named after the virtual host with a `dhparam` suffix and `.pem` extension. For example, a container with `VIRTUAL_HOST=foo.bar.com` -should have a `foo.bar.com.dhparam.pem` file in the certs directory. +should have a `foo.bar.com.dhparam.pem` file in the `/etc/nginx/certs` directory. #### Wildcard Certificates From 6f2b3f1c54b7a4abcd2f89305ede04b183587b6c Mon Sep 17 00:00:00 2001 From: Steve Kamerman Date: Thu, 29 Sep 2016 17:10:17 -0400 Subject: [PATCH 02/76] Issue #586 Removed DES-based SSL ciphers --- nginx.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nginx.tmpl b/nginx.tmpl index 9eb9520..b6629f5 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -144,7 +144,7 @@ server { access_log /var/log/nginx/access.log vhost; 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:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS'; + 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'; ssl_prefer_server_ciphers on; ssl_session_timeout 5m; From c51c9980cf8f36bac521c061e01a5b3cce984196 Mon Sep 17 00:00:00 2001 From: Steve Kamerman Date: Thu, 29 Sep 2016 19:52:20 -0400 Subject: [PATCH 03/76] Removed TLS 1.0 as it is considered unsafe and must be disabled for PCI compliance --- nginx.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nginx.tmpl b/nginx.tmpl index b6629f5..626f508 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -143,7 +143,7 @@ server { listen 443 ssl http2 {{ $default_server }}; access_log /var/log/nginx/access.log vhost; - ssl_protocols TLSv1 TLSv1.1 TLSv1.2; + ssl_protocols 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'; ssl_prefer_server_ciphers on; From d3a0da451abf2b73757cd9642c2df5abddc66b4c Mon Sep 17 00:00:00 2001 From: Steve Kamerman Date: Thu, 29 Sep 2016 21:35:37 -0400 Subject: [PATCH 04/76] TLSv1 End-of-life pushed to June 30, 2018, rolled back for compatibility --- nginx.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nginx.tmpl b/nginx.tmpl index 626f508..b6629f5 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -143,7 +143,7 @@ server { listen 443 ssl http2 {{ $default_server }}; access_log /var/log/nginx/access.log vhost; - ssl_protocols TLSv1.1 TLSv1.2; + 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'; ssl_prefer_server_ciphers on; From ebbf7a7b74395e316d0c08267d4bacc2150e6395 Mon Sep 17 00:00:00 2001 From: Steve Kamerman Date: Thu, 29 Sep 2016 21:57:28 -0400 Subject: [PATCH 05/76] Expanded documentation in SSL/TLS support --- README.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 0a7593d..c4a629e 100644 --- a/README.md +++ b/README.md @@ -162,10 +162,13 @@ and `CERT_NAME=shared` will then use this shared cert. #### How SSL Support Works -The SSL cipher configuration is based on [mozilla nginx intermediate profile](https://wiki.mozilla.org/Security/Server_Side_TLS#Nginx) which +The SSL cipher configuration is based on the [Mozilla nginx intermediate profile](https://wiki.mozilla.org/Security/Server_Side_TLS#Nginx) 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. The configuration also enables HSTS, and SSL -session caches. +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, 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 behavior for the proxy when port 80 and 443 are exposed is as follows: From c091d08fee673670218e77b89bc40119ff0be368 Mon Sep 17 00:00:00 2001 From: Steve Kamerman Date: Thu, 29 Sep 2016 22:24:06 -0400 Subject: [PATCH 06/76] Updated docs for issue #562 --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index c4a629e..919d762 100644 --- a/README.md +++ b/README.md @@ -78,6 +78,8 @@ In this example, the `my-nginx-proxy` container will be connected to `my-network If you would like to connect to your backend using HTTPS instead of HTTP, set `VIRTUAL_PROTO=https` on the backend container. +> Note: If you use `VIRTUAL_PROTO=https` and your backend container exposes port 80 and 443, `nginx-proxy` will use HTTPS on port 80. This is almost certainly not what you want, so you should also include `VIRTUAL_PORT=443`. + ### uWSGI Backends If you would like to connect to uWSGI backend, set `VIRTUAL_PROTO=uwsgi` on the From 8534185b0cac3e172a2296a1a19bd94da3271307 Mon Sep 17 00:00:00 2001 From: Steve Kamerman Date: Mon, 3 Oct 2016 10:05:55 -0400 Subject: [PATCH 07/76] Added newline to config --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index ad9a159..0eb78d6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -12,7 +12,7 @@ RUN apt-get update \ # Generate dhparam.pem, configure Nginx, apply fix for very long server names RUN openssl dhparam -out /etc/nginx/dhparam.pem 2048 \ && echo "daemon off;" >> /etc/nginx/nginx.conf \ - && sed -i 's|^http {|&\n server_names_hash_bucket_size 128; ssl_dhparam /etc/nginx/dhparam.pem;|g' /etc/nginx/nginx.conf + && sed -i 's|^http {|&\n server_names_hash_bucket_size 128;\n ssl_dhparam /etc/nginx/dhparam.pem;|g' /etc/nginx/nginx.conf # Install Forego ADD https://github.com/jwilder/forego/releases/download/v0.16.1/forego /usr/local/bin/forego From b0de80d46b63f353a198e2110aa2b03ad26e691d Mon Sep 17 00:00:00 2001 From: Steve Kamerman Date: Mon, 3 Oct 2016 10:21:31 -0400 Subject: [PATCH 08/76] Moved config edits from Dockerfile to template --- Dockerfile | 5 ++--- nginx.tmpl | 6 ++++++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index 0eb78d6..0a1df5d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -9,10 +9,9 @@ RUN apt-get update \ && apt-get clean \ && rm -r /var/lib/apt/lists/* -# Generate dhparam.pem, configure Nginx, apply fix for very long server names +# Generate dhparam.pem, configure nginx RUN openssl dhparam -out /etc/nginx/dhparam.pem 2048 \ - && echo "daemon off;" >> /etc/nginx/nginx.conf \ - && sed -i 's|^http {|&\n server_names_hash_bucket_size 128;\n ssl_dhparam /etc/nginx/dhparam.pem;|g' /etc/nginx/nginx.conf + && echo "daemon off;" >> /etc/nginx/nginx.conf # Install Forego ADD https://github.com/jwilder/forego/releases/download/v0.16.1/forego /usr/local/bin/forego diff --git a/nginx.tmpl b/nginx.tmpl index b6629f5..779d217 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -31,6 +31,12 @@ map $http_upgrade $proxy_connection { '' close; } +# Apply fix for very long server names +server_names_hash_bucket_size 128; + +# Default dhparam +ssl_dhparam /etc/nginx/dhparam.pem; + gzip_types text/plain text/css application/javascript application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript; log_format vhost '$host $remote_addr - $remote_user [$time_local] ' From dfdd67f5a4606d8c9269d71b14d37f04cde947dd Mon Sep 17 00:00:00 2001 From: Steve Kamerman Date: Wed, 11 Jan 2017 22:39:04 -0500 Subject: [PATCH 09/76] Implemented background dhparam generation --- Dockerfile | 7 +++---- dhparam.pem.default | 8 ++++++++ docker-entrypoint.sh | 5 ++++- generate-dhparam.sh | 42 ++++++++++++++++++++++++++++++++++++++++++ nginx.tmpl | 2 +- 5 files changed, 58 insertions(+), 6 deletions(-) create mode 100644 dhparam.pem.default create mode 100755 generate-dhparam.sh diff --git a/Dockerfile b/Dockerfile index 228254f..786db25 100644 --- a/Dockerfile +++ b/Dockerfile @@ -9,9 +9,8 @@ RUN apt-get update \ && apt-get clean \ && rm -r /var/lib/apt/lists/* -# Generate dhparam.pem, configure nginx -RUN openssl dhparam -out /etc/nginx/dhparam.pem 2048 \ - && echo "daemon off;" >> /etc/nginx/nginx.conf +# Configure nginx +RUN echo "daemon off;" >> /etc/nginx/nginx.conf # Install Forego ADD https://github.com/jwilder/forego/releases/download/v0.16.1/forego /usr/local/bin/forego @@ -28,7 +27,7 @@ WORKDIR /app/ ENV DOCKER_HOST unix:///tmp/docker.sock -VOLUME ["/etc/nginx/certs"] +VOLUME ["/etc/nginx/certs", "/etc/nginx/dhparam"] ENTRYPOINT ["/app/docker-entrypoint.sh"] CMD ["forego", "start", "-r"] diff --git a/dhparam.pem.default b/dhparam.pem.default new file mode 100644 index 0000000..8548c34 --- /dev/null +++ b/dhparam.pem.default @@ -0,0 +1,8 @@ +-----BEGIN DH PARAMETERS----- +MIIBCAKCAQEAzB2nIGzpVq7afJnKBm1X0d64avwOlP2oneiKwxRHdDI/5+6TpH1P +F8ipodGuZBUMmupoB3D34pu2Qq5boNW983sm18ww9LMz2i/pxhSdB+mYAew+A6h6 +ltQ5pNtyn4NaKw1SDFkqvde3GNPhaWoPDbZDJhpHGblR3w1b/ag+lTLZUvVwcD8L +jYS9f9YWAC6T7WxAxh4zvu1Z0I1EKde8KYBxrreZNheXpXHqMNyJYZCaY2Hb/4oI +EL65qZq1GCWezpWMjhk6pOnV5gbvqfhoazCv/4OdRv6RoWOIYBNs9BmGho4AtXqV +FYLdYDhOvN4aVs9Ir+G8ouwiRnix24+UewIBAg== +-----END DH PARAMETERS----- diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh index 6353314..f43a127 100755 --- a/docker-entrypoint.sh +++ b/docker-entrypoint.sh @@ -2,7 +2,7 @@ set -e # Warn if the DOCKER_HOST socket does not exist -if [[ $DOCKER_HOST == unix://* ]]; then +if [[ $DOCKER_HOST = unix://* ]]; then socket_file=${DOCKER_HOST#unix://} if ! [ -S $socket_file ]; then cat >&2 <<-EOT @@ -14,6 +14,9 @@ if [[ $DOCKER_HOST == unix://* ]]; then fi fi +# Generate dhparam file if required +/app/generate-dhparam.sh + # If the user has run the default command and the socket doesn't exist, fail if [ "$socketMissing" = 1 -a "$1" = forego -a "$2" = start -a "$3" = '-r' ]; then exit 1 diff --git a/generate-dhparam.sh b/generate-dhparam.sh new file mode 100755 index 0000000..ed010b7 --- /dev/null +++ b/generate-dhparam.sh @@ -0,0 +1,42 @@ +#!/bin/bash -e + +# 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. +PREGEN_DHPARAM_FILE="/app/dhparam.pem.default" +DHPARAM_FILE="/etc/nginx/dhparam/dhparam.pem" +DHPARAM_BITS="2048" +GEN_LOCKFILE="/tmp/dhparam_generating.lock" + +# The hash of the pregenerated dhparam file is used to check if the pregen dhparam is already in use +PREGEN_HASH=$(md5sum $PREGEN_DHPARAM_FILE | cut -d" " -f1) +if [[ -f $DHPARAM_FILE ]]; then + CURRENT_HASH=$(md5sum $DHPARAM_FILE | cut -d" " -f1) + if [[ $PREGEN_HASH != $CURRENT_HASH ]]; then + # There is already a dhparam, and it's not the default + exit 0 + fi + + if [[ -f $GEN_LOCKFILE ]]; then + # Generation is already in progress + exit 0 + fi +fi + +cat >&2 <<-EOT +WARNING: $DHPARAM_FILE was not found. A pregenerated 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. +EOT + +# Put the default dhparam file in place so we can start immediately +cp $PREGEN_DHPARAM_FILE $DHPARAM_FILE +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 \ + && echo "dhparam generation complete, reloading nginx" \ + && nginx -s reload + ) | grep -vE '^[\.+]+' + rm $GEN_LOCKFILE +) & diff --git a/nginx.tmpl b/nginx.tmpl index b99fa23..4f39ab2 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -42,7 +42,7 @@ map $http_upgrade $proxy_connection { server_names_hash_bucket_size 128; # Default dhparam -ssl_dhparam /etc/nginx/dhparam.pem; +ssl_dhparam /etc/nginx/dhparam/dhparam.pem; # Set appropriate X-Forwarded-Ssl header map $scheme $proxy_x_forwarded_ssl { From ebfe5e9c17b76d671a03ac6ef1b1ab17797c6954 Mon Sep 17 00:00:00 2001 From: Steve Kamerman Date: Wed, 11 Jan 2017 22:49:55 -0500 Subject: [PATCH 10/76] Added note about background generation --- README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index b3e1702..e7d3f5f 100644 --- a/README.md +++ b/README.md @@ -151,12 +151,17 @@ By default, Docker is not able to mount directories on the host machine to conta #### Diffie-Hellman Groups -Diffie-Hellman groups are enabled by default, with a pregenerated key in `/etc/nginx/dhparam.pem`. +Diffie-Hellman groups are enabled by default, with a pregenerated key in `/etc/nginx/dhparam/dhparam.pem`. You can mount a different `dhparam.pem` file at that location to override the default cert. To use custom `dhparam.pem` files per-virtual-host, the files should be named after the virtual host with a `dhparam` suffix and `.pem` extension. For example, a container with `VIRTUAL_HOST=foo.bar.com` should have a `foo.bar.com.dhparam.pem` file in the `/etc/nginx/certs` directory. +> NOTE: If you don't mount a `dhparam.pem` file at `/etc/nginx/dhparam/dhparam.pem`, one will be generated +at startup. Since it can take minutes to generate a new `dhparam.pem`, it is done at low priority in the +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`. + #### Wildcard Certificates Wildcard certificates and keys should be named after the domain name with a `.crt` and `.key` extension. From 6242403d33982f927ad72c28e84221864fba823e Mon Sep 17 00:00:00 2001 From: Steve Kamerman Date: Wed, 11 Jan 2017 23:04:24 -0500 Subject: [PATCH 11/76] Added dhparam support for alpine variant --- Dockerfile.alpine | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile.alpine b/Dockerfile.alpine index 4ce9561..ef43306 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -25,7 +25,7 @@ WORKDIR /app/ ENV DOCKER_HOST unix:///tmp/docker.sock -VOLUME ["/etc/nginx/certs"] +VOLUME ["/etc/nginx/certs", "/etc/nginx/dhparam"] ENTRYPOINT ["/app/docker-entrypoint.sh"] CMD ["forego", "start", "-r"] From 7c0f7b944911d81cfe587de8e4ee53cac9ffdb2a Mon Sep 17 00:00:00 2001 From: Steve Kamerman Date: Thu, 12 Jan 2017 00:21:39 -0500 Subject: [PATCH 12/76] Fixed Alpine image, removed dhparams gen from test units --- Dockerfile.alpine | 5 ++--- generate-dhparam.sh | 2 +- test/lib/ssl/dhparam.pem | 8 ++++++++ test/test_helpers.bash | 1 + 4 files changed, 12 insertions(+), 4 deletions(-) create mode 100644 test/lib/ssl/dhparam.pem diff --git a/Dockerfile.alpine b/Dockerfile.alpine index ef43306..3d03cf3 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -3,12 +3,11 @@ MAINTAINER Jason Wilder mail@jasonwilder.com # Install wget and install/updates certificates RUN apk add --no-cache --virtual .run-deps \ - ca-certificates bash wget \ + ca-certificates bash wget openssl \ && update-ca-certificates # Configure Nginx and apply fix for very long server names -RUN echo "daemon off;" >> /etc/nginx/nginx.conf \ - && sed -i 's/^http {/&\n server_names_hash_bucket_size 128;/g' /etc/nginx/nginx.conf +RUN echo "daemon off;" >> /etc/nginx/nginx.conf # Install Forego ADD https://github.com/jwilder/forego/releases/download/v0.16.1/forego /usr/local/bin/forego diff --git a/generate-dhparam.sh b/generate-dhparam.sh index ed010b7..36c4f8b 100755 --- a/generate-dhparam.sh +++ b/generate-dhparam.sh @@ -39,4 +39,4 @@ touch $GEN_LOCKFILE && nginx -s reload ) | grep -vE '^[\.+]+' rm $GEN_LOCKFILE -) & +) &disown diff --git a/test/lib/ssl/dhparam.pem b/test/lib/ssl/dhparam.pem new file mode 100644 index 0000000..eb3218c --- /dev/null +++ b/test/lib/ssl/dhparam.pem @@ -0,0 +1,8 @@ +-----BEGIN DH PARAMETERS----- +MIIBCAKCAQEA1cae6HqPSgicEuAuSCf6Ii3d6qMX9Ta8lnwoX0JQ0CWK7mzaiiIi +dY7oHmc4cq0S3SH+g0tdLP9yqygFS9hdUGINwS2VV6poj2/vdL/dUshegyxpEH58 +nofCPnFDeKkcPDMYAlGS8zjp60TsBkRJKcrxxwnjod1Q5mWuMN5KH3sxs842udKH +0nHFE9kKW/NfXb+EGsjpocGpf786cGuCO2d00THsoItOEcM9/aI8DX1QcyxAHR6D +HaYTFJnyyx8Q44u27M15idI4pbNoKORlotiuOwCTGYCfbN14aOV+Ict7aSF8FWpP +48j9SMNuIu2DlF9pNLo6fsrOjYY3c9X12wIBAg== +-----END DH PARAMETERS----- diff --git a/test/test_helpers.bash b/test/test_helpers.bash index 0fd9532..422df24 100644 --- a/test/test_helpers.bash +++ b/test/test_helpers.bash @@ -35,6 +35,7 @@ function nginxproxy { && docker run -d \ --label bats-type="nginx-proxy" \ --name $container_name \ + -v $DIR/lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro \ "$@" \ $SUT_IMAGE \ && wait_for_nginxproxy_container_to_start $container_name \ From f73a52afaf2fa4b26168827ed082dcf275633564 Mon Sep 17 00:00:00 2001 From: Steve Kamerman Date: Thu, 12 Jan 2017 01:45:46 -0500 Subject: [PATCH 13/76] Added BATS tests for dhparam generation --- test/ssl.bats | 9 ++--- test/ssl_dhparam.bats | 85 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+), 5 deletions(-) create mode 100644 test/ssl_dhparam.bats diff --git a/test/ssl.bats b/test/ssl.bats index e7e0eae..7ae8a78 100644 --- a/test/ssl.bats +++ b/test/ssl.bats @@ -61,13 +61,13 @@ function setup { prepare_web_container bats-ssl-hosts-4 "80 443" \ -e VIRTUAL_HOST=*.nginx-proxy.bats \ -e CERT_NAME=nginx-proxy.bats - dockergen_wait_for_event $SUT_CONTAINER start bats-ssl-hosts-1 + dockergen_wait_for_event $SUT_CONTAINER start bats-ssl-hosts-4 sleep 1 # THEN assert_301 test.nginx-proxy.bats assert_200_https test.nginx-proxy.bats - assert_output -p "Strict-Transport-Security: max-age=31536000" + assert_output -p "Strict-Transport-Security: max-age=31536000" } @test "[$TEST_FILE] test HTTPS_METHOD=noredirect disables Strict-Transport-Security" { @@ -76,16 +76,15 @@ function setup { -e VIRTUAL_HOST=*.nginx-proxy.bats \ -e CERT_NAME=nginx-proxy.bats \ -e HTTPS_METHOD=noredirect - dockergen_wait_for_event $SUT_CONTAINER start bats-ssl-hosts-3 + dockergen_wait_for_event $SUT_CONTAINER start bats-ssl-hosts-5 sleep 1 # THEN assert_200 test.nginx-proxy.bats assert_200_https test.nginx-proxy.bats - refute_output -p "Strict-Transport-Security: max-age=31536000" + refute_output -p "Strict-Transport-Security: max-age=31536000" } - @test "[$TEST_FILE] stop all bats containers" { stop_bats_containers } diff --git a/test/ssl_dhparam.bats b/test/ssl_dhparam.bats new file mode 100644 index 0000000..0490a29 --- /dev/null +++ b/test/ssl_dhparam.bats @@ -0,0 +1,85 @@ +#!/usr/bin/env bats +load test_helpers + +function setup { + # make sure to stop any web container before each test so we don't + # have any unexpected contaiener running with VIRTUAL_HOST or VIRUTAL_PORT set + stop_bats_containers web +} + +@test "[$TEST_FILE] test dhparam.pem is generated if missing (WARNING: this test is slow!):" { + SUT_CONTAINER=bats-nginx-proxy-${TEST_FILE}-1 + + # WHEN + run docker_clean $SUT_CONTAINER \ + && docker run -d \ + --label bats-type="nginx-proxy" \ + --name $SUT_CONTAINER \ + -v /var/run/docker.sock:/tmp/docker.sock:ro \ + $SUT_IMAGE \ + && wait_for_nginxproxy_container_to_start $SUT_CONTAINER \ + && docker logs $SUT_CONTAINER + + assert_success + docker_wait_for_log $SUT_CONTAINER 9 "Watching docker events" + + # THEN + run docker exec $SUT_CONTAINER ps aux + assert_output -p "openssl" + + DEFAULT_HASH=$(docker exec $SUT_CONTAINER md5sum /etc/nginx/dhparam/dhparam.pem | cut -d" " -f1) + docker_wait_for_log $SUT_CONTAINER 240 "dhparam generation complete, reloading nginx" + + run docker exec $SUT_CONTAINER md5sum /etc/nginx/dhparam/dhparam.pem + refute_output -p $DEFAULT_HASH +} + +@test "[$TEST_FILE] test dhparam.pem is generated if default one is present" { + SUT_CONTAINER=bats-nginx-proxy-${TEST_FILE}-2 + + # Copy the default dhparams to a volume and mount it in to ensure it's regenerated + TMP_DIR=/tmp/nginx-proxy-bats + if [ ! -d $TMP_DIR ]; then + mkdir $TMP_DIR + fi + cp $DIR/../dhparam.pem.default $TMP_DIR/dhparam.pem + + # WHEN + run docker_clean $SUT_CONTAINER \ + && docker run -d \ + --label bats-type="nginx-proxy" \ + --name $SUT_CONTAINER \ + -v /var/run/docker.sock:/tmp/docker.sock:ro \ + -v $TMP_DIR:/etc/nginx/dhparam \ + $SUT_IMAGE \ + && wait_for_nginxproxy_container_to_start $SUT_CONTAINER \ + && docker logs $SUT_CONTAINER + + docker logs $SUT_CONTAINER + + assert_success + docker_wait_for_log $SUT_CONTAINER 9 "Watching docker events" + + # THEN + run docker exec $SUT_CONTAINER ps aux + assert_output -p "openssl" + + docker exec $SUT_CONTAINER rm -rf /etc/nginx/dhparam/* +} + +@test "[$TEST_FILE] test dhparam.pem is not generated if custom one is present" { + SUT_CONTAINER=bats-nginx-proxy-${TEST_FILE}-3 + + # WHEN + run nginxproxy $SUT_CONTAINER -v /var/run/docker.sock:/tmp/docker.sock:ro + assert_success + docker_wait_for_log $SUT_CONTAINER 9 "Watching docker events" + + # THEN + run docker exec $SUT_CONTAINER ps aux + refute_output -p "openssl" +} + +@test "[$TEST_FILE] stop all bats containers" { + stop_bats_containers +} From c219822cd89b1f53d3e62a19b0106ac9ffaedefc Mon Sep 17 00:00:00 2001 From: Steve Kamerman Date: Thu, 12 Jan 2017 01:53:36 -0500 Subject: [PATCH 14/76] Typos --- generate-dhparam.sh | 2 +- test/ssl_dhparam.bats | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/generate-dhparam.sh b/generate-dhparam.sh index 36c4f8b..0097754 100755 --- a/generate-dhparam.sh +++ b/generate-dhparam.sh @@ -23,7 +23,7 @@ if [[ -f $DHPARAM_FILE ]]; then fi cat >&2 <<-EOT -WARNING: $DHPARAM_FILE was not found. A pregenerated dhparam.pem will be used for now while a new one +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. EOT diff --git a/test/ssl_dhparam.bats b/test/ssl_dhparam.bats index 0490a29..67fddb5 100644 --- a/test/ssl_dhparam.bats +++ b/test/ssl_dhparam.bats @@ -7,7 +7,7 @@ function setup { stop_bats_containers web } -@test "[$TEST_FILE] test dhparam.pem is generated if missing (WARNING: this test is slow!):" { +@test "[$TEST_FILE] test dhparam.pem is generated if missing (WARNING: this test is slow)" { SUT_CONTAINER=bats-nginx-proxy-${TEST_FILE}-1 # WHEN From dffc0c47cf15623376e5744e7feca9f7edd2f1d5 Mon Sep 17 00:00:00 2001 From: Steve Kamerman Date: Thu, 12 Jan 2017 10:52:56 -0500 Subject: [PATCH 15/76] Tweak test for reliability on Travis-CI --- test/ssl_dhparam.bats | 52 +++++++++++++++++++++---------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/test/ssl_dhparam.bats b/test/ssl_dhparam.bats index 67fddb5..c5470a6 100644 --- a/test/ssl_dhparam.bats +++ b/test/ssl_dhparam.bats @@ -8,30 +8,28 @@ function setup { } @test "[$TEST_FILE] test dhparam.pem is generated if missing (WARNING: this test is slow)" { - SUT_CONTAINER=bats-nginx-proxy-${TEST_FILE}-1 + SUT_CONTAINER=bats-nginx-proxy-${TEST_FILE}-1 - # WHEN - run docker_clean $SUT_CONTAINER \ - && docker run -d \ - --label bats-type="nginx-proxy" \ - --name $SUT_CONTAINER \ - -v /var/run/docker.sock:/tmp/docker.sock:ro \ - $SUT_IMAGE \ - && wait_for_nginxproxy_container_to_start $SUT_CONTAINER \ - && docker logs $SUT_CONTAINER + # WHEN + run docker_clean $SUT_CONTAINER \ + && docker run -d \ + --label bats-type="nginx-proxy" \ + --name $SUT_CONTAINER \ + -v /var/run/docker.sock:/tmp/docker.sock:ro \ + $SUT_IMAGE \ + && wait_for_nginxproxy_container_to_start $SUT_CONTAINER \ + && docker logs $SUT_CONTAINER - assert_success - docker_wait_for_log $SUT_CONTAINER 9 "Watching docker events" + DEFAULT_HASH=$(docker exec $SUT_CONTAINER md5sum /etc/nginx/dhparam/dhparam.pem | cut -d" " -f1) - # THEN - run docker exec $SUT_CONTAINER ps aux - assert_output -p "openssl" + assert_success + docker_wait_for_log $SUT_CONTAINER 9 "Generating DH parameters" - DEFAULT_HASH=$(docker exec $SUT_CONTAINER md5sum /etc/nginx/dhparam/dhparam.pem | cut -d" " -f1) - docker_wait_for_log $SUT_CONTAINER 240 "dhparam generation complete, reloading nginx" + # THEN + docker_wait_for_log $SUT_CONTAINER 240 "dhparam generation complete, reloading nginx" - run docker exec $SUT_CONTAINER md5sum /etc/nginx/dhparam/dhparam.pem - refute_output -p $DEFAULT_HASH + run docker exec $SUT_CONTAINER md5sum /etc/nginx/dhparam/dhparam.pem + refute_output -p $DEFAULT_HASH } @test "[$TEST_FILE] test dhparam.pem is generated if default one is present" { @@ -42,6 +40,13 @@ function setup { if [ ! -d $TMP_DIR ]; then mkdir $TMP_DIR fi + + # If the previous test crashed, a dhparam is left that only root can delete, so we + # delete it from within a container as root + if [ -f $TMP_DIR/dhparam.pem ]; then + docker run --rm -v $TMP_DIR:/opt busybox rm /opt/dhparam.pem + fi + cp $DIR/../dhparam.pem.default $TMP_DIR/dhparam.pem # WHEN @@ -55,14 +60,9 @@ function setup { && wait_for_nginxproxy_container_to_start $SUT_CONTAINER \ && docker logs $SUT_CONTAINER - docker logs $SUT_CONTAINER - - assert_success - docker_wait_for_log $SUT_CONTAINER 9 "Watching docker events" - # THEN - run docker exec $SUT_CONTAINER ps aux - assert_output -p "openssl" + assert_success + docker_wait_for_log $SUT_CONTAINER 9 "Generating DH parameters" docker exec $SUT_CONTAINER rm -rf /etc/nginx/dhparam/* } From 7d253dd0f37ca99ef81fcd8bf86fd6b24c02d2c6 Mon Sep 17 00:00:00 2001 From: Steve Kamerman Date: Thu, 12 Jan 2017 14:55:25 -0500 Subject: [PATCH 16/76] Allow passing DHPARAM_BITS via env, lower bits to 256 for unit tests --- docker-entrypoint.sh | 3 ++- generate-dhparam.sh | 4 +++- test/ssl_dhparam.bats | 8 +++++--- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh index f43a127..a413877 100755 --- a/docker-entrypoint.sh +++ b/docker-entrypoint.sh @@ -15,7 +15,8 @@ if [[ $DOCKER_HOST = unix://* ]]; then fi # Generate dhparam file if required -/app/generate-dhparam.sh +# Note: if $DHPARAM_BITS is not defined, generate-dhparam.sh will use 2048 as a default +/app/generate-dhparam.sh $DHPARAM_BITS # If the user has run the default command and the socket doesn't exist, fail if [ "$socketMissing" = 1 -a "$1" = forego -a "$2" = start -a "$3" = '-r' ]; then diff --git a/generate-dhparam.sh b/generate-dhparam.sh index 0097754..9f5d4ff 100755 --- a/generate-dhparam.sh +++ b/generate-dhparam.sh @@ -1,10 +1,12 @@ #!/bin/bash -e +# The first argument is the bit depth of the dhparam, or 2048 if unspecified +DHPARAM_BITS=${1:-2048} + # 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. PREGEN_DHPARAM_FILE="/app/dhparam.pem.default" DHPARAM_FILE="/etc/nginx/dhparam/dhparam.pem" -DHPARAM_BITS="2048" GEN_LOCKFILE="/tmp/dhparam_generating.lock" # The hash of the pregenerated dhparam file is used to check if the pregen dhparam is already in use diff --git a/test/ssl_dhparam.bats b/test/ssl_dhparam.bats index c5470a6..c193c5c 100644 --- a/test/ssl_dhparam.bats +++ b/test/ssl_dhparam.bats @@ -7,7 +7,7 @@ function setup { stop_bats_containers web } -@test "[$TEST_FILE] test dhparam.pem is generated if missing (WARNING: this test is slow)" { +@test "[$TEST_FILE] test dhparam.pem is generated if missing" { SUT_CONTAINER=bats-nginx-proxy-${TEST_FILE}-1 # WHEN @@ -16,6 +16,7 @@ function setup { --label bats-type="nginx-proxy" \ --name $SUT_CONTAINER \ -v /var/run/docker.sock:/tmp/docker.sock:ro \ + -e DHPARAM=256 \ $SUT_IMAGE \ && wait_for_nginxproxy_container_to_start $SUT_CONTAINER \ && docker logs $SUT_CONTAINER @@ -23,7 +24,7 @@ function setup { DEFAULT_HASH=$(docker exec $SUT_CONTAINER md5sum /etc/nginx/dhparam/dhparam.pem | cut -d" " -f1) assert_success - docker_wait_for_log $SUT_CONTAINER 9 "Generating DH parameters" + docker_wait_for_log $SUT_CONTAINER 30 "Generating DH parameters" # THEN docker_wait_for_log $SUT_CONTAINER 240 "dhparam generation complete, reloading nginx" @@ -56,13 +57,14 @@ function setup { --name $SUT_CONTAINER \ -v /var/run/docker.sock:/tmp/docker.sock:ro \ -v $TMP_DIR:/etc/nginx/dhparam \ + -e DHPARAM=256 \ $SUT_IMAGE \ && wait_for_nginxproxy_container_to_start $SUT_CONTAINER \ && docker logs $SUT_CONTAINER # THEN assert_success - docker_wait_for_log $SUT_CONTAINER 9 "Generating DH parameters" + docker_wait_for_log $SUT_CONTAINER 30 "Generating DH parameters" docker exec $SUT_CONTAINER rm -rf /etc/nginx/dhparam/* } From b0de1f19d3d551af9304eb86720eb94233406e38 Mon Sep 17 00:00:00 2001 From: Steve Kamerman Date: Thu, 12 Jan 2017 17:25:31 -0500 Subject: [PATCH 17/76] Updated to use 256-bit dhparam in tests --- test/ssl_dhparam.bats | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/test/ssl_dhparam.bats b/test/ssl_dhparam.bats index c193c5c..2d16595 100644 --- a/test/ssl_dhparam.bats +++ b/test/ssl_dhparam.bats @@ -16,12 +16,12 @@ function setup { --label bats-type="nginx-proxy" \ --name $SUT_CONTAINER \ -v /var/run/docker.sock:/tmp/docker.sock:ro \ - -e DHPARAM=256 \ + -e DHPARAM_BITS=256 \ $SUT_IMAGE \ && wait_for_nginxproxy_container_to_start $SUT_CONTAINER \ && docker logs $SUT_CONTAINER - DEFAULT_HASH=$(docker exec $SUT_CONTAINER md5sum /etc/nginx/dhparam/dhparam.pem | cut -d" " -f1) + DEFAULT_HASH=$(docker exec $SUT_CONTAINER md5sum /app/dhparam.pem.default | cut -d" " -f1) assert_success docker_wait_for_log $SUT_CONTAINER 30 "Generating DH parameters" @@ -29,7 +29,8 @@ function setup { # THEN docker_wait_for_log $SUT_CONTAINER 240 "dhparam generation complete, reloading nginx" - run docker exec $SUT_CONTAINER md5sum /etc/nginx/dhparam/dhparam.pem + run docker exec $SUT_CONTAINER su -c "md5sum /etc/nginx/dhparam/dhparam.pem" + refute_output -p $DEFAULT_HASH } @@ -57,7 +58,7 @@ function setup { --name $SUT_CONTAINER \ -v /var/run/docker.sock:/tmp/docker.sock:ro \ -v $TMP_DIR:/etc/nginx/dhparam \ - -e DHPARAM=256 \ + -e DHPARAM_BITS=256 \ $SUT_IMAGE \ && wait_for_nginxproxy_container_to_start $SUT_CONTAINER \ && docker logs $SUT_CONTAINER From 83a28f47d77ffa90b99116682d10450dc9808e18 Mon Sep 17 00:00:00 2001 From: Steve Kamerman Date: Thu, 12 Jan 2017 17:43:13 -0500 Subject: [PATCH 18/76] Fixed long server name comment, improved dhparam check --- Dockerfile.alpine | 2 +- test/ssl_dhparam.bats | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Dockerfile.alpine b/Dockerfile.alpine index 3d03cf3..25485d8 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -6,7 +6,7 @@ RUN apk add --no-cache --virtual .run-deps \ ca-certificates bash wget openssl \ && update-ca-certificates -# Configure Nginx and apply fix for very long server names +# Configure Nginx RUN echo "daemon off;" >> /etc/nginx/nginx.conf # Install Forego diff --git a/test/ssl_dhparam.bats b/test/ssl_dhparam.bats index 2d16595..2ca8a08 100644 --- a/test/ssl_dhparam.bats +++ b/test/ssl_dhparam.bats @@ -78,9 +78,11 @@ function setup { assert_success docker_wait_for_log $SUT_CONTAINER 9 "Watching docker events" + sleep 3 + run docker logs $SUT_CONTAINER + # THEN - run docker exec $SUT_CONTAINER ps aux - refute_output -p "openssl" + refute_output -p "Generating DH parameters" } @test "[$TEST_FILE] stop all bats containers" { From 0244b4e71e4ca9bbd70a85d34bd4d0eb8fadffdf Mon Sep 17 00:00:00 2001 From: Steve Kamerman Date: Tue, 7 Mar 2017 14:04:37 -0500 Subject: [PATCH 19/76] Added dhparams test in new format --- test/test_ssl/test_dhparam.py | 74 +++++++++++++++++++++++ test/test_ssl/test_dhparam.yml | 16 +++++ test/test_ssl/test_dhparam_generation.py | 54 +++++++++++++++++ test/test_ssl/test_dhparam_generation.yml | 7 +++ 4 files changed, 151 insertions(+) create mode 100644 test/test_ssl/test_dhparam.py create mode 100644 test/test_ssl/test_dhparam.yml create mode 100644 test/test_ssl/test_dhparam_generation.py create mode 100644 test/test_ssl/test_dhparam_generation.yml diff --git a/test/test_ssl/test_dhparam.py b/test/test_ssl/test_dhparam.py new file mode 100644 index 0000000..109432a --- /dev/null +++ b/test/test_ssl/test_dhparam.py @@ -0,0 +1,74 @@ +import pytest +import os +import docker +import time +import subprocess +import re + +docker_client = docker.from_env() + +def wait_for_nginxproxy_to_be_ready(): + """ + If one (and only one) container started from image jwilder/nginx-proxy:test is found, + wait for its log to contain substring "Watching docker events" + """ + containers = docker_client.containers.list(filters={"ancestor": "jwilder/nginx-proxy:test"}) + if len(containers) != 1: + return + container = containers[0] + for line in container.logs(stream=True): + if "Watching docker events" in line: + break + +def test_dhparam_is_not_generated_if_present(docker_compose, nginxproxy): + wait_for_nginxproxy_to_be_ready() + + containers = docker_client.containers.list(filters={"ancestor": "jwilder/nginx-proxy:test"}) + if len(containers) != 1: + assert 0 + return + + sut_container = containers[0] + + docker_logs = sut_container.logs(stdout=True, stderr=True, stream=False, follow=False) + + assert "Custom dhparam.pem file found, generation skipped" in docker_logs + + # Make sure the dhparam in use is not the default, pre-generated one + default_checksum = sut_container.exec_run("md5sum /app/dhparam.pem.default").split() + current_checksum = sut_container.exec_run("md5sum /etc/nginx/dhparam/dhparam.pem").split() + assert default_checksum[0] != current_checksum[0] + +def test_web5_https_works(docker_compose, nginxproxy): + r = nginxproxy.get("https://web5.nginx-proxy.tld/port", allow_redirects=False) + assert r.status_code == 200 + assert "answer from port 85\n" in r.text + +def versiontuple(v): + clean_v = re.sub("[^\d\.]", "", v) + return tuple(map(int, (clean_v.split(".")))) + + +# This code checks that the required version of OpenSSL is present, and skips the test if not +openssl_version_required = "1.0.2" +openssl_version = "0.0.0" + +try: + openssl_version = subprocess.check_output(["openssl", "version"]).split()[1] +except: + pass + +@pytest.mark.skipif(versiontuple(openssl_version) < versiontuple(openssl_version_required), + reason="openssl command is not available in test environment or is less than version %s" % openssl_version_required) + +def test_web5_dhparam_is_used(docker_compose, nginxproxy): + containers = docker_client.containers.list(filters={"ancestor": "jwilder/nginx-proxy:test"}) + if len(containers) != 1: + assert 0 + return + + sut_container = containers[0] + + host = "%s:443" % sut_container.attrs["NetworkSettings"]["IPAddress"] + r = subprocess.check_output("echo '' | openssl s_client -verify 0 -connect %s -cipher 'EDH' | grep 'Server Temp Key'" % host, shell=True) + assert "Server Temp Key: DH, 2048 bits" in r diff --git a/test/test_ssl/test_dhparam.yml b/test/test_ssl/test_dhparam.yml new file mode 100644 index 0000000..6e196b0 --- /dev/null +++ b/test/test_ssl/test_dhparam.yml @@ -0,0 +1,16 @@ +web5: + image: web + expose: + - "85" + environment: + WEB_PORTS: "85" + VIRTUAL_HOST: "web5.nginx-proxy.tld" + HTTPS_METHOD: nohttp + + +sut: + image: jwilder/nginx-proxy:test + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro + - ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro + - ./certs:/etc/nginx/certs:ro diff --git a/test/test_ssl/test_dhparam_generation.py b/test/test_ssl/test_dhparam_generation.py new file mode 100644 index 0000000..87e71f1 --- /dev/null +++ b/test/test_ssl/test_dhparam_generation.py @@ -0,0 +1,54 @@ +import pytest +import os +import docker +import time + +docker_client = docker.from_env() + +def wait_for_nginxproxy_to_be_ready(): + """ + If one (and only one) container started from image jwilder/nginx-proxy:test is found, + wait for its log to contain substring "Watching docker events" + """ + containers = docker_client.containers.list(filters={"ancestor": "jwilder/nginx-proxy:test"}) + if len(containers) != 1: + return + container = containers[0] + for line in container.logs(stream=True): + if "Watching docker events" in line: + break + +def test_dhparam_is_generated_if_missing(docker_compose, nginxproxy): + wait_for_nginxproxy_to_be_ready() + + containers = docker_client.containers.list(filters={"ancestor": "jwilder/nginx-proxy:test"}) + if len(containers) != 1: + assert 0 + return + + sut_container = containers[0] + + docker_logs = sut_container.logs(stdout=True, stderr=True, stream=False, follow=False) + + assert "Generating DH parameters" in docker_logs + + expected_line = "dhparam generation complete, reloading nginx" + max_wait = 30 + sleep_interval = 2 + current_wait = 0 + + while current_wait < max_wait: + docker_logs = sut_container.logs(stdout=True, stderr=True, stream=False, follow=False) + if expected_line in docker_logs: + break + + time.sleep(sleep_interval) + current_wait += sleep_interval + + # Re-check the logs to get better assert output on failure + assert expected_line in docker_logs + + # Make sure the dhparam in use is not the default, pre-generated one + default_checksum = sut_container.exec_run("md5sum /app/dhparam.pem.default").split() + generated_checksum = sut_container.exec_run("md5sum /etc/nginx/dhparam/dhparam.pem").split() + assert default_checksum[0] != generated_checksum[0] diff --git a/test/test_ssl/test_dhparam_generation.yml b/test/test_ssl/test_dhparam_generation.yml new file mode 100644 index 0000000..f55cb95 --- /dev/null +++ b/test/test_ssl/test_dhparam_generation.yml @@ -0,0 +1,7 @@ +sut: + image: jwilder/nginx-proxy:test + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro + - ./certs:/etc/nginx/certs:ro + environment: + - DHPARAM_BITS=256 From 98b5828f837522e412ee6f2c341d5f31f1e65c35 Mon Sep 17 00:00:00 2001 From: Steve Kamerman Date: Tue, 7 Mar 2017 14:04:44 -0500 Subject: [PATCH 20/76] Modified tests to include dhparams --- .gitignore | 1 + generate-dhparam.sh | 1 + .../Dockerfile-nginx-proxy-tester | 7 +- test/ssl_dhparam.bats | 90 ------------------- test/test_DOCKER_HOST_unix_socket.yml | 6 +- test/test_composev2.yml | 5 +- test/test_custom/test_defaults-location.yml | 9 +- test/test_custom/test_defaults.yml | 7 +- test/test_custom/test_location-per-vhost.yml | 7 +- test/test_custom/test_per-vhost.yml | 7 +- test/test_custom/test_proxy-wide.yml | 7 +- test/test_default-host.yml | 1 + test/test_dockergen/test_dockergen_v2.yml | 3 +- test/test_dockergen/test_dockergen_v3.py | 5 +- test/test_dockergen/test_dockergen_v3.yml | 3 +- test/test_events.yml | 1 + test/test_headers/test_http.yml | 3 +- test/test_headers/test_https.yml | 1 + test/test_ipv6.yml | 5 +- test/test_multiple-hosts.yml | 1 + test/test_multiple-networks.yml | 7 +- .../test_multiple-ports/test_VIRTUAL_PORT.yml | 1 + test/test_multiple-ports/test_default-80.yml | 1 + .../test_single-port-not-80.yml | 3 +- test/test_nominal.yml | 5 +- test/test_ssl/test_nohttp.yml | 1 + test/test_ssl/test_nohttps.yml | 3 +- test/test_ssl/test_noredirect.yml | 1 + test/test_ssl/test_wildcard.yml | 1 + test/test_wildcard_host.yml | 3 +- 30 files changed, 69 insertions(+), 127 deletions(-) delete mode 100644 test/ssl_dhparam.bats diff --git a/.gitignore b/.gitignore index 0b3700d..5daab4f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ **/__pycache__/ **/.cache/ +.idea/ diff --git a/generate-dhparam.sh b/generate-dhparam.sh index 9f5d4ff..3fdc77c 100755 --- a/generate-dhparam.sh +++ b/generate-dhparam.sh @@ -15,6 +15,7 @@ if [[ -f $DHPARAM_FILE ]]; then CURRENT_HASH=$(md5sum $DHPARAM_FILE | cut -d" " -f1) if [[ $PREGEN_HASH != $CURRENT_HASH ]]; then # There is already a dhparam, and it's not the default + echo "Custom dhparam.pem file found, generation skipped" exit 0 fi diff --git a/test/requirements/Dockerfile-nginx-proxy-tester b/test/requirements/Dockerfile-nginx-proxy-tester index b403ed7..27d0538 100644 --- a/test/requirements/Dockerfile-nginx-proxy-tester +++ b/test/requirements/Dockerfile-nginx-proxy-tester @@ -1,5 +1,10 @@ -FROM python:2.7 +FROM python:2.7-alpine + +# Note: we're using alpine because it has openssl 1.0.2, which we need for testing +RUN apk add --update bash openssl curl && rm -rf /var/cache/apk/* + COPY python-requirements.txt /requirements.txt RUN pip install -r /requirements.txt + WORKDIR /test ENTRYPOINT ["pytest"] diff --git a/test/ssl_dhparam.bats b/test/ssl_dhparam.bats deleted file mode 100644 index 2ca8a08..0000000 --- a/test/ssl_dhparam.bats +++ /dev/null @@ -1,90 +0,0 @@ -#!/usr/bin/env bats -load test_helpers - -function setup { - # make sure to stop any web container before each test so we don't - # have any unexpected contaiener running with VIRTUAL_HOST or VIRUTAL_PORT set - stop_bats_containers web -} - -@test "[$TEST_FILE] test dhparam.pem is generated if missing" { - SUT_CONTAINER=bats-nginx-proxy-${TEST_FILE}-1 - - # WHEN - run docker_clean $SUT_CONTAINER \ - && docker run -d \ - --label bats-type="nginx-proxy" \ - --name $SUT_CONTAINER \ - -v /var/run/docker.sock:/tmp/docker.sock:ro \ - -e DHPARAM_BITS=256 \ - $SUT_IMAGE \ - && wait_for_nginxproxy_container_to_start $SUT_CONTAINER \ - && docker logs $SUT_CONTAINER - - DEFAULT_HASH=$(docker exec $SUT_CONTAINER md5sum /app/dhparam.pem.default | cut -d" " -f1) - - assert_success - docker_wait_for_log $SUT_CONTAINER 30 "Generating DH parameters" - - # THEN - docker_wait_for_log $SUT_CONTAINER 240 "dhparam generation complete, reloading nginx" - - run docker exec $SUT_CONTAINER su -c "md5sum /etc/nginx/dhparam/dhparam.pem" - - refute_output -p $DEFAULT_HASH -} - -@test "[$TEST_FILE] test dhparam.pem is generated if default one is present" { - SUT_CONTAINER=bats-nginx-proxy-${TEST_FILE}-2 - - # Copy the default dhparams to a volume and mount it in to ensure it's regenerated - TMP_DIR=/tmp/nginx-proxy-bats - if [ ! -d $TMP_DIR ]; then - mkdir $TMP_DIR - fi - - # If the previous test crashed, a dhparam is left that only root can delete, so we - # delete it from within a container as root - if [ -f $TMP_DIR/dhparam.pem ]; then - docker run --rm -v $TMP_DIR:/opt busybox rm /opt/dhparam.pem - fi - - cp $DIR/../dhparam.pem.default $TMP_DIR/dhparam.pem - - # WHEN - run docker_clean $SUT_CONTAINER \ - && docker run -d \ - --label bats-type="nginx-proxy" \ - --name $SUT_CONTAINER \ - -v /var/run/docker.sock:/tmp/docker.sock:ro \ - -v $TMP_DIR:/etc/nginx/dhparam \ - -e DHPARAM_BITS=256 \ - $SUT_IMAGE \ - && wait_for_nginxproxy_container_to_start $SUT_CONTAINER \ - && docker logs $SUT_CONTAINER - - # THEN - assert_success - docker_wait_for_log $SUT_CONTAINER 30 "Generating DH parameters" - - docker exec $SUT_CONTAINER rm -rf /etc/nginx/dhparam/* -} - -@test "[$TEST_FILE] test dhparam.pem is not generated if custom one is present" { - SUT_CONTAINER=bats-nginx-proxy-${TEST_FILE}-3 - - # WHEN - run nginxproxy $SUT_CONTAINER -v /var/run/docker.sock:/tmp/docker.sock:ro - assert_success - docker_wait_for_log $SUT_CONTAINER 9 "Watching docker events" - - sleep 3 - run docker logs $SUT_CONTAINER - - # THEN - refute_output -p "Generating DH parameters" -} - -@test "[$TEST_FILE] stop all bats containers" { - stop_bats_containers -} diff --git a/test/test_DOCKER_HOST_unix_socket.yml b/test/test_DOCKER_HOST_unix_socket.yml index 79b4baf..dff75a8 100644 --- a/test/test_DOCKER_HOST_unix_socket.yml +++ b/test/test_DOCKER_HOST_unix_socket.yml @@ -1,5 +1,5 @@ web1: - image: web + image: web expose: - "81" environment: @@ -8,7 +8,7 @@ web1: web2: image: web - expose: + expose: - "82" environment: WEB_PORTS: 82 @@ -19,6 +19,6 @@ sut: image: jwilder/nginx-proxy:test volumes: - /var/run/docker.sock:/f00.sock:ro + - ./lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro environment: DOCKER_HOST: unix:///f00.sock - diff --git a/test/test_composev2.yml b/test/test_composev2.yml index 5ffaf57..ef4df8d 100644 --- a/test/test_composev2.yml +++ b/test/test_composev2.yml @@ -4,11 +4,12 @@ services: image: jwilder/nginx-proxy:test volumes: - /var/run/docker.sock:/tmp/docker.sock:ro + - ./lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro web: - image: web + image: web expose: - "81" environment: WEB_PORTS: 81 - VIRTUAL_HOST: web.nginx-proxy.local \ No newline at end of file + VIRTUAL_HOST: web.nginx-proxy.local diff --git a/test/test_custom/test_defaults-location.yml b/test/test_custom/test_defaults-location.yml index d2ac14a..a5b0c44 100644 --- a/test/test_custom/test_defaults-location.yml +++ b/test/test_custom/test_defaults-location.yml @@ -2,11 +2,12 @@ nginx-proxy: image: jwilder/nginx-proxy:test volumes: - /var/run/docker.sock:/tmp/docker.sock:ro + - ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro - ./my_custom_proxy_settings.conf:/etc/nginx/vhost.d/default_location:ro - ./my_custom_proxy_settings_bar.conf:/etc/nginx/vhost.d/web3.nginx-proxy.local_location:ro web1: - image: web + image: web expose: - "81" environment: @@ -14,7 +15,7 @@ web1: VIRTUAL_HOST: web1.nginx-proxy.local web2: - image: web + image: web expose: - "82" environment: @@ -22,9 +23,9 @@ web2: VIRTUAL_HOST: web2.nginx-proxy.local web3: - image: web + image: web expose: - "83" environment: WEB_PORTS: 83 - VIRTUAL_HOST: web3.nginx-proxy.local \ No newline at end of file + VIRTUAL_HOST: web3.nginx-proxy.local diff --git a/test/test_custom/test_defaults.yml b/test/test_custom/test_defaults.yml index 2b2f1bb..2cfddf0 100644 --- a/test/test_custom/test_defaults.yml +++ b/test/test_custom/test_defaults.yml @@ -4,10 +4,11 @@ services: image: jwilder/nginx-proxy:test volumes: - /var/run/docker.sock:/tmp/docker.sock:ro + - ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro - ./my_custom_proxy_settings.conf:/etc/nginx/proxy.conf:ro web1: - image: web + image: web expose: - "81" environment: @@ -15,9 +16,9 @@ services: VIRTUAL_HOST: web1.nginx-proxy.local web2: - image: web + image: web expose: - "82" environment: WEB_PORTS: 82 - VIRTUAL_HOST: web2.nginx-proxy.local \ No newline at end of file + VIRTUAL_HOST: web2.nginx-proxy.local diff --git a/test/test_custom/test_location-per-vhost.yml b/test/test_custom/test_location-per-vhost.yml index 7ec9992..988181c 100644 --- a/test/test_custom/test_location-per-vhost.yml +++ b/test/test_custom/test_location-per-vhost.yml @@ -4,10 +4,11 @@ services: image: jwilder/nginx-proxy:test volumes: - /var/run/docker.sock:/tmp/docker.sock:ro + - ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro - ./my_custom_proxy_settings.conf:/etc/nginx/vhost.d/web1.nginx-proxy.local_location:ro web1: - image: web + image: web expose: - "81" environment: @@ -15,9 +16,9 @@ services: VIRTUAL_HOST: web1.nginx-proxy.local web2: - image: web + image: web expose: - "82" environment: WEB_PORTS: 82 - VIRTUAL_HOST: web2.nginx-proxy.local \ No newline at end of file + VIRTUAL_HOST: web2.nginx-proxy.local diff --git a/test/test_custom/test_per-vhost.yml b/test/test_custom/test_per-vhost.yml index a99da1d..61ae02b 100644 --- a/test/test_custom/test_per-vhost.yml +++ b/test/test_custom/test_per-vhost.yml @@ -4,10 +4,11 @@ services: image: jwilder/nginx-proxy:test volumes: - /var/run/docker.sock:/tmp/docker.sock:ro + - ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro - ./my_custom_proxy_settings.conf:/etc/nginx/vhost.d/web1.nginx-proxy.local:ro web1: - image: web + image: web expose: - "81" environment: @@ -15,9 +16,9 @@ services: VIRTUAL_HOST: web1.nginx-proxy.local web2: - image: web + image: web expose: - "82" environment: WEB_PORTS: 82 - VIRTUAL_HOST: web2.nginx-proxy.local \ No newline at end of file + VIRTUAL_HOST: web2.nginx-proxy.local diff --git a/test/test_custom/test_proxy-wide.yml b/test/test_custom/test_proxy-wide.yml index 3018131..602f344 100644 --- a/test/test_custom/test_proxy-wide.yml +++ b/test/test_custom/test_proxy-wide.yml @@ -4,10 +4,11 @@ services: image: jwilder/nginx-proxy:test volumes: - /var/run/docker.sock:/tmp/docker.sock:ro + - ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro - ./my_custom_proxy_settings.conf:/etc/nginx/conf.d/my_custom_proxy_settings.conf:ro web1: - image: web + image: web expose: - "81" environment: @@ -15,9 +16,9 @@ services: VIRTUAL_HOST: web1.nginx-proxy.local web2: - image: web + image: web expose: - "82" environment: WEB_PORTS: 82 - VIRTUAL_HOST: web2.nginx-proxy.local \ No newline at end of file + VIRTUAL_HOST: web2.nginx-proxy.local diff --git a/test/test_default-host.yml b/test/test_default-host.yml index 590dcaa..f195f58 100644 --- a/test/test_default-host.yml +++ b/test/test_default-host.yml @@ -13,5 +13,6 @@ sut: image: jwilder/nginx-proxy:test volumes: - /var/run/docker.sock:/tmp/docker.sock:ro + - ./lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro environment: DEFAULT_HOST: web1.tld diff --git a/test/test_dockergen/test_dockergen_v2.yml b/test/test_dockergen/test_dockergen_v2.yml index 0d2cab0..0fc8af5 100644 --- a/test/test_dockergen/test_dockergen_v2.yml +++ b/test/test_dockergen/test_dockergen_v2.yml @@ -6,6 +6,7 @@ services: container_name: nginx volumes: - /etc/nginx/conf.d + - ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro dockergen: image: jwilder/docker-gen @@ -23,4 +24,4 @@ services: - "80" environment: WEB_PORTS: 80 - VIRTUAL_HOST: whoami.nginx.container.docker \ No newline at end of file + VIRTUAL_HOST: whoami.nginx.container.docker diff --git a/test/test_dockergen/test_dockergen_v3.py b/test/test_dockergen/test_dockergen_v3.py index 325d6db..7e1f58c 100644 --- a/test/test_dockergen/test_dockergen_v3.py +++ b/test/test_dockergen/test_dockergen_v3.py @@ -2,12 +2,13 @@ import os import docker import logging import pytest - +import re def versiontuple(v): + # Temporary hack to fix version parsing until PR#755 is pulled + v = re.sub("[^\d\.]", "", v) return tuple(map(int, (v.split(".")))) - docker_version = docker.from_env().version()['Version'] pytestmark = pytest.mark.skipif(versiontuple(docker_version) < versiontuple('1.13'), reason="Docker compose syntax v3 requires docker engine v1.13") diff --git a/test/test_dockergen/test_dockergen_v3.yml b/test/test_dockergen/test_dockergen_v3.yml index 643f49b..fad145a 100644 --- a/test/test_dockergen/test_dockergen_v3.yml +++ b/test/test_dockergen/test_dockergen_v3.yml @@ -5,6 +5,7 @@ services: container_name: nginx volumes: - nginx_conf:/etc/nginx/conf.d + - ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro dockergen: image: jwilder/docker-gen @@ -24,4 +25,4 @@ services: VIRTUAL_HOST: whoami.nginx.container.docker volumes: - nginx_conf: {} \ No newline at end of file + nginx_conf: {} diff --git a/test/test_events.yml b/test/test_events.yml index d534870..87b7c01 100644 --- a/test/test_events.yml +++ b/test/test_events.yml @@ -2,3 +2,4 @@ nginxproxy: image: jwilder/nginx-proxy:test volumes: - /var/run/docker.sock:/tmp/docker.sock:ro + - ./lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro diff --git a/test/test_headers/test_http.yml b/test/test_headers/test_http.yml index e3596be..8cc2e09 100644 --- a/test/test_headers/test_http.yml +++ b/test/test_headers/test_http.yml @@ -10,4 +10,5 @@ web: sut: image: jwilder/nginx-proxy:test volumes: - - /var/run/docker.sock:/tmp/docker.sock:ro \ No newline at end of file + - /var/run/docker.sock:/tmp/docker.sock:ro + - ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro diff --git a/test/test_headers/test_https.yml b/test/test_headers/test_https.yml index 8dc0744..131f61c 100644 --- a/test/test_headers/test_https.yml +++ b/test/test_headers/test_https.yml @@ -13,3 +13,4 @@ sut: - /var/run/docker.sock:/tmp/docker.sock:ro - ./certs/web.nginx-proxy.tld.crt:/etc/nginx/certs/web.nginx-proxy.tld.crt:ro - ./certs/web.nginx-proxy.tld.key:/etc/nginx/certs/web.nginx-proxy.tld.key:ro + - ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro diff --git a/test/test_ipv6.yml b/test/test_ipv6.yml index c734660..a0b504e 100644 --- a/test/test_ipv6.yml +++ b/test/test_ipv6.yml @@ -1,5 +1,5 @@ web1: - image: web + image: web expose: - "81" environment: @@ -8,7 +8,7 @@ web1: web2: image: web - expose: + expose: - "82" environment: WEB_PORTS: 82 @@ -19,5 +19,6 @@ sut: image: jwilder/nginx-proxy:test volumes: - /var/run/docker.sock:/tmp/docker.sock:ro + - ./lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro environment: ENABLE_IPV6: "true" diff --git a/test/test_multiple-hosts.yml b/test/test_multiple-hosts.yml index 95dcb4a..70269c8 100644 --- a/test/test_multiple-hosts.yml +++ b/test/test_multiple-hosts.yml @@ -11,3 +11,4 @@ sut: image: jwilder/nginx-proxy:test volumes: - /var/run/docker.sock:/tmp/docker.sock:ro + - ./lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro diff --git a/test/test_multiple-networks.yml b/test/test_multiple-networks.yml index c04a292..da3277b 100644 --- a/test/test_multiple-networks.yml +++ b/test/test_multiple-networks.yml @@ -9,12 +9,13 @@ services: image: jwilder/nginx-proxy:test volumes: - /var/run/docker.sock:/tmp/docker.sock:ro + - ./lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro networks: - net1 - net2 web1: - image: web + image: web expose: - "81" environment: @@ -24,11 +25,11 @@ services: - net1 web2: - image: web + image: web expose: - "82" environment: WEB_PORTS: 82 VIRTUAL_HOST: web2.nginx-proxy.local networks: - - net2 \ No newline at end of file + - net2 diff --git a/test/test_multiple-ports/test_VIRTUAL_PORT.yml b/test/test_multiple-ports/test_VIRTUAL_PORT.yml index d61ac6f..4eb95ea 100644 --- a/test/test_multiple-ports/test_VIRTUAL_PORT.yml +++ b/test/test_multiple-ports/test_VIRTUAL_PORT.yml @@ -12,3 +12,4 @@ sut: image: jwilder/nginx-proxy:test volumes: - /var/run/docker.sock:/tmp/docker.sock:ro + - ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro diff --git a/test/test_multiple-ports/test_default-80.yml b/test/test_multiple-ports/test_default-80.yml index 74916a6..f06ccb8 100644 --- a/test/test_multiple-ports/test_default-80.yml +++ b/test/test_multiple-ports/test_default-80.yml @@ -11,3 +11,4 @@ sut: image: jwilder/nginx-proxy:test volumes: - /var/run/docker.sock:/tmp/docker.sock:ro + - ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro diff --git a/test/test_multiple-ports/test_single-port-not-80.yml b/test/test_multiple-ports/test_single-port-not-80.yml index 650dd07..15f230a 100644 --- a/test/test_multiple-ports/test_single-port-not-80.yml +++ b/test/test_multiple-ports/test_single-port-not-80.yml @@ -10,4 +10,5 @@ web: sut: image: jwilder/nginx-proxy:test volumes: - - /var/run/docker.sock:/tmp/docker.sock:ro \ No newline at end of file + - /var/run/docker.sock:/tmp/docker.sock:ro + - ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro diff --git a/test/test_nominal.yml b/test/test_nominal.yml index 6a582a5..d436499 100644 --- a/test/test_nominal.yml +++ b/test/test_nominal.yml @@ -1,5 +1,5 @@ web1: - image: web + image: web expose: - "81" environment: @@ -8,7 +8,7 @@ web1: web2: image: web - expose: + expose: - "82" environment: WEB_PORTS: 82 @@ -19,3 +19,4 @@ sut: image: jwilder/nginx-proxy:test volumes: - /var/run/docker.sock:/tmp/docker.sock:ro + - ./lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro diff --git a/test/test_ssl/test_nohttp.yml b/test/test_ssl/test_nohttp.yml index 8486c5e..51d63c2 100644 --- a/test/test_ssl/test_nohttp.yml +++ b/test/test_ssl/test_nohttp.yml @@ -12,4 +12,5 @@ sut: image: jwilder/nginx-proxy:test volumes: - /var/run/docker.sock:/tmp/docker.sock:ro + - ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro - ./certs:/etc/nginx/certs:ro diff --git a/test/test_ssl/test_nohttps.yml b/test/test_ssl/test_nohttps.yml index 2e7623a..14140b4 100644 --- a/test/test_ssl/test_nohttps.yml +++ b/test/test_ssl/test_nohttps.yml @@ -11,4 +11,5 @@ web: sut: image: jwilder/nginx-proxy:test volumes: - - /var/run/docker.sock:/tmp/docker.sock:ro \ No newline at end of file + - /var/run/docker.sock:/tmp/docker.sock:ro + - ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro diff --git a/test/test_ssl/test_noredirect.yml b/test/test_ssl/test_noredirect.yml index 8d0b4b2..9149a87 100644 --- a/test/test_ssl/test_noredirect.yml +++ b/test/test_ssl/test_noredirect.yml @@ -12,4 +12,5 @@ sut: image: jwilder/nginx-proxy:test volumes: - /var/run/docker.sock:/tmp/docker.sock:ro + - ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro - ./certs:/etc/nginx/certs:ro diff --git a/test/test_ssl/test_wildcard.yml b/test/test_ssl/test_wildcard.yml index 27840d3..4c77796 100644 --- a/test/test_ssl/test_wildcard.yml +++ b/test/test_ssl/test_wildcard.yml @@ -10,4 +10,5 @@ sut: image: jwilder/nginx-proxy:test volumes: - /var/run/docker.sock:/tmp/docker.sock:ro + - ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro - ./certs:/etc/nginx/certs:ro diff --git a/test/test_wildcard_host.yml b/test/test_wildcard_host.yml index a78ee3c..742a8ac 100644 --- a/test/test_wildcard_host.yml +++ b/test/test_wildcard_host.yml @@ -34,4 +34,5 @@ web4: sut: image: jwilder/nginx-proxy:test volumes: - - /var/run/docker.sock:/tmp/docker.sock:ro \ No newline at end of file + - /var/run/docker.sock:/tmp/docker.sock:ro + - ./lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro From abdd5883a1cc5a6db496f6cb8b7016491b0b7e12 Mon Sep 17 00:00:00 2001 From: Thomas LEVEIL Date: Wed, 8 Mar 2017 02:37:12 +0100 Subject: [PATCH 21/76] TESTS: refactor dhparam tests --- test/test_ssl/test_dhparam.py | 123 +++++++++++++--------- test/test_ssl/test_dhparam.yml | 2 +- test/test_ssl/test_dhparam_generation.py | 66 +++++------- test/test_ssl/test_dhparam_generation.yml | 1 + 4 files changed, 101 insertions(+), 91 deletions(-) diff --git a/test/test_ssl/test_dhparam.py b/test/test_ssl/test_dhparam.py index 109432a..67b11fa 100644 --- a/test/test_ssl/test_dhparam.py +++ b/test/test_ssl/test_dhparam.py @@ -1,74 +1,93 @@ -import pytest -import os -import docker -import time -import subprocess import re +import subprocess + +import backoff +import docker +import pytest docker_client = docker.from_env() -def wait_for_nginxproxy_to_be_ready(): + +############################################################################### +# +# Tests helpers +# +############################################################################### + +@backoff.on_exception(backoff.constant, AssertionError, interval=2, max_tries=15, jitter=None) +def assert_log_contains(expected_log_line): """ - If one (and only one) container started from image jwilder/nginx-proxy:test is found, - wait for its log to contain substring "Watching docker events" + Check that the nginx-proxy container log contains a given string. + The backoff decorator will retry the check 15 times with a 2 seconds delay. + + :param expected_log_line: string to search for + :return: None + :raises: AssertError if the expected string is not found in the log """ - containers = docker_client.containers.list(filters={"ancestor": "jwilder/nginx-proxy:test"}) - if len(containers) != 1: - return - container = containers[0] - for line in container.logs(stream=True): - if "Watching docker events" in line: - break - -def test_dhparam_is_not_generated_if_present(docker_compose, nginxproxy): - wait_for_nginxproxy_to_be_ready() - - containers = docker_client.containers.list(filters={"ancestor": "jwilder/nginx-proxy:test"}) - if len(containers) != 1: - assert 0 - return - - sut_container = containers[0] - + sut_container = docker_client.containers.get("nginxproxy") docker_logs = sut_container.logs(stdout=True, stderr=True, stream=False, follow=False) + assert expected_log_line in docker_logs - assert "Custom dhparam.pem file found, generation skipped" in docker_logs + +def require_openssl(required_version): + """ + This function checks that the required version of OpenSSL is present, and skips the test if not. + Use it as a test function decorator: + + @require_openssl("2.3.4") + def test_something(): + ... + + :param required_version: minimal required version as a string: "1.2.3" + """ + + def versiontuple(v): + clean_v = re.sub("[^\d\.]", "", v) + return tuple(map(int, (clean_v.split(".")))) + + try: + command_output = subprocess.check_output(["openssl", "version"]) + except OSError: + return pytest.mark.skip("openssl command is not available in test environment") + else: + if not command_output: + raise Exception("Could not get openssl version") + openssl_version = command_output.split()[1] + return pytest.mark.skipif( + versiontuple(openssl_version) < versiontuple(required_version), + reason="openssl v%s is less than required version %s" % (openssl_version, required_version)) + + +############################################################################### +# +# Tests +# +############################################################################### + +def test_dhparam_is_not_generated_if_present(docker_compose): + sut_container = docker_client.containers.get("nginxproxy") + assert sut_container.status == "running" + + assert_log_contains("Custom dhparam.pem file found, generation skipped") # Make sure the dhparam in use is not the default, pre-generated one default_checksum = sut_container.exec_run("md5sum /app/dhparam.pem.default").split() current_checksum = sut_container.exec_run("md5sum /etc/nginx/dhparam/dhparam.pem").split() assert default_checksum[0] != current_checksum[0] + def test_web5_https_works(docker_compose, nginxproxy): r = nginxproxy.get("https://web5.nginx-proxy.tld/port", allow_redirects=False) assert r.status_code == 200 assert "answer from port 85\n" in r.text -def versiontuple(v): - clean_v = re.sub("[^\d\.]", "", v) - return tuple(map(int, (clean_v.split(".")))) - -# This code checks that the required version of OpenSSL is present, and skips the test if not -openssl_version_required = "1.0.2" -openssl_version = "0.0.0" - -try: - openssl_version = subprocess.check_output(["openssl", "version"]).split()[1] -except: - pass - -@pytest.mark.skipif(versiontuple(openssl_version) < versiontuple(openssl_version_required), - reason="openssl command is not available in test environment or is less than version %s" % openssl_version_required) - -def test_web5_dhparam_is_used(docker_compose, nginxproxy): - containers = docker_client.containers.list(filters={"ancestor": "jwilder/nginx-proxy:test"}) - if len(containers) != 1: - assert 0 - return - - sut_container = containers[0] +@require_openssl("1.0.2") +def test_web5_dhparam_is_used(docker_compose): + sut_container = docker_client.containers.get("nginxproxy") + assert sut_container.status == "running" host = "%s:443" % sut_container.attrs["NetworkSettings"]["IPAddress"] - r = subprocess.check_output("echo '' | openssl s_client -verify 0 -connect %s -cipher 'EDH' | grep 'Server Temp Key'" % host, shell=True) - assert "Server Temp Key: DH, 2048 bits" in r + r = subprocess.check_output( + "echo '' | openssl s_client -verify 0 -connect %s -cipher 'EDH' | grep 'Server Temp Key'" % host, shell=True) + assert "Server Temp Key: DH, 2048 bits\n" == r diff --git a/test/test_ssl/test_dhparam.yml b/test/test_ssl/test_dhparam.yml index 6e196b0..66b1a61 100644 --- a/test/test_ssl/test_dhparam.yml +++ b/test/test_ssl/test_dhparam.yml @@ -5,11 +5,11 @@ web5: environment: WEB_PORTS: "85" VIRTUAL_HOST: "web5.nginx-proxy.tld" - HTTPS_METHOD: nohttp sut: image: jwilder/nginx-proxy:test + container_name: nginxproxy volumes: - /var/run/docker.sock:/tmp/docker.sock:ro - ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro diff --git a/test/test_ssl/test_dhparam_generation.py b/test/test_ssl/test_dhparam_generation.py index 87e71f1..0f5398b 100644 --- a/test/test_ssl/test_dhparam_generation.py +++ b/test/test_ssl/test_dhparam_generation.py @@ -1,52 +1,42 @@ -import pytest -import os +import backoff import docker -import time docker_client = docker.from_env() -def wait_for_nginxproxy_to_be_ready(): + +############################################################################### +# +# Tests helpers +# +############################################################################### + +@backoff.on_exception(backoff.constant, AssertionError, interval=2, max_tries=15, jitter=None) +def assert_log_contains(expected_log_line): """ - If one (and only one) container started from image jwilder/nginx-proxy:test is found, - wait for its log to contain substring "Watching docker events" + Check that the nginx-proxy container log contains a given string. + The backoff decorator will retry the check 15 times with a 2 seconds delay. + + :param expected_log_line: string to search for + :return: None + :raises: AssertError if the expected string is not found in the log """ - containers = docker_client.containers.list(filters={"ancestor": "jwilder/nginx-proxy:test"}) - if len(containers) != 1: - return - container = containers[0] - for line in container.logs(stream=True): - if "Watching docker events" in line: - break - -def test_dhparam_is_generated_if_missing(docker_compose, nginxproxy): - wait_for_nginxproxy_to_be_ready() - - containers = docker_client.containers.list(filters={"ancestor": "jwilder/nginx-proxy:test"}) - if len(containers) != 1: - assert 0 - return - - sut_container = containers[0] - + sut_container = docker_client.containers.get("nginxproxy") docker_logs = sut_container.logs(stdout=True, stderr=True, stream=False, follow=False) + assert expected_log_line in docker_logs - assert "Generating DH parameters" in docker_logs - expected_line = "dhparam generation complete, reloading nginx" - max_wait = 30 - sleep_interval = 2 - current_wait = 0 +############################################################################### +# +# Tests +# +############################################################################### - while current_wait < max_wait: - docker_logs = sut_container.logs(stdout=True, stderr=True, stream=False, follow=False) - if expected_line in docker_logs: - break +def test_dhparam_is_generated_if_missing(docker_compose): + sut_container = docker_client.containers.get("nginxproxy") + assert sut_container.status == "running" - time.sleep(sleep_interval) - current_wait += sleep_interval - - # Re-check the logs to get better assert output on failure - assert expected_line in docker_logs + assert_log_contains("Generating DH parameters") + assert_log_contains("dhparam generation complete, reloading nginx") # Make sure the dhparam in use is not the default, pre-generated one default_checksum = sut_container.exec_run("md5sum /app/dhparam.pem.default").split() diff --git a/test/test_ssl/test_dhparam_generation.yml b/test/test_ssl/test_dhparam_generation.yml index f55cb95..35f3067 100644 --- a/test/test_ssl/test_dhparam_generation.yml +++ b/test/test_ssl/test_dhparam_generation.yml @@ -1,5 +1,6 @@ sut: image: jwilder/nginx-proxy:test + container_name: nginxproxy volumes: - /var/run/docker.sock:/tmp/docker.sock:ro - ./certs:/etc/nginx/certs:ro From a3fbaa59909c81d14ce7c29bdf1555bb5f4537bc Mon Sep 17 00:00:00 2001 From: Thomas LEVEIL Date: Tue, 21 Feb 2017 01:01:00 +0100 Subject: [PATCH 22/76] 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 23/76] 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 24/76] 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 25/76] 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 8414a94d59bf70d4928c4f8785966d3b987c115f Mon Sep 17 00:00:00 2001 From: Thomas LEVEIL Date: Wed, 15 Mar 2017 02:11:21 +0100 Subject: [PATCH 26/76] TESTS: add test for the case in which a wildcard cert matches a container having `nohttps` set --- .../wildcard_cert_and_nohttps/README.md | 6 ++ .../certs/default.crt | 70 ++++++++++++++++++ .../certs/default.key | 27 +++++++ .../certs/web.nginx-proxy.tld.crt | 71 +++++++++++++++++++ .../certs/web.nginx-proxy.tld.key | 27 +++++++ .../docker-compose.yml | 33 +++++++++ .../test_wildcard_cert_nohttps.py | 31 ++++++++ 7 files changed, 265 insertions(+) create mode 100644 test/test_ssl/wildcard_cert_and_nohttps/README.md create mode 100644 test/test_ssl/wildcard_cert_and_nohttps/certs/default.crt create mode 100644 test/test_ssl/wildcard_cert_and_nohttps/certs/default.key create mode 100644 test/test_ssl/wildcard_cert_and_nohttps/certs/web.nginx-proxy.tld.crt create mode 100644 test/test_ssl/wildcard_cert_and_nohttps/certs/web.nginx-proxy.tld.key create mode 100644 test/test_ssl/wildcard_cert_and_nohttps/docker-compose.yml create mode 100644 test/test_ssl/wildcard_cert_and_nohttps/test_wildcard_cert_nohttps.py diff --git a/test/test_ssl/wildcard_cert_and_nohttps/README.md b/test/test_ssl/wildcard_cert_and_nohttps/README.md new file mode 100644 index 0000000..0ccdd2e --- /dev/null +++ b/test/test_ssl/wildcard_cert_and_nohttps/README.md @@ -0,0 +1,6 @@ +In this scenario, we have a wildcard certificate for `*.web.nginx-proxy.tld` and 3 web containers: +- 1.web.nginx-proxy.tld +- 2.web.nginx-proxy.tld +- 3.web.nginx-proxy.tld + +We want web containers 1 and 2 to support SSL, but 3 should not (using `HTTPS_METHOD=nohttps`) \ No newline at end of file diff --git a/test/test_ssl/wildcard_cert_and_nohttps/certs/default.crt b/test/test_ssl/wildcard_cert_and_nohttps/certs/default.crt new file mode 100644 index 0000000..81af239 --- /dev/null +++ b/test/test_ssl/wildcard_cert_and_nohttps/certs/default.crt @@ -0,0 +1,70 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 4096 (0x1000) + Signature Algorithm: sha256WithRSAEncryption + Issuer: O=nginx-proxy test suite, CN=www.nginx-proxy.tld + Validity + Not Before: Mar 15 00:17:52 2017 GMT + Not After : Jul 31 00:17:52 2044 GMT + Subject: CN=nginx-proxy.tld + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:f2:fd:79:70:99:0c:da:63:5c:81:28:72:31:01: + 62:e9:68:d7:cb:8d:c6:95:f9:ec:26:34:1c:08:c6: + 6d:de:ad:d8:b0:c0:ae:48:03:73:76:6b:3f:c5:35: + 86:c6:42:91:53:3c:aa:85:89:84:92:67:92:ef:a9: + 5b:f2:d4:04:73:34:02:35:d4:6a:fa:c2:da:91:4a: + a9:70:87:25:38:84:1d:93:99:3c:d7:03:61:a6:6d: + 33:6f:83:45:04:af:4f:96:62:1e:c1:79:87:c9:d5: + 4c:e9:8f:85:e2:c8:1b:5b:fc:b8:02:ff:7b:6d:34: + 4c:5d:40:73:44:9e:c5:1f:5f:e0:0f:89:88:c4:35: + 2b:04:53:8c:8e:a0:7c:7c:97:16:20:c2:4f:a1:c0: + dd:bf:d5:13:2d:64:25:03:f2:d8:d5:27:01:70:c9: + f4:37:33:36:7e:7b:48:54:ec:37:2b:81:3d:50:3c: + d4:5f:05:19:e2:0b:ba:76:f6:2c:3b:23:4b:82:78: + 5f:e9:e3:57:fc:39:4a:5c:42:82:72:c8:a3:af:b7: + b3:91:e4:01:9c:2c:47:5e:ff:aa:ad:63:1c:e7:9c: + 2e:a2:ac:5d:51:30:83:67:6e:f8:5a:ed:0b:70:e4: + 68:d4:e9:5e:a7:f5:5e:87:3b:e8:31:ad:00:04:f8: + 7b:d9 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Alternative Name: + DNS:nginx-proxy.tld + Signature Algorithm: sha256WithRSAEncryption + 39:d4:cc:78:a3:5e:64:e9:ab:9d:a9:89:3b:9e:18:01:98:cb: + e2:0c:ef:e9:2b:50:34:ed:63:ed:e6:0e:53:59:30:80:e0:3b: + 5e:08:ca:09:55:da:e3:3e:c2:01:d8:d6:ca:92:2a:0b:ee:2c: + a1:93:18:7b:15:28:8d:2a:17:25:76:eb:ef:70:e0:d7:02:d3: + ad:81:33:47:9b:fb:d8:52:87:69:a4:3a:20:a4:9a:2d:3f:40: + 5f:52:bf:0b:96:e3:52:c3:59:55:dc:5a:37:f3:e6:d6:16:46: + 64:e4:20:32:5d:cd:4b:da:2b:ef:e9:85:af:00:a1:ca:a1:08: + ed:0f:f4:65:dc:2a:c9:b3:4e:cc:f3:82:d7:69:3a:4d:fc:8e: + db:10:95:28:20:07:55:f0:d1:11:1f:c5:00:74:88:c6:c9:94: + 15:90:93:3a:de:90:85:fb:72:9c:d8:57:58:05:7d:bb:6a:36: + eb:d8:12:22:41:0e:fc:c9:24:79:c0:28:4f:4f:1b:4b:59:f9: + e4:c6:97:be:b1:94:74:de:a7:65:d3:cb:0a:56:3b:d3:63:fc: + b2:05:fc:e7:ec:bb:45:04:91:9f:21:f9:05:3b:5d:4c:af:8e: + 84:04:f5:25:fb:4d:ab:db:23:56:74:7e:4f:b3:da:bb:27:e7: + ea:fb:bd:00 +-----BEGIN CERTIFICATE----- +MIIC8zCCAdugAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwPzEfMB0GA1UECgwWbmdp +bngtcHJveHkgdGVzdCBzdWl0ZTEcMBoGA1UEAwwTd3d3Lm5naW54LXByb3h5LnRs +ZDAeFw0xNzAzMTUwMDE3NTJaFw00NDA3MzEwMDE3NTJaMBoxGDAWBgNVBAMMD25n +aW54LXByb3h5LnRsZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPL9 +eXCZDNpjXIEocjEBYulo18uNxpX57CY0HAjGbd6t2LDArkgDc3ZrP8U1hsZCkVM8 +qoWJhJJnku+pW/LUBHM0AjXUavrC2pFKqXCHJTiEHZOZPNcDYaZtM2+DRQSvT5Zi +HsF5h8nVTOmPheLIG1v8uAL/e200TF1Ac0SexR9f4A+JiMQ1KwRTjI6gfHyXFiDC +T6HA3b/VEy1kJQPy2NUnAXDJ9DczNn57SFTsNyuBPVA81F8FGeILunb2LDsjS4J4 +X+njV/w5SlxCgnLIo6+3s5HkAZwsR17/qq1jHOecLqKsXVEwg2du+FrtC3DkaNTp +Xqf1Xoc76DGtAAT4e9kCAwEAAaMeMBwwGgYDVR0RBBMwEYIPbmdpbngtcHJveHku +dGxkMA0GCSqGSIb3DQEBCwUAA4IBAQA51Mx4o15k6audqYk7nhgBmMviDO/pK1A0 +7WPt5g5TWTCA4DteCMoJVdrjPsIB2NbKkioL7iyhkxh7FSiNKhclduvvcODXAtOt +gTNHm/vYUodppDogpJotP0BfUr8LluNSw1lV3Fo38+bWFkZk5CAyXc1L2ivv6YWv +AKHKoQjtD/Rl3CrJs07M84LXaTpN/I7bEJUoIAdV8NERH8UAdIjGyZQVkJM63pCF ++3Kc2FdYBX27ajbr2BIiQQ78ySR5wChPTxtLWfnkxpe+sZR03qdl08sKVjvTY/yy +Bfzn7LtFBJGfIfkFO11Mr46EBPUl+02r2yNWdH5Ps9q7J+fq+70A +-----END CERTIFICATE----- diff --git a/test/test_ssl/wildcard_cert_and_nohttps/certs/default.key b/test/test_ssl/wildcard_cert_and_nohttps/certs/default.key new file mode 100644 index 0000000..af5fa34 --- /dev/null +++ b/test/test_ssl/wildcard_cert_and_nohttps/certs/default.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpQIBAAKCAQEA8v15cJkM2mNcgShyMQFi6WjXy43GlfnsJjQcCMZt3q3YsMCu +SANzdms/xTWGxkKRUzyqhYmEkmeS76lb8tQEczQCNdRq+sLakUqpcIclOIQdk5k8 +1wNhpm0zb4NFBK9PlmIewXmHydVM6Y+F4sgbW/y4Av97bTRMXUBzRJ7FH1/gD4mI +xDUrBFOMjqB8fJcWIMJPocDdv9UTLWQlA/LY1ScBcMn0NzM2fntIVOw3K4E9UDzU +XwUZ4gu6dvYsOyNLgnhf6eNX/DlKXEKCcsijr7ezkeQBnCxHXv+qrWMc55wuoqxd +UTCDZ274Wu0LcORo1Olep/VehzvoMa0ABPh72QIDAQABAoIBAQDqcaW5/fFoxHV8 +KIoEvlGw4ndS7nesPHacZaqmzM01DIcGAuIkmS/OEax1mi9vGsschGwCa6x9lXEv +yzfsEqQ4gvWe+lQ9ncNEa8UPzVUcMlxXDIKm8ZxF9xapgP4Whw9DCWijQ57AHg0X +TGLhbDD5j9v7CIUN2GfVkVml24pVuUoeXqv7ZLzTJKZ+Q/eqxyeIikjFheXzaQxb +bUHbEHIXJtHMYULXmfc5WCxuobHqal3z0ymCijoZVXV8hp8dtDP34tRV9MID9wck +lRUVqboFCIXxmLLRTZgyCbiFLkCIu2nmgNobWCNfkHN7QQhToPEecSFMZzYtmo6/ +T1fHE3ABAoGBAP1J1Izfc4CF9t2iPGzXyn8oNkXHLMPKtFQ2Rb8XwBryUOOrAHqT +FIZ2FsDJr0VvS1ihFs1kbO+WAY5W5GytwiiVXvztHz3/f5JnGgvMCeUcEmaj90vq +sTyfHc2OKFjumIjGe87uav3bgac7nOWLO+RIJ/ua6UO7/8psqwryxY4FAoGBAPWX +a502kT56VwI3Gf8hb37PZ/PD+gOzgzVcMn13yLZ4gC9xoP4TKUBHSz4wO8asjKk5 +1RD/DITXYKelyRXynOtMW+2j2s5bVBpOshN/n9jRC1haoGJZYb2JVP6+8WoZKQOF +NwgNlI4he32kSFw59fjkdG64iw7KY8ZYUatkrgrFAoGBAPozTjUCHfRdYOi6c/oI +h81oCYSQJVYbDFsLaYZEjc2Qg/sBVm2+kE3qpLs3/10VfVZFemLVyw44Hb1fdDEu +y1aPhs9N5Mi3dGtIUWBJ45RgUIT3fzeM1BtQCn6c6JpAxoiFmJNmzGWLyd1Kc8gD +69uqs2RFOBtiwGBTS/p6qk+JAoGBAM1QkpnzFYf69SSX9jbRuAl20Xv8GdbgS0/f +zSIRcw4BPYDsaOAgGrtvHttVrZORi2KqQ5Ma9ldUS6y8L5kWo9MemjfYZUNhHLWF +luAwMO0tDmQGF9FA0jKHTjROYzsE38Heq7wixk/wc/H81rWrixRRwXkS9MYfszwN +d/FmkQ3VAoGAXHZrDEygUmf4q0LwjLVF0TPzElh530qVmyhPa0OBs/hVh9Mwv/i6 +fj3+k7uYWgKDzcaVXSMOFGt515F8qy0AUEY9r+IjAn01KTLKO4ZuPiSpxliqDbCs +gzsX9CWVSVgTN+TY15QCoJNpzLiyrXe3uldAP5JEBQSnjt9OfSJQ5IU= +-----END RSA PRIVATE KEY----- diff --git a/test/test_ssl/wildcard_cert_and_nohttps/certs/web.nginx-proxy.tld.crt b/test/test_ssl/wildcard_cert_and_nohttps/certs/web.nginx-proxy.tld.crt new file mode 100644 index 0000000..9020a44 --- /dev/null +++ b/test/test_ssl/wildcard_cert_and_nohttps/certs/web.nginx-proxy.tld.crt @@ -0,0 +1,71 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 4096 (0x1000) + Signature Algorithm: sha256WithRSAEncryption + Issuer: O=nginx-proxy test suite, CN=www.nginx-proxy.tld + Validity + Not Before: Mar 14 23:19:36 2017 GMT + Not After : Jul 30 23:19:36 2044 GMT + Subject: CN=*.web.nginx-proxy.tld + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:ce:2b:74:13:b2:1a:d5:72:5c:3e:10:f7:63:01: + 22:df:e8:d9:cf:0b:8a:3f:40:75:62:58:78:27:9e: + af:33:d2:a1:19:6a:e1:b7:57:db:d9:8f:05:70:c2: + 35:5d:f1:44:0d:51:62:74:73:e5:77:d9:bb:c6:d0: + 33:7a:43:88:e9:e6:3c:2d:d4:39:9d:61:34:5a:19: + f3:c1:96:e0:bd:26:5b:69:18:a6:4c:8c:21:04:d8: + fa:56:22:ec:55:0d:ba:49:4d:8e:27:69:7f:82:e9: + e7:e9:c4:b7:87:70:d7:d7:4b:49:d1:c1:8c:b0:5a: + 13:62:db:de:c1:94:31:d1:c9:74:c4:63:01:50:10: + 70:42:73:67:c4:76:32:fb:d2:b7:91:2f:e8:cf:3a: + 96:4a:ee:8e:0d:13:74:73:1b:e4:74:83:e7:66:d6: + 8d:81:19:54:5b:d8:47:3e:3b:b5:fd:35:a2:df:f3: + 7d:1c:9e:67:ee:50:da:28:9c:02:0a:ad:75:8d:04: + f7:28:1f:04:89:13:ac:ed:a9:34:26:dc:f7:f9:1f: + 72:21:d5:72:fb:09:d9:cb:40:c0:0d:36:3c:c0:77: + 0e:9a:f7:41:f1:3b:dd:b6:05:ab:13:60:c5:fd:c6: + 5f:f5:05:c4:42:00:ba:b5:ef:fb:dc:64:98:d9:4d: + 2b:07 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Alternative Name: + DNS:*.web.nginx-proxy.tld + Signature Algorithm: sha256WithRSAEncryption + 9b:78:39:b3:90:8f:31:8c:7d:02:aa:6f:46:3d:8c:f5:93:86: + 03:e2:d8:9b:73:d1:e7:70:f1:d6:e6:3c:41:41:8c:76:c9:29: + a4:83:47:c7:10:fd:d0:8b:fa:60:26:a8:36:41:a4:69:89:81: + ec:bf:fd:33:72:bb:83:ea:42:e4:59:3f:10:df:d1:de:e2:bb: + eb:fa:97:44:fe:f4:55:29:69:ca:a5:88:b2:94:60:58:5a:1a: + 19:16:fb:9f:42:4c:7c:d3:6b:21:45:22:56:5c:76:07:97:35: + 27:8f:46:d2:77:5b:65:1b:94:99:cb:73:37:ae:cf:61:6c:7a: + 5c:b3:3b:19:f2:9f:99:8f:89:eb:98:0b:74:0d:30:f5:49:19: + d6:41:32:4e:c9:fc:59:2a:4a:53:2c:83:89:3d:e8:89:ed:37: + d0:b4:f1:09:49:b5:0b:76:fd:a5:75:23:fb:01:c8:bb:59:02: + 5c:e4:8e:9c:f9:5b:85:5f:67:fb:04:40:de:bc:e8:c3:15:2f: + ba:00:5c:36:57:47:e3:1a:95:44:5f:f4:10:55:b0:c4:af:12: + dc:0e:6c:18:4a:70:9e:73:90:8d:55:37:73:a5:1a:41:7f:00: + 79:96:34:01:6b:10:2d:e9:61:3d:8f:8a:9a:c8:b6:bc:0f:57: + 91:84:7c:26 +-----BEGIN CERTIFICATE----- +MIIC/zCCAeegAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwPzEfMB0GA1UECgwWbmdp +bngtcHJveHkgdGVzdCBzdWl0ZTEcMBoGA1UEAwwTd3d3Lm5naW54LXByb3h5LnRs +ZDAeFw0xNzAzMTQyMzE5MzZaFw00NDA3MzAyMzE5MzZaMCAxHjAcBgNVBAMMFSou +d2ViLm5naW54LXByb3h5LnRsZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAM4rdBOyGtVyXD4Q92MBIt/o2c8Lij9AdWJYeCeerzPSoRlq4bdX29mPBXDC +NV3xRA1RYnRz5XfZu8bQM3pDiOnmPC3UOZ1hNFoZ88GW4L0mW2kYpkyMIQTY+lYi +7FUNuklNjidpf4Lp5+nEt4dw19dLSdHBjLBaE2Lb3sGUMdHJdMRjAVAQcEJzZ8R2 +MvvSt5Ev6M86lkrujg0TdHMb5HSD52bWjYEZVFvYRz47tf01ot/zfRyeZ+5Q2iic +AgqtdY0E9ygfBIkTrO2pNCbc9/kfciHVcvsJ2ctAwA02PMB3Dpr3QfE73bYFqxNg +xf3GX/UFxEIAurXv+9xkmNlNKwcCAwEAAaMkMCIwIAYDVR0RBBkwF4IVKi53ZWIu +bmdpbngtcHJveHkudGxkMA0GCSqGSIb3DQEBCwUAA4IBAQCbeDmzkI8xjH0Cqm9G +PYz1k4YD4tibc9HncPHW5jxBQYx2ySmkg0fHEP3Qi/pgJqg2QaRpiYHsv/0zcruD +6kLkWT8Q39He4rvr+pdE/vRVKWnKpYiylGBYWhoZFvufQkx802shRSJWXHYHlzUn +j0bSd1tlG5SZy3M3rs9hbHpcszsZ8p+Zj4nrmAt0DTD1SRnWQTJOyfxZKkpTLIOJ +PeiJ7TfQtPEJSbULdv2ldSP7Aci7WQJc5I6c+VuFX2f7BEDevOjDFS+6AFw2V0fj +GpVEX/QQVbDErxLcDmwYSnCec5CNVTdzpRpBfwB5ljQBaxAt6WE9j4qayLa8D1eR +hHwm +-----END CERTIFICATE----- diff --git a/test/test_ssl/wildcard_cert_and_nohttps/certs/web.nginx-proxy.tld.key b/test/test_ssl/wildcard_cert_and_nohttps/certs/web.nginx-proxy.tld.key new file mode 100644 index 0000000..358eb4b --- /dev/null +++ b/test/test_ssl/wildcard_cert_and_nohttps/certs/web.nginx-proxy.tld.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEAzit0E7Ia1XJcPhD3YwEi3+jZzwuKP0B1Ylh4J56vM9KhGWrh +t1fb2Y8FcMI1XfFEDVFidHPld9m7xtAzekOI6eY8LdQ5nWE0WhnzwZbgvSZbaRim +TIwhBNj6ViLsVQ26SU2OJ2l/gunn6cS3h3DX10tJ0cGMsFoTYtvewZQx0cl0xGMB +UBBwQnNnxHYy+9K3kS/ozzqWSu6ODRN0cxvkdIPnZtaNgRlUW9hHPju1/TWi3/N9 +HJ5n7lDaKJwCCq11jQT3KB8EiROs7ak0Jtz3+R9yIdVy+wnZy0DADTY8wHcOmvdB +8TvdtgWrE2DF/cZf9QXEQgC6te/73GSY2U0rBwIDAQABAoIBAGVkDVPaVUP/V8nW +QjNYTbRcKTGfdT+iDZht9blWWsdboIqFe7fU53PY2E4Z1HD8xADgs1Cd5o3IcIZX +wdkw+VY+Of43zpXNRhfBh5T/BEtBX9cRnkcq6todcw+FYUB63dBK6cwMH/9b1Qes +DK35GszwY79aNjxMMBiAFM6SeOW4EElPsV8wd9ldX/ndiZuwkZ6k9PfyWrfeeaF+ +EwVf/HaT0bV7cHQ73tYqzKjMpdbzIyaMzuAMGZDwPfLK+O1rEsWvLvK0ypl2Omzw +ndon8U3z0JPNmBGoq+SFS2qtCeOezNX3lPz+TWxG05R5iiFtuK83zJ5qGqCgCNZ6 +qzpZsOECgYEA/NvWqT5MdZS1fdL2wROzFMTH4OBdUGr1Gh/DsNZj4qFVSFl969mA +7Vntm+koNLFsJt2EB67kC3ZWjozLXomHJ55/uKNnJ5LrLxczQ9x4l52CsTzrlvFq +crYjQZDmeN3B4Z+8RSi2icq6j1PeaCZRTvcz6eBjNYj/v/O0SmiXIp8CgYEA0Lsh +fZWuw23a8UXS2YUrXXqfIEdisVMnLRu3Zi0Y1R4lIpuwn5+2n+TxnuWcY1q+ZTMw +dcmGPi6aRj81kEN/Kw5raKoVb6YywTNB4/Dwz7PRQH386FrjfivGXGEEINgbPQ09 +2u0QV2Cr9yMGZ5qNXut70RYewkxjF7+s6L8+RpkCgYB9ikBHgtC/R/fb4pP0RG2T +ECgUtBBgTtomAENOVwL8kBEhfJ0SLcjfDtjzoYz+rF//49cbYW+DaVuMJscJxso9 +l2neJ/KdKUpu9NvVA280B1XN3WsyY+Xv0hIrCWAD/kW2WXJF+/K08twxMPipSOzx +gbZalbdr6vrfOIX4s3jmDQKBgDiXA3Vw53jEh99x9sBSgndNj2bI89DvomdwZECn +aVweWCMR4sjkHDctcvSJe+TT7VqyjijhAixJpjn1WShLpGaf+i7eLgGfJZOLugl6 +gU9OiSTbA35bZeIHLDhPdTcSYBAlTufT7eJCq1zNeicMl9dsMJ13Sc+TtinyJYbU +kqXBAoGBAL9gRa1PkNkpCJ5F9aYSohCAXB7DaAgYvVyvOTQ8Bw2uACPgdnpHmxQd +/sT7qJ1h8ZCtn89Ug/4yx79eUcOImugoCRIUVtq1xhyXUdVl55Tuy5bKBSSAe/Vh +T7sAmryCkzn9ihRziY2j84vK0mdMkCU5AoatPg5l0g1adn5zcY6q +-----END RSA PRIVATE KEY----- diff --git a/test/test_ssl/wildcard_cert_and_nohttps/docker-compose.yml b/test/test_ssl/wildcard_cert_and_nohttps/docker-compose.yml new file mode 100644 index 0000000..bffffc1 --- /dev/null +++ b/test/test_ssl/wildcard_cert_and_nohttps/docker-compose.yml @@ -0,0 +1,33 @@ +version: "3" + +services: + + proxy: + image: jwilder/nginx-proxy:test + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro + - ./certs:/etc/nginx/certs:ro + + web1: + image: web + expose: + - "81" + environment: + WEB_PORTS: "81" + VIRTUAL_HOST: "1.web.nginx-proxy.tld" + web2: + image: web + expose: + - "82" + environment: + WEB_PORTS: "82" + VIRTUAL_HOST: "2.web.nginx-proxy.tld" + + web3_nohttps: + image: web + expose: + - "83" + environment: + WEB_PORTS: "83" + VIRTUAL_HOST: "3.web.nginx-proxy.tld" + HTTPS_METHOD: nohttps \ No newline at end of file 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 new file mode 100644 index 0000000..db18809 --- /dev/null +++ b/test/test_ssl/wildcard_cert_and_nohttps/test_wildcard_cert_nohttps.py @@ -0,0 +1,31 @@ +import pytest +from backports.ssl_match_hostname import CertificateError + + +@pytest.mark.parametrize("subdomain,should_redirect_to_https", [ + (1, True), + (2, True), + (3, False), +]) +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 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 + + +@pytest.mark.parametrize("subdomain", [1, 2]) +def test_https_get_served(docker_compose, nginxproxy, subdomain): + r = nginxproxy.get("https://%s.web.nginx-proxy.tld/port" % subdomain, allow_redirects=False) + assert r.status_code == 200 + assert "answer from port 8%s\n" % subdomain == r.text + + +def test_web3_https_is_500_and_SSL_validation_fails(docker_compose, nginxproxy): + with pytest.raises(CertificateError) as excinfo: + nginxproxy.get("https://3.web.nginx-proxy.tld/port") + assert """hostname '3.web.nginx-proxy.tld' doesn't match 'nginx-proxy.tld'""" in str(excinfo.value) + + r = nginxproxy.get("https://3.web.nginx-proxy.tld/port", verify=False) + assert r.status_code == 500 From f2487741dc526ed979d1e0565f4cc8a976f710d1 Mon Sep 17 00:00:00 2001 From: Roberto Alvarez Date: Wed, 3 May 2017 11:06:34 -0500 Subject: [PATCH 27/76] Fix README typo Fixed a small typo/error with "the a" host --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c41c426..0dc42f4 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ Then start any containers you want proxied with an env var `VIRTUAL_HOST=subdoma 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`. -Provided your DNS is setup to forward foo.bar.com to the a host running nginx-proxy, the request will be routed to a container with the VIRTUAL_HOST env var set. +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. ### Image variants From 2c4102d39627b2fc539cec01b04c1027abbfb01e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20H=C3=BCske?= Date: Thu, 4 May 2017 18:57:00 +0200 Subject: [PATCH 28/76] Upgrade to 1.13.0 --- 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 b0c3cf7..f8f76a1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM nginx:1.11.13 +FROM nginx:1.13.0 MAINTAINER Jason Wilder mail@jasonwilder.com # Install wget and install/updates certificates diff --git a/Dockerfile.alpine b/Dockerfile.alpine index b92145c..b7443f0 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -1,4 +1,4 @@ -FROM nginx:1.11.13-alpine +FROM nginx:1.13.0-alpine MAINTAINER Jason Wilder mail@jasonwilder.com # Install wget and install/updates certificates diff --git a/README.md b/README.md index 0dc42f4..34ef8fb 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -![nginx 1.11.13](https://img.shields.io/badge/nginx-1.11.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.13.0](https://img.shields.io/badge/nginx-1.13.0-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 52f728f..adacb5e 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.11.13) +CONTAINER=$(docker run -d -v $DIR:/work -w /work -e SAN="$ALTERNATE_DOMAINS" nginx:1.13.0) # Configure openssl docker exec $CONTAINER bash -c ' mkdir -p /ca/{certs,crl,private,newcerts} 2>/dev/null From 4e4733f68e0fa44b0cb686d9046b7cf62c210d00 Mon Sep 17 00:00:00 2001 From: Jason Wilder Date: Fri, 9 Jun 2017 12:55:39 -0600 Subject: [PATCH 29/76] Trim $host and $proto before they are used --- nginx.tmpl | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/nginx.tmpl b/nginx.tmpl index a5b1d32..b340473 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -99,10 +99,14 @@ server { {{ end }} {{ range $host, $containers := groupByMulti $ "Env.VIRTUAL_HOST" "," }} + +{{ $host := trim $host }} {{ $is_regexp := hasPrefix "~" $host }} {{ $upstream_name := when $is_regexp (sha1 $host) $host }} + # {{ $host }} upstream {{ $upstream_name }} { + {{ range $container := $containers }} {{ $addrLen := len $container.Addresses }} @@ -131,7 +135,7 @@ upstream {{ $upstream_name }} { {{ $default_server := index (dict $host "" $default_host "default_server") $host }} {{/* Get the VIRTUAL_PROTO defined by containers w/ the same vhost, falling back to "http" */}} -{{ $proto := or (first (groupByKeys $containers "Env.VIRTUAL_PROTO")) "http" }} +{{ $proto := trim (or (first (groupByKeys $containers "Env.VIRTUAL_PROTO")) "http") }} {{/* 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" }} @@ -205,6 +209,7 @@ server { {{ else }} proxy_pass {{ trim $proto }}://{{ trim $upstream_name }}; {{ end }} + {{ if (exists (printf "/etc/nginx/htpasswd/%s" $host)) }} auth_basic "Restricted {{ $host }}"; auth_basic_user_file {{ (printf "/etc/nginx/htpasswd/%s" $host) }}; From a8ee64b0596ffc0a8df369e88d1115b80afb04fa Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 10 Jun 2017 15:07:45 +0800 Subject: [PATCH 30/76] running proxy on host network --- nginx.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nginx.tmpl b/nginx.tmpl index a5b1d32..9d7faef 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -108,7 +108,7 @@ upstream {{ $upstream_name }} { {{ range $knownNetwork := $CurrentContainer.Networks }} {{ range $containerNetwork := $container.Networks }} - {{ if eq $knownNetwork.Name $containerNetwork.Name }} + {{ if or (eq $knownNetwork.Name $containerNetwork.Name) (eq $knownNetwork.Name "host") }} ## Can be connect with "{{ $containerNetwork.Name }}" network {{/* If only 1 port exposed, use that */}} From 1867228ccee886090bd24061c06080618fa952d3 Mon Sep 17 00:00:00 2001 From: neil Date: Mon, 12 Jun 2017 15:59:55 +0800 Subject: [PATCH 31/76] fix worker_processes to "auto" --- Dockerfile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index f8f76a1..88a4c75 100644 --- a/Dockerfile +++ b/Dockerfile @@ -11,7 +11,8 @@ RUN apt-get update \ # Configure Nginx and apply fix for very long server names RUN echo "daemon off;" >> /etc/nginx/nginx.conf \ - && sed -i 's/^http {/&\n server_names_hash_bucket_size 128;/g' /etc/nginx/nginx.conf + && sed -i 's/^http {/&\n server_names_hash_bucket_size 128;/g' /etc/nginx/nginx.conf \ + && sed -i 's/worker_processes 1/worker_processes auto/' /etc/nginx/nginx.conf # Install Forego ADD https://github.com/jwilder/forego/releases/download/v0.16.1/forego /usr/local/bin/forego From a3cd96ead45911b27c3f20ab6cb0c092b466b366 Mon Sep 17 00:00:00 2001 From: neil Date: Tue, 13 Jun 2017 09:11:27 +0800 Subject: [PATCH 32/76] alpine fix worker_processes to "auto" --- Dockerfile.alpine | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Dockerfile.alpine b/Dockerfile.alpine index b7443f0..b70b8bb 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -8,7 +8,8 @@ RUN apk add --no-cache --virtual .run-deps \ # Configure Nginx and apply fix for very long server names RUN echo "daemon off;" >> /etc/nginx/nginx.conf \ - && sed -i 's/^http {/&\n server_names_hash_bucket_size 128;/g' /etc/nginx/nginx.conf + && sed -i 's/^http {/&\n server_names_hash_bucket_size 128;/g' /etc/nginx/nginx.conf \ + && sed -i 's/worker_processes 1/worker_processes auto/' /etc/nginx/nginx.conf # Install Forego ADD https://github.com/jwilder/forego/releases/download/v0.16.1/forego /usr/local/bin/forego From 761bbf9dbc8ed48a654b1094ce50563efeb1f851 Mon Sep 17 00:00:00 2001 From: Steve Kamerman Date: Sun, 18 Jun 2017 21:21:05 -0400 Subject: [PATCH 33/76] Removed duplicate server_names_hash_bucket_size directive --- Dockerfile | 1 - Dockerfile.alpine | 1 - 2 files changed, 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 656f0ba..19690cf 100644 --- a/Dockerfile +++ b/Dockerfile @@ -12,7 +12,6 @@ RUN apt-get update \ # Configure Nginx and apply fix for very long server names RUN echo "daemon off;" >> /etc/nginx/nginx.conf \ - && sed -i 's/^http {/&\n server_names_hash_bucket_size 128;/g' /etc/nginx/nginx.conf \ && sed -i 's/worker_processes 1/worker_processes auto/' /etc/nginx/nginx.conf # Install Forego diff --git a/Dockerfile.alpine b/Dockerfile.alpine index 874a236..2a4ebf8 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -9,7 +9,6 @@ RUN apk add --no-cache --virtual .run-deps \ # Configure Nginx and apply fix for very long server names RUN echo "daemon off;" >> /etc/nginx/nginx.conf \ - && sed -i 's/^http {/&\n server_names_hash_bucket_size 128;/g' /etc/nginx/nginx.conf \ && sed -i 's/worker_processes 1/worker_processes auto/' /etc/nginx/nginx.conf # Install Forego From 026ba7cdac0868834ba63116b2d7d0a2793f4439 Mon Sep 17 00:00:00 2001 From: Steve Kamerman Date: Sun, 18 Jun 2017 21:30:59 -0400 Subject: [PATCH 34/76] Added DHParam compatibility note --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 3ad39f9..df3e838 100644 --- a/README.md +++ b/README.md @@ -184,6 +184,11 @@ 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 +> 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`. + #### Wildcard Certificates Wildcard certificates and keys should be named after the domain name with a `.crt` and `.key` extension. From a318b57408e5099c0490312f8c2f883f69321704 Mon Sep 17 00:00:00 2001 From: Jason Wilder Date: Thu, 22 Jun 2017 11:36:40 -0600 Subject: [PATCH 35/76] Update docker --- .travis.yml | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index a453ac7..268e275 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,20 +1,17 @@ dist: trusty sudo: required -services: - - docker env: - global: - - DOCKER_VERSION=1.13.1-0~ubuntu-trusty matrix: - TEST_TARGET: test-debian - TEST_TARGET: test-alpine before_install: - # list docker-engine versions - - apt-cache madison docker-engine - # upgrade docker-engine to specific version - - sudo apt-get -o Dpkg::Options::="--force-confnew" install -y --force-yes docker-engine=${DOCKER_VERSION} + - sudo apt-get remove docker docker-engine + - 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 + - sudo apt-get -y install docker-ce - docker version - docker info # prepare docker test requirements From 8ac755e1d661ba382da9cb6864e7eac1026080bf Mon Sep 17 00:00:00 2001 From: NaiXiaoXin Date: Sat, 24 Jun 2017 13:51:02 +0800 Subject: [PATCH 36/76] support fastcgi --- README.md | 10 ++++++++++ nginx.tmpl | 12 ++++++++++++ 2 files changed, 22 insertions(+) diff --git a/README.md b/README.md index df3e838..aecf4e5 100644 --- a/README.md +++ b/README.md @@ -108,6 +108,16 @@ If you would like to connect to uWSGI backend, set `VIRTUAL_PROTO=uwsgi` on the backend container. Your backend container should then listen on a port rather than a socket and expose that port. +### FastCGI Backends + +If you would like to connect to FastCGI backend, set `VIRTUAL_PROTO=fastcgi` on the +backend container. Your backend container should then listen on a port rather +than a socket and expose that port. + +### FastCGI Filr Root Directory + +If you use fastcgi,you can set `VIRTUAL_ROOT=xxx` for your root directory + ### Default Host To set the default host for nginx use the env var `DEFAULT_HOST=foo.bar.com` for example diff --git a/nginx.tmpl b/nginx.tmpl index f23e627..57e04a7 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -146,6 +146,10 @@ 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 VIRTUAL_ROOT By containers w/ use fastcgi root */}} +{{ $vhost_root := or (first (groupByKeys $containers "Env.VIRTUAL_ROOT")) "/var/www/public" }} + + {{/* Get the first cert name defined by containers w/ the same vhost */}} {{ $certName := (first (groupByKeys $containers "Env.CERT_NAME")) }} @@ -212,6 +216,10 @@ server { {{ if eq $proto "uwsgi" }} include uwsgi_params; uwsgi_pass {{ trim $proto }}://{{ trim $upstream_name }}; + {{ else if eq $proto "fastcgi" }} + root {{ trim $vhost_root }}; + include fastcgi.conf; + fastcgi_pass {{ trim $upstream_name }}; {{ else }} proxy_pass {{ trim $proto }}://{{ trim $upstream_name }}; {{ end }} @@ -250,6 +258,10 @@ server { {{ if eq $proto "uwsgi" }} include uwsgi_params; uwsgi_pass {{ trim $proto }}://{{ trim $upstream_name }}; + {{ else if eq $proto "fastcgi" }} + root {{ trim $vhost_root }}; + include fastcgi.conf; + fastcgi_pass {{ trim $upstream_name }}; {{ else }} proxy_pass {{ trim $proto }}://{{ trim $upstream_name }}; {{ end }} From 29fffd6de80b76239aa2024ff685da22a508612d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=80=90=E5=B0=8F=E5=BF=83?= Date: Sat, 24 Jun 2017 14:05:42 +0800 Subject: [PATCH 37/76] Revert "support fastcgi" This reverts commit 8ac755e1d661ba382da9cb6864e7eac1026080bf. --- README.md | 10 ---------- nginx.tmpl | 12 ------------ 2 files changed, 22 deletions(-) diff --git a/README.md b/README.md index aecf4e5..df3e838 100644 --- a/README.md +++ b/README.md @@ -108,16 +108,6 @@ If you would like to connect to uWSGI backend, set `VIRTUAL_PROTO=uwsgi` on the backend container. Your backend container should then listen on a port rather than a socket and expose that port. -### FastCGI Backends - -If you would like to connect to FastCGI backend, set `VIRTUAL_PROTO=fastcgi` on the -backend container. Your backend container should then listen on a port rather -than a socket and expose that port. - -### FastCGI Filr Root Directory - -If you use fastcgi,you can set `VIRTUAL_ROOT=xxx` for your root directory - ### Default Host To set the default host for nginx use the env var `DEFAULT_HOST=foo.bar.com` for example diff --git a/nginx.tmpl b/nginx.tmpl index 57e04a7..f23e627 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -146,10 +146,6 @@ 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 VIRTUAL_ROOT By containers w/ use fastcgi root */}} -{{ $vhost_root := or (first (groupByKeys $containers "Env.VIRTUAL_ROOT")) "/var/www/public" }} - - {{/* Get the first cert name defined by containers w/ the same vhost */}} {{ $certName := (first (groupByKeys $containers "Env.CERT_NAME")) }} @@ -216,10 +212,6 @@ server { {{ if eq $proto "uwsgi" }} include uwsgi_params; uwsgi_pass {{ trim $proto }}://{{ trim $upstream_name }}; - {{ else if eq $proto "fastcgi" }} - root {{ trim $vhost_root }}; - include fastcgi.conf; - fastcgi_pass {{ trim $upstream_name }}; {{ else }} proxy_pass {{ trim $proto }}://{{ trim $upstream_name }}; {{ end }} @@ -258,10 +250,6 @@ server { {{ if eq $proto "uwsgi" }} include uwsgi_params; uwsgi_pass {{ trim $proto }}://{{ trim $upstream_name }}; - {{ else if eq $proto "fastcgi" }} - root {{ trim $vhost_root }}; - include fastcgi.conf; - fastcgi_pass {{ trim $upstream_name }}; {{ else }} proxy_pass {{ trim $proto }}://{{ trim $upstream_name }}; {{ end }} From 2eb2ae9c93c46ebb7031a2a71beef2bf18da89b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=80=90=E5=B0=8F=E5=BF=83?= Date: Sat, 24 Jun 2017 14:48:05 +0800 Subject: [PATCH 38/76] support fastcgi --- README.md | 11 +++++++++++ nginx.tmpl | 14 +++++++++++++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index df3e838..1cf11cb 100644 --- a/README.md +++ b/README.md @@ -108,6 +108,17 @@ If you would like to connect to uWSGI backend, set `VIRTUAL_PROTO=uwsgi` on the backend container. Your backend container should then listen on a port rather than a socket and expose that port. +### FastCGI Backends + +If you would like to connect to FastCGI backend, set `VIRTUAL_PROTO=fastcgi` on the +backend container. Your backend container should then listen on a port rather +than a socket and expose that port. + +### FastCGI Filr Root Directory + +If you use fastcgi,you can set `VIRTUAL_ROOT=xxx` for your root directory + + ### Default Host To set the default host for nginx use the env var `DEFAULT_HOST=foo.bar.com` for example diff --git a/nginx.tmpl b/nginx.tmpl index f23e627..1b3ff86 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -146,6 +146,10 @@ 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 VIRTUAL_ROOT By containers w/ use fastcgi root */}} +{{ $vhost_root := or (first (groupByKeys $containers "Env.VIRTUAL_ROOT")) "/var/www/public" }} + + {{/* Get the first cert name defined by containers w/ the same vhost */}} {{ $certName := (first (groupByKeys $containers "Env.CERT_NAME")) }} @@ -212,6 +216,10 @@ server { {{ if eq $proto "uwsgi" }} include uwsgi_params; uwsgi_pass {{ trim $proto }}://{{ trim $upstream_name }}; + {{ else if eq $proto "fastcgi" }} + root {{ trim $vhost_root }}; + include fastcgi.conf; + fastcgi_pass {{ trim $upstream_name }}; {{ else }} proxy_pass {{ trim $proto }}://{{ trim $upstream_name }}; {{ end }} @@ -250,6 +258,10 @@ server { {{ if eq $proto "uwsgi" }} include uwsgi_params; uwsgi_pass {{ trim $proto }}://{{ trim $upstream_name }}; + {{ else if eq $proto "fastcgi" }} + root {{ trim $vhost_root }}; + include fastcgi.conf; + fastcgi_pass {{ trim $upstream_name }}; {{ else }} proxy_pass {{ trim $proto }}://{{ trim $upstream_name }}; {{ end }} @@ -281,4 +293,4 @@ server { {{ end }} {{ end }} -{{ end }} +{{ end }} \ No newline at end of file From febf85d7e2c918de278e988fced70ba147df14d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20D=C3=B6ring?= Date: Fri, 21 Jul 2017 13:45:33 +0200 Subject: [PATCH 39/76] Move to 1.13 base image to get auto updates Less maintenance and more security Resolves #880 --- 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 19690cf..851bcaa 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM nginx:1.13.0 +FROM nginx:1.13 MAINTAINER Jason Wilder mail@jasonwilder.com # Install wget and install/updates certificates diff --git a/Dockerfile.alpine b/Dockerfile.alpine index 2a4ebf8..1d588d3 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -1,4 +1,4 @@ -FROM nginx:1.13.0-alpine +FROM nginx:1.13-alpine MAINTAINER Jason Wilder mail@jasonwilder.com # Install wget and install/updates certificates diff --git a/README.md b/README.md index df3e838..c3f7643 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -![nginx 1.13.0](https://img.shields.io/badge/nginx-1.13.0-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.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-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 adacb5e..bffc27e 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.0) +CONTAINER=$(docker run -d -v $DIR:/work -w /work -e SAN="$ALTERNATE_DOMAINS" nginx:1.13) # Configure openssl docker exec $CONTAINER bash -c ' mkdir -p /ca/{certs,crl,private,newcerts} 2>/dev/null From 0cc71fad49bbacefe6e3b1bb8381f164fedb84b5 Mon Sep 17 00:00:00 2001 From: Steve Kamerman Date: Sat, 1 Oct 2016 10:42:58 -0400 Subject: [PATCH 40/76] Add dynamically-computed DNS resolvers to nginx (for PR #574) --- docker-entrypoint.sh | 6 ++++++ nginx.tmpl | 10 ++++++++++ 2 files changed, 16 insertions(+) diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh index a413877..ed2e882 100755 --- a/docker-entrypoint.sh +++ b/docker-entrypoint.sh @@ -18,6 +18,12 @@ fi # Note: if $DHPARAM_BITS is not defined, generate-dhparam.sh will use 2048 as a default /app/generate-dhparam.sh $DHPARAM_BITS +# Compute the DNS resolvers for use in the templates +export RESOLVERS=$(awk '$1 == "nameserver" {print $2}' ORS=' ' /etc/resolv.conf | sed 's/ *$//g') +if [ "x$RESOLVERS" = "x" ]; then + echo "Warning: unable to determine DNS resolvers for nginx" >&2 +fi + # If the user has run the default command and the socket doesn't exist, fail if [ "$socketMissing" = 1 -a "$1" = forego -a "$2" = start -a "$3" = '-r' ]; then exit 1 diff --git a/nginx.tmpl b/nginx.tmpl index f23e627..2ef7646 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -58,6 +58,10 @@ log_format vhost '$host $remote_addr - $remote_user [$time_local] ' access_log off; +{{ if ne $.Env.RESOLVERS "" }} +resolver {{ $.Env.RESOLVERS }}; +{{ end }} + {{ if (exists "/etc/nginx/proxy.conf") }} include /etc/nginx/proxy.conf; {{ else }} @@ -198,6 +202,12 @@ server { ssl_dhparam {{ printf "/etc/nginx/certs/%s.dhparam.pem" $cert }}; {{ end }} + {{ if (exists (printf "/etc/nginx/certs/%s.chain.crt" $cert)) }} + ssl_stapling on; + ssl_stapling_verify on; + ssl_trusted_certificate {{ printf "/etc/nginx/certs/%s.chain.crt" $cert }}; + {{ end }} + {{ if (ne $https_method "noredirect") }} add_header Strict-Transport-Security "max-age=31536000"; {{ end }} From dfe7677eb54e12146b0cc322946d6ec66b7f43e0 Mon Sep 17 00:00:00 2001 From: Teoh Han Hui Date: Mon, 19 Sep 2016 15:23:46 +0800 Subject: [PATCH 41/76] Enable OCSP stapling if certificate trust chain is provided Previously disabled in 080a5157e6b1de3637e339a7cf54105f0316cfa7 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c3f7643..a3b490c 100644 --- a/README.md +++ b/README.md @@ -206,7 +206,7 @@ and `CERT_NAME=shared` will then use this shared cert. The SSL cipher configuration is based on the [Mozilla nginx intermediate profile](https://wiki.mozilla.org/Security/Server_Side_TLS#Nginx) 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, and SSL session caches. Currently TLS 1.0, 1.1 and 1.2 +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. From 065dd7f1ea51f9a908c26dca840ff0a3d6cba606 Mon Sep 17 00:00:00 2001 From: Teoh Han Hui Date: Mon, 6 Feb 2017 18:20:54 +0800 Subject: [PATCH 42/76] Fix build --- docker-entrypoint.sh | 1 + nginx.tmpl | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh index ed2e882..2afd5bf 100755 --- a/docker-entrypoint.sh +++ b/docker-entrypoint.sh @@ -22,6 +22,7 @@ fi export RESOLVERS=$(awk '$1 == "nameserver" {print $2}' ORS=' ' /etc/resolv.conf | sed 's/ *$//g') if [ "x$RESOLVERS" = "x" ]; then echo "Warning: unable to determine DNS resolvers for nginx" >&2 + unset RESOLVERS fi # If the user has run the default command and the socket doesn't exist, fail diff --git a/nginx.tmpl b/nginx.tmpl index 2ef7646..09a709c 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -58,7 +58,7 @@ log_format vhost '$host $remote_addr - $remote_user [$time_local] ' access_log off; -{{ if ne $.Env.RESOLVERS "" }} +{{ if $.Env.RESOLVERS }} resolver {{ $.Env.RESOLVERS }}; {{ end }} From fff84de367621c3456f57dfdb2bed78331334ecd Mon Sep 17 00:00:00 2001 From: Remi Pichon Date: Thu, 10 Aug 2017 12:30:00 +0200 Subject: [PATCH 43/76] Do not bind upstream with 'ingress' network Merging https://github.com/jwilder/nginx-proxy/pull/774 and https://github.com/jwilder/nginx-proxy/commit/a8ee64b0596ffc0a8df369e88d1115b80afb04fa --- nginx.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nginx.tmpl b/nginx.tmpl index f23e627..85be0aa 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -118,7 +118,7 @@ upstream {{ $upstream_name }} { {{ range $knownNetwork := $CurrentContainer.Networks }} {{ range $containerNetwork := $container.Networks }} - {{ if or (eq $knownNetwork.Name $containerNetwork.Name) (eq $knownNetwork.Name "host") }} + {{ if (and (ne $containerNetwork.Name "ingress") (or (eq $knownNetwork.Name $containerNetwork.Name) (eq $knownNetwork.Name "host"))) }} ## Can be connect with "{{ $containerNetwork.Name }}" network {{/* If only 1 port exposed, use that */}} From 343791b6570588c369d06a5d1027166b235ababd Mon Sep 17 00:00:00 2001 From: Brikou CARRE Date: Sat, 12 Aug 2017 07:37:05 +0200 Subject: [PATCH 44/76] Simplify docker-compose.yml example Remove `container_name` as not required --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index c3f7643..6e3383c 100644 --- a/README.md +++ b/README.md @@ -39,10 +39,10 @@ This image is based on the nginx:alpine image. Use this image to fully support H ```yaml version: '2' + services: nginx-proxy: image: jwilder/nginx-proxy - container_name: nginx-proxy ports: - "80:80" volumes: @@ -50,7 +50,6 @@ services: whoami: image: jwilder/whoami - container_name: whoami environment: - VIRTUAL_HOST=whoami.local ``` From 3156b97f3a70d164384c248d265a67cd796982a8 Mon Sep 17 00:00:00 2001 From: Patrick Date: Wed, 13 Sep 2017 12:37:06 +0200 Subject: [PATCH 45/76] 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 93d90884e290dad2076079ded8fefd98c2da6237 Mon Sep 17 00:00:00 2001 From: Steve Kamerman Date: Wed, 18 Oct 2017 12:57:59 -0400 Subject: [PATCH 46/76] Implemented NETWORK_ACCESS (squash commit) --- Dockerfile | 2 ++ README.md | 19 +++++++++++++++++++ network_internal.conf | 6 ++++++ nginx.tmpl | 36 ++++++++++++++++++++++++++---------- 4 files changed, 53 insertions(+), 10 deletions(-) create mode 100644 network_internal.conf diff --git a/Dockerfile b/Dockerfile index 851bcaa..cdf47c5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -24,6 +24,8 @@ RUN wget https://github.com/jwilder/docker-gen/releases/download/$DOCKER_GEN_VER && tar -C /usr/local/bin -xvzf docker-gen-linux-amd64-$DOCKER_GEN_VERSION.tar.gz \ && rm /docker-gen-linux-amd64-$DOCKER_GEN_VERSION.tar.gz +COPY network_internal.conf /etc/nginx/ + COPY . /app/ WORKDIR /app/ diff --git a/README.md b/README.md index 639289c..8fa4bc5 100644 --- a/README.md +++ b/README.md @@ -95,6 +95,25 @@ $ docker network connect my-other-network my-nginx-proxy In this example, the `my-nginx-proxy` container will be connected to `my-network` and `my-other-network` and will be able to proxy to other containers attached to those networks. +### Internet vs. Local Network Access + +If you allow traffic from the public internet to access your `nginx-proxy` container, you may want to restrict some containers to the internal network only, so they cannot be accessed from the public internet. On containers that should be restricted to the internal network, you should set the environment variable `NETWORK_ACCESS=internal`. By default, the *internal* network is defined as `127.0.0.0/8, 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16`. To change the list of networks considered internal, mount a file on the `nginx-proxy` at `/etc/nginx/network_internal.conf` with these contents, edited to suit your needs: + +``` +# These networks are considered "internal" +allow 127.0.0.0/8; +allow 10.0.0.0/8; +allow 192.168.0.0/16; +allow 172.16.0.0/12; + +# Traffic from all other networks will be rejected +deny all; +``` + +When internal-only access is enabled, external clients with be denied with an `HTTP 403 Forbidden` + +> If there is a load-balancer / reverse proxy in front of `nginx-proxy` that hides the client IP (example: AWS Application/Elastic Load Balancer), you will need to use the nginx `realip` module (already installed) to extract the client's IP from the HTTP request headers. Please see the [nginx realip module configuration](http://nginx.org/en/docs/http/ngx_http_realip_module.html) for more details. This configuration can be added to a new config file and mounted in `/etc/nginx/conf.d/`. + ### SSL Backends If you would like the reverse proxy to connect to your backend using HTTPS instead of HTTP, set `VIRTUAL_PROTO=https` on the backend container. diff --git a/network_internal.conf b/network_internal.conf new file mode 100644 index 0000000..cdf3c9c --- /dev/null +++ b/network_internal.conf @@ -0,0 +1,6 @@ +# Only allow traffic from internal clients +allow 127.0.0.0/8; +allow 10.0.0.0/8; +allow 192.168.0.0/16; +allow 172.16.0.0/12; +deny all; diff --git a/nginx.tmpl b/nginx.tmpl index 3c26a9c..cf4f6f1 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -147,6 +147,12 @@ upstream {{ $upstream_name }} { {{/* Get the VIRTUAL_PROTO defined by containers w/ the same vhost, falling back to "http" */}} {{ $proto := trim (or (first (groupByKeys $containers "Env.VIRTUAL_PROTO")) "http") }} +{{/* Get the NETWORK_ACCESS defined by containers w/ the same vhost, falling back to "external" */}} +{{ $network_tag := or (first (groupByKeys $containers "Env.NETWORK_ACCESS")) "external" }} + +{{/* 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" }} @@ -187,6 +193,11 @@ server { {{ end }} access_log /var/log/nginx/access.log vhost; + {{ if eq $network_tag "internal" }} + # Only allow traffic from internal clients + include /etc/nginx/network_internal.conf; + {{ end }} + 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'; @@ -230,11 +241,11 @@ server { auth_basic "Restricted {{ $host }}"; auth_basic_user_file {{ (printf "/etc/nginx/htpasswd/%s" $host) }}; {{ end }} - {{ if (exists (printf "/etc/nginx/vhost.d/%s_location" $host)) }} - include {{ printf "/etc/nginx/vhost.d/%s_location" $host}}; - {{ else if (exists "/etc/nginx/vhost.d/default_location") }} - include /etc/nginx/vhost.d/default_location; - {{ end }} + {{ if (exists (printf "/etc/nginx/vhost.d/%s_location" $host)) }} + include {{ printf "/etc/nginx/vhost.d/%s_location" $host}}; + {{ else if (exists "/etc/nginx/vhost.d/default_location") }} + include /etc/nginx/vhost.d/default_location; + {{ end }} } } @@ -250,6 +261,11 @@ server { {{ end }} access_log /var/log/nginx/access.log vhost; + {{ if eq $network_tag "internal" }} + # Only allow traffic from internal clients + include /etc/nginx/network_internal.conf; + {{ end }} + {{ if (exists (printf "/etc/nginx/vhost.d/%s" $host)) }} include {{ printf "/etc/nginx/vhost.d/%s" $host }}; {{ else if (exists "/etc/nginx/vhost.d/default") }} @@ -267,11 +283,11 @@ server { auth_basic "Restricted {{ $host }}"; auth_basic_user_file {{ (printf "/etc/nginx/htpasswd/%s" $host) }}; {{ end }} - {{ if (exists (printf "/etc/nginx/vhost.d/%s_location" $host)) }} - include {{ printf "/etc/nginx/vhost.d/%s_location" $host}}; - {{ else if (exists "/etc/nginx/vhost.d/default_location") }} - include /etc/nginx/vhost.d/default_location; - {{ end }} + {{ if (exists (printf "/etc/nginx/vhost.d/%s_location" $host)) }} + include {{ printf "/etc/nginx/vhost.d/%s_location" $host}}; + {{ else if (exists "/etc/nginx/vhost.d/default_location") }} + include /etc/nginx/vhost.d/default_location; + {{ end }} } } From 5d503b48cb414026c268069b273aef2ce6708b0f Mon Sep 17 00:00:00 2001 From: Steve Kamerman Date: Thu, 19 Oct 2017 20:58:34 -0400 Subject: [PATCH 47/76] Added support for IPv6 DNS servers in resolver generation (issue #938) --- docker-entrypoint.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh index 2afd5bf..7e7a312 100755 --- a/docker-entrypoint.sh +++ b/docker-entrypoint.sh @@ -18,8 +18,8 @@ fi # Note: if $DHPARAM_BITS is not defined, generate-dhparam.sh will use 2048 as a default /app/generate-dhparam.sh $DHPARAM_BITS -# Compute the DNS resolvers for use in the templates -export RESOLVERS=$(awk '$1 == "nameserver" {print $2}' ORS=' ' /etc/resolv.conf | sed 's/ *$//g') +# Compute the DNS resolvers for use in the templates - if the IP contains ":", it's IPv6 and must be enclosed in [] +export RESOLVERS=$(awk '$1 == "nameserver" {print ($2 ~ ":")? "["$2"]": $2}' ORS=' ' /etc/resolv.conf | sed 's/ *$//g') if [ "x$RESOLVERS" = "x" ]; then echo "Warning: unable to determine DNS resolvers for nginx" >&2 unset RESOLVERS From 2528a35656c69145a0cfff19768b44b1e0a473b1 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Wed, 25 Oct 2017 12:32:09 +0200 Subject: [PATCH 48/76] Don't presume the existence of default dhparam The default dhparam at /etc/nginx/dhparam/dhparam.pem won't be auto generated with the separate containers setup. --- nginx.tmpl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/nginx.tmpl b/nginx.tmpl index 65faa0b..28f745a 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -42,7 +42,9 @@ map $http_upgrade $proxy_connection { server_names_hash_bucket_size 128; # Default dhparam +{{ if (exists "/etc/nginx/dhparam/dhparam.pem") }} ssl_dhparam /etc/nginx/dhparam/dhparam.pem; +{{ end }} # Set appropriate X-Forwarded-Ssl header map $scheme $proxy_x_forwarded_ssl { @@ -319,4 +321,4 @@ server { {{ end }} {{ end }} -{{ end }} \ No newline at end of file +{{ end }} From 3ac478f2848b938f645a35e0cba536b383fd76d8 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Wed, 25 Oct 2017 12:34:22 +0200 Subject: [PATCH 49/76] Update Diffie-Hellman Groups doc + corrected a typo --- README.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index f8c0c9f..91052d4 100644 --- a/README.md +++ b/README.md @@ -210,7 +210,7 @@ should have a `foo.bar.com.dhparam.pem` file in the `/etc/nginx/certs` directory > NOTE: If you don't mount a `dhparam.pem` file at `/etc/nginx/dhparam/dhparam.pem`, one will be generated at startup. Since it can take minutes to generate a new `dhparam.pem`, it is done at low priority in the -background. Once generation is complete, the `dhparams.pem` is saved on a persistent volume and nginx +background. Once generation is complete, the `dhparam.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 @@ -218,6 +218,12 @@ is reloaded. This generation process only occurs the first time you start `ngin > 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`. +In the separate container setup, no pregenerated key will be available and neither the +[jwilder/docker-gen](https://index.docker.io/u/jwilder/docker-gen/) image nor the offical +[nginx](https://registry.hub.docker.com/_/nginx/) image will generate one. If you still want A+ security +in a separate container setup, you'll have to generate a 2048 bits DH key file manually and mount it on the +nginx container, at `/etc/nginx/dhparam/dhparam.pem`. + #### Wildcard Certificates Wildcard certificates and keys should be named after the domain name with a `.crt` and `.key` extension. From ea98780960a3966e22abfcbdc7efa86eebdf2b10 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Fri, 27 Oct 2017 10:09:32 +0200 Subject: [PATCH 50/76] 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 51/76] 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 55610b8425549863bc04ed80e0797bc8e1e5995f Mon Sep 17 00:00:00 2001 From: cglewis Date: Tue, 31 Oct 2017 18:21:12 -0700 Subject: [PATCH 52/76] MAINTAINER is deprecated, using LABEL now --- Dockerfile | 2 +- Dockerfile.alpine | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index cdf47c5..149fb90 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ FROM nginx:1.13 -MAINTAINER Jason Wilder mail@jasonwilder.com +LABEL maintainer="Jason Wilder mail@jasonwilder.com" # Install wget and install/updates certificates RUN apt-get update \ diff --git a/Dockerfile.alpine b/Dockerfile.alpine index 1d588d3..fce6aae 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -1,5 +1,5 @@ FROM nginx:1.13-alpine -MAINTAINER Jason Wilder mail@jasonwilder.com +LABEL maintainer="Jason Wilder mail@jasonwilder.com" # Install wget and install/updates certificates RUN apk add --no-cache --virtual .run-deps \ From a312472fb57cbc0e9747898ee96b390232b30340 Mon Sep 17 00:00:00 2001 From: Steve Kamerman Date: Wed, 8 Nov 2017 22:30:24 -0500 Subject: [PATCH 53/76] Added custom HSTS support (issue #953) --- README.md | 7 +++++++ nginx.tmpl | 7 +++++-- test/test_ssl/test_hsts.py | 19 +++++++++++++++++++ test/test_ssl/test_hsts.yml | 32 ++++++++++++++++++++++++++++++++ 4 files changed, 63 insertions(+), 2 deletions(-) create mode 100644 test/test_ssl/test_hsts.py create mode 100644 test/test_ssl/test_hsts.yml diff --git a/README.md b/README.md index 91052d4..6d67e6e 100644 --- a/README.md +++ b/README.md @@ -267,6 +267,13 @@ site after changing this setting, your browser has probably cached the HSTS poli redirecting you back to HTTPS. You will need to clear your browser's HSTS cache or use an incognito window / different browser. +By default, [HTTP Strict Transport Security (HSTS)](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security) +is enabled with `max-age=31536000` for HTTPS sites. You can disable HSTS with the environment variable +`HSTS=off` or use a custom HSTS configuration like `HSTS=max-age=31536000; includeSubDomains; preload`. +*WARNING*: HSTS will force your users to visit the HTTPS version of your site for the `max-age` time - +even if they type in `http://` manually. The only way to get to an HTTP site after receiving an HSTS +response is to clear your browser's HSTS cache. + ### Basic Authentication Support In order to be able to secure your virtual host, you have to create a file named as its equivalent VIRTUAL_HOST variable on directory diff --git a/nginx.tmpl b/nginx.tmpl index 28f745a..5147fee 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 HSTS defined by containers w/ the same vhost, falling back to "max-age=31536000" */}} +{{ $hsts := or (first (groupByKeys $containers "Env.HSTS")) "max-age=31536000" }} + {{/* Get the VIRTUAL_ROOT By containers w/ use fastcgi root */}} {{ $vhost_root := or (first (groupByKeys $containers "Env.VIRTUAL_ROOT")) "/var/www/public" }} @@ -225,8 +228,8 @@ server { ssl_trusted_certificate {{ printf "/etc/nginx/certs/%s.chain.crt" $cert }}; {{ end }} - {{ if (ne $https_method "noredirect") }} - add_header Strict-Transport-Security "max-age=31536000"; + {{ if (and (ne $https_method "noredirect") (ne $hsts "off")) }} + add_header Strict-Transport-Security "{{ trim $hsts }}"; {{ end }} {{ if (exists (printf "/etc/nginx/vhost.d/%s" $host)) }} diff --git a/test/test_ssl/test_hsts.py b/test/test_ssl/test_hsts.py new file mode 100644 index 0000000..180f274 --- /dev/null +++ b/test/test_ssl/test_hsts.py @@ -0,0 +1,19 @@ +import pytest + + +def test_web1_HSTS_default(docker_compose, nginxproxy): + r = nginxproxy.get("https://web1.nginx-proxy.tld/port", allow_redirects=False) + assert "answer from port 81\n" in r.text + assert "Strict-Transport-Security" in r.headers + assert "max-age=31536000" == r.headers["Strict-Transport-Security"] + +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 + assert "Strict-Transport-Security" not in r.headers + +def test_web3_HSTS_custom(docker_compose, nginxproxy): + r = nginxproxy.get("https://web3.nginx-proxy.tld/port", allow_redirects=False) + assert "answer from port 81\n" in r.text + assert "Strict-Transport-Security" in r.headers + assert "max-age=86400; includeSubDomains; preload" == r.headers["Strict-Transport-Security"] diff --git a/test/test_ssl/test_hsts.yml b/test/test_ssl/test_hsts.yml new file mode 100644 index 0000000..5c04cf0 --- /dev/null +++ b/test/test_ssl/test_hsts.yml @@ -0,0 +1,32 @@ +web1: + image: web + expose: + - "81" + environment: + WEB_PORTS: "81" + VIRTUAL_HOST: "web1.nginx-proxy.tld" + +web2: + image: web + expose: + - "81" + environment: + WEB_PORTS: "81" + VIRTUAL_HOST: "web2.nginx-proxy.tld" + HSTS: "off" + +web3: + image: web + expose: + - "81" + environment: + WEB_PORTS: "81" + VIRTUAL_HOST: "web3.nginx-proxy.tld" + HSTS: "max-age=86400; includeSubDomains; preload" + +sut: + image: jwilder/nginx-proxy:test + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro + - ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro + - ./certs:/etc/nginx/certs:ro From 58a02f107eb0e43a631eb9b99a18c5c13ccec4f0 Mon Sep 17 00:00:00 2001 From: Steve Kamerman Date: Wed, 8 Nov 2017 22:42:52 -0500 Subject: [PATCH 54/76] Removed '-verify 0' - to disable verification, exclude -verify entirely --- 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 67b11fa..fd60217 100644 --- a/test/test_ssl/test_dhparam.py +++ b/test/test_ssl/test_dhparam.py @@ -89,5 +89,5 @@ def test_web5_dhparam_is_used(docker_compose): host = "%s:443" % sut_container.attrs["NetworkSettings"]["IPAddress"] r = subprocess.check_output( - "echo '' | openssl s_client -verify 0 -connect %s -cipher 'EDH' | grep 'Server Temp Key'" % host, shell=True) + "echo '' | openssl s_client -connect %s -cipher 'EDH' | grep 'Server Temp Key'" % host, shell=True) assert "Server Temp Key: DH, 2048 bits\n" == r From ebd1485b09ad2ab70bdf4a13d4e39152fc1fda27 Mon Sep 17 00:00:00 2001 From: Steve Kamerman Date: Wed, 8 Nov 2017 22:53:44 -0500 Subject: [PATCH 55/76] Catch SSLError instead of CertificateError --- .../wildcard_cert_and_nohttps/test_wildcard_cert_nohttps.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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 db18809..12b04c7 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 @@ -1,6 +1,5 @@ import pytest -from backports.ssl_match_hostname import CertificateError - +from requests.exceptions import SSLError @pytest.mark.parametrize("subdomain,should_redirect_to_https", [ (1, True), @@ -23,9 +22,10 @@ def test_https_get_served(docker_compose, nginxproxy, subdomain): def test_web3_https_is_500_and_SSL_validation_fails(docker_compose, nginxproxy): - with pytest.raises(CertificateError) as excinfo: + with pytest.raises(SSLError) as excinfo: nginxproxy.get("https://3.web.nginx-proxy.tld/port") assert """hostname '3.web.nginx-proxy.tld' doesn't match 'nginx-proxy.tld'""" in str(excinfo.value) + r = nginxproxy.get("https://3.web.nginx-proxy.tld/port", verify=False) assert r.status_code == 500 From 612bf72ceb3157a0ebad12b2dd09ad2874b24013 Mon Sep 17 00:00:00 2001 From: Steve Kamerman Date: Wed, 8 Nov 2017 23:19:13 -0500 Subject: [PATCH 56/76] Support old and new versions of requests --- .../wildcard_cert_and_nohttps/test_wildcard_cert_nohttps.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) 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 12b04c7..de4b298 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 @@ -1,6 +1,8 @@ import pytest +from backports.ssl_match_hostname import CertificateError from requests.exceptions import SSLError + @pytest.mark.parametrize("subdomain,should_redirect_to_https", [ (1, True), (2, True), @@ -22,10 +24,9 @@ def test_https_get_served(docker_compose, nginxproxy, subdomain): def test_web3_https_is_500_and_SSL_validation_fails(docker_compose, nginxproxy): - with pytest.raises(SSLError) as excinfo: + with pytest.raises( (CertificateError, SSLError) ) as excinfo: nginxproxy.get("https://3.web.nginx-proxy.tld/port") assert """hostname '3.web.nginx-proxy.tld' doesn't match 'nginx-proxy.tld'""" in str(excinfo.value) - r = nginxproxy.get("https://3.web.nginx-proxy.tld/port", verify=False) assert r.status_code == 500 From bf16afc66540b8a4eb2337776991c6a78f230dd4 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Thu, 16 Nov 2017 23:34:42 +0100 Subject: [PATCH 57/76] 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 58/76] 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 59/76] 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 60/76] 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 61/76] 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 62/76] 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 63/76] 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 64/76] 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 65/76] 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 66/76] 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 67/76] 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 68/76] 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 69/76] 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 70/76] 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 c417813df916789fa29a83c3e31f196777e718d3 Mon Sep 17 00:00:00 2001 From: Steve Kamerman Date: Sun, 22 Apr 2018 16:03:43 -0400 Subject: [PATCH 71/76] 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 72/76] 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 73/76] 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 74/76] 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 75/76] 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 58c1fe360687a3a005ff9eae23ac3b6c4c4c3123 Mon Sep 17 00:00:00 2001 From: Gpkfr Date: Fri, 9 Nov 2018 15:26:01 +0100 Subject: [PATCH 76/76] 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