├── .gitignore ├── Dockerfile ├── LICENSE ├── README.md ├── html └── gitplaceholder ├── nginx.conf ├── scripts ├── startup.py └── templates │ └── proxy.conf ├── sites-enabled └── gitplaceholder └── ssl └── gitplaceholder /.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:14.04 2 | MAINTAINER Jason Feinstein 3 | 4 | RUN apt-get update 5 | RUN apt-get install -y nginx python python-dev python-pip 6 | 7 | RUN pip install Jinja2 8 | 9 | RUN rm /etc/nginx/sites-enabled/default 10 | ADD html/ /usr/share/nginx/html/ 11 | ADD sites-enabled/ /etc/nginx/sites-enabled/ 12 | ADD ssl/ /etc/nginx/ssl/ 13 | ADD nginx.conf /etc/nginx/ 14 | 15 | ADD scripts/ /scripts/ 16 | 17 | VOLUME ["/etc/nginx/ssl/", "/scripts/"] 18 | 19 | EXPOSE 80 443 20 | 21 | WORKDIR /scripts/ 22 | CMD ["python", "startup.py"] 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Jason Wyatt Feinstein 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # docker-nginx-loadbalancer 2 | 3 | This image will auto-generate its own config file for a load-balancer. 4 | 5 | It looks for environment variables in the following formats: 6 | 7 | __PORT_80_TCP_ADDR=x.x.x.x 8 | _PATH= 9 | 10 | Optional/Conditional environment variables: 11 | 12 | _REMOTE_PORT= (optional - default: 80) 13 | _REMOTE_PATH= (optional - default: /) 14 | _BALANCING_TYPE=[ip_hash|least_conn] (optional) 15 | _EXPOSE_PROTOCOL=[http|https|both] (optional - default: http) 16 | _HOSTNAME= (required if _EXPOSE_PROTOCOL is https or both) 17 | _ACCESS_LOG=[/dev/stdout|off] (optional - default: /dev/stdout) 18 | _ERROR_LOG=[/dev/stdout|/dev/null] (optional - default: /dev/stdout) 19 | _LOG_LEVEL=[emerg|alert|crit|error|warn|notice|info|debug'] (optional - default: error) 20 | _SSL_CERTIFICATE= (required if the vhost will need ssl support) 21 | _SSL_CERTIFICATE_KEY= (required if the vhost will need ssl support) 22 | _SSL_DHPARAM= (required if the vhost will need ssl support) 23 | _SSL_CIPHERS=<"colon separated ciphers wrapped in quotes"> (required if the vhost will need ssl support) 24 | _SSL_PROTOCOLS= (required if the vhost will need ssl support) 25 | 26 | And will build an nginx config file. 27 | 28 | Example: 29 | 30 | # automatically created environment variables (docker links) 31 | WEBAPP_1_PORT_80_TCP_ADDR=192.168.0.2 32 | WEBAPP_2_PORT_80_TCP_ADDR=192.168.0.3 33 | WEBAPP_3_PORT_80_TCP_ADDR=192.168.0.4 34 | API_1_PORT_80_TCP_ADDR=192.168.0.5 35 | API_2_PORT_80_TCP_ADDR=192.168.0.6 36 | TOMCAT_1_PORT_8080_TCP_ADDR=192.168.0.7 37 | TOMCAT_2_PORT_8080_TCP_ADDR=192.168.0.8 38 | 39 | # special environment variables 40 | WEBAPP_PATH=/ 41 | WEBAPP_BALANCING_TYPE=ip_hash 42 | WEBAPP_EXPOSE_PROTOCOL=both 43 | WEBAPP_HOSTNAME=www.example.com 44 | WEBAPP_ACCESS_LOG=off 45 | WEBAPP_ERROR_LOG=/dev/stdout 46 | WEBAPP_LOG_LEVEL=emerg 47 | API_PATH=/api/ 48 | API_EXPOSE_PROTOCOL=https 49 | API_HOSTNAME=www.example.com 50 | WWW_EXAMPLE_COM_SSL_CERTIFICATE=ssl/something.pem 51 | WWW_EXAMPLE_COM_SSL_CERTIFICATE_KEY=ssl/something.key 52 | WWW_EXAMPLE_COM_SSL_DHPARAM=ssl/dhparam.pem 53 | WWW_EXAMPLE_COM_SSL_CIPHERS="ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256" 54 | WWW_EXAMPLE_COM_SSL_PROTOCOLS=TLSv1.2 55 | TOMCAT_PATH=/javaapp 56 | TOMCAT_REMOTE_PORT=8080 57 | TOMCAT_REMOTE_PATH=/javaapp 58 | 59 | Generates (/etc/nginx/sites-enabled/proxy.conf): 60 | 61 | upstream webapp { 62 | ip_hash; 63 | server 192.168.0.2; 64 | server 192.168.0.3; 65 | server 192.168.0.4; 66 | } 67 | 68 | upstream api { 69 | server 192.168.0.5; 70 | server 192.168.0.6; 71 | } 72 | 73 | upstream tomcat { 74 | server 192.168.0.7; 75 | server 192.168.0.8; 76 | } 77 | 78 | server { 79 | listen 80; 80 | listen [::]:80 ipv6only=on; 81 | server_name www.example.com; 82 | 83 | error_log /dev/stdout emerg; 84 | access_log off; 85 | 86 | root /usr/share/nginx/html; 87 | 88 | location / { 89 | proxy_pass http://webapp:80/; 90 | proxy_set_header Host $host; 91 | proxy_set_header X-Real-IP $remote_addr; 92 | proxy_http_version 1.1; 93 | proxy_set_header Connection ""; 94 | proxy_buffering off; 95 | } 96 | } 97 | 98 | server { 99 | listen 443; 100 | server_name www.example.com; 101 | 102 | root html; 103 | index index.html index.htm; 104 | 105 | ssl on; 106 | ssl_certificate ssl/something.pem; 107 | ssl_certificate_key ssl/something.key; 108 | 109 | # Diffie-Hellman parameter for DHE ciphersuites, recommended 2048 bits 110 | ssl_dhparam ssl/dhparam.pem; 111 | 112 | ssl_session_timeout 5m; 113 | 114 | ssl_protocols TLSv1.2; 115 | ssl_ciphers "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256"; 116 | ssl_prefer_server_ciphers on; 117 | 118 | root /usr/share/nginx/html; 119 | 120 | location / { 121 | proxy_pass http://webapp:80/; 122 | proxy_set_header Host $host; 123 | proxy_set_header X-Real-IP $remote_addr; 124 | proxy_http_version 1.1; 125 | proxy_set_header Connection ""; 126 | proxy_buffering off; 127 | } 128 | location /api/ { 129 | proxy_pass http://api:80/; 130 | proxy_set_header Host $host; 131 | proxy_set_header X-Real-IP $remote_addr; 132 | proxy_http_version 1.1; 133 | proxy_set_header Connection ""; 134 | proxy_buffering off; 135 | } 136 | } 137 | 138 | server { 139 | listen 80; 140 | listen [::]:80 ipv6only=on; 141 | 142 | root /usr/share/nginx/html; 143 | 144 | location /javaapp { 145 | proxy_pass http://tomcat:8080/javaapp; 146 | proxy_set_header Host $host; 147 | proxy_set_header X-Real-IP $remote_addr; 148 | proxy_http_version 1.1; 149 | proxy_set_header Connection ""; 150 | proxy_buffering off; 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /html/gitplaceholder: -------------------------------------------------------------------------------- 1 | Here so git picks up the directory. -------------------------------------------------------------------------------- /nginx.conf: -------------------------------------------------------------------------------- 1 | user www-data; 2 | daemon off; 3 | worker_processes 4; 4 | pid /run/nginx.pid; 5 | 6 | events { 7 | worker_connections 2000; 8 | # multi_accept on; 9 | } 10 | 11 | http { 12 | 13 | ## 14 | # Basic Settings 15 | ## 16 | 17 | sendfile on; 18 | tcp_nopush on; 19 | tcp_nodelay on; 20 | keepalive_timeout 65; 21 | types_hash_max_size 2048; 22 | client_max_body_size 10M; 23 | 24 | include /etc/nginx/mime.types; 25 | default_type application/octet-stream; 26 | 27 | ## 28 | # Logging Settings 29 | ## 30 | 31 | access_log /dev/stdout; 32 | error_log /dev/stdout; 33 | 34 | ## 35 | # Gzip Settings 36 | ## 37 | 38 | gzip on; 39 | gzip_disable "msie6"; 40 | 41 | ## 42 | # Virtual Host Configs 43 | ## 44 | 45 | include /etc/nginx/conf.d/*.conf; 46 | include /etc/nginx/sites-enabled/*.conf; 47 | } 48 | -------------------------------------------------------------------------------- /scripts/startup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | ''' 3 | This script will be run on start-up to evaluate the Docker link environment 4 | variables and automatically generate upstream and location modules for 5 | reverse-proxying and load-balancing. 6 | 7 | It looks for environment variables in the following formats: 8 | __PORT_80_TCP_ADDR=x.x.x.x 9 | _PATH= 10 | 11 | Optional/Conditional environment variables: 12 | _BALANCING_TYPE=[ip_hash|least_conn] (optional) 13 | _EXPOSE_PROTOCOL=[http|https|both] (optional - default: http) 14 | _HOSTNAME= (required if _EXPOSE_PROTOCOL is https or both) 15 | _SSL_CERTIFICATE= (required if the vhost will need ssl support) 16 | _SSL_CERTIFICATE_KEY= (required if the vhost will need ssl support) 17 | 18 | And will build an nginx config file. 19 | 20 | Example: 21 | 22 | # automatically created environment variables (docker links) 23 | WEBAPP_1_PORT_80_TCP_ADDR=192.168.0.2 24 | WEBAPP_2_PORT_80_TCP_ADDR=192.168.0.3 25 | WEBAPP_3_PORT_80_TCP_ADDR=192.168.0.4 26 | API_1_PORT_80_TCP_ADDR=192.168.0.5 27 | API_2_PORT_80_TCP_ADDR=192.168.0.6 28 | 29 | # special environment variables 30 | WEBAPP_PATH=/ 31 | WEBAPP_BALANCING_TYPE=ip_hash 32 | WEBAPP_EXPOSE_PROTOCOL=both 33 | WEBAPP_HOSTNAME=www.example.com 34 | API_PATH=/api/ 35 | API_EXPOSE_PROTOCOL=https 36 | API_HOSTNAME=www.example.com 37 | WWW_EXAMPLE_COM_SSL_CERTIFICATE=something.pem 38 | WWW_EXAMPLE_COM_SSL_CERTIFICATE_KEY=something.key 39 | 40 | Generates (/etc/nginx/sites-enabled/proxy.conf): 41 | 42 | upstream webapp { 43 | ip_hash; 44 | server 192.168.0.2; 45 | server 192.168.0.3; 46 | server 192.168.0.4; 47 | } 48 | 49 | upstream api { 50 | server 192.168.0.5; 51 | server 192.168.0.6; 52 | } 53 | 54 | server { 55 | listen 80; 56 | listen [::]:80 ipv6only=on; 57 | server_name www.example.com; 58 | 59 | root /usr/share/nginx/html; 60 | 61 | location / { 62 | proxy_pass http://webapp:80; 63 | proxy_set_header Host $host; 64 | proxy_set_header X-Real-IP $remote_addr; 65 | } 66 | } 67 | 68 | server { 69 | listen 443; 70 | server_name www.example.com; 71 | 72 | root html; 73 | index index.html index.htm; 74 | 75 | ssl on; 76 | ssl_certificate ssl/something.pem; 77 | ssl_certificate_key ssl/something.key; 78 | 79 | ssl_session_timeout 5m; 80 | 81 | ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2; 82 | ssl_ciphers "HIGH:!aNULL:!MD5 or HIGH:!aNULL:!MD5:!3DES"; 83 | ssl_prefer_server_ciphers on; 84 | 85 | root /usr/share/nginx/html; 86 | 87 | location / { 88 | proxy_pass http://webapp:80; 89 | proxy_set_header Host $host; 90 | proxy_set_header X-Real-IP $remote_addr; 91 | } 92 | location /api/ { 93 | proxy_pass http://api:80; 94 | proxy_set_header Host $host; 95 | proxy_set_header X-Real-IP $remote_addr; 96 | } 97 | } 98 | 99 | ''' 100 | 101 | import sys 102 | import os 103 | import re 104 | import argparse 105 | import json 106 | import textwrap 107 | import subprocess 108 | from jinja2 import Environment, FileSystemLoader 109 | 110 | env = Environment( 111 | loader=FileSystemLoader( 112 | os.path.join(os.path.dirname(os.path.realpath(__file__)), 'templates') 113 | ) 114 | ) 115 | parser = argparse.ArgumentParser( 116 | description='Docker-based Nginx Load Balancer Startup Script', 117 | formatter_class=argparse.RawTextHelpFormatter) 118 | parser.add_argument( 119 | '-t', 120 | '--test', 121 | action='store', 122 | choices=['conf', 'parse'], 123 | help=textwrap.dedent('''\ 124 | Test against your environment variables 125 | without modifying the config files. 126 | 'conf' - Preview the generated Nginx config file's contents. 127 | 'parse' - View a detailed parsing of the environment. 128 | ''')) 129 | parser.add_argument( 130 | '-o', 131 | '--output-file', 132 | action='store', 133 | help='Location where the generated Nginx config file will be placed.', 134 | default='/etc/nginx/sites-enabled/proxy.conf' 135 | ) 136 | 137 | def build_conf(hosts, services): 138 | template = env.get_template('proxy.conf') 139 | return template.render(hosts=hosts, services=services) 140 | 141 | def parse_env(env=os.environ): 142 | prefix = env.get('ENV_PREFIX') 143 | if prefix: 144 | prefix = prefix.upper() + '_' 145 | print 'Using prefix: %s' % (prefix) 146 | else: 147 | prefix = '' 148 | print 'No fig prefix found.' 149 | 150 | link_pattern = re.compile(r'^%s(?P[a-zA-Z_]+)(_[\d]+)?_PORT_(?P[\d]+)_TCP_ADDR$' % (prefix)) 151 | 152 | services = {} 153 | hosts = {} 154 | 155 | # find services and collect addresses 156 | for var, value in env.iteritems(): 157 | m = link_pattern.match(var) 158 | if m: 159 | service_name = m.group('service_name') 160 | service_port = int(m.group('service_port')) 161 | if service_port != 80: 162 | service_port = env.get('%s_REMOTE_PORT' % (service_name)) 163 | if not service_port: 164 | continue 165 | if service_name in services: 166 | services[service_name]['addresses'].append(value) 167 | else: 168 | print 'Found service: %s' % service_name 169 | services[service_name] = { 170 | 'addresses': [value], 171 | 'port': service_port, 172 | 'balancing_type': None, 173 | } 174 | 175 | # find service details 176 | for service_name, value in services.iteritems(): 177 | path = value['location'] = env.get('%s_PATH' % (service_name)) 178 | remote_path = value['remote_path'] = env.get('%s_REMOTE_PATH' % (service_name), '/') 179 | balancing_type = value['balancing_type'] = env.get('%s_BALANCING_TYPE' % (service_name)) 180 | expose_protocol = value['expose_protocol'] = env.get('%s_EXPOSE_PROTOCOL' % (service_name), 'http') 181 | hostname = value['host'] = env.get('%s_HOSTNAME' % (service_name)) 182 | 183 | assert path != None, 'Could not find %s_PATH environment variable for service %s.' % (service_name, service_name) 184 | assert balancing_type in [None, 'ip_hash', 'least_conn'], 'Invalid value for %s_BALANCING_TYPE: %s, must be "ip_hash", "least_conn", or nonexistant.' % (service_name, balancing_type) 185 | assert expose_protocol in ['http', 'https', 'both'], 'Invalid value for %s_EXPOSE_PROTOCOL: %s, must be "http", "https", or "both"' % (service_name, expose_protocol) 186 | assert expose_protocol == 'http' or hostname != None, 'With %s_EXPOSE_PROTOCOL=%s, you must supply %s_HOSTNAME.' % (service_name, expose_protocol, service_name) 187 | 188 | if hostname == None: 189 | hostname = value['host'] = '0.0.0.0' 190 | 191 | if hosts.get(hostname) == None: 192 | hosts[hostname] = { 193 | 'protocols': {'http': False, 'https': False}, 194 | 'services': [] 195 | } 196 | 197 | hosts[hostname]['services'].append(service_name) 198 | 199 | if expose_protocol == 'both': 200 | hosts[hostname]['protocols']['http'] = True 201 | hosts[hostname]['protocols']['https'] = True 202 | else: 203 | hosts[hostname]['protocols'][expose_protocol] = True 204 | 205 | for hostname, value in hosts.iteritems(): 206 | formatted_hostname = format_hostname(hostname) 207 | 208 | access_log = value['access_log'] = env.get('%s_ACCESS_LOG' % (service_name), '/dev/stdout') 209 | log_level = value['log_level'] = env.get('%s_LOG_LEVEL' % (service_name), 'error') 210 | error_log = value['error_log'] = env.get('%s_ERROR_LOG' % (service_name), '/dev/stdout') 211 | assert access_log in ['/dev/stdout', 'off'], 'Invalid value for %s_ERROR_LOG: %s, must be "/dev/stdout" or "off"' % (service_name, access_log) 212 | assert log_level in [None, 'emerg', 'alert', 'crit', 'error', 'warn', 'notice', 'info', 'debug'], 'Invalid value for %s_LOG_LEVEL: %s, must be "emerg", "alert", "crit", "error", "warn", "notice", "info", "debug" or nonexistant.' % (service_name, log_level) 213 | assert error_log in ['/dev/stdout', '/dev/null'], 'Invalid value for %s_ERROR_LOG: %s, must be "/dev/stdout" or "/dev/null"' % (service_name, error_log) 214 | 215 | if value['protocols']['https']: 216 | ssl_certificate = env.get('%s_SSL_CERTIFICATE' % formatted_hostname) 217 | ssl_certificate_key = env.get('%s_SSL_CERTIFICATE_KEY' % formatted_hostname) 218 | ssl_dhparam = env.get('%s_SSL_DHPARAM' % formatted_hostname) 219 | ssl_ciphers = env.get('%s_SSL_CIPHERS' % formatted_hostname) 220 | ssl_protocols = env.get('%s_SSL_PROTOCOLS' % formatted_hostname) 221 | 222 | assert ssl_certificate, 'SSL certificate .pem not provided for https host: %s, please set %s_SSL_CERTIFICATE' % (hostname, formatted_hostname) 223 | assert ssl_certificate_key, 'SSL certificate .key not provided for https host: %s, please set %s_SSL_CERTIFICATE_KEY' % (hostname, formatted_hostname) 224 | assert ssl_dhparam, 'SSL dhparam .pem not provided for https host: %s, please set %s_SSL_DHPARAM' % (hostname, formatted_hostname) 225 | assert os.path.isfile(os.path.join('/etc/nginx/', ssl_certificate)), 'SSL certificate file: %s could not be found for %s' % (ssl_certificate, hostname) 226 | assert os.path.isfile(os.path.join('/etc/nginx/', ssl_certificate_key)), 'SSL certificate file: %s could not be found for %s' % (ssl_certificate_key, hostname) 227 | assert os.path.isfile(os.path.join('/etc/nginx/', ssl_certificate_key)), 'SSL dhparam file: %s could not be found for %s' % (ssl_dhparam, hostname) 228 | assert ssl_ciphers, 'SSL ciphers have not been provided for https host: %s, please set %s_SSL_CIPHERS (e.g. %s_SSL_CIPHERS="ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256")' % (hostname, formatted_hostname) 229 | assert ssl_protocols, 'SSL protocols have not been provided for https host: %s, please set %s_SSL_PROTOCOLS (e.g. %s_SSL_PROTOCOLS=TLSv1.2)' % (hostname, formatted_hostname) 230 | 231 | value['ssl_certificate'] = ssl_certificate 232 | value['ssl_certificate_key'] = ssl_certificate_key 233 | value['ssl_dhparam'] = ssl_dhparam 234 | value['ssl_ciphers'] = ssl_ciphers 235 | value['ssl_protocols'] = ssl_protocols 236 | 237 | return hosts, services 238 | 239 | def format_hostname(hostname): 240 | return hostname.replace('.', '_').upper() 241 | 242 | if __name__ == "__main__": 243 | args = parser.parse_args() 244 | 245 | hosts, services = parse_env() 246 | if args.test == 'parse': 247 | print "Services:" 248 | print "%s\n" % json.dumps(services, sort_keys=True, indent=4, separators=(',', ': ')) 249 | print "Hosts:" 250 | print "%s" % json.dumps(hosts, sort_keys=True, indent=4, separators=(',', ': ')) 251 | exit(0) 252 | 253 | conf_contents = build_conf(hosts, services) 254 | sys.stdout.flush() 255 | if args.test == 'conf': 256 | print "Contents of proxy.conf:%s" % conf_contents.replace('\n', '\n ') 257 | exit(0) 258 | 259 | f = open(args.output_file, 'w') 260 | f.write(conf_contents) 261 | f.close() 262 | 263 | sys.stdout.write("Starting Nginx...\n") 264 | sys.stdout.flush() 265 | 266 | p = subprocess.Popen(['nginx'], stdout=subprocess.PIPE, bufsize=0) 267 | while True: 268 | char = p.stdout.read(1) 269 | sys.stdout.write(char) 270 | sys.stdout.flush() 271 | if char == '' and p.poll() != None: 272 | break 273 | 274 | p.stdout.close() 275 | -------------------------------------------------------------------------------- /scripts/templates/proxy.conf: -------------------------------------------------------------------------------- 1 | {%- for service_name, service in services.iteritems() %} 2 | upstream {{service_name|lower}} { 3 | {%- if service.balancing_type %} 4 | {{service['balancing_type']}}; 5 | {%- endif %} 6 | {%- for address in service['addresses'] %} 7 | server {{address}}:{{services[service_name]['port']}}; 8 | {%- endfor %} 9 | } 10 | 11 | {% endfor %} 12 | 13 | {%- for hostname, host in hosts.iteritems() %} 14 | {%- if host['protocols']['http'] %} 15 | server { 16 | listen 80; 17 | server_name {{hostname}}; 18 | 19 | {%- if host['error_log'] %} 20 | error_log {{host['error_log']}} {{host['log_level']}}; 21 | {%- endif %} 22 | {%- if host['access_log'] %} 23 | access_log {{host['access_log']}}; 24 | {%- endif %} 25 | 26 | root /usr/share/nginx/html; 27 | {%- for service_name in host['services'] %} 28 | 29 | # For service: {{service_name}} 30 | location {{services[service_name]['location']}} { 31 | proxy_set_header Host $host; 32 | proxy_set_header X-Real-IP $remote_addr; 33 | proxy_pass http://{{service_name|lower}}{{services[service_name]['remote_path']}}; 34 | proxy_http_version 1.1; 35 | proxy_set_header Connection ""; 36 | proxy_buffering off; 37 | }{% endfor %} 38 | } 39 | {%- endif %} 40 | {%- if host['protocols']['https'] %} 41 | server { 42 | listen 443; 43 | server_name {{hostname}}; 44 | 45 | {%- if host['error_log'] %} 46 | error_log {{host['error_log']}} {{host['log_level']}}; 47 | {%- endif %} 48 | {%- if host['access_log'] %} 49 | access_log {{host['access_log']}}; 50 | {%- endif %} 51 | 52 | root /usr/share/nginx/html; 53 | 54 | ssl on; 55 | ssl_certificate {{host['ssl_certificate']}}; 56 | ssl_certificate_key {{host['ssl_certificate_key']}}; 57 | 58 | # Diffie-Hellman parameter for DHE ciphersuites, recommended 2048 bits 59 | ssl_dhparam {{host['ssl_dhparam']}}; 60 | 61 | ssl_session_timeout 5m; 62 | 63 | ssl_protocols {{host['ssl_protocols']}}; 64 | ssl_ciphers {{host['ssl_ciphers']}}; 65 | ssl_prefer_server_ciphers on; 66 | 67 | {%- for service_name in host['services'] %} 68 | # For service: {{service_name}} 69 | location {{services[service_name]['location']}} { 70 | proxy_set_header Host $host; 71 | proxy_set_header X-Real-IP $remote_addr; 72 | proxy_pass http://{{service_name|lower}}{{services[service_name]['remote_path']}}; 73 | proxy_http_version 1.1; 74 | proxy_set_header Connection ""; 75 | proxy_buffering off; 76 | }{%- endfor %} 77 | } 78 | {%- endif %} 79 | {%- endfor %} 80 | -------------------------------------------------------------------------------- /sites-enabled/gitplaceholder: -------------------------------------------------------------------------------- 1 | Here so git picks up the directory. -------------------------------------------------------------------------------- /ssl/gitplaceholder: -------------------------------------------------------------------------------- 1 | Here so git picks up the dir. --------------------------------------------------------------------------------