|
1 |
| -{{ $CurrentContainer := where $ "ID" .Docker.CurrentContainerID | first }} |
2 |
| - |
3 |
| -{{ $external_http_port := coalesce $.Env.HTTP_PORT "80" }} |
4 |
| -{{ $external_https_port := coalesce $.Env.HTTPS_PORT "443" }} |
5 |
| - |
6 |
| -{{ define "upstream" }} |
7 |
| - {{ if .Address }} |
8 |
| - {{/* If we got the containers from swarm and this container's port is published to host, use host IP:PORT */}} |
9 |
| - {{ if and .Container.Node.ID .Address.HostPort }} |
10 |
| - # {{ .Container.Node.Name }}/{{ .Container.Name }} |
11 |
| - server {{ .Container.Node.Address.IP }}:{{ .Address.HostPort }}; |
12 |
| - {{/* If there is no swarm node or the port is not published on host, use container's IP:PORT */}} |
13 |
| - {{ else if .Network }} |
14 |
| - # {{ .Container.Name }} |
15 |
| - server {{ .Network.IP }}:{{ .Address.Port }}; |
16 |
| - {{ end }} |
17 |
| - {{ else if .Network }} |
18 |
| - # {{ .Container.Name }} |
19 |
| - {{ if .Network.IP }} |
20 |
| - server {{ .Network.IP }} down; |
21 |
| - {{ else }} |
22 |
| - server 127.0.0.1 down; |
23 |
| - {{ end }} |
24 |
| - {{ end }} |
25 |
| - |
26 |
| -{{ end }} |
27 |
| - |
28 |
| -{{ define "ssl_policy" }} |
29 |
| - {{ if eq .ssl_policy "Mozilla-Modern" }} |
30 |
| - ssl_protocols TLSv1.3; |
31 |
| - {{/* nginx currently lacks ability to choose ciphers in TLS 1.3 in configuration, see https://trac.nginx.org/nginx/ticket/1529 /*}} |
32 |
| - {{/* a possible workaround can be modify /etc/ssl/openssl.cnf to change it globally (see https://trac.nginx.org/nginx/ticket/1529#comment:12 ) /*}} |
33 |
| - {{/* explicitly set ngnix default value in order to allow single servers to override the global http value */}} |
34 |
| - ssl_ciphers HIGH:!aNULL:!MD5; |
35 |
| - ssl_prefer_server_ciphers off; |
36 |
| - {{ else if eq .ssl_policy "Mozilla-Intermediate" }} |
37 |
| - ssl_protocols TLSv1.2 TLSv1.3; |
38 |
| - ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384'; |
39 |
| - ssl_prefer_server_ciphers off; |
40 |
| - {{ else if eq .ssl_policy "Mozilla-Old" }} |
41 |
| - ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; |
42 |
| - ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA256:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA'; |
43 |
| - ssl_prefer_server_ciphers on; |
44 |
| - {{ else if eq .ssl_policy "AWS-TLS-1-2-2017-01" }} |
45 |
| - ssl_protocols TLSv1.2 TLSv1.3; |
46 |
| - 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'; |
47 |
| - ssl_prefer_server_ciphers on; |
48 |
| - {{ else if eq .ssl_policy "AWS-TLS-1-1-2017-01" }} |
49 |
| - ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3; |
50 |
| - 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'; |
51 |
| - ssl_prefer_server_ciphers on; |
52 |
| - {{ else if eq .ssl_policy "AWS-2016-08" }} |
53 |
| - ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; |
54 |
| - 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'; |
55 |
| - ssl_prefer_server_ciphers on; |
56 |
| - {{ else if eq .ssl_policy "AWS-2015-05" }} |
57 |
| - ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; |
58 |
| - 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'; |
59 |
| - ssl_prefer_server_ciphers on; |
60 |
| - {{ else if eq .ssl_policy "AWS-2015-03" }} |
61 |
| - ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; |
62 |
| - 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'; |
63 |
| - ssl_prefer_server_ciphers on; |
64 |
| - {{ else if eq .ssl_policy "AWS-2015-02" }} |
65 |
| - ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; |
66 |
| - 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'; |
67 |
| - ssl_prefer_server_ciphers on; |
68 |
| - {{ end }} |
69 |
| -{{ end }} |
| 1 | +# nginx-proxy{{ if $.Env.NGINX_PROXY_VERSION }} version : {{ $.Env.NGINX_PROXY_VERSION }}{{ end }} |
| 2 | + |
| 3 | +{{- /* |
| 4 | + * Global values. Values are stored in this map rather than in individual |
| 5 | + * global variables so that the values can be easily passed to embedded |
| 6 | + * templates (Go templates cannot access variables outside of their own |
| 7 | + * scope) and displayed in the debug endpoint output. |
| 8 | + */}} |
| 9 | +{{- $globals := dict }} |
| 10 | +{{- $_ := set $globals "containers" $ }} |
| 11 | +{{- $_ := set $globals "Env" $.Env }} |
| 12 | +{{- $_ := set $globals "Docker" $.Docker }} |
| 13 | +{{- $_ := set $globals "CurrentContainer" (where $globals.containers "ID" $globals.Docker.CurrentContainerID | first) }} |
| 14 | + |
| 15 | +{{- $config := dict }} |
| 16 | +{{- $_ := set $config "nginx_proxy_version" $.Env.NGINX_PROXY_VERSION }} |
| 17 | +{{- $_ := set $config "default_cert_ok" (and (exists "/etc/nginx/certs/default.crt") (exists "/etc/nginx/certs/default.key")) }} |
| 18 | +{{- $_ := set $config "external_http_port" ($globals.Env.HTTP_PORT | default "80") }} |
| 19 | +{{- $_ := set $config "external_https_port" ($globals.Env.HTTPS_PORT | default "443") }} |
| 20 | +{{- $_ := set $config "sha1_upstream_name" ($globals.Env.SHA1_UPSTREAM_NAME | default "false" | parseBool) }} |
| 21 | +{{- $_ := set $config "default_root_response" ($globals.Env.DEFAULT_ROOT | default "404") }} |
| 22 | +{{- $_ := set $config "trust_default_cert" ($globals.Env.TRUST_DEFAULT_CERT | default "true") }} |
| 23 | +{{- $_ := set $config "trust_downstream_proxy" ($globals.Env.TRUST_DOWNSTREAM_PROXY | default "true" | parseBool) }} |
| 24 | +{{- $_ := set $config "enable_access_log" ($globals.Env.DISABLE_ACCESS_LOGS | default "false" | parseBool | not) }} |
| 25 | +{{- $_ := set $config "enable_ipv6" ($globals.Env.ENABLE_IPV6 | default "false" | parseBool) }} |
| 26 | +{{- $_ := set $config "prefer_ipv6_network" ($globals.Env.PREFER_IPV6_NETWORK | default "false" | parseBool) }} |
| 27 | +{{- $_ := set $config "ssl_policy" ($globals.Env.SSL_POLICY | default "Mozilla-Intermediate") }} |
| 28 | +{{- $_ := set $config "enable_debug_endpoint" ($globals.Env.DEBUG_ENDPOINT | default "false") }} |
| 29 | +{{- $_ := set $config "hsts" ($globals.Env.HSTS | default "max-age=31536000") }} |
| 30 | +{{- $_ := set $config "acme_http_challenge" ($globals.Env.ACME_HTTP_CHALLENGE_LOCATION | default "true") }} |
| 31 | +{{- $_ := set $config "enable_http2" ($globals.Env.ENABLE_HTTP2 | default "true") }} |
| 32 | +{{- $_ := set $config "enable_http3" ($globals.Env.ENABLE_HTTP3 | default "false") }} |
| 33 | +{{- $_ := set $config "enable_http_on_missing_cert" ($globals.Env.ENABLE_HTTP_ON_MISSING_CERT | default "true") }} |
| 34 | +{{- $_ := set $config "https_method" ($globals.Env.HTTPS_METHOD | default "redirect") }} |
| 35 | +{{- $_ := set $config "non_get_redirect" ($globals.Env.NON_GET_REDIRECT | default "301") }} |
| 36 | +{{- $_ := set $config "default_host" $globals.Env.DEFAULT_HOST }} |
| 37 | +{{- $_ := set $config "resolvers" $globals.Env.RESOLVERS }} |
| 38 | +{{- /* LOG_JSON is a shorthand that sets logging defaults to JSON format */}} |
| 39 | +{{- $_ := set $config "enable_json_logs" ($globals.Env.LOG_JSON | default "false" | parseBool) }} |
| 40 | +{{- $_ := set $config "log_format" $globals.Env.LOG_FORMAT }} |
| 41 | +{{- $_ := set $config "log_format_escape" $globals.Env.LOG_FORMAT_ESCAPE }} |
| 42 | + |
| 43 | +{{- $_ := set $globals "config" $config }} |
| 44 | + |
| 45 | +{{- $_ := set $globals "vhosts" (dict) }} |
| 46 | +{{- $_ := set $globals "networks" (dict) }} |
| 47 | +# Networks available to the container running docker-gen (which are assumed to |
| 48 | +# match the networks available to the container running nginx): |
| 49 | +{{- /* |
| 50 | + * Note: $globals.CurrentContainer may be nil in some circumstances due to |
| 51 | + * <https://github.com/nginx-proxy/docker-gen/issues/458>. For more context |
| 52 | + * see <https://github.com/nginx-proxy/nginx-proxy/issues/2189>. |
| 53 | + */}} |
| 54 | +{{- if $globals.CurrentContainer }} |
| 55 | + {{- range sortObjectsByKeysAsc $globals.CurrentContainer.Networks "Name" }} |
| 56 | + {{- $_ := set $globals.networks .Name . }} |
| 57 | +# {{ .Name }} |
| 58 | + {{- else }} |
| 59 | +# (none) |
| 60 | + {{- end }} |
| 61 | +{{- else }} |
| 62 | +# /!\ WARNING: Failed to find the Docker container running docker-gen. All |
| 63 | +# upstream (backend) application containers will appear to be |
| 64 | +# unreachable. Try removing the -only-exposed and -only-published |
| 65 | +# arguments to docker-gen if you pass either of those. See |
| 66 | +# <https://github.com/nginx-proxy/docker-gen/issues/458>. |
| 67 | +{{- end }} |
| 68 | + |
| 69 | +{{- /* |
| 70 | + * Template used as a function to get a container's IP address. This |
| 71 | + * template only outputs debug comments; the IP address is "returned" by |
| 72 | + * storing the value in the provided dot dict. |
| 73 | + * |
| 74 | + * The provided dot dict is expected to have the following entries: |
| 75 | + * - "globals": Global values. |
| 76 | + * - "container": The container's RuntimeContainer struct. |
| 77 | + * |
| 78 | + * The return value will be added to the dot dict with key "ip". |
| 79 | + */}} |
| 80 | +{{- define "container_ip" }} |
| 81 | + {{- $ipv4 := "" }} |
| 82 | + {{- $ipv6 := "" }} |
| 83 | + # networks: |
| 84 | + {{- range sortObjectsByKeysAsc $.container.Networks "Name" }} |
| 85 | + {{- /* |
| 86 | + * TODO: Only ignore the "ingress" network for Swarm tasks (in case |
| 87 | + * the user is not using Swarm mode and names a network "ingress"). |
| 88 | + */}} |
| 89 | + {{- if eq .Name "ingress" }} |
| 90 | + # {{ .Name }} (ignored) |
| 91 | + {{- continue }} |
| 92 | + {{- end }} |
| 93 | + {{- if eq .Name "host" }} |
| 94 | + {{- /* Handle containers in host nework mode */}} |
| 95 | + {{- if (index $.globals.networks "host") }} |
| 96 | + # both container and proxy are in host network mode, using localhost IP |
| 97 | + {{- $ipv4 = "127.0.0.1" }} |
| 98 | + {{- continue }} |
| 99 | + {{- end }} |
| 100 | + {{- range sortObjectsByKeysAsc $.globals.CurrentContainer.Networks "Name" }} |
| 101 | + {{- if and . .Gateway (not .Internal) }} |
| 102 | + # container is in host network mode, using {{ .Name }} gateway IP |
| 103 | + {{- $ipv4 = .Gateway }} |
| 104 | + {{- break }} |
| 105 | + {{- end }} |
| 106 | + {{- end }} |
| 107 | + {{- if $ipv4 }} |
| 108 | + {{- continue }} |
| 109 | + {{- end }} |
| 110 | + {{- end }} |
| 111 | + {{- if and (not (index $.globals.networks .Name)) (not $.globals.networks.host) }} |
| 112 | + # {{ .Name }} (unreachable) |
| 113 | + {{- continue }} |
| 114 | + {{- end }} |
| 115 | + {{- /* |
| 116 | + * Do not emit multiple `server` directives for this container if it |
| 117 | + * is reachable over multiple networks or multiple IP stacks. This avoids |
| 118 | + * accidentally inflating the effective round-robin weight of a server due |
| 119 | + * to the redundant upstream addresses that nginx sees as belonging to |
| 120 | + * distinct servers. |
| 121 | + */}} |
| 122 | + {{- if or $ipv4 $ipv6 }} |
| 123 | + # {{ .Name }} (ignored; reachable but redundant) |
| 124 | + {{- continue }} |
| 125 | + {{- end }} |
| 126 | + # {{ .Name }} (reachable) |
| 127 | + {{- if and . .IP }} |
| 128 | + {{- $ipv4 = .IP }} |
| 129 | + {{- end }} |
| 130 | + {{- if and . .GlobalIPv6Address }} |
| 131 | + {{- $ipv6 = .GlobalIPv6Address }} |
| 132 | + {{- end }} |
| 133 | + {{- if and (empty $ipv4) (empty $ipv6) }} |
| 134 | + # /!\ No IPv4 or IPv6 for this network! |
| 135 | + {{- end }} |
| 136 | + {{- else }} |
| 137 | + # (none) |
| 138 | + {{- end }} |
| 139 | + {{ if and $ipv6 $.globals.config.prefer_ipv6_network }} |
| 140 | + # IPv4 address: {{ if $ipv4 }}{{ $ipv4 }} (ignored; reachable but IPv6 prefered){{ else }}(none usable){{ end }} |
| 141 | + # IPv6 address: {{ $ipv6 }} |
| 142 | + {{- $_ := set $ "ip" (printf "[%s]" $ipv6) }} |
| 143 | + {{- else }} |
| 144 | + # IPv4 address: {{ if $ipv4 }}{{ $ipv4 }}{{ else }}(none usable){{ end }} |
| 145 | + # IPv6 address: {{ if $ipv6 }}{{ $ipv6 }}{{ if $ipv4 }} (ignored; reachable but IPv4 prefered){{ end }}{{ else }}(none usable){{ end }} |
| 146 | + {{- if $ipv4 }} |
| 147 | + {{- $_ := set $ "ip" $ipv4 }} |
| 148 | + {{- else if $ipv6}} |
| 149 | + {{- $_ := set $ "ip" (printf "[%s]" $ipv6) }} |
| 150 | + {{- end }} |
| 151 | + {{- end }} |
| 152 | +{{- end }} |
| 153 | + |
| 154 | +{{- /* |
| 155 | + * Template used as a function to get the port of the server in the given |
| 156 | + * container. This template only outputs debug comments; the port is |
| 157 | + * "returned" by storing the value in the provided dot dict. |
| 158 | + * |
| 159 | + * The provided dot dict is expected to have the following entries: |
| 160 | + * - "container": The container's RuntimeContainer struct. |
| 161 | + * |
| 162 | + * The return value will be added to the dot dict with key "port". |
| 163 | + */}} |
| 164 | +{{- define "container_port" }} |
| 165 | + {{- /* If only 1 port exposed, use that as a default, else 80. */}} |
| 166 | + # exposed ports (first ten):{{ range $index, $address := (sortObjectsByKeysAsc $.container.Addresses "Port") }}{{ if lt $index 10 }} {{ $address.Port }}/{{ $address.Proto }}{{ end }}{{ else }} (none){{ end }} |
| 167 | + {{- $default_port := when (eq (len $.container.Addresses) 1) (first $.container.Addresses).Port "80" }} |
| 168 | + # default port: {{ $default_port }} |
| 169 | + {{- $port := eq $.port "default" | ternary $default_port $.port }} |
| 170 | + # using port: {{ $port }} |
| 171 | + {{- $addr_obj := where $.container.Addresses "Port" $port | first }} |
| 172 | + {{- if and $addr_obj $addr_obj.HostPort }} |
| 173 | + # /!\ WARNING: Virtual port published on host. Clients |
| 174 | + # might be able to bypass nginx-proxy and |
| 175 | + # access the container's server directly. |
| 176 | + {{- end }} |
| 177 | + {{- $_ := set $ "port" $port }} |
| 178 | +{{- end }} |
| 179 | + |
| 180 | +{{- define "ssl_policy" }} |
| 181 | + {{- if eq .ssl_policy "Mozilla-Modern" }} |
| 182 | + ssl_protocols TLSv1.3; |
| 183 | + {{- /* |
| 184 | + * This ssl_ciphers directive is not used but necessary to get TLSv1.3 only. |
| 185 | + * see https://serverfault.com/questions/1023766/nginx-with-only-tls1-3-cipher-suites |
| 186 | + */}} |
| 187 | + ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384; |
| 188 | + ssl_conf_command Ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256; |
| 189 | + ssl_prefer_server_ciphers off; |
| 190 | + {{- else if eq .ssl_policy "Mozilla-Intermediate" }} |
| 191 | + ssl_protocols TLSv1.2 TLSv1.3; |
| 192 | + ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305'; |
| 193 | + ssl_prefer_server_ciphers off; |
| 194 | + {{- else if eq .ssl_policy "Mozilla-Old" }} |
| 195 | + ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; |
| 196 | + ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA256:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:@SECLEVEL=0'; |
| 197 | + ssl_prefer_server_ciphers on; |
| 198 | + {{- else if eq .ssl_policy "AWS-TLS13-1-3-2021-06" }} |
| 199 | + ssl_protocols TLSv1.3; |
| 200 | + {{- /* |
| 201 | + * This ssl_ciphers directive is not used but necessary to get TLSv1.3 only. |
| 202 | + * see https://serverfault.com/questions/1023766/nginx-with-only-tls1-3-cipher-suites |
| 203 | + */}} |
| 204 | + ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384; |
| 205 | + ssl_conf_command Ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256; |
| 206 | + ssl_prefer_server_ciphers on; |
| 207 | + {{- else if eq .ssl_policy "AWS-TLS13-1-2-2021-06" }} |
| 208 | + ssl_protocols TLSv1.2 TLSv1.3; |
| 209 | + 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'; |
| 210 | + ssl_prefer_server_ciphers on; |
| 211 | + {{- else if eq .ssl_policy "AWS-TLS13-1-2-Res-2021-06" }} |
| 212 | + ssl_protocols TLSv1.2 TLSv1.3; |
| 213 | + ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384'; |
| 214 | + ssl_prefer_server_ciphers on; |
| 215 | + {{- else if eq .ssl_policy "AWS-TLS13-1-2-Ext1-2021-06" }} |
| 216 | + ssl_protocols TLSv1.2 TLSv1.3; |
| 217 | + 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'; |
| 218 | + ssl_prefer_server_ciphers on; |
| 219 | + {{- else if eq .ssl_policy "AWS-TLS13-1-2-Ext2-2021-06" }} |
| 220 | + ssl_protocols TLSv1.2 TLSv1.3; |
| 221 | + 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'; |
| 222 | + ssl_prefer_server_ciphers on; |
| 223 | + {{- else if eq .ssl_policy "AWS-TLS13-1-1-2021-06" }} |
| 224 | + ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3; |
| 225 | + 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:@SECLEVEL=0'; |
| 226 | + ssl_prefer_server_ciphers on; |
| 227 | + {{- else if eq .ssl_policy "AWS-TLS13-1-0-2021-06" }} |
| 228 | + ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; |
| 229 | + 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:@SECLEVEL=0'; |
| 230 | + ssl_prefer_server_ciphers on; |
| 231 | + {{- else if eq .ssl_policy "AWS-FS-1-2-Res-2020-10" }} |
| 232 | + ssl_protocols TLSv1.2; |
| 233 | + ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384'; |
| 234 | + ssl_prefer_server_ciphers on; |
| 235 | + {{- else if eq .ssl_policy "AWS-FS-1-2-Res-2019-08" }} |
| 236 | + ssl_protocols TLSv1.2; |
| 237 | + 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'; |
| 238 | + ssl_prefer_server_ciphers on; |
| 239 | + {{- else if eq .ssl_policy "AWS-FS-1-2-2019-08" }} |
| 240 | + ssl_protocols TLSv1.2; |
| 241 | + 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'; |
| 242 | + ssl_prefer_server_ciphers on; |
| 243 | + {{- else if eq .ssl_policy "AWS-FS-1-1-2019-08" }} |
| 244 | + ssl_protocols TLSv1.1 TLSv1.2; |
| 245 | + 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:@SECLEVEL=0'; |
| 246 | + ssl_prefer_server_ciphers on; |
| 247 | + {{- else if eq .ssl_policy "AWS-FS-2018-06" }} |
| 248 | + ssl_protocols TLSv1 TLSv1.1 TLSv1.2; |
| 249 | + 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:@SECLEVEL=0'; |
| 250 | + ssl_prefer_server_ciphers on; |
| 251 | + {{- else if eq .ssl_policy "AWS-TLS-1-2-Ext-2018-06" }} |
| 252 | + ssl_protocols TLSv1.2; |
| 253 | + 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'; |
| 254 | + ssl_prefer_server_ciphers on; |
| 255 | + {{- else if eq .ssl_policy "AWS-TLS-1-2-2017-01" }} |
| 256 | + ssl_protocols TLSv1.2; |
| 257 | + 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'; |
| 258 | + ssl_prefer_server_ciphers on; |
| 259 | + {{- else if eq .ssl_policy "AWS-TLS-1-1-2017-01" }} |
| 260 | + ssl_protocols TLSv1.1 TLSv1.2; |
| 261 | + 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:@SECLEVEL=0'; |
| 262 | + ssl_prefer_server_ciphers on; |
| 263 | + {{- else if eq .ssl_policy "AWS-2016-08" }} |
| 264 | + ssl_protocols TLSv1 TLSv1.1 TLSv1.2; |
| 265 | + 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:@SECLEVEL=0'; |
| 266 | + ssl_prefer_server_ciphers on; |
| 267 | + {{- else if eq .ssl_policy "AWS-2015-05" }} |
| 268 | + ssl_protocols TLSv1 TLSv1.1 TLSv1.2; |
| 269 | + 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:@SECLEVEL=0'; |
| 270 | + ssl_prefer_server_ciphers on; |
| 271 | + {{- else if eq .ssl_policy "AWS-2015-03" }} |
| 272 | + ssl_protocols TLSv1 TLSv1.1 TLSv1.2; |
| 273 | + 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:@SECLEVEL=0'; |
| 274 | + ssl_prefer_server_ciphers on; |
| 275 | + {{- else if eq .ssl_policy "AWS-2015-02" }} |
| 276 | + ssl_protocols TLSv1 TLSv1.1 TLSv1.2; |
| 277 | + 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:@SECLEVEL=0'; |
| 278 | + ssl_prefer_server_ciphers on; |
| 279 | + {{- end }} |
| 280 | +{{- end }} |
| 281 | + |
| 282 | +{{- define "location" }} |
| 283 | + {{- $vpath := .VPath }} |
| 284 | + {{- $override := printf "/etc/nginx/vhost.d/%s_%s_location_override" .Host (sha1 .Path) }} |
| 285 | + {{- if and (eq .Path "/") (not (exists $override)) }} |
| 286 | + {{- $override = printf "/etc/nginx/vhost.d/%s_location_override" .Host }} |
| 287 | + {{- end }} |
| 288 | + {{- if exists $override }} |
| 289 | + include {{ $override }}; |
| 290 | + {{- else }} |
| 291 | + {{- $keepalive := $vpath.keepalive }} |
| 292 | + location {{ .Path }} { |
| 293 | + {{- if eq $vpath.network_tag "internal" }} |
| 294 | + # Only allow traffic from internal clients |
| 295 | + include /etc/nginx/network_internal.conf; |
| 296 | + {{- end }} |
| 297 | + |
| 298 | + {{ $proto := $vpath.proto }} |
| 299 | + {{ $upstream := $vpath.upstream }} |
| 300 | + {{ $dest := $vpath.dest }} |
| 301 | + {{- if eq $proto "uwsgi" }} |
| 302 | + include uwsgi_params; |
| 303 | + uwsgi_pass {{ trim $proto }}://{{ trim $upstream }}; |
| 304 | + {{- else if eq $proto "fastcgi" }} |
| 305 | + {{- if (exists "/etc/nginx/fastcgi.conf") }} |
| 306 | + include fastcgi.conf; |
| 307 | + {{- else if (exists "/etc/nginx/fastcgi_params") }} |
| 308 | + include fastcgi_params; |
| 309 | + {{- else }} |
| 310 | + # neither /etc/nginx/fastcgi.conf nor /etc/nginx/fastcgi_params found, fastcgi won't work |
| 311 | + {{- end }} |
| 312 | + root {{ trim .VhostRoot }}; |
| 313 | + fastcgi_pass {{ trim $upstream }}; |
| 314 | + {{- if ne $keepalive "disabled" }} |
| 315 | + fastcgi_keep_conn on; |
| 316 | + {{- end }} |
| 317 | + {{- else if eq $proto "grpc" }} |
| 318 | + grpc_pass {{ trim $proto }}://{{ trim $upstream }}; |
| 319 | + {{- else if eq $proto "grpcs" }} |
| 320 | + grpc_pass {{ trim $proto }}://{{ trim $upstream }}; |
| 321 | + {{- else }} |
| 322 | + proxy_pass {{ trim $proto }}://{{ trim $upstream }}{{ trim $dest }}; |
| 323 | + set $upstream_keepalive {{ if ne $keepalive "disabled" }}true{{ else }}false{{ end }}; |
| 324 | + {{- end }} |
| 325 | + |
| 326 | + {{- if (exists (printf "/etc/nginx/htpasswd/%s_%s" .Host (sha1 .Path) )) }} |
| 327 | + auth_basic "Restricted {{ .Host }}{{ .Path }}"; |
| 328 | + auth_basic_user_file {{ (printf "/etc/nginx/htpasswd/%s_%s" .Host (sha1 .Path)) }}; |
| 329 | + {{- else if (exists (printf "/etc/nginx/htpasswd/%s" .Host)) }} |
| 330 | + auth_basic "Restricted {{ .HostIsRegexp | ternary "access" .Host }}"; |
| 331 | + auth_basic_user_file {{ (printf "/etc/nginx/htpasswd/%s" .Host) }}; |
| 332 | + {{- end }} |
| 333 | + |
| 334 | + {{- if (exists (printf "/etc/nginx/vhost.d/%s_%s_location" .Host (sha1 .Path) )) }} |
| 335 | + include {{ printf "/etc/nginx/vhost.d/%s_%s_location" .Host (sha1 .Path) }}; |
| 336 | + {{- else if (exists (printf "/etc/nginx/vhost.d/%s_location" .Host)) }} |
| 337 | + include {{ printf "/etc/nginx/vhost.d/%s_location" .Host}}; |
| 338 | + {{- else if (exists "/etc/nginx/vhost.d/default_location") }} |
| 339 | + include /etc/nginx/vhost.d/default_location; |
| 340 | + {{- end }} |
| 341 | + } |
| 342 | + {{- end }} |
| 343 | +{{- end }} |
| 344 | + |
| 345 | +{{- define "upstream" }} |
| 346 | + {{- $path := .Path }} |
| 347 | + {{- $vpath := .VPath }} |
| 348 | +upstream {{ $vpath.upstream }} { |
| 349 | + {{- $servers := 0 }} |
| 350 | + {{- $loadbalance := $vpath.loadbalance }} |
| 351 | + {{- if $loadbalance }} |
| 352 | + # From the container's loadbalance label: |
| 353 | + {{ $loadbalance }} |
| 354 | + {{- end }} |
| 355 | + {{- range $port, $containers := $vpath.ports }} |
| 356 | + {{- range $container := $containers }} |
| 357 | + # Container: {{ $container.Name }} |
| 358 | + {{- $args := dict "globals" $.globals "container" $container }} |
| 359 | + {{- template "container_ip" $args }} |
| 360 | + {{- $ip := $args.ip }} |
| 361 | + {{- $args = dict "container" $container "path" $path "port" $port }} |
| 362 | + {{- template "container_port" $args }} |
| 363 | + {{- if $ip }} |
| 364 | + {{- $servers = add1 $servers }} |
| 365 | + server {{ $ip }}:{{ $args.port }}; |
| 366 | + {{- end }} |
| 367 | + {{- end }} |
| 368 | + {{- end }} |
| 369 | + {{- /* nginx-proxy/nginx-proxy#1105 */}} |
| 370 | + {{- if lt $servers 1 }} |
| 371 | + # Fallback entry |
| 372 | + server 127.0.0.1 down; |
| 373 | + {{- end }} |
| 374 | + {{- $keepalive := $vpath.keepalive }} |
| 375 | + {{- if and (ne $keepalive "disabled") (gt $servers 0) }} |
| 376 | + {{- if eq $keepalive "auto" }} |
| 377 | + keepalive {{ mul $servers 2 }}; |
| 378 | + {{- else }} |
| 379 | + keepalive {{ $keepalive }}; |
| 380 | + {{- end }} |
| 381 | + {{- end }} |
| 382 | +} |
| 383 | +{{- end }} |
| 384 | + |
| 385 | +{{- /* debug "endpoint" location template */}} |
| 386 | +{{- define "debug_location" }} |
| 387 | + {{- $debug_paths := dict }} |
| 388 | + {{- range $path, $vpath := .VHost.paths }} |
| 389 | + {{- $tmp_ports := dict }} |
| 390 | + {{- range $port, $containers := $vpath.ports }} |
| 391 | + {{- $tmp_containers := list }} |
| 392 | + {{- range $container := $containers }} |
| 393 | + {{- $tmp_containers = dict "Name" $container.Name | append $tmp_containers }} |
| 394 | + {{- end }} |
| 395 | + {{- $_ := set $tmp_ports $port $tmp_containers }} |
| 396 | + {{- end }} |
| 397 | + {{- $debug_vpath := deepCopy $vpath | merge (dict "ports" $tmp_ports) }} |
| 398 | + {{- $_ := set $debug_paths $path $debug_vpath }} |
| 399 | + {{- end }} |
| 400 | + |
| 401 | + {{- $debug_vhost := deepCopy .VHost }} |
| 402 | + {{- /* If it's a regexp, do not render the Hostname to the response to avoid rendering config breaking characters */}} |
| 403 | + {{- $_ := set $debug_vhost "hostname" (.VHost.is_regexp | ternary "Hostname is a regexp and unsafe to include in the debug response." .Hostname) }} |
| 404 | + {{- $_ := set $debug_vhost "paths" $debug_paths }} |
| 405 | + |
| 406 | + {{- $debug_response := dict |
| 407 | + "global" .GlobalConfig |
| 408 | + "request" (dict |
| 409 | + "host" "$host" |
| 410 | + "https" "$https" |
| 411 | + "http2" "$http2" |
| 412 | + "http3" "$http3" |
| 413 | + "ssl_cipher" "$ssl_cipher" |
| 414 | + "ssl_protocol" "$ssl_protocol" |
| 415 | + ) |
| 416 | + "vhost" $debug_vhost |
| 417 | + }} |
| 418 | + |
| 419 | + {{- /* |
| 420 | + * The maximum line length in an nginx config is 4096 characters. |
| 421 | + * If we're nearing this limit (with headroom for the rest |
| 422 | + * of the directive), strip vhost.paths from the response. |
| 423 | + */}} |
| 424 | + {{- if gt (toJson $debug_response | len) 4000 }} |
| 425 | + {{- $_ := unset $debug_vhost "paths" }} |
| 426 | + {{- $_ := set $debug_response "warning" "Virtual paths configuration for this hostname is too large and has been stripped from response." }} |
| 427 | + {{- end }} |
| 428 | + |
| 429 | + location /nginx-proxy-debug { |
| 430 | + default_type application/json; |
| 431 | + return 200 '{{ toJson $debug_response }}{{ "\\n" }}'; |
| 432 | + } |
| 433 | +{{- end }} |
| 434 | + |
| 435 | +{{- define "access_log" }} |
| 436 | + {{- when .Enable "access_log /var/log/nginx/access.log vhost;" "" }} |
| 437 | +{{- end }} |
70 | 438 |
|
71 | 439 | # If we receive X-Forwarded-Proto, pass it through; otherwise, pass along the
|
72 | 440 | # scheme used to connect to this server
|
73 | 441 | map $http_x_forwarded_proto $proxy_x_forwarded_proto {
|
74 |
| - default $http_x_forwarded_proto; |
75 |
| - '' $scheme; |
| 442 | + default {{ if $globals.config.trust_downstream_proxy }}$http_x_forwarded_proto{{ else }}$scheme{{ end }}; |
| 443 | + '' $scheme; |
| 444 | +} |
| 445 | + |
| 446 | +map $http_x_forwarded_host $proxy_x_forwarded_host { |
| 447 | + default {{ if $globals.config.trust_downstream_proxy }}$http_x_forwarded_host{{ else }}$host{{ end }}; |
| 448 | + '' $host; |
76 | 449 | }
|
77 | 450 |
|
78 | 451 | # If we receive X-Forwarded-Port, pass it through; otherwise, pass along the
|
79 | 452 | # server port the client connected to
|
80 | 453 | map $http_x_forwarded_port $proxy_x_forwarded_port {
|
81 |
| - default $http_x_forwarded_port; |
82 |
| - '' $server_port; |
| 454 | + default {{ if $globals.config.trust_downstream_proxy }}$http_x_forwarded_port{{ else }}$server_port{{ end }}; |
| 455 | + '' $server_port; |
| 456 | +} |
| 457 | + |
| 458 | +# Include the port in the Host header sent to the container if it is non-standard |
| 459 | +map $server_port $host_port { |
| 460 | + default :$server_port; |
| 461 | + 80 ''; |
| 462 | + 443 ''; |
83 | 463 | }
|
84 | 464 |
|
85 |
| -# If we receive Upgrade, set Connection to "upgrade"; otherwise, delete any |
86 |
| -# Connection header that may have been passed to this server |
| 465 | +# If the request from the downstream client has an "Upgrade:" header (set to any |
| 466 | +# non-empty value), pass "Connection: upgrade" to the upstream (backend) server. |
| 467 | +# Otherwise, the value for the "Connection" header depends on whether the user |
| 468 | +# has enabled keepalive to the upstream server. |
87 | 469 | map $http_upgrade $proxy_connection {
|
88 |
| - default upgrade; |
89 |
| - '' close; |
| 470 | + default upgrade; |
| 471 | + '' $proxy_connection_noupgrade; |
| 472 | +} |
| 473 | +map $upstream_keepalive $proxy_connection_noupgrade { |
| 474 | + # Preserve nginx's default behavior (send "Connection: close"). |
| 475 | + default close; |
| 476 | + # Use an empty string to cancel nginx's default behavior. |
| 477 | + true ''; |
| 478 | +} |
| 479 | +# Abuse the map directive (see <https://stackoverflow.com/q/14433309>) to ensure |
| 480 | +# that $upstream_keepalive is always defined. This is necessary because: |
| 481 | +# - The $proxy_connection variable is indirectly derived from |
| 482 | +# $upstream_keepalive, so $upstream_keepalive must be defined whenever |
| 483 | +# $proxy_connection is resolved. |
| 484 | +# - The $proxy_connection variable is used in a proxy_set_header directive in |
| 485 | +# the http block, so it is always fully resolved for every request -- even |
| 486 | +# those where proxy_pass is not used (e.g., unknown virtual host). |
| 487 | +map "" $upstream_keepalive { |
| 488 | + # The value here should not matter because it should always be overridden in |
| 489 | + # a location block (see the "location" template) for all requests where the |
| 490 | + # value actually matters. |
| 491 | + default false; |
90 | 492 | }
|
91 | 493 |
|
92 | 494 | # Apply fix for very long server names
|
93 | 495 | server_names_hash_bucket_size 128;
|
94 | 496 |
|
95 | 497 | # Default dhparam
|
96 |
| -{{ if (exists "/etc/nginx/dhparam/dhparam.pem") }} |
| 498 | +{{- if (exists "/etc/nginx/dhparam/dhparam.pem") }} |
97 | 499 | ssl_dhparam /etc/nginx/dhparam/dhparam.pem;
|
98 |
| -{{ end }} |
| 500 | +{{- end }} |
99 | 501 |
|
100 |
| -# Set appropriate X-Forwarded-Ssl header |
101 |
| -map $scheme $proxy_x_forwarded_ssl { |
102 |
| - default off; |
103 |
| - https on; |
| 502 | +# Set appropriate X-Forwarded-Ssl header based on $proxy_x_forwarded_proto |
| 503 | +map $proxy_x_forwarded_proto $proxy_x_forwarded_ssl { |
| 504 | + default off; |
| 505 | + https on; |
104 | 506 | }
|
105 | 507 |
|
106 | 508 | gzip_types text/plain text/css application/javascript application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
|
107 | 509 |
|
108 |
| -log_format vhost '$host $remote_addr - $remote_user [$time_local] ' |
109 |
| - '"$request" $status $body_bytes_sent ' |
110 |
| - '"$http_referer" "$http_user_agent"'; |
| 510 | + |
| 511 | +{{- /* See https://nginx.org/en/docs/http/ngx_http_log_module.html#log_format for details and variables |
| 512 | + * LOG_FORMAT_ESCAPE sets the escape part of the log format |
| 513 | + * LOG_FORMAT sets the log format |
| 514 | + */}} |
| 515 | +{{- $logEscape := $globals.config.log_format_escape | default "default" | printf "escape=%s" }} |
| 516 | +{{- $logFormat := $globals.config.log_format | default `$host $remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" "$upstream_addr"` }} |
| 517 | + |
| 518 | +{{- if $globals.config.enable_json_logs }} |
| 519 | +# JSON Logging enabled (via LOG_JSON env variable) |
| 520 | + {{- $logEscape = $globals.config.log_format_escape | default "json" | printf "escape=%s" }} |
| 521 | + {{- $logFormat = $globals.config.log_format | default `{"time_local":"$time_iso8601","client_ip":"$http_x_forwarded_for","remote_addr":"$remote_addr","request":"$request","status":"$status","body_bytes_sent":"$body_bytes_sent","request_time":"$request_time","upstream_response_time":"$upstream_response_time","upstream_addr":"$upstream_addr","http_referrer":"$http_referer","http_user_agent":"$http_user_agent","request_id":"$request_id"}` }} |
| 522 | +{{- end }} |
| 523 | + |
| 524 | +log_format vhost {{ $logEscape }} '{{ $logFormat }}'; |
111 | 525 |
|
112 | 526 | access_log off;
|
113 | 527 |
|
114 |
| -{{/* Get the SSL_POLICY defined by this container, falling back to "Mozilla-Intermediate" */}} |
115 |
| -{{ $ssl_policy := or ($.Env.SSL_POLICY) "Mozilla-Intermediate" }} |
116 |
| -{{ template "ssl_policy" (dict "ssl_policy" $ssl_policy) }} |
| 528 | +{{- /* Lower the SSL policy of the http context |
| 529 | + * if at least one vhost use a TLSv1 or TLSv1.1 policy |
| 530 | + * so TLSv1 and TLSv1.1 can be enabled on those vhosts |
| 531 | + */}} |
| 532 | +{{- $httpContextSslPolicy := $globals.config.ssl_policy }} |
| 533 | +{{- $inUseSslPolicies := groupByKeys $globals.containers "Env.SSL_POLICY" }} |
| 534 | +{{- range $tls1Policy := list "AWS-TLS13-1-1-2021-06" "AWS-TLS13-1-0-2021-06" "AWS-FS-1-1-2019-08" "AWS-FS-2018-06" "AWS-TLS-1-1-2017-01" "AWS-2016-08" "AWS-2015-05" "AWS-2015-03" "AWS-2015-02" "Mozilla-Old" }} |
| 535 | + {{- if has $tls1Policy $inUseSslPolicies }} |
| 536 | +# Using Mozilla-Old SSL policy on the http context to allow TLSv1 and TLSv1.1 |
| 537 | + {{- $httpContextSslPolicy = "Mozilla-Old" }} |
| 538 | + {{- break }} |
| 539 | + {{- end }} |
| 540 | +{{- end }} |
| 541 | + |
| 542 | +{{- template "ssl_policy" (dict "ssl_policy" $httpContextSslPolicy) }} |
| 543 | +error_log /dev/stderr; |
117 | 544 |
|
118 |
| -{{ if $.Env.RESOLVERS }} |
119 |
| -resolver {{ $.Env.RESOLVERS }}; |
120 |
| -{{ end }} |
| 545 | +{{- if $globals.config.resolvers }} |
| 546 | +resolver {{ $globals.config.resolvers }}; |
| 547 | +{{- end }} |
121 | 548 |
|
122 |
| -{{ if (exists "/etc/nginx/proxy.conf") }} |
| 549 | +{{- if (exists "/etc/nginx/proxy.conf") }} |
123 | 550 | include /etc/nginx/proxy.conf;
|
124 |
| -{{ else }} |
| 551 | +{{- else }} |
125 | 552 | # HTTP 1.1 support
|
126 | 553 | proxy_http_version 1.1;
|
127 |
| -proxy_buffering off; |
128 |
| -proxy_set_header Host $http_host; |
| 554 | +proxy_set_header Host $host$host_port; |
129 | 555 | proxy_set_header Upgrade $http_upgrade;
|
130 | 556 | proxy_set_header Connection $proxy_connection;
|
131 | 557 | proxy_set_header X-Real-IP $remote_addr;
|
132 | 558 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
| 559 | +proxy_set_header X-Forwarded-Host $proxy_x_forwarded_host; |
133 | 560 | proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
134 | 561 | proxy_set_header X-Forwarded-Ssl $proxy_x_forwarded_ssl;
|
135 | 562 | proxy_set_header X-Forwarded-Port $proxy_x_forwarded_port;
|
| 563 | +proxy_set_header X-Original-URI $request_uri; |
136 | 564 |
|
137 | 565 | # Mitigate httpoxy attack (see README for details)
|
138 | 566 | proxy_set_header Proxy "";
|
139 |
| -{{ end }} |
| 567 | +{{- end }} |
140 | 568 |
|
141 |
| -{{ $access_log := (or (and (not $.Env.DISABLE_ACCESS_LOGS) "access_log /var/log/nginx/access.log vhost;") "") }} |
| 569 | +{{- /* Precompute and store some information about vhost that use VIRTUAL_HOST_MULTIPORTS. */}} |
| 570 | +{{- range $vhosts_yaml, $containers := groupBy $globals.containers "Env.VIRTUAL_HOST_MULTIPORTS" }} |
| 571 | + {{- /* Print a warning in the config if VIRTUAL_HOST_MULTIPORTS can't be parsed. */}} |
| 572 | + {{- $parsedVhosts := fromYaml $vhosts_yaml }} |
| 573 | + {{- if (empty $parsedVhosts) }} |
| 574 | + {{- $containerNames := list }} |
| 575 | + {{- range $container := $containers }} |
| 576 | + {{- $containerNames = append $containerNames $container.Name }} |
| 577 | + {{- end }} |
| 578 | +# /!\ WARNING: the VIRTUAL_HOST_MULTIPORTS environment variable used for {{ len $containerNames | plural "this container" "those containers" }} is not a valid YAML string: |
| 579 | +# {{ $containerNames | join ", " }} |
| 580 | + {{- continue }} |
| 581 | + {{- end }} |
142 | 582 |
|
143 |
| -{{ $enable_ipv6 := eq (or ($.Env.ENABLE_IPV6) "") "true" }} |
144 |
| -server { |
145 |
| - server_name _; # This is just an invalid value which will never trigger on a real hostname. |
146 |
| - listen {{ $external_http_port }}; |
147 |
| - {{ if $enable_ipv6 }} |
148 |
| - listen [::]:{{ $external_http_port }}; |
149 |
| - {{ end }} |
150 |
| - {{ $access_log }} |
151 |
| - return 503; |
152 |
| -} |
| 583 | + {{- range $hostname, $vhost := $parsedVhosts }} |
| 584 | + {{- $vhost_data := get $globals.vhosts $hostname | default (dict) }} |
| 585 | + {{- $paths := $vhost_data.paths | default (dict) }} |
153 | 586 |
|
154 |
| -{{ if (and (exists "/etc/nginx/certs/default.crt") (exists "/etc/nginx/certs/default.key")) }} |
155 |
| -server { |
156 |
| - server_name _; # This is just an invalid value which will never trigger on a real hostname. |
157 |
| - listen {{ $external_https_port }} ssl http2; |
158 |
| - {{ if $enable_ipv6 }} |
159 |
| - listen [::]:{{ $external_https_port }} ssl http2; |
160 |
| - {{ end }} |
161 |
| - {{ $access_log }} |
162 |
| - return 503; |
163 |
| - |
164 |
| - ssl_session_cache shared:SSL:50m; |
165 |
| - ssl_session_tickets off; |
166 |
| - ssl_certificate /etc/nginx/certs/default.crt; |
167 |
| - ssl_certificate_key /etc/nginx/certs/default.key; |
168 |
| -} |
169 |
| -{{ end }} |
170 |
| - |
171 |
| -{{ range $host, $containers := groupByMulti $ "Env.VIRTUAL_HOST" "," }} |
172 |
| - |
173 |
| -{{ $host := trim $host }} |
174 |
| -{{ $is_regexp := hasPrefix "~" $host }} |
175 |
| -{{ $upstream_name := when $is_regexp (sha1 $host) $host }} |
176 |
| - |
177 |
| -# {{ $host }} |
178 |
| -upstream {{ $upstream_name }} { |
179 |
| - |
180 |
| -{{ range $container := $containers }} |
181 |
| - {{ $addrLen := len $container.Addresses }} |
182 |
| - |
183 |
| - {{ range $knownNetwork := $CurrentContainer.Networks }} |
184 |
| - {{ range $containerNetwork := $container.Networks }} |
185 |
| - {{ if (and (ne $containerNetwork.Name "ingress") (or (eq $knownNetwork.Name $containerNetwork.Name) (eq $knownNetwork.Name "host"))) }} |
186 |
| - ## Can be connected with "{{ $containerNetwork.Name }}" network |
187 |
| - |
188 |
| - {{/* If only 1 port exposed, use that */}} |
189 |
| - {{ if eq $addrLen 1 }} |
190 |
| - {{ $address := index $container.Addresses 0 }} |
191 |
| - {{ template "upstream" (dict "Container" $container "Address" $address "Network" $containerNetwork) }} |
192 |
| - {{/* If more than one port exposed, use the one matching VIRTUAL_PORT env var, falling back to standard web port 80 */}} |
193 |
| - {{ else }} |
194 |
| - {{ $port := coalesce $container.Env.VIRTUAL_PORT "80" }} |
195 |
| - {{ $address := where $container.Addresses "Port" $port | first }} |
196 |
| - {{ template "upstream" (dict "Container" $container "Address" $address "Network" $containerNetwork) }} |
197 |
| - {{ end }} |
198 |
| - {{ else }} |
199 |
| - # Cannot connect to network of this container |
200 |
| - server 127.0.0.1 down; |
201 |
| - {{ end }} |
202 |
| - {{ end }} |
203 |
| - {{ end }} |
204 |
| -{{ end }} |
205 |
| -} |
| 587 | + {{- if (empty $vhost) }} |
| 588 | + {{ $vhost = dict "/" (dict) }} |
| 589 | + {{- end }} |
206 | 590 |
|
207 |
| -{{ $default_host := or ($.Env.DEFAULT_HOST) "" }} |
208 |
| -{{ $default_server := index (dict $host "" $default_host "default_server") $host }} |
| 591 | + {{- range $path, $vpath := $vhost }} |
| 592 | + {{- if (empty $vpath) }} |
| 593 | + {{- $vpath = dict |
| 594 | + "dest" "" |
| 595 | + "port" "default" |
| 596 | + "proto" "http" |
| 597 | + }} |
| 598 | + {{- end }} |
209 | 599 |
|
210 |
| -{{/* Get the VIRTUAL_PROTO defined by containers w/ the same vhost, falling back to "http" */}} |
211 |
| -{{ $proto := trim (or (first (groupByKeys $containers "Env.VIRTUAL_PROTO")) "http") }} |
| 600 | + {{- $dest := $vpath.dest | default "" }} |
| 601 | + {{- $port := $vpath.port | default "default" | toString }} |
| 602 | + {{- $proto := $vpath.proto | default "http" }} |
212 | 603 |
|
213 |
| -{{/* Get the NETWORK_ACCESS defined by containers w/ the same vhost, falling back to "external" */}} |
214 |
| -{{ $network_tag := or (first (groupByKeys $containers "Env.NETWORK_ACCESS")) "external" }} |
| 604 | + {{- $path_data := get $paths $path | default (dict) }} |
| 605 | + {{- $path_ports := $path_data.ports | default (dict) }} |
| 606 | + {{- $path_port_containers := get $path_ports $port | default (list) | concat $containers }} |
| 607 | + {{- $_ := set $path_ports $port $path_port_containers }} |
| 608 | + {{- $_ := set $path_data "ports" $path_ports }} |
| 609 | + |
| 610 | + {{- if (not (hasKey $path_data "dest")) }} |
| 611 | + {{- $_ := set $path_data "dest" $dest }} |
| 612 | + {{- end }} |
215 | 613 |
|
216 |
| -{{/* Get the HTTPS_METHOD defined by containers w/ the same vhost, falling back to "redirect" */}} |
217 |
| -{{ $https_method := or (first (groupByKeys $containers "Env.HTTPS_METHOD")) (or $.Env.HTTPS_METHOD "redirect") }} |
| 614 | + {{- if (not (hasKey $path_data "proto")) }} |
| 615 | + {{- $_ := set $path_data "proto" $proto }} |
| 616 | + {{- end }} |
| 617 | + |
| 618 | + {{- $_ := set $paths $path $path_data }} |
| 619 | + {{- end }} |
| 620 | + {{- $_ := set $vhost_data "paths" $paths }} |
| 621 | + {{- $_ := set $globals.vhosts $hostname $vhost_data }} |
| 622 | + {{- end }} |
| 623 | +{{- end }} |
218 | 624 |
|
219 |
| -{{/* Get the SSL_POLICY defined by containers w/ the same vhost, falling back to empty string (use default) */}} |
220 |
| -{{ $ssl_policy := or (first (groupByKeys $containers "Env.SSL_POLICY")) "" }} |
| 625 | +{{- /* Precompute and store some information about vhost that use VIRTUAL_HOST. */}} |
| 626 | +{{- range $hostname, $containers := groupByMulti $globals.containers "Env.VIRTUAL_HOST" "," }} |
| 627 | + {{- /* Ignore containers with VIRTUAL_HOST set to the empty string. */}} |
| 628 | + {{- $hostname = trim $hostname }} |
| 629 | + {{- if not $hostname }} |
| 630 | + {{- continue }} |
| 631 | + {{- end }} |
221 | 632 |
|
222 |
| -{{/* Get the HSTS defined by containers w/ the same vhost, falling back to "max-age=31536000" */}} |
223 |
| -{{ $hsts := or (first (groupByKeys $containers "Env.HSTS")) (or $.Env.HSTS "max-age=31536000") }} |
| 633 | + {{- /* Drop containers with both VIRTUAL_HOST and VIRTUAL_HOST_MULTIPORTS set |
| 634 | + * (VIRTUAL_HOST_MULTIPORTS takes precedence thanks to the previous loop). |
| 635 | + */}} |
| 636 | + {{- range $_, $containers_to_drop := groupBy $containers "Env.VIRTUAL_HOST_MULTIPORTS" }} |
| 637 | + {{- range $container := $containers_to_drop }} |
| 638 | + {{- $containers = without $containers $container }} |
| 639 | + {{- end }} |
| 640 | + {{- end }} |
| 641 | + {{- if (eq (len $containers) 0) }} |
| 642 | + {{- continue }} |
| 643 | + {{- end }} |
224 | 644 |
|
225 |
| -{{/* Get the VIRTUAL_ROOT By containers w/ use fastcgi root */}} |
226 |
| -{{ $vhost_root := or (first (groupByKeys $containers "Env.VIRTUAL_ROOT")) "/var/www/public" }} |
| 645 | + {{- $vhost_data := get $globals.vhosts $hostname | default (dict) }} |
| 646 | + {{- $paths := $vhost_data.paths | default (dict) }} |
227 | 647 |
|
| 648 | + {{- $tmp_paths := groupByWithDefault $containers "Env.VIRTUAL_PATH" "/" }} |
228 | 649 |
|
229 |
| -{{/* Get the first cert name defined by containers w/ the same vhost */}} |
230 |
| -{{ $certName := (first (groupByKeys $containers "Env.CERT_NAME")) }} |
| 650 | + {{- range $path, $containers := $tmp_paths }} |
| 651 | + {{- $dest := groupByKeys $containers "Env.VIRTUAL_DEST" | first | default "" }} |
| 652 | + {{- $proto := groupByKeys $containers "Env.VIRTUAL_PROTO" | first | default "http" | trim }} |
231 | 653 |
|
232 |
| -{{/* Get the best matching cert by name for the vhost. */}} |
233 |
| -{{ $vhostCert := (closest (dir "/etc/nginx/certs") (printf "%s.crt" $host))}} |
| 654 | + {{- $path_data := get $paths $path | default (dict) }} |
| 655 | + {{- $path_ports := $path_data.ports | default (dict) }} |
| 656 | + {{- range $port, $containers := groupByWithDefault $containers "Env.VIRTUAL_PORT" "default" }} |
| 657 | + {{- $path_port_containers := get $path_ports $port | default (list) | concat $containers }} |
| 658 | + {{- $_ := set $path_ports $port $path_port_containers }} |
| 659 | + {{- end }} |
| 660 | + {{- $_ := set $path_data "ports" $path_ports }} |
234 | 661 |
|
235 |
| -{{/* vhostCert is actually a filename so remove any suffixes since they are added later */}} |
236 |
| -{{ $vhostCert := trimSuffix ".crt" $vhostCert }} |
237 |
| -{{ $vhostCert := trimSuffix ".key" $vhostCert }} |
| 662 | + {{- if (not (hasKey $path_data "dest")) }} |
| 663 | + {{- $_ := set $path_data "dest" $dest }} |
| 664 | + {{- end }} |
238 | 665 |
|
239 |
| -{{/* Use the cert specified on the container or fallback to the best vhost match */}} |
240 |
| -{{ $cert := (coalesce $certName $vhostCert) }} |
| 666 | + {{- if (not (hasKey $path_data "proto")) }} |
| 667 | + {{- $_ := set $path_data "proto" $proto }} |
| 668 | + {{- end }} |
| 669 | + |
| 670 | + {{- $_ := set $paths $path $path_data }} |
| 671 | + {{- end }} |
| 672 | + {{- $_ := set $vhost_data "paths" $paths }} |
| 673 | + {{- $_ := set $globals.vhosts $hostname $vhost_data }} |
| 674 | +{{- end }} |
241 | 675 |
|
242 |
| -{{ $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))) }} |
| 676 | +{{- /* Loop over $globals.vhosts and update it with the remaining informations about each vhost. */}} |
| 677 | +{{- range $hostname, $vhost_data := $globals.vhosts }} |
| 678 | + {{- $is_regexp := hasPrefix "~" $hostname }} |
| 679 | + {{- $upstream_name := or $is_regexp $globals.config.sha1_upstream_name | ternary (sha1 $hostname) $hostname }} |
243 | 680 |
|
244 |
| -{{ if $is_https }} |
| 681 | + {{- $vhost_containers := list }} |
245 | 682 |
|
246 |
| -{{ if eq $https_method "redirect" }} |
247 |
| -server { |
248 |
| - server_name {{ $host }}; |
249 |
| - listen {{ $external_http_port }} {{ $default_server }}; |
250 |
| - {{ if $enable_ipv6 }} |
251 |
| - listen [::]:{{ $external_http_port }} {{ $default_server }}; |
252 |
| - {{ end }} |
253 |
| - {{ $access_log }} |
254 |
| - |
255 |
| - # Do not HTTPS redirect Let'sEncrypt ACME challenge |
256 |
| - location /.well-known/acme-challenge/ { |
257 |
| - auth_basic off; |
258 |
| - allow all; |
259 |
| - root /usr/share/nginx/html; |
260 |
| - try_files $uri =404; |
261 |
| - break; |
262 |
| - } |
263 |
| - |
264 |
| - location / { |
265 |
| - return 301 https://$host$request_uri; |
266 |
| - } |
267 |
| -} |
268 |
| -{{ end }} |
| 683 | + {{- range $path, $vpath_data := $vhost_data.paths }} |
| 684 | + {{- $vpath_containers := list }} |
| 685 | + {{- range $port, $vport_containers := $vpath_data.ports }} |
| 686 | + {{ $vpath_containers = concat $vpath_containers $vport_containers }} |
| 687 | + {{- end }} |
| 688 | + |
| 689 | + {{- /* Get the NETWORK_ACCESS defined by containers w/ the same vhost, falling back to "external". */}} |
| 690 | + {{- $network_tag := groupByKeys $vpath_containers "Env.NETWORK_ACCESS" | first | default "external" }} |
| 691 | + |
| 692 | + {{- $loadbalance := groupByLabel $vpath_containers "com.github.nginx-proxy.nginx-proxy.loadbalance" | keys | first }} |
| 693 | + {{- $keepalive := groupByLabel $vpath_containers "com.github.nginx-proxy.nginx-proxy.keepalive" | keys | first | default "auto" }} |
| 694 | + |
| 695 | + {{- $upstream := $upstream_name }} |
| 696 | + {{- if (not (eq $path "/")) }} |
| 697 | + {{- $sum := sha1 $path }} |
| 698 | + {{- $upstream = printf "%s-%s" $upstream $sum }} |
| 699 | + {{- end }} |
| 700 | + |
| 701 | + {{- $_ := set $vpath_data "network_tag" $network_tag }} |
| 702 | + {{- $_ := set $vpath_data "upstream" $upstream }} |
| 703 | + {{- $_ := set $vpath_data "loadbalance" $loadbalance }} |
| 704 | + {{- $_ := set $vpath_data "keepalive" $keepalive }} |
| 705 | + {{- $_ := set $vhost_data.paths $path $vpath_data }} |
| 706 | + |
| 707 | + {{ $vhost_containers = concat $vhost_containers $vpath_containers }} |
| 708 | + {{- end }} |
| 709 | + |
| 710 | + {{- $userIdentifiedCert := groupByKeys $vhost_containers "Env.CERT_NAME" | first }} |
| 711 | + |
| 712 | + {{- $vhostCert := "" }} |
| 713 | + {{- if exists (printf "/etc/nginx/certs/%s.crt" $hostname) }} |
| 714 | + {{- $vhostCert = $hostname }} |
| 715 | + {{- end }} |
| 716 | + |
| 717 | + {{- $parentVhostCert := "" }} |
| 718 | + {{- if gt ($hostname | sprigSplit "." | len) 2 }} |
| 719 | + {{- $parentHostname := ($hostname | sprigSplitn "." 2)._1 }} |
| 720 | + {{- if exists (printf "/etc/nginx/certs/%s.crt" $parentHostname) }} |
| 721 | + {{- $parentVhostCert = $parentHostname }} |
| 722 | + {{- end }} |
| 723 | + {{- end }} |
| 724 | + |
| 725 | + {{- $trust_default_cert := groupByLabel $vhost_containers "com.github.nginx-proxy.nginx-proxy.trust-default-cert" | keys | first | default $globals.config.trust_default_cert | parseBool }} |
| 726 | + {{- $defaultCert := and $trust_default_cert $globals.config.default_cert_ok | ternary "default" "" }} |
| 727 | + |
| 728 | + {{- $cert := or $userIdentifiedCert $vhostCert $parentVhostCert $defaultCert }} |
| 729 | + {{- $cert_ok := and (ne $cert "") (exists (printf "/etc/nginx/certs/%s.crt" $cert)) (exists (printf "/etc/nginx/certs/%s.key" $cert)) }} |
| 730 | + |
| 731 | + {{- $enable_debug_endpoint := groupByLabel $vhost_containers "com.github.nginx-proxy.nginx-proxy.debug-endpoint" | keys | first | default $globals.config.enable_debug_endpoint | parseBool }} |
| 732 | + {{- $default := eq $globals.config.default_host $hostname }} |
| 733 | + {{- $https_method := groupByKeys $vhost_containers "Env.HTTPS_METHOD" | first | default $globals.config.https_method }} |
| 734 | + {{- $enable_http_on_missing_cert := groupByKeys $vhost_containers "Env.ENABLE_HTTP_ON_MISSING_CERT" | first | default $globals.config.enable_http_on_missing_cert | parseBool }} |
| 735 | + {{- /* When no trusted certs (default and/or vhost) are present we want to ensure that HTTP is enabled; hence switching from 'nohttp' or 'redirect' to 'noredirect' */}} |
| 736 | + {{- $https_method_disable_http := list "nohttp" "redirect" | has $https_method }} |
| 737 | + {{- if and $https_method_disable_http (not $cert_ok) $enable_http_on_missing_cert }} |
| 738 | + {{- $https_method = "noredirect" }} |
| 739 | + {{- end }} |
| 740 | + {{- $non_get_redirect := groupByLabel $vhost_containers "com.github.nginx-proxy.nginx-proxy.non-get-redirect" | keys | first | default $globals.config.non_get_redirect }} |
| 741 | + |
| 742 | + {{- $http2_enabled := groupByLabel $vhost_containers "com.github.nginx-proxy.nginx-proxy.http2.enable" | keys | first | default $globals.config.enable_http2 | parseBool }} |
| 743 | + {{- $http3_enabled := groupByLabel $vhost_containers "com.github.nginx-proxy.nginx-proxy.http3.enable" | keys | first | default $globals.config.enable_http3 | parseBool }} |
| 744 | + |
| 745 | + {{- $acme_http_challenge := groupByKeys $vhost_containers "Env.ACME_HTTP_CHALLENGE_LOCATION" | first | default $globals.config.acme_http_challenge }} |
| 746 | + {{- $acme_http_challenge_legacy := eq $acme_http_challenge "legacy" }} |
| 747 | + {{- $acme_http_challenge_enabled := false }} |
| 748 | + {{- if (not $acme_http_challenge_legacy) }} |
| 749 | + {{- $acme_http_challenge_enabled = parseBool $acme_http_challenge }} |
| 750 | + {{- end }} |
269 | 751 |
|
| 752 | + {{- /* Get the SERVER_TOKENS defined by containers w/ the same vhost, falling back to "". */}} |
| 753 | + {{- $server_tokens := groupByKeys $vhost_containers "Env.SERVER_TOKENS" | first | default "" | trim }} |
| 754 | + |
| 755 | + {{- /* Get the SSL_POLICY defined by containers w/ the same vhost, falling back to empty string (use default). */}} |
| 756 | + {{- $ssl_policy := groupByKeys $vhost_containers "Env.SSL_POLICY" | first | default "" }} |
| 757 | + |
| 758 | + {{- /* Get the HSTS defined by containers w/ the same vhost, falling back to "max-age=31536000". */}} |
| 759 | + {{- $hsts := groupByKeys $vhost_containers "Env.HSTS" | first | default $globals.config.hsts }} |
| 760 | + |
| 761 | + {{- /* Get the VIRTUAL_ROOT By containers w/ use fastcgi root */}} |
| 762 | + {{- $vhost_root := groupByKeys $vhost_containers "Env.VIRTUAL_ROOT" | first | default "/var/www/public" }} |
| 763 | + |
| 764 | + {{- $vhost_data = merge $vhost_data (dict |
| 765 | + "cert" $cert |
| 766 | + "cert_ok" $cert_ok |
| 767 | + "enable_debug_endpoint" $enable_debug_endpoint |
| 768 | + "default" $default |
| 769 | + "hsts" $hsts |
| 770 | + "https_method" $https_method |
| 771 | + "non_get_redirect" $non_get_redirect |
| 772 | + "http2_enabled" $http2_enabled |
| 773 | + "http3_enabled" $http3_enabled |
| 774 | + "is_regexp" $is_regexp |
| 775 | + "acme_http_challenge_legacy" $acme_http_challenge_legacy |
| 776 | + "acme_http_challenge_enabled" $acme_http_challenge_enabled |
| 777 | + "server_tokens" $server_tokens |
| 778 | + "ssl_policy" $ssl_policy |
| 779 | + "trust_default_cert" $trust_default_cert |
| 780 | + "upstream_name" $upstream_name |
| 781 | + "vhost_root" $vhost_root |
| 782 | + ) }} |
| 783 | + {{- $_ := set $globals.vhosts $hostname $vhost_data }} |
| 784 | +{{- end }} |
| 785 | + |
| 786 | + |
| 787 | +{{- /* |
| 788 | + * If needed, create a catch-all fallback server to send an error code to |
| 789 | + * clients that request something from an unknown vhost. |
| 790 | + * |
| 791 | + * This server must appear first in the generated config because nginx uses |
| 792 | + * the first `server` directive to handle requests that don't match any of |
| 793 | + * the other `server` directives. An alternative approach would be to add |
| 794 | + * the `default_server` option to the `listen` directives inside this |
| 795 | + * `server`, but some users inject a custom `server` directive that uses |
| 796 | + * `default_server`. Using `default_server` here would cause nginx to fail |
| 797 | + * to start for those users. See |
| 798 | + * <https://github.com/nginx-proxy/nginx-proxy/issues/2212>. |
| 799 | + */}} |
| 800 | +{{- block "fallback_server" $globals }} |
| 801 | + {{- $globals := . }} |
| 802 | + {{- $http_exists := false }} |
| 803 | + {{- $https_exists := false }} |
| 804 | + {{- $default_http_exists := false }} |
| 805 | + {{- $default_https_exists := false }} |
| 806 | + {{- $http3_enabled := false }} |
| 807 | + {{- range $vhost := $globals.vhosts }} |
| 808 | + {{- $http := ne $vhost.https_method "nohttp" }} |
| 809 | + {{- $https := ne $vhost.https_method "nohttps" }} |
| 810 | + {{- $http_exists = or $http_exists $http }} |
| 811 | + {{- $https_exists = or $https_exists $https }} |
| 812 | + {{- $default_http_exists = or $default_http_exists (and $http $vhost.default) }} |
| 813 | + {{- $default_https_exists = or $default_https_exists (and $https $vhost.default) }} |
| 814 | + {{- $http3_enabled = or $http3_enabled $vhost.http3_enabled }} |
| 815 | + {{- end }} |
| 816 | + {{- $fallback_http := not $default_http_exists }} |
| 817 | + {{- $fallback_https := not $default_https_exists }} |
| 818 | + {{- /* |
| 819 | + * If there are no vhosts at all, create fallbacks for both plain http |
| 820 | + * and https so that clients get something more useful than a connection |
| 821 | + * refused error. |
| 822 | + */}} |
| 823 | + {{- if and (not $http_exists) (not $https_exists) }} |
| 824 | + {{- $fallback_https = true }} |
| 825 | + {{- end }} |
| 826 | + {{- if or $fallback_http $fallback_https }} |
270 | 827 | server {
|
271 |
| - server_name {{ $host }}; |
272 |
| - listen {{ $external_https_port }} ssl http2 {{ $default_server }}; |
273 |
| - {{ if $enable_ipv6 }} |
274 |
| - listen [::]:{{ $external_https_port }} ssl http2 {{ $default_server }}; |
275 |
| - {{ end }} |
276 |
| - {{ $access_log }} |
277 |
| - |
278 |
| - {{ if eq $network_tag "internal" }} |
279 |
| - # Only allow traffic from internal clients |
280 |
| - include /etc/nginx/network_internal.conf; |
281 |
| - {{ end }} |
282 |
| - |
283 |
| - {{ template "ssl_policy" (dict "ssl_policy" $ssl_policy) }} |
284 |
| - |
285 |
| - ssl_session_timeout 5m; |
286 |
| - ssl_session_cache shared:SSL:50m; |
287 |
| - ssl_session_tickets off; |
288 |
| - |
289 |
| - ssl_certificate /etc/nginx/certs/{{ (printf "%s.crt" $cert) }}; |
290 |
| - ssl_certificate_key /etc/nginx/certs/{{ (printf "%s.key" $cert) }}; |
291 |
| - |
292 |
| - {{ if (exists (printf "/etc/nginx/certs/%s.dhparam.pem" $cert)) }} |
293 |
| - ssl_dhparam {{ printf "/etc/nginx/certs/%s.dhparam.pem" $cert }}; |
294 |
| - {{ end }} |
295 |
| - |
296 |
| - {{ if (exists (printf "/etc/nginx/certs/%s.chain.pem" $cert)) }} |
297 |
| - ssl_stapling on; |
298 |
| - ssl_stapling_verify on; |
299 |
| - ssl_trusted_certificate {{ printf "/etc/nginx/certs/%s.chain.pem" $cert }}; |
300 |
| - {{ end }} |
301 |
| - |
302 |
| - {{ if (not (or (eq $https_method "noredirect") (eq $hsts "off"))) }} |
303 |
| - add_header Strict-Transport-Security "{{ trim $hsts }}" always; |
304 |
| - {{ end }} |
305 |
| - |
306 |
| - {{ if (exists (printf "/etc/nginx/vhost.d/%s" $host)) }} |
307 |
| - include {{ printf "/etc/nginx/vhost.d/%s" $host }}; |
308 |
| - {{ else if (exists "/etc/nginx/vhost.d/default") }} |
309 |
| - include /etc/nginx/vhost.d/default; |
310 |
| - {{ end }} |
311 |
| - |
312 |
| - location / { |
313 |
| - {{ if eq $proto "uwsgi" }} |
314 |
| - include uwsgi_params; |
315 |
| - uwsgi_pass {{ trim $proto }}://{{ trim $upstream_name }}; |
316 |
| - {{ else if eq $proto "fastcgi" }} |
317 |
| - root {{ trim $vhost_root }}; |
318 |
| - include fastcgi_params; |
319 |
| - fastcgi_pass {{ trim $upstream_name }}; |
320 |
| - {{ else if eq $proto "grpc" }} |
321 |
| - grpc_pass {{ trim $proto }}://{{ trim $upstream_name }}; |
322 |
| - {{ else }} |
323 |
| - proxy_pass {{ trim $proto }}://{{ trim $upstream_name }}; |
324 |
| - {{ end }} |
325 |
| - |
326 |
| - {{ if (exists (printf "/etc/nginx/htpasswd/%s" $host)) }} |
327 |
| - auth_basic "Restricted {{ $host }}"; |
328 |
| - auth_basic_user_file {{ (printf "/etc/nginx/htpasswd/%s" $host) }}; |
329 |
| - {{ end }} |
330 |
| - {{ if (exists (printf "/etc/nginx/vhost.d/%s_location" $host)) }} |
331 |
| - include {{ printf "/etc/nginx/vhost.d/%s_location" $host}}; |
332 |
| - {{ else if (exists "/etc/nginx/vhost.d/default_location") }} |
333 |
| - include /etc/nginx/vhost.d/default_location; |
334 |
| - {{ end }} |
335 |
| - } |
| 828 | + server_name _; # This is just an invalid value which will never trigger on a real hostname. |
| 829 | + server_tokens off; |
| 830 | + {{ template "access_log" (dict "Enable" $globals.config.enable_access_log) }} |
| 831 | + http2 on; |
| 832 | + {{- if $fallback_http }} |
| 833 | + listen {{ $globals.config.external_http_port }}; {{- /* Do not add `default_server` (see comment above). */}} |
| 834 | + {{- if $globals.config.enable_ipv6 }} |
| 835 | + listen [::]:{{ $globals.config.external_http_port }}; {{- /* Do not add `default_server` (see comment above). */}} |
| 836 | + {{- end }} |
| 837 | + {{- end }} |
| 838 | + {{- if $fallback_https }} |
| 839 | + listen {{ $globals.config.external_https_port }} ssl; {{- /* Do not add `default_server` (see comment above). */}} |
| 840 | + {{- if $globals.config.enable_ipv6 }} |
| 841 | + listen [::]:{{ $globals.config.external_https_port }} ssl; {{- /* Do not add `default_server` (see comment above). */}} |
| 842 | + {{- end }} |
| 843 | + {{- if $http3_enabled }} |
| 844 | + http3 on; |
| 845 | + listen {{ $globals.config.external_https_port }} quic reuseport; {{- /* Do not add `default_server` (see comment above). */}} |
| 846 | + {{- if $globals.config.enable_ipv6 }} |
| 847 | + listen [::]:{{ $globals.config.external_https_port }} quic reuseport; {{- /* Do not add `default_server` (see comment above). */}} |
| 848 | + {{- end }} |
| 849 | + {{- end }} |
| 850 | + ssl_session_cache shared:SSL:50m; |
| 851 | + ssl_session_tickets off; |
| 852 | + {{- end }} |
| 853 | + {{- if $globals.config.default_cert_ok }} |
| 854 | + ssl_certificate /etc/nginx/certs/default.crt; |
| 855 | + ssl_certificate_key /etc/nginx/certs/default.key; |
| 856 | + {{- else }} |
| 857 | + # No default certificate found, so reject SSL handshake; |
| 858 | + ssl_reject_handshake on; |
| 859 | + {{- end }} |
| 860 | + |
| 861 | + {{- if (exists "/usr/share/nginx/html/errors/50x.html") }} |
| 862 | + error_page 500 502 503 504 /50x.html; |
| 863 | + location /50x.html { |
| 864 | + root /usr/share/nginx/html/errors; |
| 865 | + internal; |
| 866 | + } |
| 867 | + {{- end }} |
| 868 | + location ^~ / { |
| 869 | + return 503; |
| 870 | + } |
336 | 871 | }
|
| 872 | + {{- end }} |
| 873 | +{{- end }} |
337 | 874 |
|
338 |
| -{{ end }} |
| 875 | +{{- range $hostname, $vhost := $globals.vhosts }} |
| 876 | + {{- $default_server := when $vhost.default "default_server" "" }} |
339 | 877 |
|
340 |
| -{{ if or (not $is_https) (eq $https_method "noredirect") }} |
| 878 | + {{- range $path, $vpath := $vhost.paths }} |
| 879 | +# {{ $hostname }}{{ $path }} |
| 880 | + {{ template "upstream" (dict "globals" $globals "Path" $path "VPath" $vpath) }} |
| 881 | + {{- end }} |
341 | 882 |
|
| 883 | + {{- if (eq $vhost.https_method "redirect") }} |
342 | 884 | server {
|
343 |
| - server_name {{ $host }}; |
344 |
| - listen {{ $external_http_port }} {{ $default_server }}; |
345 |
| - {{ if $enable_ipv6 }} |
346 |
| - listen [::]:80 {{ $default_server }}; |
347 |
| - {{ end }} |
348 |
| - {{ $access_log }} |
349 |
| - |
350 |
| - {{ if eq $network_tag "internal" }} |
351 |
| - # Only allow traffic from internal clients |
352 |
| - include /etc/nginx/network_internal.conf; |
353 |
| - {{ end }} |
354 |
| - |
355 |
| - {{ if (exists (printf "/etc/nginx/vhost.d/%s" $host)) }} |
356 |
| - include {{ printf "/etc/nginx/vhost.d/%s" $host }}; |
357 |
| - {{ else if (exists "/etc/nginx/vhost.d/default") }} |
358 |
| - include /etc/nginx/vhost.d/default; |
359 |
| - {{ end }} |
360 |
| - |
361 |
| - location / { |
362 |
| - {{ if eq $proto "uwsgi" }} |
363 |
| - include uwsgi_params; |
364 |
| - uwsgi_pass {{ trim $proto }}://{{ trim $upstream_name }}; |
365 |
| - {{ else if eq $proto "fastcgi" }} |
366 |
| - root {{ trim $vhost_root }}; |
367 |
| - include fastcgi_params; |
368 |
| - fastcgi_pass {{ trim $upstream_name }}; |
369 |
| - {{ else if eq $proto "grpc" }} |
370 |
| - grpc_pass {{ trim $proto }}://{{ trim $upstream_name }}; |
371 |
| - {{ else }} |
372 |
| - proxy_pass {{ trim $proto }}://{{ trim $upstream_name }}; |
373 |
| - {{ end }} |
374 |
| - {{ if (exists (printf "/etc/nginx/htpasswd/%s" $host)) }} |
375 |
| - auth_basic "Restricted {{ $host }}"; |
376 |
| - auth_basic_user_file {{ (printf "/etc/nginx/htpasswd/%s" $host) }}; |
377 |
| - {{ end }} |
378 |
| - {{ if (exists (printf "/etc/nginx/vhost.d/%s_location" $host)) }} |
379 |
| - include {{ printf "/etc/nginx/vhost.d/%s_location" $host}}; |
380 |
| - {{ else if (exists "/etc/nginx/vhost.d/default_location") }} |
381 |
| - include /etc/nginx/vhost.d/default_location; |
382 |
| - {{ end }} |
383 |
| - } |
| 885 | + server_name {{ $hostname }}; |
| 886 | + {{- if $vhost.server_tokens }} |
| 887 | + server_tokens {{ $vhost.server_tokens }}; |
| 888 | + {{- end }} |
| 889 | + {{ template "access_log" (dict "Enable" $globals.config.enable_access_log) }} |
| 890 | + listen {{ $globals.config.external_http_port }} {{ $default_server }}; |
| 891 | + {{- if $globals.config.enable_ipv6 }} |
| 892 | + listen [::]:{{ $globals.config.external_http_port }} {{ $default_server }}; |
| 893 | + {{- end }} |
| 894 | + |
| 895 | + {{- if (or $vhost.acme_http_challenge_legacy $vhost.acme_http_challenge_enabled) }} |
| 896 | + # Do not HTTPS redirect Let's Encrypt ACME challenge |
| 897 | + location ^~ /.well-known/acme-challenge/ { |
| 898 | + auth_basic off; |
| 899 | + auth_request off; |
| 900 | + allow all; |
| 901 | + root /usr/share/nginx/html; |
| 902 | + try_files $uri =404; |
| 903 | + break; |
| 904 | + } |
| 905 | + {{- end }} |
| 906 | + |
| 907 | + {{- if $vhost.enable_debug_endpoint }} |
| 908 | + {{ template "debug_location" (dict "GlobalConfig" $globals.config "Hostname" $hostname "VHost" $vhost) }} |
| 909 | + {{- end }} |
| 910 | + |
| 911 | + location / { |
| 912 | + {{- $redirect_uri := "https://$host$request_uri" }} |
| 913 | + {{- if ne $globals.config.external_https_port "443" }} |
| 914 | + {{- $redirect_uri = printf "https://$host:%s$request_uri" $globals.config.external_https_port }} |
| 915 | + {{- end}} |
| 916 | + if ($request_method ~ (OPTIONS|POST|PUT|PATCH|DELETE)) { |
| 917 | + return {{ $vhost.non_get_redirect }} {{ $redirect_uri }}; |
| 918 | + } |
| 919 | + return 301 {{ $redirect_uri }}; |
| 920 | + } |
384 | 921 | }
|
| 922 | + {{- end }} |
385 | 923 |
|
386 |
| -{{ if (and (not $is_https) (exists "/etc/nginx/certs/default.crt") (exists "/etc/nginx/certs/default.key")) }} |
387 | 924 | server {
|
388 |
| - server_name {{ $host }}; |
389 |
| - listen {{ $external_https_port }} ssl http2 {{ $default_server }}; |
390 |
| - {{ if $enable_ipv6 }} |
391 |
| - listen [::]:{{ $external_https_port }} ssl http2 {{ $default_server }}; |
392 |
| - {{ end }} |
393 |
| - {{ $access_log }} |
394 |
| - return 500; |
395 |
| - |
396 |
| - ssl_certificate /etc/nginx/certs/default.crt; |
397 |
| - ssl_certificate_key /etc/nginx/certs/default.key; |
398 |
| -} |
399 |
| -{{ end }} |
| 925 | + {{- if $vhost.is_regexp }} |
| 926 | + {{- if or |
| 927 | + (printf "/etc/nginx/vhost.d/%s" $hostname | exists) |
| 928 | + (printf "/etc/nginx/vhost.d/%s_location" $hostname | exists) |
| 929 | + (printf "/etc/nginx/vhost.d/%s_location_override" $hostname | exists) |
| 930 | + (printf "/etc/nginx/htpasswd/%s" $hostname | exists) |
| 931 | + }} |
| 932 | + # https://github.com/nginx-proxy/nginx-proxy/issues/2529#issuecomment-2437609249 |
| 933 | + # Support for vhost config file(s) named like a regexp ({{ $hostname }}) has been removed from nginx-proxy. |
| 934 | + # Please name your vhost config file(s) with the sha1 of the regexp instead ({{ $hostname }} -> {{ sha1 $hostname }}) : |
| 935 | + # - /etc/nginx/vhost.d/{{ sha1 $hostname }} |
| 936 | + # - /etc/nginx/vhost.d/{{ sha1 $hostname }}_location |
| 937 | + # - /etc/nginx/vhost.d/{{ sha1 $hostname }}_location_override |
| 938 | + # - /etc/nginx/htpasswd/{{ sha1 $hostname }} |
| 939 | + {{- end }} |
| 940 | + {{- end }} |
| 941 | + |
| 942 | + server_name {{ $hostname }}; |
| 943 | + {{- if $vhost.server_tokens }} |
| 944 | + server_tokens {{ $vhost.server_tokens }}; |
| 945 | + {{- end }} |
| 946 | + {{ template "access_log" (dict "Enable" $globals.config.enable_access_log) }} |
| 947 | + {{- if $vhost.http2_enabled }} |
| 948 | + http2 on; |
| 949 | + {{- end }} |
| 950 | + {{- if or (eq $vhost.https_method "nohttps") (eq $vhost.https_method "noredirect") }} |
| 951 | + listen {{ $globals.config.external_http_port }} {{ $default_server }}; |
| 952 | + {{- if $globals.config.enable_ipv6 }} |
| 953 | + listen [::]:{{ $globals.config.external_http_port }} {{ $default_server }}; |
| 954 | + {{- end }} |
| 955 | + |
| 956 | + {{- if (and (eq $vhost.https_method "noredirect") $vhost.acme_http_challenge_enabled) }} |
| 957 | + location /.well-known/acme-challenge/ { |
| 958 | + auth_basic off; |
| 959 | + allow all; |
| 960 | + root /usr/share/nginx/html; |
| 961 | + try_files $uri =404; |
| 962 | + break; |
| 963 | + } |
| 964 | + {{- end }} |
| 965 | + {{- end }} |
| 966 | + {{- if ne $vhost.https_method "nohttps" }} |
| 967 | + listen {{ $globals.config.external_https_port }} ssl {{ $default_server }}; |
| 968 | + {{- if $globals.config.enable_ipv6 }} |
| 969 | + listen [::]:{{ $globals.config.external_https_port }} ssl {{ $default_server }}; |
| 970 | + {{- end }} |
| 971 | + |
| 972 | + {{- if $vhost.http3_enabled }} |
| 973 | + http3 on; |
| 974 | + add_header alt-svc 'h3=":{{ $globals.config.external_https_port }}"; ma=86400;'; |
| 975 | + listen {{ $globals.config.external_https_port }} quic {{ $default_server }}; |
| 976 | + {{- if $globals.config.enable_ipv6 }} |
| 977 | + listen [::]:{{ $globals.config.external_https_port }} quic {{ $default_server }}; |
| 978 | + {{- end }} |
| 979 | + {{- end }} |
| 980 | + |
| 981 | + {{- if $vhost.cert_ok }} |
| 982 | + {{- template "ssl_policy" (dict "ssl_policy" $vhost.ssl_policy) }} |
| 983 | + |
| 984 | + ssl_session_timeout 5m; |
| 985 | + ssl_session_cache shared:SSL:50m; |
| 986 | + ssl_session_tickets off; |
| 987 | + |
| 988 | + ssl_certificate /etc/nginx/certs/{{ (printf "%s.crt" $vhost.cert) }}; |
| 989 | + ssl_certificate_key /etc/nginx/certs/{{ (printf "%s.key" $vhost.cert) }}; |
400 | 990 |
|
401 |
| -{{ end }} |
402 |
| -{{ end }} |
| 991 | + {{- if (exists (printf "/etc/nginx/certs/%s.dhparam.pem" $vhost.cert)) }} |
| 992 | + ssl_dhparam {{ printf "/etc/nginx/certs/%s.dhparam.pem" $vhost.cert }}; |
| 993 | + {{- end }} |
| 994 | + |
| 995 | + {{- if (exists (printf "/etc/nginx/certs/%s.chain.pem" $vhost.cert)) }} |
| 996 | + ssl_stapling on; |
| 997 | + ssl_stapling_verify on; |
| 998 | + ssl_trusted_certificate {{ printf "/etc/nginx/certs/%s.chain.pem" $vhost.cert }}; |
| 999 | + {{- end }} |
| 1000 | + |
| 1001 | + {{- if (not (or (eq $vhost.https_method "noredirect") (eq $vhost.hsts "off"))) }} |
| 1002 | + set $sts_header ""; |
| 1003 | + if ($https) { |
| 1004 | + set $sts_header "{{ trim $vhost.hsts }}"; |
| 1005 | + } |
| 1006 | + add_header Strict-Transport-Security $sts_header always; |
| 1007 | + {{- end }} |
| 1008 | + {{- else if not $vhost.trust_default_cert | and $globals.config.default_cert_ok }} |
| 1009 | + # No certificate found for this vhost, and the default certificate isn't trusted, so reject SSL handshake. |
| 1010 | + ssl_reject_handshake on; |
| 1011 | + {{- else }} |
| 1012 | + # No certificate for this vhost nor default certificate found, so reject SSL handshake. |
| 1013 | + ssl_reject_handshake on; |
| 1014 | + {{- end }} |
| 1015 | + {{- end }} |
| 1016 | + |
| 1017 | + {{- $vhostFileName := $vhost.is_regexp | ternary (sha1 $hostname) $hostname }} |
| 1018 | + |
| 1019 | + {{- if (exists (printf "/etc/nginx/vhost.d/%s" $vhostFileName)) }} |
| 1020 | + include {{ printf "/etc/nginx/vhost.d/%s" $vhostFileName }}; |
| 1021 | + {{- else if (exists "/etc/nginx/vhost.d/default") }} |
| 1022 | + include /etc/nginx/vhost.d/default; |
| 1023 | + {{- end }} |
| 1024 | + |
| 1025 | + {{- if $vhost.enable_debug_endpoint }} |
| 1026 | + {{ template "debug_location" (dict "GlobalConfig" $globals.config "Hostname" $hostname "VHost" $vhost) }} |
| 1027 | + {{- end }} |
| 1028 | + |
| 1029 | + {{- range $path, $vpath := $vhost.paths }} |
| 1030 | + {{- template "location" (dict |
| 1031 | + "Path" $path |
| 1032 | + "Host" $vhostFileName |
| 1033 | + "HostIsRegexp" $vhost.is_regexp |
| 1034 | + "VhostRoot" $vhost.vhost_root |
| 1035 | + "VPath" $vpath |
| 1036 | + ) }} |
| 1037 | + {{- end }} |
| 1038 | + |
| 1039 | + {{- if and (not (contains $vhost.paths "/")) (ne $globals.config.default_root_response "none")}} |
| 1040 | + location / { |
| 1041 | + return {{ $globals.config.default_root_response }}; |
| 1042 | + } |
| 1043 | + {{- end }} |
| 1044 | +} |
| 1045 | +{{- end }} |
0 commit comments