1
0
mirror of https://github.com/thib8956/nginx-proxy synced 2025-04-16 18:51:01 +00:00

Merge pull request #2533 from nginx-proxy/2529

fix: use sha1 hash for config files name when using regex host
This commit is contained in:
Nicolas Duchon 2024-11-02 14:11:22 +01:00 committed by GitHub
commit a3db62bb14
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 102 additions and 15 deletions

View File

@ -181,8 +181,9 @@ In this example, the incoming request `http://example.tld/app1/foo` will be prox
### Per-VIRTUAL_PATH location configuration
The same options as from [Per-VIRTUAL_HOST location configuration](#Per-VIRTUAL_HOST-location-configuration) are available on a `VIRTUAL_PATH` basis.
The only difference is that the filename gets an additional block `HASH=$(echo -n $VIRTUAL_PATH | sha1sum | awk '{ print $1 }')`. This is the sha1-hash of the `VIRTUAL_PATH` (no newline). This is done filename sanitization purposes.
The used filename is `${VIRTUAL_HOST}_${HASH}_location`
The only difference is that the filename gets an additional block `HASH=$(echo -n $VIRTUAL_PATH | sha1sum | awk '{ print $1 }')`. This is the sha1-hash of the `VIRTUAL_PATH` (no newline). This is done for filename sanitization purposes.
The used filename is `${VIRTUAL_HOST}_${PATH_HASH}_location`, or when `VIRTUAL_HOST` is a regex, `${VIRTUAL_HOST_HASH}_${PATH_HASH}_location`.
The filename of the previous example would be `example.tld_8610f6c344b4096614eab6e09d58885349f42faf_location`.
@ -328,7 +329,7 @@ See the [nginx keepalive documentation](https://nginx.org/en/docs/http/ngx_http_
## Basic Authentication Support
In order to be able to secure your virtual host, you have to create a file named as its equivalent `VIRTUAL_HOST` variable in directory
In order to be able to secure your virtual host, you have to create a file named as its equivalent `VIRTUAL_HOST` variable (or if using a regex `VIRTUAL_HOST`, as the sha1 hash of the regex) in directory
`/etc/nginx/htpasswd/{$VIRTUAL_HOST}`
```console
@ -738,7 +739,7 @@ docker run -d -p 80:80 -p 443:443 -v /path/to/my_proxy.conf:/etc/nginx/conf.d/my
### Per-VIRTUAL_HOST
To add settings on a per-`VIRTUAL_HOST` basis, add your configuration file under `/etc/nginx/vhost.d`. Unlike in the proxy-wide case, which allows multiple config files with any name ending in `.conf`, the per-`VIRTUAL_HOST` file must be named exactly after the `VIRTUAL_HOST`.
To add settings on a per-`VIRTUAL_HOST` basis, add your configuration file under `/etc/nginx/vhost.d`. Unlike in the proxy-wide case, which allows multiple config files with any name ending in `.conf`, the per-`VIRTUAL_HOST` file must be named exactly after the `VIRTUAL_HOST`, or if `VIRTUAL_HOST` is a regex, after the sha1 hash of the regex.
In order to allow virtual hosts to be dynamically configured as backends are added and removed, it makes the most sense to mount an external directory as `/etc/nginx/vhost.d` as opposed to using derived images or mounting individual configuration files.
@ -762,7 +763,7 @@ If you want most of your virtual hosts to use a default single configuration and
### Per-VIRTUAL_HOST location configuration
To add settings to the "location" block on a per-`VIRTUAL_HOST` basis, add your configuration file under `/etc/nginx/vhost.d` just like the previous section except with the suffix `_location`.
To add settings to the "location" block on a per-`VIRTUAL_HOST` basis, add your configuration file under `/etc/nginx/vhost.d` just like the per-`VIRTUAL_HOST` section except with the suffix `_location` (like this section, if your `VIRTUAl_HOST` is a regex, use the sha1 hash of the regex instead, with the suffix `_location` appended).
For example, if you have a virtual host named `app.example.com` and you have configured a proxy_cache `my-cache` in another custom file, you could tell it to use a proxy cache as follows:
@ -790,7 +791,7 @@ The `${VIRTUAL_HOST}_${PATH_HASH}_location`, `${VIRTUAL_HOST}_location`, and `de
/etc/nginx/vhost.d/${VIRTUAL_HOST}_${PATH_HASH}_location_override
```
where `${VIRTUAL_HOST}` is the name of the virtual host (the `VIRTUAL_HOST` environment variable) and `${PATH_HASH}` is the SHA-1 hash of the path, as [described above](#per-virtual_path-location-configuration).
where `${VIRTUAL_HOST}` is the name of the virtual host (the `VIRTUAL_HOST` environment variable), or the sha1 hash of `VIRTUAL_HOST` when it's a regex, and `${PATH_HASH}` is the SHA-1 hash of the path, as [described above](#per-virtual_path-location-configuration).
For convenience, the `_${PATH_HASH}` part can be omitted if the path is `/`:

View File

@ -289,7 +289,7 @@
auth_basic "Restricted {{ .Host }}{{ .Path }}";
auth_basic_user_file {{ (printf "/etc/nginx/htpasswd/%s_%s" .Host (sha1 .Path)) }};
{{- else if (exists (printf "/etc/nginx/htpasswd/%s" .Host)) }}
auth_basic "Restricted {{ .Host }}";
auth_basic "Restricted {{ .HostIsRegexp | ternary "access" .Host }}";
auth_basic_user_file {{ (printf "/etc/nginx/htpasswd/%s" .Host) }};
{{- end }}
@ -570,7 +570,9 @@ proxy_set_header Proxy "";
{{- /* Loop over $globals.vhosts and update it with the remaining informations about each vhost. */}}
{{- range $hostname, $vhost_data := $globals.vhosts }}
{{- $is_regexp := hasPrefix "~" $hostname }}
{{- $vhost_containers := list }}
{{- range $path, $vpath_data := $vhost_data.paths }}
{{- $vpath_containers := list }}
{{- range $port, $vport_containers := $vpath_data.ports }}
@ -644,6 +646,7 @@ proxy_set_header Proxy "";
"https_method" $https_method
"http2_enabled" $http2_enabled
"http3_enabled" $http3_enabled
"is_regexp" $is_regexp
"acme_http_challenge_legacy" $acme_http_challenge_legacy
"acme_http_challenge_enabled" $acme_http_challenge_enabled
"server_tokens" $server_tokens
@ -785,6 +788,23 @@ server {
{{- end }}
server {
{{- if $vhost.is_regexp }}
{{- if or
(printf "/etc/nginx/vhost.d/%s" $hostname | exists)
(printf "/etc/nginx/vhost.d/%s_location" $hostname | exists)
(printf "/etc/nginx/vhost.d/%s_location_override" $hostname | exists)
(printf "/etc/nginx/htpasswd/%s" $hostname | exists)
}}
# https://github.com/nginx-proxy/nginx-proxy/issues/2529#issuecomment-2437609249
# Support for vhost config file(s) named like a regexp ({{ $hostname }}) has been removed from nginx-proxy.
# Please name your vhost config file(s) with the sha1 of the regexp instead ({{ $hostname }} -> {{ sha1 $hostname }}) :
# - /etc/nginx/vhost.d/{{ sha1 $hostname }}
# - /etc/nginx/vhost.d/{{ sha1 $hostname }}_location
# - /etc/nginx/vhost.d/{{ sha1 $hostname }}_location_override
# - /etc/nginx/htpasswd/{{ sha1 $hostname }}
{{- end }}
{{- end }}
server_name {{ $hostname }};
{{- if $vhost.server_tokens }}
server_tokens {{ $vhost.server_tokens }};
@ -865,8 +885,10 @@ server {
{{- end }}
{{- end }}
{{- if (exists (printf "/etc/nginx/vhost.d/%s" $hostname)) }}
include {{ printf "/etc/nginx/vhost.d/%s" $hostname }};
{{- $vhostFileName := $vhost.is_regexp | ternary (sha1 $hostname) $hostname }}
{{- if (exists (printf "/etc/nginx/vhost.d/%s" $vhostFileName)) }}
include {{ printf "/etc/nginx/vhost.d/%s" $vhostFileName }};
{{- else if (exists "/etc/nginx/vhost.d/default") }}
include /etc/nginx/vhost.d/default;
{{- end }}
@ -874,7 +896,8 @@ server {
{{- range $path, $vpath := $vhost.paths }}
{{- template "location" (dict
"Path" $path
"Host" $hostname
"Host" $vhostFileName
"HostIsRegexp" $vhost.is_regexp
"VhostRoot" $vhost.vhost_root
"VPath" $vpath
) }}

View File

@ -5,7 +5,7 @@ services:
image: nginxproxy/nginx-proxy:test
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
- ./my_custom_proxy_settings.conf:/etc/nginx/vhost.d/default_location:ro
- ./my_custom_proxy_settings_f00.conf:/etc/nginx/vhost.d/default_location:ro
- ./my_custom_proxy_settings_bar.conf:/etc/nginx/vhost.d/web3.nginx-proxy.example_location:ro
web1:

View File

@ -5,7 +5,7 @@ services:
image: nginxproxy/nginx-proxy:test
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
- ./my_custom_proxy_settings.conf:/etc/nginx/proxy.conf:ro
- ./my_custom_proxy_settings_f00.conf:/etc/nginx/proxy.conf:ro
web1:
image: web

View File

@ -12,6 +12,13 @@ def test_custom_conf_applies_to_web1(docker_compose, nginxproxy):
assert "X-test" in r.headers
assert "f00" == r.headers["X-test"]
def test_custom_conf_applies_to_regex(docker_compose, nginxproxy):
r = nginxproxy.get("http://regex.foo.nginx-proxy.example/port")
assert r.status_code == 200
assert r.text == "answer from port 83\n"
assert "X-test" in r.headers
assert "bar" == r.headers["X-test"]
def test_custom_conf_does_not_apply_to_web2(docker_compose, nginxproxy):
r = nginxproxy.get("http://web2.nginx-proxy.example/port")
assert r.status_code == 200

View File

@ -5,7 +5,8 @@ services:
image: nginxproxy/nginx-proxy:test
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
- ./my_custom_proxy_settings.conf:/etc/nginx/vhost.d/web1.nginx-proxy.example_location:ro
- ./my_custom_proxy_settings_f00.conf:/etc/nginx/vhost.d/web1.nginx-proxy.example_location:ro
- ./my_custom_proxy_settings_bar.conf:/etc/nginx/vhost.d/561032515ede3ab3a015edfb244608b72409c430_location:ro
web1:
image: web
@ -22,3 +23,11 @@ services:
environment:
WEB_PORTS: 82
VIRTUAL_HOST: web2.nginx-proxy.example
regex:
image: web
expose:
- "83"
environment:
WEB_PORTS: 83
VIRTUAL_HOST: ~^regex.*\.nginx-proxy\.example$

View File

@ -12,6 +12,13 @@ def test_custom_conf_applies_to_web1(docker_compose, nginxproxy):
assert "X-test" in r.headers
assert "f00" == r.headers["X-test"]
def test_custom_conf_applies_to_regex(docker_compose, nginxproxy):
r = nginxproxy.get("http://regex.foo.nginx-proxy.example/port")
assert r.status_code == 200
assert r.text == "answer from port 83\n"
assert "X-test" in r.headers
assert "bar" == r.headers["X-test"]
def test_custom_conf_does_not_apply_to_web2(docker_compose, nginxproxy):
r = nginxproxy.get("http://web2.nginx-proxy.example/port")
assert r.status_code == 200

View File

@ -5,7 +5,8 @@ services:
image: nginxproxy/nginx-proxy:test
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
- ./my_custom_proxy_settings.conf:/etc/nginx/vhost.d/web1.nginx-proxy.example:ro
- ./my_custom_proxy_settings_f00.conf:/etc/nginx/vhost.d/web1.nginx-proxy.example:ro
- ./my_custom_proxy_settings_bar.conf:/etc/nginx/vhost.d/561032515ede3ab3a015edfb244608b72409c430:ro
web1:
image: web
@ -22,3 +23,11 @@ services:
environment:
WEB_PORTS: 82
VIRTUAL_HOST: web2.nginx-proxy.example
regex:
image: web
expose:
- "83"
environment:
WEB_PORTS: 83
VIRTUAL_HOST: ~^regex.*\.nginx-proxy\.example$

View File

@ -5,7 +5,7 @@ services:
image: nginxproxy/nginx-proxy:test
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
- ./my_custom_proxy_settings.conf:/etc/nginx/conf.d/my_custom_proxy_settings.conf:ro
- ./my_custom_proxy_settings_f00.conf:/etc/nginx/conf.d/my_custom_proxy_settings_f00.conf:ro
web1:
image: web

View File

@ -0,0 +1 @@
vhost:$2a$13$/aPYmoK0mmgyAI4TpKdFY.6441Ugo39MdXjhpm.Pp6D15rbz9tvz.

View File

@ -0,0 +1,13 @@
import pytest
def test_htpasswd_regex_virtual_host_is_restricted(docker_compose, nginxproxy):
r = nginxproxy.get("http://regex.htpasswd.nginx-proxy.example/port")
assert r.status_code == 401
assert "WWW-Authenticate" in r.headers
assert r.headers["WWW-Authenticate"] == 'Basic realm="Restricted access"'
def test_htpasswd_regex_virtual_host_basic_auth(docker_compose, nginxproxy):
r = nginxproxy.get("http://regex.htpasswd.nginx-proxy.example/port", auth=("vhost", "password"))
assert r.status_code == 200
assert r.text == "answer from port 80\n"

View File

@ -0,0 +1,17 @@
version: "2"
services:
regex:
image: web
expose:
- "80"
environment:
WEB_PORTS: 80
VIRTUAL_HOST: ~^regex.*\.nginx-proxy\.example$
sut:
container_name: sut
image: nginxproxy/nginx-proxy:test
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
- ./htpasswd:/etc/nginx/htpasswd:ro