فهرست منبع

Merge pull request #298 from kamermans/master

Added env var to disable SSL redirect
Jason Wilder 9 سال پیش
والد
کامیت
5b9264d945
6فایلهای تغییر یافته به همراه204 افزوده شده و 4 حذف شده
  1. 5 1
      README.md
  2. 13 3
      nginx.tmpl
  3. 24 0
      test/lib/ssl/nginx-proxy.bats.crt
  4. 28 0
      test/lib/ssl/nginx-proxy.bats.key
  5. 117 0
      test/ssl.bats
  6. 17 0
      test/test_helpers.bash

+ 5 - 1
README.md

@@ -130,7 +130,7 @@ should provide compatibility with clients back to Firefox 1, Chrome 1, IE 7, Ope
 Windows XP IE8, Android 2.3, Java 7.  The configuration also enables HSTS, and SSL
 Windows XP IE8, Android 2.3, Java 7.  The configuration also enables HSTS, and SSL
 session caches.
 session caches.
 
 
-The behavior for the proxy when port 80 and 443 are exposed is as follows:
+The default behavior for the proxy when port 80 and 443 are exposed is as follows:
 
 
 * If a container has a usable cert, port 80 will redirect to 443 for that container so that HTTPS
 * If a container has a usable cert, port 80 will redirect to 443 for that container so that HTTPS
 is always preferred when available.
 is always preferred when available.
@@ -141,6 +141,10 @@ to establish a connection.  A self-signed or generic cert named `default.crt` an
 will allow a client browser to make a SSL connection (likely w/ a warning) and subsequently receive
 will allow a client browser to make a SSL connection (likely w/ a warning) and subsequently receive
 a 503.
 a 503.
 
 
+To serve traffic in both SSL and non-SSL modes without redirecting to SSL, you can include the
+environment variable `HTTPS_METHOD=noredirect` (the default is `HTTPS_METHOD=redirect`).  You can also
+disable the non-SSL site entirely with `HTTPS_METHOD=nohttp`. 
+
 ### Basic Authentication Support
 ### 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 on directory
 In order to be able to secure your virtual host, you have to create a file named as its equivalent VIRTUAL_HOST variable on directory

+ 13 - 3
nginx.tmpl

@@ -105,6 +105,9 @@ upstream {{ $host }} {
 {{/* Get the VIRTUAL_PROTO defined by containers w/ the same vhost, falling back to "http" */}}
 {{/* Get the VIRTUAL_PROTO defined by containers w/ the same vhost, falling back to "http" */}}
 {{ $proto := or (first (groupByKeys $containers "Env.VIRTUAL_PROTO")) "http" }}
 {{ $proto := or (first (groupByKeys $containers "Env.VIRTUAL_PROTO")) "http" }}
 
 
+{{/* 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" }}
+
 {{/* Get the first cert name defined by containers w/ the same vhost */}}
 {{/* Get the first cert name defined by containers w/ the same vhost */}}
 {{ $certName := (first (groupByKeys $containers "Env.CERT_NAME")) }}
 {{ $certName := (first (groupByKeys $containers "Env.CERT_NAME")) }}
 
 
@@ -118,14 +121,18 @@ upstream {{ $host }} {
 {{/* Use the cert specifid on the container or fallback to the best vhost match */}}
 {{/* Use the cert specifid on the container or fallback to the best vhost match */}}
 {{ $cert := (coalesce $certName $vhostCert) }}
 {{ $cert := (coalesce $certName $vhostCert) }}
 
 
-{{ if (and (ne $cert "") (exists (printf "/etc/nginx/certs/%s.crt" $cert)) (exists (printf "/etc/nginx/certs/%s.key" $cert))) }}
+{{ $is_https := (and (ne $cert "") (exists (printf "/etc/nginx/certs/%s.crt" $cert)) (exists (printf "/etc/nginx/certs/%s.key" $cert))) }}
+
+{{ if $is_https }}
 
 
+{{ if eq $https_method "redirect" }}
 server {
 server {
 	server_name {{ $host }};
 	server_name {{ $host }};
 	listen 80 {{ $default_server }};
 	listen 80 {{ $default_server }};
 	access_log /var/log/nginx/access.log vhost;
 	access_log /var/log/nginx/access.log vhost;
 	return 301 https://$host$request_uri;
 	return 301 https://$host$request_uri;
 }
 }
+{{ end }}
 
 
 server {
 server {
 	server_name {{ $host }};
 	server_name {{ $host }};
@@ -167,7 +174,10 @@ server {
                 {{ end }}
                 {{ end }}
 	}
 	}
 }
 }
-{{ else }}
+
+{{ end }}
+
+{{ if or (not $is_https) (eq $https_method "noredirect") }}
 
 
 server {
 server {
 	server_name {{ $host }};
 	server_name {{ $host }};
@@ -194,7 +204,7 @@ server {
 	}
 	}
 }
 }
 
 
-{{ if (and (exists "/etc/nginx/certs/default.crt") (exists "/etc/nginx/certs/default.key")) }}
+{{ if (and (not $is_https) (exists "/etc/nginx/certs/default.crt") (exists "/etc/nginx/certs/default.key")) }}
 server {
 server {
 	server_name {{ $host }};
 	server_name {{ $host }};
 	listen 443 ssl http2 {{ $default_server }};
 	listen 443 ssl http2 {{ $default_server }};

+ 24 - 0
test/lib/ssl/nginx-proxy.bats.crt

@@ -0,0 +1,24 @@
+-----BEGIN CERTIFICATE-----
+MIID7TCCAtWgAwIBAgIJAOGkf5EnexJVMA0GCSqGSIb3DQEBCwUAMIGMMQswCQYD
+VQQGEwJVUzERMA8GA1UECAwIVmlyZ2luaWExDzANBgNVBAcMBlJlc3RvbjERMA8G
+A1UECgwIRmFrZSBPcmcxGzAZBgNVBAMMEioubmdpbngtcHJveHkuYmF0czEpMCcG
+CSqGSIb3DQEJARYad2VibWFzdGVyQG5naW54LXByb3h5LmJhdHMwHhcNMTYwNDIw
+MTUzOTUxWhcNMjYwNDE4MTUzOTUxWjCBjDELMAkGA1UEBhMCVVMxETAPBgNVBAgM
+CFZpcmdpbmlhMQ8wDQYDVQQHDAZSZXN0b24xETAPBgNVBAoMCEZha2UgT3JnMRsw
+GQYDVQQDDBIqLm5naW54LXByb3h5LmJhdHMxKTAnBgkqhkiG9w0BCQEWGndlYm1h
+c3RlckBuZ2lueC1wcm94eS5iYXRzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEA0Amkj3iaQn8Z2CW6n24zSuWu2OoLCkHZAk8eprkI4kKoPBvjusynkm8E
+phq65jebToHoldfuQ0wM61DzhD15bHwS3x9CrOVbShsmdnGALz+wdR0/4Likx50I
+YZdecTOAlkoZudnX5FZ4ngOxjqcym7p5T8TrSS97a0fx99gitZY0p+Nu2tip4o3t
+WBMs+SoPWTlQ1SrSmL8chC8O2knyBl/w1nHmDnMuR6FGcHdhLncApw9t5spgfv7p
+OrMF4tQxJQNk10TnflmEMkGmy+pfk2e0cQ1Kwp3Nmzm7ECkggxxyjU3ihKiFK+09
+8aSCi7gDAY925+mV6LZ5oLMpO3KJvQIDAQABo1AwTjAdBgNVHQ4EFgQU+NvFo37z
+9Dyq8Mu82SPtV7q1gYQwHwYDVR0jBBgwFoAU+NvFo37z9Dyq8Mu82SPtV7q1gYQw
+DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAI1ityDV0UsCVHSpB2LN+
+QXlk8XS0ACIJ8Q0hbOj3BmYrdAVglG4P6upDEueaaxwsaBTagkTP8nxZ9dhfZHyZ
+5YLNwYsiG5iqb8e0ecHx3uJT/0YiXn/8rBvxEZna4Fl8seGdp7BjOWUAS2Nv8tn4
+EJJvRdfX/O8XgPc95DM4lwQ/dvyWmavMI4lnl0n1IQV9WPGaIQhYPU9WEQK6iMUB
+o1kx8YbOJQD0ZBRfqpriNt1/8ylkkSYYav8QT9JFvQFCWEvaX71QF+cuOwC7ZYBH
+4ElXwEUrYBHKiPo0q0VsTtMvLh7h/T5czrIhG/NpfVJPtQOk8aVwNScL3/n+TGU8
+6g==
+-----END CERTIFICATE-----

+ 28 - 0
test/lib/ssl/nginx-proxy.bats.key

@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDQCaSPeJpCfxnY
+JbqfbjNK5a7Y6gsKQdkCTx6muQjiQqg8G+O6zKeSbwSmGrrmN5tOgeiV1+5DTAzr
+UPOEPXlsfBLfH0Ks5VtKGyZ2cYAvP7B1HT/guKTHnQhhl15xM4CWShm52dfkVnie
+A7GOpzKbunlPxOtJL3trR/H32CK1ljSn427a2Knije1YEyz5Kg9ZOVDVKtKYvxyE
+Lw7aSfIGX/DWceYOcy5HoUZwd2EudwCnD23mymB+/uk6swXi1DElA2TXROd+WYQy
+QabL6l+TZ7RxDUrCnc2bObsQKSCDHHKNTeKEqIUr7T3xpIKLuAMBj3bn6ZXotnmg
+syk7com9AgMBAAECggEAa7wCp3XqVPNjW+c1/ShhkbDeWmDhtL8i9aopkmeSbTHd
+07sRtQQU56Vsf+Sp010KpZ5q52Z6cglpS1eRtHLtdbvPPhL/QXBJVVg4E/B1VIKk
+DBJIqUSVuPXeiEOOWgs01R+ssO1ae1o4foQlKF33vGPWPPQacL0RKh6I9TPNzcD7
+n4rujlHk72N/bNydyK2rnyKB4vAI5TbZPLps+Xe123CmgZnW3JClcWV9B4foRmiu
+a5Iq1WYAK2GYKbYwgqDRyYBC27m91a7U31pE4GQD+xQdlz6kcOlCU5hAcPK3h7j0
+fLQqn8g+YAtc0nBKKB4NZe3QEzTiVMorT0VitxI71QKBgQDnirardZaXOFzYGzB3
+j+FGB9BUW54hnHr5BxOYrfmEJ5umJjJWaGupfYrQsPArrJP1//WbqVZIPvdQParD
+mQhLmSp1r/VNzGB6pISmzU1ZGDHsmBxYseh366om5YBQUFU2vmbil9VkrkM4fsJG
+tcS9V/nVY/EM7Yp3PzjfLlhC1wKBgQDmA1YJmnZvIbLp3PoKqM69QiCLKztVm7nX
+xpu3b3qbXEzXkt2sP5PHmr+s13hOPQFKRJ2hk4UN9WqpnFoHw5E5eWWhSa/peUZm
+r10Y5XspiFtRHHiu6ABXB49eB4fen+vHEZHKyRJ4rFthKjjBHdNPC8bmwnT3jE85
+/8a26FLZiwKBgQDXEi8JZslBn9YF2oOTm28KCLoHka551AsaA+u892T8z3mxxGsf
+fhD7N6TYonIEb2Jkr6OpOortwqcgvpc+5oghCJ27AX2fDUdUxDp/YdYF+wZsmQJD
+lMW1lo7PYIBmmaf9mLCiq5xIz+GauYul+LNNmUl0YEgI1SC4EV63WCodswKBgDMX
+GJxHd/kVViVGFTAa8NjvAEWJU8OfNHduQRZMp8IsjVDw6VYiRRP4Fo0wyyMtv8Sc
+WxsRpmNEWO3VsdW5pd9LTLy3nmBQtMeIOjiWeHXwOMBaf5/yHmk2X6z2JULY6Mkt
+6OFPKlAtkJqTg0m58z7Ckeqd1NdLjimG27+y+PwjAoGAFt0cbC1Ust2BE6YEspSX
+ofpAnJsyKrbF9iVUyXDUP99sdqYQfPJ5uqPGkP59lJGkTLtebuitqi6FCyrsT6Fq
+AWLiExbqebAqcuAZw2S+iuK27S4rrkjVGF53J7vH3rOzCBUXaRx6GKfTjUqedHdg
+9Kw+LP6IFnMTb+EGLo+GqHs=
+-----END PRIVATE KEY-----

+ 117 - 0
test/ssl.bats

@@ -0,0 +1,117 @@
+#!/usr/bin/env bats
+load test_helpers
+SUT_CONTAINER=bats-nginx-proxy-${TEST_FILE}
+
+function setup {
+	# make sure to stop any web container before each test so we don't
+	# have any unexpected contaiener running with VIRTUAL_HOST or VIRUTAL_PORT set
+	stop_bats_containers web
+}
+
+
+@test "[$TEST_FILE] start a nginx-proxy container" {
+	run nginxproxy $SUT_CONTAINER -v /var/run/docker.sock:/tmp/docker.sock:ro -v ${DIR}/lib/ssl:/etc/nginx/certs:ro
+	assert_success
+	docker_wait_for_log $SUT_CONTAINER 9 "Watching docker events"
+}
+
+@test "[$TEST_FILE] test SSL for VIRTUAL_HOST=*.nginx-proxy.bats" {
+	# WHEN
+	prepare_web_container bats-ssl-hosts-1 "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
+	sleep 1
+
+	# THEN
+	assert_301 test.nginx-proxy.bats
+	assert_200_https test.nginx-proxy.bats
+}
+
+@test "[$TEST_FILE] test HTTPS_METHOD=nohttp" {
+	# WHEN
+	prepare_web_container bats-ssl-hosts-2 "80 443" \
+		-e VIRTUAL_HOST=*.nginx-proxy.bats \
+		-e CERT_NAME=nginx-proxy.bats \
+		-e HTTPS_METHOD=nohttp
+	dockergen_wait_for_event $SUT_CONTAINER start bats-ssl-hosts-2
+	sleep 1
+
+	# THEN
+	assert_503 test.nginx-proxy.bats
+	assert_200_https test.nginx-proxy.bats
+}
+
+@test "[$TEST_FILE] test HTTPS_METHOD=noredirect" {
+	# WHEN
+	prepare_web_container bats-ssl-hosts-3 "80 443" \
+		-e VIRTUAL_HOST=*.nginx-proxy.bats \
+		-e CERT_NAME=nginx-proxy.bats \
+		-e HTTPS_METHOD=noredirect
+	dockergen_wait_for_event $SUT_CONTAINER start bats-ssl-hosts-3
+	sleep 1
+
+	# THEN
+	assert_200 test.nginx-proxy.bats
+	assert_200_https test.nginx-proxy.bats
+}
+
+
+@test "[$TEST_FILE] stop all bats containers" {
+	stop_bats_containers
+}
+
+
+# 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
+function assert_200 {
+	local -r host=$1
+
+	run curl_container $SUT_CONTAINER / --head --header "Host: $host"
+	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
+function assert_503 {
+	local -r host=$1
+
+	run curl_container $SUT_CONTAINER / --head --header "Host: $host"
+	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
+# $1 Host HTTP header to use when querying nginx-proxy
+function assert_301 {
+	local -r host=$1
+
+	run curl_container $SUT_CONTAINER / --head --header "Host: $host"
+	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
+function assert_200_https {
+	local -r host=$1
+
+	run curl_container_https $SUT_CONTAINER / --head --header "Host: $host"
+	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
+function assert_503_https {
+	local -r host=$1
+
+	run curl_container_https $SUT_CONTAINER / --head --header "Host: $host"
+	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
+# $1 Host HTTP header to use when querying nginx-proxy
+function assert_301_https {
+	local -r host=$1
+
+	run curl_container_https $SUT_CONTAINER / --head --header "Host: $host"
+	assert_output -l 0 $'HTTP/1.1 301 Moved Permanently\r'
+}

+ 17 - 0
test/test_helpers.bash

@@ -74,6 +74,23 @@ function curl_container {
 		http://$(docker_ip $container)${path}
 		http://$(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
+# $@ additional options to pass to the curl command
+function curl_container_https {
+	local -r container=$1
+	local -r path=$2
+	shift 2
+	docker run --label bats-type="curl" appropriate/curl --silent \
+		--connect-timeout 5 \
+		--max-time 20 \
+		--insecure \
+		"$@" \
+		https://$(docker_ip $container)${path}
+}
 
 
 # start a container running (one or multiple) webservers listening on given ports
 # start a container running (one or multiple) webservers listening on given ports
 #
 #