From 1e344897a2605a0ce488a18737fe974a666be09e Mon Sep 17 00:00:00 2001 From: Daniel Carrera Date: Sat, 14 Dec 2019 20:45:18 -0500 Subject: [PATCH 1/8] Added VIRTUAL_HOST_ALIAS to template Updated README --- README.md | 25 ++++++++++++++++ nginx.tmpl | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 110 insertions(+) diff --git a/README.md b/README.md index b5e0825..1883ca6 100644 --- a/README.md +++ b/README.md @@ -82,6 +82,31 @@ If you need to support multiple virtual hosts for a container, you can separate You can also use wildcards at the beginning and the end of host name, like `*.bar.com` or `foo.bar.*`. Or even a regular expression, which can be very useful in conjunction with a wildcard DNS service like [xip.io](http://xip.io), using `~^foo\.bar\..*\.xip\.io` will match `foo.bar.127.0.0.1.xip.io`, `foo.bar.10.0.2.2.xip.io` and all other given IPs. More information about this topic can be found in the nginx documentation about [`server_names`](http://nginx.org/en/docs/http/server_names.html). +### Virtual Host Aliases + +You can add aliases that will redirect (301) to the first entry in `VIRTUAL_HOST` by adding the `VIRTUAL_HOST_ALIAS` env var: + + $ docker run -e VIRTUAL_HOST=example.com -e VIRTUAL_HOST_ALIAS=www.example.com,old.example.com ... + +This will setup the following redirects: +- `http://www.example.com` → `http://example.com` +- `http://old.example.com` → `http://example.com` + +If you are using [letsencrypt-nginx-proxy-companion](https://github.com/JrCs/docker-letsencrypt-nginx-proxy-companion) for SSL support, then you would run: + + $ docker run -e VIRTUAL_HOST=example.com \ + -e VIRTUAL_HOST_ALIAS=www.example.com,old.example.com + -e LETSENCRYPT_HOST=example.com,www.example.com,old.example.com + ... + +This will setup the following redirects: + - `http://example.com` → `https://example.com` + - `http://www.example.com` → `https://www.example.com` → `https://example.com` + - `http://old.example.com` → `http://example.com` → `https://example.com` + - `https://www.example.com` → `https://example.com` + - `https://old.example.com` → `https://example.com` + + ### Multiple Networks With the addition of [overlay networking](https://docs.docker.com/engine/userguide/networking/get-started-overlay/) in Docker 1.9, your `nginx-proxy` container may need to connect to backend containers on multiple networks. By default, if you don't pass the `--net` flag when your `nginx-proxy` container is created, it will only be attached to the default `bridge` network. This means that it will not be able to connect to containers on networks other than `bridge`. diff --git a/nginx.tmpl b/nginx.tmpl index ae9639b..4e52f7f 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -400,3 +400,88 @@ server { {{ end }} {{ end }} + +# VIRTUAL_HOST_ALIAS +{{ range $host_alias, $containers := groupByMulti $ "Env.VIRTUAL_HOST_ALIAS" "," }} + +{{ $first_host := (first (groupByKeys $containers "Env.VIRTUAL_HOST")) }} +# First Host {{ $first_host }} + +#Alias: {{ $host_alias }} +server { + server_name {{ $host_alias }}; + return 301 $scheme://{{ $first_host }}$request_uri; +} + +{{ $default_host := or ($.Env.DEFAULT_HOST) "" }} +{{ $default_server := index (dict $host_alias "" $default_host "default_server") $host_alias }} + +{{/* Get the HTTPS_METHOD defined by containers w/ the same vhost, falling back to "redirect" */}} +{{ $https_method := or (first (groupByKeys $containers "Env.HTTPS_METHOD")) "redirect" }} + +{{/* Get the SSL_POLICY defined by containers w/ the same vhost, falling back to empty string (use default) */}} +{{ $ssl_policy := or (first (groupByKeys $containers "Env.SSL_POLICY")) "" }} + +{{/* Get the HSTS defined by containers w/ the same vhost, falling back to "max-age=31536000" */}} +{{ $hsts := or (first (groupByKeys $containers "Env.HSTS")) "max-age=31536000" }} + +{{/* Get the first cert name defined by containers w/ the same vhost */}} +{{ $certName := (first (groupByKeys $containers "Env.CERT_NAME")) }} + +{{/* Get the best matching cert by name for the vhost. */}} +{{ $vhostCert := (closest (dir "/etc/nginx/certs") (printf "%s.crt" $host_alias))}} + +{{/* vhostCert is actually a filename so remove any suffixes since they are added later */}} +{{ $vhostCert := trimSuffix ".crt" $vhostCert }} +{{ $vhostCert := trimSuffix ".key" $vhostCert }} + +{{/* Use the cert specified on the container or fallback to the best vhost match */}} +{{ $cert := (coalesce $certName $vhostCert) }} + +{{ $is_https := (and (ne $https_method "nohttps") (ne $cert "") (exists (printf "/etc/nginx/certs/%s.crt" $cert)) (exists (printf "/etc/nginx/certs/%s.key" $cert))) }} + +{{ if $is_https }} + +server { + server_name {{ $host_alias }}; + listen 443 ssl http2 {{ $default_server }}; + {{ if $enable_ipv6 }} + listen [::]:443 ssl http2 {{ $default_server }}; + {{ end }} + access_log /var/log/nginx/access.log vhost; + + {{ template "ssl_policy" (dict "ssl_policy" $ssl_policy) }} + + ssl_session_timeout 5m; + ssl_session_cache shared:SSL:50m; + ssl_session_tickets off; + + ssl_certificate /etc/nginx/certs/{{ (printf "%s.crt" $cert) }}; + ssl_certificate_key /etc/nginx/certs/{{ (printf "%s.key" $cert) }}; + + {{ if (exists (printf "/etc/nginx/certs/%s.dhparam.pem" $cert)) }} + ssl_dhparam {{ printf "/etc/nginx/certs/%s.dhparam.pem" $cert }}; + {{ end }} + + {{ if (exists (printf "/etc/nginx/certs/%s.chain.pem" $cert)) }} + ssl_stapling on; + ssl_stapling_verify on; + ssl_trusted_certificate {{ printf "/etc/nginx/certs/%s.chain.pem" $cert }}; + {{ end }} + + {{ if (not (or (eq $https_method "noredirect") (eq $hsts "off"))) }} + add_header Strict-Transport-Security "{{ trim $hsts }}" always; + {{ end }} + + {{ if (exists (printf "/etc/nginx/vhost.d/%s" $host_alias)) }} + include {{ printf "/etc/nginx/vhost.d/%s" $host_alias }}; + {{ else if (exists "/etc/nginx/vhost.d/default") }} + include /etc/nginx/vhost.d/default; + {{ end }} + + return 301 https://{{ $first_host }}$request_uri; +} + +{{ end }} + +{{ end }} \ No newline at end of file From b4b5d63fe899881539b04cb9c7463cad7a4030ca Mon Sep 17 00:00:00 2001 From: Daniel Carrera Date: Sat, 14 Dec 2019 21:47:54 -0500 Subject: [PATCH 2/8] virtual_host_alias & ssl redirects with single 301 --- README.md | 4 ++-- nginx.tmpl | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 60 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 1883ca6..16bb48c 100644 --- a/README.md +++ b/README.md @@ -101,8 +101,8 @@ If you are using [letsencrypt-nginx-proxy-companion](https://github.com/JrCs/doc This will setup the following redirects: - `http://example.com` → `https://example.com` - - `http://www.example.com` → `https://www.example.com` → `https://example.com` - - `http://old.example.com` → `http://example.com` → `https://example.com` + - `http://www.example.com` → `https://example.com` + - `http://old.example.com` → `https://example.com` - `https://www.example.com` → `https://example.com` - `https://old.example.com` → `https://example.com` diff --git a/nginx.tmpl b/nginx.tmpl index 4e52f7f..d221859 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -404,18 +404,21 @@ server { # VIRTUAL_HOST_ALIAS {{ range $host_alias, $containers := groupByMulti $ "Env.VIRTUAL_HOST_ALIAS" "," }} +{{ $host_alias := trim $host_alias }} + {{ $first_host := (first (groupByKeys $containers "Env.VIRTUAL_HOST")) }} +{{ $first_host := trim $first_host }} + # First Host {{ $first_host }} #Alias: {{ $host_alias }} -server { - server_name {{ $host_alias }}; - return 301 $scheme://{{ $first_host }}$request_uri; -} {{ $default_host := or ($.Env.DEFAULT_HOST) "" }} {{ $default_server := index (dict $host_alias "" $default_host "default_server") $host_alias }} +{{/* 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" }} @@ -442,6 +445,17 @@ server { {{ if $is_https }} +{{ if eq $https_method "redirect" }} +server { + server_name {{ $host_alias }}; + listen 80 {{ $default_server }}; + {{ if $enable_ipv6 }} + listen [::]:80 {{ $default_server }}; + {{ end }} + access_log /var/log/nginx/access.log vhost; + return 301 https://{{ $first_host }}$request_uri; +} +{{ end }} server { server_name {{ $host_alias }}; listen 443 ssl http2 {{ $default_server }}; @@ -484,4 +498,44 @@ server { {{ end }} +{{ if or (not $is_https) (eq $https_method "noredirect") }} + +server { + server_name {{ $host_alias }}; + listen 80 {{ $default_server }}; + {{ if $enable_ipv6 }} + listen [::]:80 {{ $default_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_alias)) }} + include {{ printf "/etc/nginx/vhost.d/%s" $host_alias }}; + {{ else if (exists "/etc/nginx/vhost.d/default") }} + include /etc/nginx/vhost.d/default; + {{ end }} + + return 301 http://{{ $first_host }}$request_uri; +} + +{{ if (and (not $is_https) (exists "/etc/nginx/certs/default.crt") (exists "/etc/nginx/certs/default.key")) }} +server { + server_name {{ $host_alias }}; + listen 443 ssl http2 {{ $default_server }}; + {{ if $enable_ipv6 }} + listen [::]:443 ssl http2 {{ $default_server }}; + {{ end }} + access_log /var/log/nginx/access.log vhost; + return 500; + + ssl_certificate /etc/nginx/certs/default.crt; + ssl_certificate_key /etc/nginx/certs/default.key; +} +{{ end }} + +{{ end }} {{ end }} \ No newline at end of file From 5108e8e3135d24b5edd941c76f34df046cfbd6fd Mon Sep 17 00:00:00 2001 From: Daniel Carrera Date: Thu, 25 Jun 2020 18:05:26 -0400 Subject: [PATCH 3/8] Merge http & https server blocks --- nginx.tmpl | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/nginx.tmpl b/nginx.tmpl index d221859..48ac467 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -445,22 +445,17 @@ server { {{ if $is_https }} -{{ if eq $https_method "redirect" }} server { server_name {{ $host_alias }}; - listen 80 {{ $default_server }}; - {{ if $enable_ipv6 }} - listen [::]:80 {{ $default_server }}; + {{ if eq $https_method "redirect" }} + listen {{ $external_http_port }} {{ $default_server }}; {{ end }} - access_log /var/log/nginx/access.log vhost; - return 301 https://{{ $first_host }}$request_uri; -} -{{ end }} -server { - server_name {{ $host_alias }}; - listen 443 ssl http2 {{ $default_server }}; + listen {{ $external_https_port }} ssl http2 {{ $default_server }}; {{ if $enable_ipv6 }} - listen [::]:443 ssl http2 {{ $default_server }}; + {{ if eq $https_method "redirect" }} + listen [::]:{{ $external_http_port }} {{ $default_server }}; + {{ end }} + listen [::]:{{ $external_https_port }} ssl http2 {{ $default_server }}; {{ end }} access_log /var/log/nginx/access.log vhost; From 2d860b04fce225b4aee1d014ab099229d15a579c Mon Sep 17 00:00:00 2001 From: Daniel Carrera Date: Thu, 25 Jun 2020 18:35:15 -0400 Subject: [PATCH 4/8] Do not HTTPS redirect Let'sEncrypt ACME challenge --- nginx.tmpl | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/nginx.tmpl b/nginx.tmpl index 48ac467..273a557 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -514,7 +514,18 @@ server { include /etc/nginx/vhost.d/default; {{ end }} - return 301 http://{{ $first_host }}$request_uri; + # Do not HTTPS redirect Let'sEncrypt ACME challenge + location /.well-known/acme-challenge/ { + auth_basic off; + allow all; + root /usr/share/nginx/html; + try_files $uri =404; + break; + } + + location / { + return 301 https://{{ $first_host }}$request_uri; + } } {{ if (and (not $is_https) (exists "/etc/nginx/certs/default.crt") (exists "/etc/nginx/certs/default.key")) }} From 72e96ab0c668ea6263e625594de539ed3d47ef0b Mon Sep 17 00:00:00 2001 From: Hannes Happle Date: Fri, 31 Jul 2020 14:31:36 +0200 Subject: [PATCH 5/8] replaced two numeric ports with variables --- nginx.tmpl | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/nginx.tmpl b/nginx.tmpl index cbba4bb..4209be2 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -251,7 +251,7 @@ server { listen [::]:{{ $external_http_port }} {{ $default_server }}; {{ end }} {{ $access_log }} - + # Do not HTTPS redirect Let'sEncrypt ACME challenge location /.well-known/acme-challenge/ { auth_basic off; @@ -260,7 +260,7 @@ server { try_files $uri =404; break; } - + location / { return 301 https://$host$request_uri; } @@ -497,7 +497,7 @@ server { server { server_name {{ $host_alias }}; - listen 80 {{ $default_server }}; + listen {{ $external_http_port }} {{ $default_server }}; {{ if $enable_ipv6 }} listen [::]:80 {{ $default_server }}; {{ end }} @@ -522,7 +522,7 @@ server { try_files $uri =404; break; } - + location / { return 301 https://{{ $first_host }}$request_uri; } @@ -531,7 +531,7 @@ server { {{ if (and (not $is_https) (exists "/etc/nginx/certs/default.crt") (exists "/etc/nginx/certs/default.key")) }} server { server_name {{ $host_alias }}; - listen 443 ssl http2 {{ $default_server }}; + listen {{ $external_https_port }} ssl http2 {{ $default_server }}; {{ if $enable_ipv6 }} listen [::]:443 ssl http2 {{ $default_server }}; {{ end }} @@ -544,4 +544,4 @@ server { {{ end }} {{ end }} -{{ end }} \ No newline at end of file +{{ end }} From 663a79bfa9529c0d20df017d2aab03f327a88c5f Mon Sep 17 00:00:00 2001 From: Hannes Happle Date: Fri, 31 Jul 2020 14:32:41 +0200 Subject: [PATCH 6/8] all aliases in same server block (don't split >=3) --- nginx.tmpl | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/nginx.tmpl b/nginx.tmpl index 4209be2..1f8c926 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -402,9 +402,8 @@ server { {{ end }} # VIRTUAL_HOST_ALIAS -{{ range $host_alias, $containers := groupByMulti $ "Env.VIRTUAL_HOST_ALIAS" "," }} - -{{ $host_alias := trim $host_alias }} +{{ range $host_alias, $containers := groupBy $ "Env.VIRTUAL_HOST_ALIAS" }} +{{ $host_alias := replace $host_alias "," " " 99 }} {{ $first_host := (first (groupByKeys $containers "Env.VIRTUAL_HOST")) }} {{ $first_host := trim $first_host }} From 70acecaa4f40b5239002349278dd7f8a771a07a9 Mon Sep 17 00:00:00 2001 From: Hannes Happle Date: Fri, 31 Jul 2020 15:09:30 +0200 Subject: [PATCH 7/8] avoid duplicate acme location include in alias --- nginx.tmpl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/nginx.tmpl b/nginx.tmpl index 1f8c926..2f7fde2 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -513,6 +513,7 @@ server { include /etc/nginx/vhost.d/default; {{ end }} + {{ if not (exists "/etc/nginx/vhost.d/default") }} # Do not HTTPS redirect Let'sEncrypt ACME challenge location /.well-known/acme-challenge/ { auth_basic off; @@ -521,6 +522,7 @@ server { try_files $uri =404; break; } + {{ end }} location / { return 301 https://{{ $first_host }}$request_uri; From 1614afeaf4d5e62f840732c5920a32422550f6de Mon Sep 17 00:00:00 2001 From: Hannes Happle Date: Fri, 31 Jul 2020 15:32:40 +0200 Subject: [PATCH 8/8] don't redirect http aliases in final config --- nginx.tmpl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/nginx.tmpl b/nginx.tmpl index 2f7fde2..1551362 100644 --- a/nginx.tmpl +++ b/nginx.tmpl @@ -487,7 +487,9 @@ server { include /etc/nginx/vhost.d/default; {{ end }} - return 301 https://{{ $first_host }}$request_uri; + location / { + return 301 https://{{ $first_host }}$request_uri; + } } {{ end }}