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..f27c467 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. @@ -181,8 +181,12 @@ Finally, start your containers with `VIRTUAL_HOST` environment variables. $ docker run -e VIRTUAL_HOST=foo.bar.com ... ### SSL Support using letsencrypt -[letsencrypt-nginx-proxy-companion](https://github.com/JrCs/docker-letsencrypt-nginx-proxy-companion) is a lightweight companion container for the nginx-proxy. It allow the creation/renewal of Let's Encrypt certificates automatically. +[letsencrypt-nginx-proxy-companion](https://github.com/JrCs/docker-letsencrypt-nginx-proxy-companion) is a lightweight companion container for the nginx-proxy. It allow the creation/renewal of Let's Encrypt certificates automatically. +Set `DHPARAM_GENERATION` environment variable to `false` to disabled Diffie-Hellman parameters completely. This will also ignore auto-generation made by `nginx-proxy`. +The default value is `true` + + $ docker run -e DHPARAM_GENERATION=false .... ### SSL Support SSL is supported using single host, wildcard and SNI certificates using naming conventions for @@ -214,7 +218,7 @@ at startup. Since it can take minutes to generate a new `dhparam.pem`, it is do 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 +> 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`. @@ -282,12 +286,12 @@ a 500. To serve traffic in both SSL and non-SSL modes without redirecting to SSL, you can include the environment variable `HTTPS_METHOD=noredirect` (the default is `HTTPS_METHOD=redirect`). You can also -disable the non-SSL site entirely with `HTTPS_METHOD=nohttp`, or disable the HTTPS site with -`HTTPS_METHOD=nohttps`. `HTTPS_METHOD` must be specified on each container for which you want to -override the default behavior. If `HTTPS_METHOD=noredirect` is used, Strict Transport Security (HSTS) -is disabled to prevent HTTPS users from being redirected by the client. If you cannot get to the HTTP -site after changing this setting, your browser has probably cached the HSTS policy and is automatically -redirecting you back to HTTPS. You will need to clear your browser's HSTS cache or use an incognito +disable the non-SSL site entirely with `HTTPS_METHOD=nohttp`, or disable the HTTPS site with +`HTTPS_METHOD=nohttps`. `HTTPS_METHOD` must be specified on each container for which you want to +override the default behavior. If `HTTPS_METHOD=noredirect` is used, Strict Transport Security (HSTS) +is disabled to prevent HTTPS users from being redirected by the client. If you cannot get to the HTTP +site after changing this setting, your browser has probably cached the HSTS policy and is automatically +redirecting you back to HTTPS. You will need to clear your browser's HSTS cache or use an incognito window / different browser. By default, [HTTP Strict Transport Security (HSTS)](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security) @@ -410,7 +414,7 @@ Before submitting pull requests or issues, please check github to make sure an e To run tests, you need to prepare the docker image to test which must be tagged `jwilder/nginx-proxy:test`: docker build -t jwilder/nginx-proxy:test . # build the Debian variant image - + and call the [test/pytest.sh](test/pytest.sh) script. Then build the Alpine variant of the image: @@ -423,7 +427,7 @@ and call the [test/pytest.sh](test/pytest.sh) script again. If your system has the `make` command, you can automate those tasks by calling: make test - + You can learn more about how the test suite works and how to write new tests in the [test/README.md](test/README.md) file. diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh index 7e7a312..b425dfe 100755 --- a/docker-entrypoint.sh +++ b/docker-entrypoint.sh @@ -16,7 +16,8 @@ fi # Generate dhparam file if required # Note: if $DHPARAM_BITS is not defined, generate-dhparam.sh will use 2048 as a default -/app/generate-dhparam.sh $DHPARAM_BITS +# Note2: if $DHPARAM_GENERATION is set to false in environment variable, dh param generator will skip completely +/app/generate-dhparam.sh $DHPARAM_BITS $DHPARAM_GENERATION # Compute the DNS resolvers for use in the templates - 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') diff --git a/generate-dhparam.sh b/generate-dhparam.sh index 3fdc77c..4099dde 100755 --- a/generate-dhparam.sh +++ b/generate-dhparam.sh @@ -2,6 +2,7 @@ # The first argument is the bit depth of the dhparam, or 2048 if unspecified DHPARAM_BITS=${1:-2048} +GENERATE_DHPARAM=${2:-true} # If a dhparam file is not available, use the pre-generated one and generate a new one in the background. # Note that /etc/nginx/dhparam is a volume, so this dhparam will persist restarts. @@ -25,6 +26,11 @@ if [[ -f $DHPARAM_FILE ]]; then fi fi +if [[ $GENERATE_DHPARAM =~ ^[Ff][Aa][Ll][Ss][Ee]$ ]]; then + echo "Skipping Diffie-Hellman parameters generation and Ignoring pre-generated dhparam.pem" + exit 0 +fi + cat >&2 <<-EOT WARNING: $DHPARAM_FILE was not found. A pre-generated dhparam.pem will be used for now while a new one is being generated in the background. Once the new dhparam.pem is in place, nginx will be reloaded. @@ -37,7 +43,8 @@ touch $GEN_LOCKFILE # Generate a new dhparam in the background in a low priority and reload nginx when finished (grep removes the progress indicator). ( ( - nice -n +5 openssl dhparam -out $DHPARAM_FILE $DHPARAM_BITS 2>&1 \ + nice -n +5 openssl dhparam -out $DHPARAM_FILE.tmp $DHPARAM_BITS 2>&1 \ + && mv $DHPARAM_FILE.tmp $DHPARAM_FILE \ && echo "dhparam generation complete, reloading nginx" \ && nginx -s reload ) | grep -vE '^[\.+]+' diff --git a/nginx.tmpl b/nginx.tmpl index fab54f1..c6d7d4f 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -19,7 +19,7 @@ server 127.0.0.1 down; {{ end }} {{ end }} - + {{ end }} # If we receive X-Forwarded-Proto, pass it through; otherwise, pass along the @@ -261,7 +261,7 @@ server { ssl_trusted_certificate {{ printf "/etc/nginx/certs/%s.chain.pem" $cert }}; {{ end }} - {{ if (and (ne $https_method "noredirect") (ne $hsts "off")) }} + {{ if (not (or (eq $https_method "noredirect") (eq $hsts "off"))) }} add_header Strict-Transport-Security "{{ trim $hsts }}" always; {{ end }} diff --git a/test/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 diff --git a/test/test_ssl/test_hsts.py b/test/test_ssl/test_hsts.py index 554d79a..12bbcc4 100644 --- a/test/test_ssl/test_hsts.py +++ b/test/test_ssl/test_hsts.py @@ -24,3 +24,10 @@ def test_web3_HSTS_custom(docker_compose, nginxproxy): assert "answer from port 81\n" in r.text assert "Strict-Transport-Security" in r.headers assert "max-age=86400; includeSubDomains; preload" == r.headers["Strict-Transport-Security"] + +# Regression test for issue 1080 +# https://github.com/jwilder/nginx-proxy/issues/1080 +def test_web4_HSTS_off_noredirect(docker_compose, nginxproxy): + r = nginxproxy.get("https://web4.nginx-proxy.tld/port", allow_redirects=False) + assert "answer from port 81\n" in r.text + assert "Strict-Transport-Security" not in r.headers diff --git a/test/test_ssl/test_hsts.yml b/test/test_ssl/test_hsts.yml index 5c04cf0..f6f39a7 100644 --- a/test/test_ssl/test_hsts.yml +++ b/test/test_ssl/test_hsts.yml @@ -24,6 +24,16 @@ web3: VIRTUAL_HOST: "web3.nginx-proxy.tld" HSTS: "max-age=86400; includeSubDomains; preload" +web4: + image: web + expose: + - "81" + environment: + WEB_PORTS: "81" + VIRTUAL_HOST: "web4.nginx-proxy.tld" + HSTS: "off" + HTTPS_METHOD: "noredirect" + sut: image: jwilder/nginx-proxy:test volumes: diff --git a/test/test_ssl/wildcard_cert_and_nohttps/docker-compose.yml b/test/test_ssl/wildcard_cert_and_nohttps/docker-compose.yml index bffffc1..20cd1b2 100644 --- a/test/test_ssl/wildcard_cert_and_nohttps/docker-compose.yml +++ b/test/test_ssl/wildcard_cert_and_nohttps/docker-compose.yml @@ -7,6 +7,7 @@ services: volumes: - /var/run/docker.sock:/tmp/docker.sock:ro - ./certs:/etc/nginx/certs:ro + - ../../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro web1: image: web @@ -30,4 +31,4 @@ services: environment: WEB_PORTS: "83" VIRTUAL_HOST: "3.web.nginx-proxy.tld" - HTTPS_METHOD: nohttps \ No newline at end of file + HTTPS_METHOD: nohttps diff --git a/test/test_ssl/wildcard_cert_and_nohttps/test_wildcard_cert_nohttps.py b/test/test_ssl/wildcard_cert_and_nohttps/test_wildcard_cert_nohttps.py index de4b298..2808dee 100644 --- a/test/test_ssl/wildcard_cert_and_nohttps/test_wildcard_cert_nohttps.py +++ b/test/test_ssl/wildcard_cert_and_nohttps/test_wildcard_cert_nohttps.py @@ -11,6 +11,7 @@ from requests.exceptions import SSLError def test_http_redirects_to_https(docker_compose, nginxproxy, subdomain, should_redirect_to_https): r = nginxproxy.get("http://%s.web.nginx-proxy.tld/port" % subdomain) if should_redirect_to_https: + assert len(r.history) > 0 assert r.history[0].is_redirect assert r.history[0].headers.get("Location") == "https://%s.web.nginx-proxy.tld/port" % subdomain assert "answer from port 8%s\n" % subdomain == r.text