Explorar el Código

Merge pull request #56 from jwilder/jw-https

Add SSL Support
Jason Wilder hace 10 años
padre
commit
61c3933e0e
Se han modificado 3 ficheros con 106 adiciones y 3 borrados
  1. 4 3
      Dockerfile
  2. 44 0
      README.md
  3. 58 0
      nginx.tmpl

+ 4 - 3
Dockerfile

@@ -21,7 +21,7 @@ RUN echo "daemon off;" >> /etc/nginx/nginx.conf \
 RUN wget -P /usr/local/bin https://godist.herokuapp.com/projects/ddollar/forego/releases/current/linux-amd64/forego \
  && chmod u+x /usr/local/bin/forego
 
-ENV DOCKER_GEN_VERSION 0.3.4
+ENV DOCKER_GEN_VERSION 0.3.6
 
 RUN wget https://github.com/jwilder/docker-gen/releases/download/$DOCKER_GEN_VERSION/docker-gen-linux-amd64-$DOCKER_GEN_VERSION.tar.gz \
  && tar -C /usr/local/bin -xvzf docker-gen-linux-amd64-$DOCKER_GEN_VERSION.tar.gz \
@@ -30,8 +30,9 @@ RUN wget https://github.com/jwilder/docker-gen/releases/download/$DOCKER_GEN_VER
 COPY . /app/
 WORKDIR /app/
 
-
-EXPOSE 80
+EXPOSE 80 443
 ENV DOCKER_HOST unix:///tmp/docker.sock
 
+VOLUME ["/etc/nginx/certs"]
+
 CMD ["forego", "start", "-r"]

+ 44 - 0
README.md

@@ -51,3 +51,47 @@ $ docker run --volumes-from nginx \
 Finally, start your containers with `VIRTUAL_HOST` environment variables.
 
     $ docker run -e VIRTUAL_HOST=foo.bar.com  ...
+
+### SSL Support
+
+SSL is supported single host, wildcards and SNI certificates using naming conventions for
+certificates or optionally specify a cert name (for SNI) as an environment variable.
+
+To enable SSL:
+
+    $ docker run -d -p 80:80 -p 443:443 -v /path/to/certs:/etc/nginx/certs -v /var/run/docker.sock:/tmp/docker.sock jwilder/nginx-proxy
+
+The contents of `/path/to/certs` should contain the certificates and private keys for any virtual
+hosts in use.  The certificate and keys should be named after the virtual host with a `.crt` and
+`.key` extension.  For example, a container with `VIRTUAL_HOST=foo.bar.com` should have a
+`foo.bar.com.crt` and 'foo.bar.com.key' file in the certs directory.
+
+#### Wildcard Certificates
+
+Wildcard certificate and keys should be name after the domain name with a `.crt` and `.key` extension.
+For example `VIRTUAL_HOST=foo.bar.com` could also use cert name `bar.com.crt` and `bar.com.key`.
+
+#### SNI
+
+If your certificate(s) supports multiple domain names, you can start a container with `CERT_NAME=<name>`
+to identify the certificate to be used.  For example, a certificate for `*.foo.com` and `*.bar.com`
+could be name `shared.crt` and `shared.key`.  A container running with `VIRTUAL_HOST=foo.bar.com`
+and `CERT_NAME=shared` will then use this shared cert.
+
+#### How SSL Support Works
+
+The SSL cipher configuration is based on [mozilla nginx intermediate profile](https://wiki.mozilla.org/Security/Server_Side_TLS#Nginx) which
+should provide compatibility with clients back to Firefox 1, Chrome 1, IE 7, Opera 5, Safari 1,
+Windows XP IE8, Android 2.3, Java 7.  The configuration also enables OCSP stapling, HSTS, and SSL
+session caches.
+
+The 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
+is always preferred when available.
+* If the container does not have a usable cert, a 503 will be returned.
+
+Note that in the latter case, a browser may get an connection error as no certificate is available
+to establish a connection.  A self-signed or generic cert can be defined as "default.crt" and "default.key"
+which will allow a client browser to make a SSL connection (likely w/ a warning) and subsequently receive
+a 503.

+ 58 - 0
nginx.tmpl

@@ -36,6 +36,7 @@ server {
 }
 
 {{ range $host, $containers := groupByMulti $ "Env.VIRTUAL_HOST" "," }}
+
 upstream {{ $host }} {
 {{ range $container := $containers }}
 	{{ $addrLen := len $container.Addresses }}
@@ -65,11 +66,68 @@ upstream {{ $host }} {
 {{ end }}
 }
 
+{{/* Get the first cert name defined by containers w/ the same vhost */}}
+{{ $certName := (first (groupByKeys $containers "Env.CERT_NAME")) }}
+
+{{/* Get the best matching cert  by name for the vhost. */}}
+{{ $vhostCert := (closest (dir "/etc/nginx/certs") (printf "%s.crt" $host))}}
+
+{{/* vhostCert is actually a filename so remove any suffixes since they are added later */}}
+{{ $vhostCert := replace $vhostCert ".crt" "" -1 }}
+{{ $vhostCert := replace $vhostCert ".key" "" -1 }}
+
+{{/* Use the cert specifid on the container or fallback to the best vhost match */}}
+{{ $cert := (coalesce $certName $vhostCert) }}
+
+{{ if (ne $cert "") }}
+
+server {
+	server_name {{ $host }};
+	rewrite ^(.*) https://{{ $host }}$1 permanent;
+}
+
 server {
 	server_name {{ $host }};
+	listen 443 ssl;
+
+	ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
+	ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA;
+
+	ssl_prefer_server_ciphers on;
+	ssl_session_timeout 5m;
+	ssl_session_cache shared:SSL:50m;
+	ssl_stapling on;
+	ssl_stapling_verify on;
+
+	ssl_certificate /etc/nginx/certs/{{ (printf "%s.crt" $cert) }};
+	ssl_certificate_key /etc/nginx/certs/{{ (printf "%s.key" $cert) }};
+
+	add_header Strict-Transport-Security "max-age=31536000; includeSubdomains";
 
 	location / {
 		proxy_pass http://{{ $host }};
 	}
 }
+{{ else }}
+
+server {
+	server_name {{ $host }};
+
+	location / {
+		proxy_pass http://{{ $host }};
+	}
+}
+
+server {
+	server_name {{ $host }};
+	listen 443 ssl;
+	return 503;
+
+	{{ if (and (exists "/etc/nginx/certs/default.crt") (exists "/etc/nginx/certs/default.key")) }}
+	ssl_certificate /etc/nginx/certs/default.crt;
+	ssl_certificate_key /etc/nginx/certs/default.key;
+	{{ end }}
+}
+
+{{ end }}
 {{ end }}