Skip to content

Commit

Permalink
Add vhost.d includes to nginx.tmpl's https redirect server block
Browse files Browse the repository at this point in the history
Adds customization points to https redirect responses that are analogous
to other response handling. This gives you the opportunity to add
response headers or etc. before returning the 301 redirect.

If `$host` or `default` exist in `/etc/nginx/vhost.d/`, we rely on
nginx-proxy/acme-companion to add the Let's Encrypt acme challenge
location block there, so it's only included here if those files don't
exist.

New tests in `test_ssl` are similar to tests in `test_custom`, except they
expect 301 responses along with custom configs.

Fixes #1613
  • Loading branch information
dakotahawkins committed May 7, 2021
1 parent e3e8d24 commit 8a9a267
Show file tree
Hide file tree
Showing 9 changed files with 219 additions and 2 deletions.
16 changes: 14 additions & 2 deletions nginx.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,12 @@ server {
listen [::]:{{ $external_http_port }} {{ $default_server }};
{{ end }}
{{ $access_log }}


{{ if (exists (printf "/etc/nginx/vhost.d/%s" $host)) }}
include {{ printf "/etc/nginx/vhost.d/%s" $host }};
{{ else if (exists "/etc/nginx/vhost.d/default") }}
include /etc/nginx/vhost.d/default;
{{ else }}
# Do not HTTPS redirect Let'sEncrypt ACME challenge
location ^~ /.well-known/acme-challenge/ {
auth_basic off;
Expand All @@ -261,8 +266,15 @@ server {
try_files $uri =404;
break;
}

{{ end }}

location / {
{{ 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") }}
include /etc/nginx/vhost.d/default_location;
{{ end }}

return 301 https://$host$request_uri;
}
}
Expand Down
27 changes: 27 additions & 0 deletions test/test_ssl/test_redirect_custom_defaults-location.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import pytest

def test_custom_default_conf_does_not_apply_to_unknown_vhost(docker_compose, nginxproxy):
r = nginxproxy.get("http://nginx-proxy/", allow_redirects=False)
assert r.status_code == 503
assert "X-test" not in r.headers

def test_custom_default_conf_applies_to_web2(docker_compose, nginxproxy):
url = "web2.nginx-proxy.tld/port"
r = nginxproxy.get(f"http://{url}", allow_redirects=False)
assert r.status_code == 301
assert "301 Moved Permanently" in r.text
assert "X-test" in r.headers
assert "f00" == r.headers["X-test"]
assert "Location" in r.headers
assert f"https://{url}" == r.headers["Location"]


def test_custom_default_conf_is_overriden_for_web3(docker_compose, nginxproxy):
url = "web3.nginx-proxy.tld/port"
r = nginxproxy.get(f"http://{url}", allow_redirects=False)
assert r.status_code == 301
assert "301 Moved Permanently" in r.text
assert "X-test" in r.headers
assert "bar" == r.headers["X-test"]
assert "Location" in r.headers
assert f"https://{url}" == r.headers["Location"]
24 changes: 24 additions & 0 deletions test/test_ssl/test_redirect_custom_defaults-location.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
nginx-proxy:
image: nginxproxy/nginx-proxy:test
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
- ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro
- ./certs:/etc/nginx/certs:ro
- ../test_custom/my_custom_proxy_settings.conf:/etc/nginx/vhost.d/default_location:ro
- ../test_custom/my_custom_proxy_settings_bar.conf:/etc/nginx/vhost.d/web3.nginx-proxy.tld_location:ro

web2:
image: web
expose:
- "82"
environment:
WEB_PORTS: 82
VIRTUAL_HOST: web2.nginx-proxy.tld

web3:
image: web
expose:
- "83"
environment:
WEB_PORTS: 83
VIRTUAL_HOST: web3.nginx-proxy.tld
26 changes: 26 additions & 0 deletions test/test_ssl/test_redirect_custom_defaults.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import pytest

def test_custom_conf_does_not_apply_to_unknown_vhost(docker_compose, nginxproxy):
r = nginxproxy.get("http://nginx-proxy/", allow_redirects=False)
assert r.status_code == 503
assert "X-test" not in r.headers

def test_custom_conf_applies_to_web2(docker_compose, nginxproxy):
url = "web2.nginx-proxy.tld/port"
r = nginxproxy.get(f"http://{url}", allow_redirects=False)
assert r.status_code == 301
assert "301 Moved Permanently" in r.text
assert "X-test" in r.headers
assert "f00" == r.headers["X-test"]
assert "Location" in r.headers
assert f"https://{url}" == r.headers["Location"]

def test_custom_conf_applies_to_web3(docker_compose, nginxproxy):
url = "web3.nginx-proxy.tld/port"
r = nginxproxy.get(f"http://{url}", allow_redirects=False)
assert r.status_code == 301
assert "301 Moved Permanently" in r.text
assert "X-test" in r.headers
assert "f00" == r.headers["X-test"]
assert "Location" in r.headers
assert f"https://{url}" == r.headers["Location"]
25 changes: 25 additions & 0 deletions test/test_ssl/test_redirect_custom_defaults.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
version: '2'
services:
nginx-proxy:
image: nginxproxy/nginx-proxy:test
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
- ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro
- ./certs:/etc/nginx/certs:ro
- ../test_custom/my_custom_proxy_settings.conf:/etc/nginx/proxy.conf:ro

web2:
image: web
expose:
- "82"
environment:
WEB_PORTS: 82
VIRTUAL_HOST: web2.nginx-proxy.tld

web3:
image: web
expose:
- "83"
environment:
WEB_PORTS: 83
VIRTUAL_HOST: web3.nginx-proxy.tld
28 changes: 28 additions & 0 deletions test/test_ssl/test_redirect_custom_location-per-vhost.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import pytest

def test_custom_conf_does_not_apply_to_unknown_vhost(docker_compose, nginxproxy):
r = nginxproxy.get("http://nginx-proxy/", allow_redirects=False)
assert r.status_code == 503
assert "X-test" not in r.headers

def test_custom_conf_applies_to_web2(docker_compose, nginxproxy):
url = "web2.nginx-proxy.tld/port"
r = nginxproxy.get(f"http://{url}", allow_redirects=False)
assert r.status_code == 301
assert "301 Moved Permanently" in r.text
assert "X-test" in r.headers
assert "f00" == r.headers["X-test"]
assert "Location" in r.headers
assert f"https://{url}" == r.headers["Location"]

def test_custom_conf_does_not_apply_to_web3(docker_compose, nginxproxy):
url = "web3.nginx-proxy.tld/port"
r = nginxproxy.get(f"http://{url}", allow_redirects=False)
assert r.status_code == 301
assert "301 Moved Permanently" in r.text
assert "X-test" not in r.headers
assert "Location" in r.headers
assert f"https://{url}" == r.headers["Location"]

def test_custom_block_is_present_in_nginx_generated_conf(docker_compose, nginxproxy):
assert b"include /etc/nginx/vhost.d/web2.nginx-proxy.tld_location;" in nginxproxy.get_conf()
25 changes: 25 additions & 0 deletions test/test_ssl/test_redirect_custom_location-per-vhost.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
version: '2'
services:
nginx-proxy:
image: nginxproxy/nginx-proxy:test
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
- ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro
- ./certs:/etc/nginx/certs:ro
- ../test_custom/my_custom_proxy_settings.conf:/etc/nginx/vhost.d/web2.nginx-proxy.tld_location:ro

web2:
image: web
expose:
- "82"
environment:
WEB_PORTS: 82
VIRTUAL_HOST: web2.nginx-proxy.tld

web3:
image: web
expose:
- "83"
environment:
WEB_PORTS: 83
VIRTUAL_HOST: web3.nginx-proxy.tld
25 changes: 25 additions & 0 deletions test/test_ssl/test_redirect_custom_per-vhost.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import pytest

def test_custom_conf_does_not_apply_to_unknown_vhost(docker_compose, nginxproxy):
r = nginxproxy.get("http://nginx-proxy/", allow_redirects=False)
assert r.status_code == 503
assert "X-test" not in r.headers

def test_custom_conf_applies_to_web2(docker_compose, nginxproxy):
url = "web2.nginx-proxy.tld/port"
r = nginxproxy.get(f"http://{url}", allow_redirects=False)
assert r.status_code == 301
assert "301 Moved Permanently" in r.text
assert "X-test" in r.headers
assert "f00" == r.headers["X-test"]
assert "Location" in r.headers
assert f"https://{url}" == r.headers["Location"]

def test_custom_conf_does_not_apply_to_web3(docker_compose, nginxproxy):
url = "web3.nginx-proxy.tld/port"
r = nginxproxy.get(f"http://{url}", allow_redirects=False)
assert r.status_code == 301
assert "301 Moved Permanently" in r.text
assert "X-test" not in r.headers
assert "Location" in r.headers
assert f"https://{url}" == r.headers["Location"]
25 changes: 25 additions & 0 deletions test/test_ssl/test_redirect_custom_per-vhost.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
version: '2'
services:
nginx-proxy:
image: nginxproxy/nginx-proxy:test
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
- ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro
- ./certs:/etc/nginx/certs:ro
- ../test_custom/my_custom_proxy_settings.conf:/etc/nginx/vhost.d/web2.nginx-proxy.tld:ro

web2:
image: web
expose:
- "82"
environment:
WEB_PORTS: 82
VIRTUAL_HOST: web2.nginx-proxy.tld

web3:
image: web
expose:
- "83"
environment:
WEB_PORTS: 83
VIRTUAL_HOST: web3.nginx-proxy.tld

0 comments on commit 8a9a267

Please sign in to comment.