Add vhost.d includes to nginx.tmpl's https redirect server block

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
This commit is contained in:
Dakota Hawkins 2021-05-05 17:09:25 -04:00 committed by Nicolas Duchon
parent df638c3fe6
commit 9bad218f23
No known key found for this signature in database
GPG key ID: EA3151C66A4D79E7
9 changed files with 219 additions and 2 deletions

View file

@ -265,7 +265,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;
@ -275,8 +280,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 }}
{{ if eq $external_https_port "443" }}
return 301 https://$host$request_uri;
{{ else }}

View file

@ -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"]

View file

@ -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

View file

@ -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"]

View file

@ -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

View file

@ -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()

View file

@ -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

View file

@ -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"]

View file

@ -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