├── Dockerfile ├── README.md └── rootfs ├── etc ├── cont-init.d │ ├── 00-initialize-logfifos │ ├── 01-generate-dhparam │ └── 02-renderizr-onetime ├── fix-attrs.d │ └── 01-nginx ├── nginx │ └── nginx.conf.tmpl └── services.d │ ├── nginx-access-log │ └── run │ ├── nginx-error-log │ └── run │ ├── nginx │ ├── finish │ └── run │ └── renderizr │ └── run └── var ├── lib └── nginx │ └── .gitignore └── log ├── nginx-access-logs └── .gitignore └── nginx-error-logs └── .gitignore /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM quay.io/justcontainers/base-alpine:v0.10.0 2 | MAINTAINER Gorka Lerchundi Osa 3 | 4 | ## 5 | ## INSTALL 6 | ## 7 | 8 | # nginx 9 | RUN apk-install ca-certificates nginx=1.8.0-r1 10 | 11 | # renderizr 12 | ADD https://github.com/glerchundi/renderizr/releases/download/v0.1.3/renderizr-linux-amd64 /usr/bin/renderizr 13 | RUN chmod 0755 /usr/bin/renderizr 14 | 15 | ## 16 | ## ROOTFS 17 | ## 18 | 19 | # root filesystem 20 | COPY rootfs / 21 | 22 | # s6-fdholderd active by default 23 | RUN s6-rmrf /etc/s6/services/s6-fdholderd/down 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # nginx-loadbalancer [![Docker Repository on Quay.io](https://quay.io/repository/justcontainers/nginx-loadbalancer/status "Docker Repository on Quay.io")](https://quay.io/repository/justcontainers/nginx-loadbalancer) 2 | 3 | ``` 4 | docker run -ti -e CONFD_PREFIX=/lb quay.io/justcontainers/nginx-loadbalancer 5 | ``` 6 | 7 | Backend should follow this rules in order to provide to nginx all required information: 8 | 9 | ``` 10 | /lb 11 | /settings 12 | /.nginx = '{}' 13 | /hosts 14 | /lisa.contoso.com 15 | /listeners 16 | /ls1 = 17 | /.nginx = '{}' 18 | /value = '{ 19 | "protocol": "http", 20 | "address": "0.0.0.0:80" 21 | }' 22 | /locations 23 | /loc2 24 | /.nginx = '{}' 25 | /value = '{ 26 | "path": "/api/.*", 27 | "upstream": "up1" 28 | }' 29 | /upstreams 30 | /up1 31 | /servers 32 | /e1 = '{ "url": "10.10.10.10:8085" }' 33 | /e2 = '{ "url": "10.10.10.11:8085" }' 34 | /up2 35 | /servers 36 | /e1 = '{ "url": "10.10.10.10:8086" }' 37 | /e2 = '{ "url": "10.10.10.11:8086" }' 38 | ``` -------------------------------------------------------------------------------- /rootfs/etc/cont-init.d/00-initialize-logfifos: -------------------------------------------------------------------------------- 1 | #!/usr/bin/execlineb -P 2 | 3 | if { logutil-newfifo /var/run/s6/nginx-access-log-fifo } 4 | if { logutil-newfifo /var/run/s6/nginx-error-log-fifo } 5 | -------------------------------------------------------------------------------- /rootfs/etc/cont-init.d/01-generate-dhparam: -------------------------------------------------------------------------------- 1 | #!/usr/bin/execlineb -P 2 | 3 | if { s6-mkdir -p /etc/nginx/certs } 4 | if -t { s6-test ! -f /etc/nginx/certs/dhparam.pem } 5 | if 6 | { 7 | export RANDFILE .rnd 8 | openssl dhparam -out /etc/nginx/certs/dhparam.pem 2048 9 | } 10 | if { s6-envuidgid nginx s6-chown -U -- /etc/nginx/certs/dhparam.pem } 11 | -------------------------------------------------------------------------------- /rootfs/etc/cont-init.d/02-renderizr-onetime: -------------------------------------------------------------------------------- 1 | #!/usr/bin/execlineb -P 2 | 3 | with-contenv 4 | s6-envuidgid nginx 5 | multisubstitute 6 | { 7 | importas -u uid UID 8 | importas -u gid GID 9 | define check_cmd "/usr/sbin/nginx -t -c {{.}}" 10 | } 11 | renderizr --onetime --template "/etc/nginx/nginx.conf.tmpl;/etc/nginx/nginx.conf;${uid}:${gid};0600;${check_cmd};" etcd 12 | -------------------------------------------------------------------------------- /rootfs/etc/fix-attrs.d/01-nginx: -------------------------------------------------------------------------------- 1 | /etc/nginx true nginx 0600 0700 2 | /var/lib/nginx true nginx 0600 0700 3 | /var/log/nginx-error-logs false nobody,32768:32768 0755 2700 4 | /var/log/nginx-access-logs false nobody,32768:32768 0755 2700 5 | -------------------------------------------------------------------------------- /rootfs/etc/nginx/nginx.conf.tmpl: -------------------------------------------------------------------------------- 1 | user nginx; 2 | 3 | {{define "settings"}} 4 | worker_processes {{or .worker_processes "auto"}}; 5 | 6 | error_log /var/run/s6/nginx-error-log-fifo warn; 7 | pid /var/run/nginx/nginx.pid; 8 | 9 | events { 10 | worker_connections {{or .worker_connections "1024"}}; 11 | } 12 | {{end}} 13 | 14 | {{define "location"}} 15 | {{if ls (printf "/upstreams/%s" .data.upstream)}} 16 | {{$servers := gets (printf "/upstreams/%s/servers/*" .data.upstream)}}{{if $servers}} 17 | location {{.data.path}} { 18 | # 19 | {{range $key,$value := .nginx}}{{$key}} {{$value}}; 20 | {{end}} 21 | # 22 | access_log off; 23 | proxy_pass http://{{.data.upstream}}; 24 | proxy_set_header Host $host; 25 | proxy_set_header X-Real-IP $remote_addr; 26 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 27 | } 28 | {{end}}{{end}} 29 | {{end}} 30 | 31 | {{define "listener"}} 32 | server { 33 | server_name {{base .host}}; 34 | 35 | {{if eq .data.protocol "http"}} 36 | listen {{.data.address}}; 37 | {{else if eq .data.protocol "https"}} 38 | listen {{.data.address}} ssl; 39 | 40 | ssl on; 41 | ssl_certificate /etc/nginx/certs/{{base .host}}.crt; 42 | ssl_certificate_key /etc/nginx/certs/{{base .host}}.key; 43 | 44 | # enable session resumption to improve https performance 45 | # http://vincent.bernat.im/en/blog/2011-ssl-session-reuse-rfc5077.html 46 | ssl_session_cache shared:SSL:50m; 47 | ssl_session_timeout 5m; 48 | 49 | # Diffie-Hellman parameter for DHE ciphersuites, recommended 2048 bits 50 | ssl_dhparam /etc/nginx/certs/dhparam.pem; 51 | 52 | # enables server-side protection from BEAST attacks 53 | # http://blog.ivanristic.com/2013/09/is-beast-still-a-threat.html 54 | ssl_prefer_server_ciphers on; 55 | 56 | # disable SSLv3(enabled by default since nginx 0.8.19) since it's less secure then TLS http://en.wikipedia.org/wiki/Secure_Sockets_Layer#SSL_3.0 57 | ssl_protocols TLSv1 TLSv1.1 TLSv1.2; 58 | 59 | # ciphers chosen for forward secrecy and compatibility 60 | # http://blog.ivanristic.com/2013/08/configuring-apache-nginx-and-openssl-for-forward-secrecy.html 61 | ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384: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-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:ECDHE-RSA-RC4-SHA:ECDHE-ECDSA-RC4-SHA:RC4-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!3DES:!MD5:!PSK'; 62 | 63 | # enable ocsp stapling (mechanism by which a site can convey certificate revocation information to visitors in a privacy-preserving, scalable manner) 64 | # http://blog.mozilla.org/security/2013/07/29/ocsp-stapling-in-firefox/ 65 | ssl_stapling on; 66 | ssl_stapling_verify off; 67 | ssl_trusted_certificate /etc/nginx/certs/{{base .host}}.crt; 68 | 69 | # config to enable HSTS(HTTP Strict Transport Security) https://developer.mozilla.org/en-US/docs/Security/HTTP_Strict_Transport_Security 70 | # to avoid ssl stripping https://en.wikipedia.org/wiki/SSL_stripping#SSL_stripping 71 | add_header Strict-Transport-Security "max-age=31536000; includeSubdomains;"; 72 | {{end}} 73 | 74 | # 75 | {{range $key,$value := .nginx}}{{$key}} {{$value}}; 76 | {{end}} 77 | # 78 | 79 | {{$locations := printf "%s/locations" .host}}{{range $locationbase := ls (printf "%s/" $locations)}} 80 | {{$location := printf "%s/%s" $locations $locationbase}} 81 | {{if exists $location}} 82 | {{template "location" (json (printf "{\"nginx\":{},\"data\":%s}" (getv $location)))}} 83 | {{else if exists (printf "%s/value" $location)}} 84 | {{$nginxKey := printf "%s/.nginx" $location}} 85 | {{$locationKey := printf "%s/value" $location}} 86 | {{if exists $nginxKey}} 87 | {{template "location" (json (printf "{\"nginx\":%s,\"data\":%s}" (getv $nginxKey) (getv $locationKey)))}} 88 | {{else}} 89 | {{template "location" (json (printf "{\"nginx\":%s,\"data\":%s}" (print "{}") (getv $locationKey)))}} 90 | {{end}} 91 | {{end}} 92 | {{end}} 93 | } 94 | {{end}} 95 | 96 | {{if exists "/settings"}} 97 | {{template "settings" (json (getv "/settings"))}} 98 | {{else if exists "/settings/.nginx"}} 99 | {{template "settings" (json (getv "/settings/.nginx"))}} 100 | {{else}} 101 | {{template "settings" (json `{}`)}} 102 | {{end}} 103 | 104 | http { 105 | include /etc/nginx/mime.types; 106 | default_type application/octet-stream; 107 | 108 | log_format main '$remote_addr - $remote_user [$time_local] "$request" ' 109 | '$status $body_bytes_sent "$http_referer" ' 110 | '"$http_user_agent" "$http_x_forwarded_for"'; 111 | access_log /var/run/s6/nginx-access-log-fifo main; 112 | 113 | # NGINX OPTIMIZATION: UNDERSTANDING SENDFILE, TCP_NODELAY AND TCP_NOPUSH 114 | # https://t37.net/nginx-optimization-understanding-sendfile-tcp_nodelay-and-tcp_nopush.html 115 | sendfile on; 116 | tcp_nopush on; 117 | tcp_nodelay on; 118 | 119 | types_hash_max_size 2048; 120 | keepalive_timeout 65; 121 | 122 | gzip on; 123 | gzip_disable "msie6"; 124 | 125 | # Guidelines: 126 | # http://tautt.com/best-nginx-configuration-for-security/ 127 | 128 | # don't send the nginx version number in error pages and Server header 129 | server_tokens off; 130 | 131 | # config to don't allow the browser to render the page inside an frame or iframe 132 | # and avoid clickjacking http://en.wikipedia.org/wiki/Clickjacking 133 | # if you need to allow [i]frames, you can use SAMEORIGIN or even set an uri with ALLOW-FROM uri 134 | # https://developer.mozilla.org/en-US/docs/HTTP/X-Frame-Options 135 | add_header X-Frame-Options SAMEORIGIN; 136 | 137 | # when serving user-supplied content, include a X-Content-Type-Options: nosniff header along with the Content-Type: header, 138 | # to disable content-type sniffing on some browsers. 139 | # https://www.owasp.org/index.php/List_of_useful_HTTP_headers 140 | # currently suppoorted in IE > 8 http://blogs.msdn.com/b/ie/archive/2008/09/02/ie8-security-part-vi-beta-2-update.aspx 141 | # http://msdn.microsoft.com/en-us/library/ie/gg622941(v=vs.85).aspx 142 | # 'soon' on Firefox https://bugzilla.mozilla.org/show_bug.cgi?id=471020 143 | add_header X-Content-Type-Options nosniff; 144 | 145 | # This header enables the Cross-site scripting (XSS) filter built into most recent web browsers. 146 | # It's usually enabled by default anyway, so the role of this header is to re-enable the filter for 147 | # this particular website if it was disabled by the user. 148 | # https://www.owasp.org/index.php/List_of_useful_HTTP_headers 149 | add_header X-XSS-Protection "1; mode=block"; 150 | 151 | # with Content Security Policy (CSP) enabled(and a browser that supports it(http://caniuse.com/#feat=contentsecuritypolicy), 152 | # you can tell the browser that it can only download content from the domains you explicitly allow 153 | # http://www.html5rocks.com/en/tutorials/security/content-security-policy/ 154 | # https://www.owasp.org/index.php/Content_Security_Policy 155 | # I need to change our application code so we can increase security by disabling 'unsafe-inline' 'unsafe-eval' 156 | # directives for css and js(if you have inline css or js, you will need to keep it too). 157 | # more: http://www.html5rocks.com/en/tutorials/security/content-security-policy/#inline-code-considered-harmful 158 | #add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://ssl.google-analytics.com https://assets.zendesk.com https://connect.facebook.net; img-src 'self' https://ssl.google-analytics.com https://s-static.ak.facebook.com https://assets.zendesk.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com https://assets.zendesk.com; font-src 'self' https://themes.googleusercontent.com; frame-src https://assets.zendesk.com https://www.facebook.com https://s-static.ak.facebook.com https://tautt.zendesk.com; object-src 'none'"; 159 | 160 | {{$upstreams := "/upstreams"}}{{range $upstreambase := ls (printf "%s/" $upstreams)}} 161 | {{$upstream := printf "%s/%s" $upstreams $upstreambase}} 162 | {{$servers := gets (printf "%s/servers/*" $upstream)}}{{with $servers}} 163 | upstream {{base $upstream}} { 164 | {{range $server := $servers}}{{with json .Value}} 165 | server {{.url}}; 166 | {{end}}{{end}} 167 | } 168 | {{end}} 169 | {{end}} 170 | 171 | server { 172 | listen 80 default_server; 173 | return 404; 174 | } 175 | 176 | {{$hosts := "/hosts"}}{{range $hostbase := ls (printf "%s/" $hosts)}} 177 | {{$host := printf "%s/%s" $hosts $hostbase}} 178 | {{$listeners := printf "%s/listeners" $host}}{{range $listenerbase := ls (printf "%s/" $listeners)}} 179 | {{$listener := printf "%s/%s" $listeners $listenerbase}} 180 | {{if exists $listener}} 181 | {{template "listener" (json (printf "{\"nginx\":{},\"host\":\"%s\",\"data\":%s}" $host (getv $listener)))}} 182 | {{else if exists (printf "%s/value" $listener)}} 183 | {{$nginxKey := printf "%s/.nginx" $listener}} 184 | {{$listenerKey := printf "%s/value" $listener}} 185 | {{if exists $nginxKey}} 186 | {{template "listener" (json (printf "{\"nginx\":%s,\"host\":\"%s\",\"data\":%s}" (getv $nginxKey) $host (getv $listenerKey)))}} 187 | {{else}} 188 | {{template "listener" (json (printf "{\"nginx\":%s,\"host\":\"%s\",\"data\":%s}" (print "{}") $host (getv $listenerKey)))}} 189 | {{end}} 190 | {{end}} 191 | {{end}} 192 | {{end}} 193 | } 194 | -------------------------------------------------------------------------------- /rootfs/etc/services.d/nginx-access-log/run: -------------------------------------------------------------------------------- 1 | #!/usr/bin/execlineb -P 2 | logutil-service -f /var/run/s6/nginx-access-log-fifo /var/log/nginx-access-logs 3 | -------------------------------------------------------------------------------- /rootfs/etc/services.d/nginx-error-log/run: -------------------------------------------------------------------------------- 1 | #!/usr/bin/execlineb -P 2 | logutil-service -f /var/run/s6/nginx-error-log-fifo /var/log/nginx-error-logs 3 | -------------------------------------------------------------------------------- /rootfs/etc/services.d/nginx/finish: -------------------------------------------------------------------------------- 1 | #!/usr/bin/execlineb -P 2 | s6-svscanctl -t /var/run/s6/services 3 | -------------------------------------------------------------------------------- /rootfs/etc/services.d/nginx/run: -------------------------------------------------------------------------------- 1 | #!/usr/bin/execlineb -P 2 | nginx -g "daemon off;" 3 | -------------------------------------------------------------------------------- /rootfs/etc/services.d/renderizr/run: -------------------------------------------------------------------------------- 1 | #!/usr/bin/execlineb -P 2 | 3 | with-contenv 4 | s6-envuidgid nginx 5 | multisubstitute 6 | { 7 | importas -u uid UID 8 | importas -u gid GID 9 | define check_cmd "/usr/sbin/nginx -t -c {{.}}" 10 | define reload_cmd "/usr/sbin/nginx -s reload" 11 | } 12 | renderizr --watch --template "/etc/nginx/nginx.conf.tmpl;/etc/nginx/nginx.conf;${uid}:${gid};0600;${check_cmd};${reload_cmd}" etcd 13 | -------------------------------------------------------------------------------- /rootfs/var/lib/nginx/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /rootfs/var/log/nginx-access-logs/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /rootfs/var/log/nginx-error-logs/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | --------------------------------------------------------------------------------