Add options to listen on custom port

This commit is contained in:
Nicky Gerritsen 2016-10-14 17:31:13 +02:00 committed by Nicky Gerritsen
parent 0670a13d92
commit 31259e5e87
6 changed files with 267 additions and 19 deletions

View file

@ -56,9 +56,17 @@ proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
proxy_set_header Proxy "";
{{ end }}
{{ $http_ports := (groupByKeys $ "Env.VIRTUAL_LISTEN_PORT_HTTP") }}
{{ $https_ports := (groupByKeys $ "Env.VIRTUAL_LISTEN_PORT_HTTPS") }}
server {
server_name _; # This is just an invalid value which will never trigger on a real hostname.
listen 80;
{{ range $port := $http_ports }}
{{ if ne $port "80" }}
listen {{ $port }};
{{ end }}
{{ end }}
access_log /var/log/nginx/access.log vhost;
return 503;
}
@ -67,6 +75,11 @@ server {
server {
server_name _; # This is just an invalid value which will never trigger on a real hostname.
listen 443 ssl http2;
{{ range $port := $https_ports }}
{{ if ne $port "443" }}
listen {{ $port }} ssl http2;
{{ end }}
{{ end }}
access_log /var/log/nginx/access.log vhost;
return 503;
@ -104,11 +117,17 @@ upstream {{ $host }} {
}
{{ $default_host := or ($.Env.DEFAULT_HOST) "" }}
{{ $default_server := index (dict $host "" $default_host "default_server") $host }}
{{ $default_server := index (dict $host 0 $default_host 1) $host }}
{{/* Get the VIRTUAL_PROTO defined by containers w/ the same vhost, falling back to "http" */}}
{{ $proto := or (first (groupByKeys $containers "Env.VIRTUAL_PROTO")) "http" }}
{{/* Get the port to listen on for HTTP connections, falling back to 80 */}}
{{ $http_port := or (first (groupByKeys $containers "Env.VIRTUAL_LISTEN_PORT_HTTP")) "80" }}
{{/* Get the port to listen on for HTTPS connections, falling back to 443 */}}
{{ $https_port := or (first (groupByKeys $containers "Env.VIRTUAL_LISTEN_PORT_HTTPS")) "443" }}
{{/* Get the HTTPS_METHOD defined by containers w/ the same vhost, falling back to "redirect" */}}
{{ $https_method := or (first (groupByKeys $containers "Env.HTTPS_METHOD")) "redirect" }}
@ -132,7 +151,16 @@ upstream {{ $host }} {
{{ if eq $https_method "redirect" }}
server {
server_name {{ $host }};
listen 80 {{ $default_server }};
{{ if eq $default_server 1 }}
listen 80 default_server;
{{ range $port := $http_ports }}
{{ if ne $port "80" }}
listen {{ $port }} default_server;
{{ end }}
{{ end }}
{{ else }}
listen {{ $http_port }};
{{ end }}
access_log /var/log/nginx/access.log vhost;
return 301 https://$host$request_uri;
}
@ -140,7 +168,16 @@ server {
server {
server_name {{ $host }};
listen 443 ssl http2 {{ $default_server }};
{{ if eq $default_server 1 }}
listen 443 ssl http2 default_server;
{{ range $port := $http_ports }}
{{ if ne $port "443" }}
listen {{ $port }} ssl http2 default_server;
{{ end }}
{{ end }}
{{ else }}
listen {{ $https_port }} ssl http2;
{{ end }}
access_log /var/log/nginx/access.log vhost;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
@ -193,7 +230,16 @@ server {
server {
server_name {{ $host }};
listen 80 {{ $default_server }};
{{ if eq $default_server 1 }}
listen 80 default_server;
{{ range $port := $http_ports }}
{{ if ne $port "80" }}
listen {{ $port }} default_server;
{{ end }}
{{ end }}
{{ else }}
listen {{ $http_port }};
{{ end }}
access_log /var/log/nginx/access.log vhost;
{{ if (exists (printf "/etc/nginx/vhost.d/%s" $host)) }}
@ -224,7 +270,16 @@ server {
{{ if (and (not $is_https) (exists "/etc/nginx/certs/default.crt") (exists "/etc/nginx/certs/default.key")) }}
server {
server_name {{ $host }};
listen 443 ssl http2 {{ $default_server }};
{{ if eq $default_server 1 }}
listen 443 ssl http2 default_server;
{{ range $port := $https_ports }}
{{ if ne $port "443" }}
listen {{ $port }} ssl http2 default_server;
{{ end }}
{{ end }}
{{ else }}
listen {{ $https_port }} ssl http2;
{{ end }}
access_log /var/log/nginx/access.log vhost;
return 500;

View file

@ -11,8 +11,8 @@ function setup {
@test "[$TEST_FILE] DEFAULT_HOST=web1.bats" {
SUT_CONTAINER=bats-nginx-proxy-${TEST_FILE}-1
# GIVEN a webserver with VIRTUAL_HOST set to web.bats
prepare_web_container bats-web 80 -e VIRTUAL_HOST=web.bats
# GIVEN a webserver with VIRTUAL_HOST set to web.bats and VIRTUAL_LISTEN_PORT_HTTP set to 81
prepare_web_container bats-web 80 -e VIRTUAL_HOST=web.bats -e VIRTUAL_LISTEN_PORT_HTTP=81
# WHEN nginx-proxy runs with DEFAULT_HOST set to web.bats
run nginxproxy $SUT_CONTAINER -v /var/run/docker.sock:/tmp/docker.sock:ro -e DEFAULT_HOST=web.bats
@ -26,6 +26,14 @@ function setup {
# THEN querying the proxy with any other Host header → 200
run curl_container $SUT_CONTAINER / --head --header "Host: something.I.just.made.up"
assert_output -l 0 $'HTTP/1.1 200 OK\r'
# THEN querying the proxy without Host header on port 81 → 200
run curl_container_port $SUT_CONTAINER / 81 --head
assert_output -l 0 $'HTTP/1.1 200 OK\r'
# THEN querying the proxy with any other Host header on port 81 → 200
run curl_container_port $SUT_CONTAINER / 81 --head --header "Host: something.I.just.made.up"
assert_output -l 0 $'HTTP/1.1 200 OK\r'
}
@test "[$TEST_FILE] stop all bats containers" {

View file

@ -38,6 +38,45 @@ function setup {
assert_output "answer from port 80"
}
@test "[$TEST_FILE] nginx-proxy forwards requests for 2 hosts on another port" {
# WHEN a container runs a web server with VIRTUAL_HOST set for multiple hosts and a VIRTUAL_LISTEN_PORT_HTTP
prepare_web_container bats-multiple-hosts-1 80 -e VIRTUAL_HOST=multiple-hosts-1-A.bats,multiple-hosts-1-B.bats -e VIRTUAL_LISTEN_PORT_HTTP=81
dockergen_wait_for_event $SUT_CONTAINER start bats-multiple-hosts-1
sleep 1
# THEN querying the proxy without Host header → 503
run curl_container $SUT_CONTAINER / --head
assert_output -l 0 $'HTTP/1.1 503 Service Temporarily Unavailable\r'
# THEN querying the proxy without Host header on port 81 → 503
run curl_container_port $SUT_CONTAINER / 81 --head
assert_output -l 0 $'HTTP/1.1 503 Service Temporarily Unavailable\r'
# THEN querying the proxy with unknown Host header → 503
run curl_container $SUT_CONTAINER /data --header "Host: webFOO.bats" --head
assert_output -l 0 $'HTTP/1.1 503 Service Temporarily Unavailable\r'
# THEN querying the proxy with unknown Host header on port 81 → 503
run curl_container_port $SUT_CONTAINER /data 81 --header "Host: webFOO.bats" --head
assert_output -l 0 $'HTTP/1.1 503 Service Temporarily Unavailable\r'
# THEN querying the proxy with known Host header on wrong port → 503
run curl_container $SUT_CONTAINER /data --header 'Host: multiple-hosts-1-A.bats' --head
assert_output -l 0 $'HTTP/1.1 503 Service Temporarily Unavailable\r'
# THEN querying the proxy with known Host header on wrong port → 503
run curl_container $SUT_CONTAINER /data --header 'Host: multiple-hosts-1-B.bats' --head
assert_output -l 0 $'HTTP/1.1 503 Service Temporarily Unavailable\r'
# THEN
run curl_container_port $SUT_CONTAINER /data 81 --header 'Host: multiple-hosts-1-A.bats'
assert_output "answer from port 80" # 80 because we forward 81 to 80
# THEN
run curl_container_port $SUT_CONTAINER /data 81 --header 'Host: multiple-hosts-1-B.bats'
assert_output "answer from port 80" # 80 because we forward 81 to 80
}
@test "[$TEST_FILE] stop all bats containers" {
stop_bats_containers
}

View file

@ -27,6 +27,16 @@ function setup {
assert_response_is_from_port 80
}
@test "[$TEST_FILE] nginx-proxy defaults to the service running on port 80 when listening on another port" {
# WHEN
prepare_web_container bats-web-${TEST_FILE}-1 "80 90" -e VIRTUAL_HOST=web.bats -e VIRTUAL_LISTEN_PORT_HTTP=90
dockergen_wait_for_event $SUT_CONTAINER start bats-web-${TEST_FILE}-1
sleep 1
# THEN
assert_response_is_from_port 80 90
}
@test "[$TEST_FILE] VIRTUAL_PORT=90 while port 80 is also exposed" {
# GIVEN
@ -38,6 +48,15 @@ function setup {
assert_response_is_from_port 90
}
@test "[$TEST_FILE] VIRTUAL_PORT=90 while port 80 is also exposed when listening on another port" {
# GIVEN
prepare_web_container bats-web-${TEST_FILE}-2 "80 90" -e VIRTUAL_HOST=web.bats -e VIRTUAL_PORT=90 -e VIRTUAL_LISTEN_PORT_HTTP=90
dockergen_wait_for_event $SUT_CONTAINER start bats-web-${TEST_FILE}-2
sleep 1
# THEN
assert_response_is_from_port 90 90
}
@test "[$TEST_FILE] single exposed port != 80" {
# GIVEN
@ -49,6 +68,16 @@ function setup {
assert_response_is_from_port 1234
}
@test "[$TEST_FILE] single exposed port != 80 when listening on another port" {
# GIVEN
prepare_web_container bats-web-${TEST_FILE}-3 1234 -e VIRTUAL_HOST=web.bats -e VIRTUAL_LISTEN_PORT_HTTP=1234
dockergen_wait_for_event $SUT_CONTAINER start bats-web-${TEST_FILE}-3
sleep 1
# THEN
assert_response_is_from_port 1234 1234
}
@test "[$TEST_FILE] stop all bats containers" {
stop_bats_containers
}
@ -58,7 +87,12 @@ function setup {
# $1 port we are expecting an response from
function assert_response_is_from_port {
local -r port=$1
run curl_container $SUT_CONTAINER /data --header "Host: web.bats"
local -r curl_port=$2
if [ -z "${curl_port}" ]; then
run curl_container $SUT_CONTAINER /data --header "Host: web.bats"
else
run curl_container_port $SUT_CONTAINER /data ${curl_port} --header "Host: web.bats"
fi
assert_output "answer from port $port"
}

View file

@ -28,6 +28,22 @@ function setup {
assert_200_https test.nginx-proxy.bats
}
@test "[$TEST_FILE] test SSL for VIRTUAL_HOST=*.nginx-proxy.bats with different ports" {
# WHEN
prepare_web_container bats-ssl-hosts-1-ports "80 443" \
-e VIRTUAL_HOST=*.nginx-proxy.bats \
-e VIRTUAL_LISTEN_PORT_HTTP=81 \
-e VIRTUAL_LISTEN_PORT_HTTPS=444 \
-e CERT_NAME=nginx-proxy.bats
dockergen_wait_for_event $SUT_CONTAINER start bats-ssl-hosts-1-ports
sleep 1
# THEN
assert_503 test.nginx-proxy.bats
assert_301 test.nginx-proxy.bats 81
assert_200_https test.nginx-proxy.bats 444
}
@test "[$TEST_FILE] test HTTPS_METHOD=nohttp" {
# WHEN
prepare_web_container bats-ssl-hosts-2 "80 443" \
@ -42,6 +58,23 @@ function setup {
assert_200_https test.nginx-proxy.bats
}
@test "[$TEST_FILE] test HTTPS_METHOD=nohttp with different ports" {
# WHEN
prepare_web_container bats-ssl-hosts-2-ports "80 443" \
-e VIRTUAL_HOST=*.nginx-proxy.bats \
-e CERT_NAME=nginx-proxy.bats \
-e VIRTUAL_LISTEN_PORT_HTTP=82 \
-e VIRTUAL_LISTEN_PORT_HTTPS=445 \
-e HTTPS_METHOD=nohttp
dockergen_wait_for_event $SUT_CONTAINER start bats-ssl-hosts-2-ports
sleep 1
# THEN
assert_503 test.nginx-proxy.bats
assert_503 test.nginx-proxy.bats 82
assert_200_https test.nginx-proxy.bats 445
}
@test "[$TEST_FILE] test HTTPS_METHOD=noredirect" {
# WHEN
prepare_web_container bats-ssl-hosts-3 "80 443" \
@ -56,12 +89,29 @@ function setup {
assert_200_https test.nginx-proxy.bats
}
@test "[$TEST_FILE] test HTTPS_METHOD=noredirect with different ports" {
# WHEN
prepare_web_container bats-ssl-hosts-3-ports "80 443" \
-e VIRTUAL_HOST=*.nginx-proxy.bats \
-e CERT_NAME=nginx-proxy.bats \
-e VIRTUAL_LISTEN_PORT_HTTP=81 \
-e VIRTUAL_LISTEN_PORT_HTTPS=444 \
-e HTTPS_METHOD=noredirect
dockergen_wait_for_event $SUT_CONTAINER start bats-ssl-hosts-3-ports
sleep 1
# THEN
assert_503 test.nginx-proxy.bats
assert_200 test.nginx-proxy.bats 81
assert_200_https test.nginx-proxy.bats 444
}
@test "[$TEST_FILE] test SSL Strict-Transport-Security" {
# WHEN
prepare_web_container bats-ssl-hosts-4 "80 443" \
-e VIRTUAL_HOST=*.nginx-proxy.bats \
-e CERT_NAME=nginx-proxy.bats
dockergen_wait_for_event $SUT_CONTAINER start bats-ssl-hosts-1
dockergen_wait_for_event $SUT_CONTAINER start bats-ssl-hosts-4
sleep 1
# THEN
@ -93,37 +143,61 @@ function setup {
# assert that querying nginx-proxy with the given Host header produces a `HTTP 200` response
# $1 Host HTTP header to use when querying nginx-proxy
# $2 (optional) HTTP port to use
function assert_200 {
local -r host=$1
local -r port=$2
run curl_container $SUT_CONTAINER / --head --header "Host: $host"
if [ -z "$port" ]; then
run curl_container $SUT_CONTAINER / --head --header "Host: $host"
else
run curl_container_port $SUT_CONTAINER / ${port} --head --header "Host: $host"
fi
assert_output -l 0 $'HTTP/1.1 200 OK\r'
}
# assert that querying nginx-proxy with the given Host header produces a `HTTP 503` response
# $1 Host HTTP header to use when querying nginx-proxy
# $2 (optional) HTTP port to use
function assert_503 {
local -r host=$1
local -r port=$2
run curl_container $SUT_CONTAINER / --head --header "Host: $host"
if [ -z "$port" ]; then
run curl_container $SUT_CONTAINER / --head --header "Host: $host"
else
run curl_container $SUT_CONTAINER / ${port} --head --header "Host: $host"
fi
assert_output -l 0 $'HTTP/1.1 503 Service Temporarily Unavailable\r'
}
# assert that querying nginx-proxy with the given Host header produces a `HTTP 503` response
# assert that querying nginx-proxy with the given Host header produces a `HTTP 301` response
# $1 Host HTTP header to use when querying nginx-proxy
# $2 (optional) HTTP port to use
function assert_301 {
local -r host=$1
local -r port=$2
run curl_container $SUT_CONTAINER / --head --header "Host: $host"
if [ -z "$port" ]; then
run curl_container $SUT_CONTAINER / --head --header "Host: $host"
else
run curl_container_port $SUT_CONTAINER / ${port} --head --header "Host: $host"
fi
assert_output -l 0 $'HTTP/1.1 301 Moved Permanently\r'
}
# assert that querying nginx-proxy with the given Host header produces a `HTTP 200` response
# $1 Host HTTP header to use when querying nginx-proxy
# $2 (optional) HTTPS port to use
function assert_200_https {
local -r host=$1
local -r port=$2
run curl_container_https $SUT_CONTAINER / --head --header "Host: $host"
if [ -z "$port" ]; then
run curl_container_https $SUT_CONTAINER / --head --header "Host: $host"
else
run curl_container_https_port $SUT_CONTAINER / ${port} --head --header "Host: $host"
fi
assert_output -l 0 $'HTTP/1.1 200 OK\r'
}

View file

@ -22,7 +22,7 @@ load ${DIR}/lib/docker_helpers.bash
# Define functions specific to our test suite
# run the SUT docker container
# run the SUT docker container
# and makes sure it remains started
# and displays the nginx-proxy start logs
#
@ -57,7 +57,7 @@ function wait_for_nginxproxy_container_to_start {
}
# Send a HTTP request to container $1 for path $2 and
# Send a HTTP request to container $1 for path $2 and
# Additional curl options can be passed as $@
#
# $1 container name
@ -74,7 +74,26 @@ function curl_container {
http://$(docker_ip $container)${path}
}
# Send a HTTPS request to container $1 for path $2 and
# Send a HTTP request to container $1 for path $2 and port $3
# Additional curl options can be passed as $@
#
# $1 container name
# $2 HTTP path to query
# $3 HTTP port
# $@ additional options to pass to the curl command
function curl_container_port {
local -r container=$1
local -r path=$2
local -r port=$3
shift 3
docker run --label bats-type="curl" appropriate/curl --silent \
--connect-timeout 5 \
--max-time 20 \
"$@" \
http://$(docker_ip $container):${port}${path}
}
# Send a HTTPS request to container $1 for path $2 and
# Additional curl options can be passed as $@
#
# $1 container name
@ -92,6 +111,26 @@ function curl_container_https {
https://$(docker_ip $container)${path}
}
# Send a HTTPS request to container $1 for path $2 and
# Additional curl options can be passed as $@
#
# $1 container name
# $2 HTTPS path to query
# $3 HTTP port
# $@ additional options to pass to the curl command
function curl_container_https_port {
local -r container=$1
local -r path=$2
local -r port=$3
shift 3
docker run --label bats-type="curl" appropriate/curl --silent \
--connect-timeout 5 \
--max-time 20 \
--insecure \
"$@" \
https://$(docker_ip $container):${port}${path}
}
# start a container running (one or multiple) webservers listening on given ports
#
# $1 container name
@ -181,4 +220,3 @@ function dockergen_wait_for_event {
local -r did=$(docker_id "$other")
docker_wait_for_log "$container" 9 "Received event $event for container ${did:0:12}"
}