From 06db3b33d62887af7f003efdf87b57ee4d1bea08 Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Thu, 2 Jan 2014 19:39:54 -0800 Subject: [PATCH] nginx-proxy: Add an Nginx proxy image I've got a bunch of HTTP server images, but I need a single proxy container that supports SNI to expose them to the world. This container can link to a colleciton of HTTP-serving containers and proxy them under arbitrary hostnames using user-supplied, per-host certificates and keys. env and sed are both in POSIX 2013 [1,2], and the: eval A=\$$B variable indirection is because POSIX [3] doesn't support Bash's indirect expansion "A=${!B}". The 'tcp' -> 'http' replacement maps Docker's tcp:://${IP}:${PORT} addresses to http://${IP}:${PORT} for use in the Nginx config. envsubst is in gettext [4] and not in POSIX [5], so it may be slightly less portable. However, envsubst and gettext are in Gentoo's x86 and amd64 stage1s, our Gentoo-based images will have it. [1]: http://pubs.opengroup.org/onlinepubs/9699919799/utilities/env.html [2]: http://pubs.opengroup.org/onlinepubs/9699919799/utilities/sed.html [3]: http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_02 [4]: http://www.gnu.org/software/gettext/ [5]: http://pubs.opengroup.org/onlinepubs/9699919799/idx/utilities.html --- README.md | 1 + build.sh | 1 + nginx-proxy/Dockerfile.template | 41 +++++++++++++++++ nginx-proxy/README.md | 31 +++++++++++++ nginx-proxy/create-vhosts-from-environment.sh | 44 +++++++++++++++++++ nginx-proxy/vhost-template.conf | 43 ++++++++++++++++++ 6 files changed, 161 insertions(+) create mode 100644 nginx-proxy/Dockerfile.template create mode 100644 nginx-proxy/README.md create mode 100755 nginx-proxy/create-vhosts-from-environment.sh create mode 100644 nginx-proxy/vhost-template.conf diff --git a/README.md b/README.md index 6c45ce4..a654a62 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,7 @@ The dependency graph is: |-- buildbot (adds a Buildbot master and slave) |-- memcached (adds Memcached) |-- nginx (adds Nginx) + | |-- nginx-proxy (SSL/TLS proxying via SNI) | `-- kibana (adds Kibana) |-- postgresql (adds PostgreSQL) |-- redis (adds Redis) diff --git a/build.sh b/build.sh index 197bdbd..77684c8 100755 --- a/build.sh +++ b/build.sh @@ -46,6 +46,7 @@ REPOS="${REPOS:- elasticsearch memcached nginx + nginx-proxy kibana postgresql redis diff --git a/nginx-proxy/Dockerfile.template b/nginx-proxy/Dockerfile.template new file mode 100644 index 0000000..0e1e184 --- /dev/null +++ b/nginx-proxy/Dockerfile.template @@ -0,0 +1,41 @@ +# Copyright (C) 2014 W. Trevor King +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +FROM ${NAMESPACE}/nginx:${TAG} +MAINTAINER ${MAINTAINER} + +# Add a framework for easy virtual hosts +RUN mkdir /etc/nginx/vhosts +RUN chown nginx:nginx /etc/nginx/vhosts +RUN sed -i 's|^\([[:space:]]*\)\(server {\)|\1include vhosts/*.conf;\n\n\1\2|' /etc/nginx/nginx.conf +ADD vhost-template.conf /etc/nginx/vhosts/TEMPLATE +RUN chown nginx:nginx /etc/nginx/vhosts/TEMPLATE +ADD create-vhosts-from-environment.sh /usr/bin/create-vhosts-from-environment + +# Uncomment the default HTTPS server +RUN sed -i 's/^\t#\([^ ]\)/\t\1/' /etc/nginx/nginx.conf +RUN sed -i 's/listen 127.0.0.1:443;/listen 443 default_server;/' /etc/nginx/nginx.conf + +CMD create-vhosts-from-environment && rc default && tail -F /var/log/messages +EXPOSE 443 diff --git a/nginx-proxy/README.md b/nginx-proxy/README.md new file mode 100644 index 0000000..109300d --- /dev/null +++ b/nginx-proxy/README.md @@ -0,0 +1,31 @@ +While the `nginx` container serves a single, unnamed host from +`/var/www/localhost/htdocs`, this container uses [Nginx] to proxy a +collection of virtual servers via hostname. It listens for both +plaintext and [TLS][] connections, and uses [Server Name Indication +(SNI)][SNI] to serve the appropriate [X.509][] certificate. + +Run this [Nginx][] image with: + + $ docker run -d -name nginx-a -v /var/www/a.net/htdocs:/var/www/localhost/htdocs wking/nginx + $ docker run -d -name nginx-b -v /var/www/b.com/htdocs:/var/www/localhost/htdocs wking/nginx + $ docker run -d -name nginx-proxy-0 -link nginx-a:a -e A_NAME=a.com -link nginx-b:b -e B_NAME=b.net -v /etc/ssl/nginx-proxy-0:/etc/ssl/nginx -p 80:80 -p 443:443 wking/nginx-proxy + +[volume-mounting][volume-mount] your certificates and keys under the +container's `/etc/ssl/nginx`. The `*_NAME` environment variables +override Docker's [default][link-name] `/${LINKER}/${LINKEE}`. For +example, without th `-e A_NAME=a.com` argument, `A_NAME` would be +`/nginx-proxy-0/a`. You should avoid link aliases with `-` and `.` in +them, because `A.NET_NAME` is not a valid shell variable. + +[HAProxy][] added native SSL support with [version 1.5-dev12 +(2012-09-10)][HAProxy-v1.5], but v1.5 isn't stable yet so I think +Nginx is the best tool for this task. + +[Nginx]: http://nginx.org/ +[TLS]: http://en.wikipedia.org/wiki/Transport_layer_security +[SNI]: http://en.wikipedia.org/wiki/Server_Name_Indication +[X.509]: http://en.wikipedia.org/wiki/X.509 +[volume-mount]: http://docs.docker.io/en/latest/use/working_with_volumes/ +[link-name]: http://docs.docker.io/en/latest/use/working_with_links_names/ +[HAProxy]: http://haproxy.1wt.eu/ +[HAProxy-v1.5]: http://haproxy.1wt.eu/download/1.5/src/CHANGELOG diff --git a/nginx-proxy/create-vhosts-from-environment.sh b/nginx-proxy/create-vhosts-from-environment.sh new file mode 100755 index 0000000..67590a4 --- /dev/null +++ b/nginx-proxy/create-vhosts-from-environment.sh @@ -0,0 +1,44 @@ +#!/bin/sh +# +# Copyright (C) 2014 W. Trevor King +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +# usage: C1_PORT=tcp://192.168.0.1:12345/ C1_NAME=a.com \ +# C2_PORT=tcp://192.168.0.2:54321/ C2_NAME=b.net \ +# create-vhosts-from-environment + +for NAME_VARIABLE in $(env | sed -n 's/^\([^=]*_NAME\)=.*/\1/p'); do + URL_VARIABLE="${NAME_VARIABLE%_NAME}_PORT" + eval NAME="\$$NAME_VARIABLE" + eval URL="\$$URL_VARIABLE" + URL="http://${URL#tcp://}" + env -i \ + NAME="${NAME}" \ + URL="${URL}" \ + envsubst ' + ${NAME} + ${URL} + ' \ + < /etc/nginx/vhosts/TEMPLATE > "/etc/nginx/vhosts/${NAME}.conf" +done diff --git a/nginx-proxy/vhost-template.conf b/nginx-proxy/vhost-template.conf new file mode 100644 index 0000000..77c403e --- /dev/null +++ b/nginx-proxy/vhost-template.conf @@ -0,0 +1,43 @@ +# Copyright (C) 2014 W. Trevor King +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +server { + listen 80; + listen 443 ssl; + server_name ${NAME}; + + ssl on; + ssl_certificate /etc/ssl/nginx/${NAME}.pem; + ssl_certificate_key /etc/ssl/nginx/${NAME}.key; + + access_log /var/log/nginx/${NAME}.ssl_access_log main; + error_log /var/log/nginx/${NAME}.ssl_error_log info; + + root /var/www/${NAME}/htdocs; + + location / { + proxy_pass ${URL}; + proxy_set_header X-Forwarded-For $remote_addr; + } +} -- 2.26.2