Skip to content

Commit

Permalink
feat: Add ability to completely override location blocks
Browse files Browse the repository at this point in the history
Co-authored-by: Trent Harvey <trent@harvdog.net>
  • Loading branch information
rhansen and harvdogg committed Jan 31, 2023
1 parent 8ac8b02 commit 2115974
Show file tree
Hide file tree
Showing 13 changed files with 161 additions and 13 deletions.
26 changes: 26 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -491,6 +491,32 @@ ln -s /path/to/vhost.d/www.example.com /path/to/vhost.d/example.com

If you want most of your virtual hosts to use a default single `location` block configuration and then override on a few specific ones, add those settings to the `/etc/nginx/vhost.d/default_location` file. This file will be used on any virtual host which does not have a `/etc/nginx/vhost.d/{VIRTUAL_HOST}_location` file associated with it.

#### Overriding `location` blocks

The `${VIRTUAL_HOST}_${PATH_HASH}_location`, `${VIRTUAL_HOST}_location`, and `default_location` files documented above make it possible to *augment* the generated [`location` block(s)](https://nginx.org/en/docs/http/ngx_http_core_module.html#location) in a virtual host. In some circumstances, you may need to *completely override* the `location` block for a particular combination of virtual host and path. To do this, create a file whose name follows this pattern:

```
/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).

For convenience, the `_${PATH_HASH}` part can be omitted if the path is `/`:

```
/etc/nginx/vhost.d/${VIRTUAL_HOST}_location_override
```

When an override file exists, the `location` block that is normally created by `nginx-proxy` is not generated. Instead, the override file is included via the [nginx `include` directive](https://nginx.org/en/docs/ngx_core_module.html#include).

You are responsible for providing a suitable `location` block in your override file as required for your service. By default, `nginx-proxy` uses the `VIRTUAL_HOST` name as the upstream name for your application's Docker container; see [here](#unhashed-vs-sha1-upstream-names) for details. As an example, if your container has a `VIRTUAL_HOST` value of `app.example.com`, then to override the location block for `/` you would create a file named `/etc/nginx/vhost.d/app.example.com_location_override` that contains something like this:

```
location / {
proxy_pass http://app.example.com;
}
```

#### Per-VIRTUAL_HOST `server_tokens` configuration
Per virtual-host `servers_tokens` directive can be configured by passing appropriate value to the `SERVER_TOKENS` environment variable. Please see the [nginx http_core module configuration](https://nginx.org/en/docs/http/ngx_http_core_module.html#server_tokens) for more details.

Expand Down
34 changes: 21 additions & 13 deletions nginx.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -76,38 +76,46 @@
{{- end }}

{{- define "location" }}
{{- $override := printf "/etc/nginx/vhost.d/%s_%s_location_override" .Host (sha1 .Path) }}
{{- if and (eq .Path "/") (not (exists $override)) }}
{{- $override = printf "/etc/nginx/vhost.d/%s_location_override" .Host }}
{{- end }}
{{- if exists $override }}
include {{ $override }};
{{- else }}
location {{ .Path }} {
{{- if eq .NetworkTag "internal" }}
{{- if eq .NetworkTag "internal" }}
# Only allow traffic from internal clients
include /etc/nginx/network_internal.conf;
{{- end }}
{{- end }}

{{- if eq .Proto "uwsgi" }}
{{- if eq .Proto "uwsgi" }}
include uwsgi_params;
uwsgi_pass {{ trim .Proto }}://{{ trim .Upstream }};
{{- else if eq .Proto "fastcgi" }}
{{- else if eq .Proto "fastcgi" }}
root {{ trim .VhostRoot }};
include fastcgi_params;
fastcgi_pass {{ trim .Upstream }};
{{- else if eq .Proto "grpc" }}
{{- else if eq .Proto "grpc" }}
grpc_pass {{ trim .Proto }}://{{ trim .Upstream }};
{{- else }}
{{- else }}
proxy_pass {{ trim .Proto }}://{{ trim .Upstream }}{{ trim .Dest }};
{{- end }}
{{- end }}

{{- if (exists (printf "/etc/nginx/htpasswd/%s" .Host)) }}
{{- if (exists (printf "/etc/nginx/htpasswd/%s" .Host)) }}
auth_basic "Restricted {{ .Host }}";
auth_basic_user_file {{ (printf "/etc/nginx/htpasswd/%s" .Host) }};
{{- end }}
{{- end }}

{{- if (exists (printf "/etc/nginx/vhost.d/%s_%s_location" .Host (sha1 .Path) )) }}
{{- if (exists (printf "/etc/nginx/vhost.d/%s_%s_location" .Host (sha1 .Path) )) }}
include {{ printf "/etc/nginx/vhost.d/%s_%s_location" .Host (sha1 .Path) }};
{{- else if (exists (printf "/etc/nginx/vhost.d/%s_location" .Host)) }}
{{- else if (exists (printf "/etc/nginx/vhost.d/%s_location" .Host)) }}
include {{ printf "/etc/nginx/vhost.d/%s_location" .Host}};
{{- else if (exists "/etc/nginx/vhost.d/default_location") }}
{{- else if (exists "/etc/nginx/vhost.d/default_location") }}
include /etc/nginx/vhost.d/default_location;
{{- end }}
{{- end }}
}
{{- end }}
{{- end }}

{{- define "upstream" }}
Expand Down
39 changes: 39 additions & 0 deletions test/test_location-override.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
def test_explicit_root_nohash(docker_compose, nginxproxy):
r = nginxproxy.get("http://explicit-root-nohash.nginx-proxy.test/port")
assert r.status_code == 418
r = nginxproxy.get("http://explicit-root-nohash.nginx-proxy.test/foo/port")
assert r.status_code == 200
assert r.text == "answer from port 82\n"

def test_explicit_root_hash(docker_compose, nginxproxy):
r = nginxproxy.get("http://explicit-root-hash.nginx-proxy.test/port")
assert r.status_code == 418
r = nginxproxy.get("http://explicit-root-hash.nginx-proxy.test/foo/port")
assert r.status_code == 200
assert r.text == "answer from port 82\n"

def test_explicit_root_hash_and_nohash(docker_compose, nginxproxy):
r = nginxproxy.get("http://explicit-root-hash-and-nohash.nginx-proxy.test/port")
assert r.status_code == 418
r = nginxproxy.get("http://explicit-root-hash-and-nohash.nginx-proxy.test/foo/port")
assert r.status_code == 200
assert r.text == "answer from port 82\n"

def test_explicit_nonroot(docker_compose, nginxproxy):
r = nginxproxy.get("http://explicit-nonroot.nginx-proxy.test/port")
assert r.status_code == 200
assert r.text == "answer from port 81\n"
r = nginxproxy.get("http://explicit-nonroot.nginx-proxy.test/foo/port")
assert r.status_code == 418

def test_implicit_root_nohash(docker_compose, nginxproxy):
r = nginxproxy.get("http://implicit-root-nohash.nginx-proxy.test/port")
assert r.status_code == 418

def test_implicit_root_hash(docker_compose, nginxproxy):
r = nginxproxy.get("http://implicit-root-hash.nginx-proxy.test/port")
assert r.status_code == 418

def test_implicit_root_hash_and_nohash(docker_compose, nginxproxy):
r = nginxproxy.get("http://implicit-root-hash-and-nohash.nginx-proxy.test/port")
assert r.status_code == 418
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
location /foo/ {
return 418;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# This file should trump the file without the hash.
location / {
return 418;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# The file with the hash should trump this file.
location / {
return 503;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
location / {
return 418;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
location / {
return 418;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# This file should trump the file without the hash.
location / {
return 418;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# The file with the hash should trump this file.
location / {
return 503;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
location / {
return 418;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
location / {
return 418;
}
44 changes: 44 additions & 0 deletions test/test_location-override.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
services:
sut:
image: nginxproxy/nginx-proxy:test
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
- ./test_location-override.vhost.d:/etc/nginx/vhost.d:ro

explicit-root:
image: web
expose:
- "81"
environment:
WEB_PORTS: "81"
VIRTUAL_HOST: >-
explicit-root-nohash.nginx-proxy.test,
explicit-root-hash.nginx-proxy.test,
explicit-root-hash-and-nohash.nginx-proxy.test,
explicit-nonroot.nginx-proxy.test
VIRTUAL_PATH: /
explicit-foo:
image: web
expose:
- "82"
environment:
WEB_PORTS: "82"
VIRTUAL_HOST: >-
explicit-root-nohash.nginx-proxy.test,
explicit-root-hash.nginx-proxy.test,
explicit-root-hash-and-nohash.nginx-proxy.test,
explicit-nonroot.nginx-proxy.test
VIRTUAL_PATH: /foo/
VIRTUAL_DEST: /

# Same as explicit-root except VIRTUAL_PATH is left unset.
implicit-root:
image: web
expose:
- "83"
environment:
WEB_PORTS: "83"
VIRTUAL_HOST: >-
implicit-root-nohash.nginx-proxy.test,
implicit-root-hash.nginx-proxy.test,
implicit-root-hash-and-nohash.nginx-proxy.test,

0 comments on commit 2115974

Please sign in to comment.