# required to run in a container
daemon off;

user nginx;
worker_processes {{ or (getv "/deis/router/workerProcesses") "auto" }};
pid /run/nginx.pid;

events {
    worker_connections {{ or (getv "/deis/router/maxWorkerConnections") "768" }};
    # multi_accept on;
}


http {
    # basic settings
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;

    # The Timeout value must be greater than the front facing load balancers timeout value.
    # Default is the deis recommended timeout value for ELB - 1200 seconds + 100s extra.
    {{ $defaultTimeout := or (getv "/deis/router/defaultTimeout") "1300" }}
    keepalive_timeout {{ $defaultTimeout }};

    types_hash_max_size 2048;
    server_names_hash_max_size {{ or (getv "/deis/router/serverNameHashMaxSize") "512" }};
    server_names_hash_bucket_size {{ or (getv "/deis/router/serverNameHashBucketSize") "64" }};

    include /opt/nginx/conf/mime.types;
    default_type application/octet-stream;
    {{ if exists "/deis/router/gzip" }}
    gzip {{ getv "/deis/router/gzip" }};
    gzip_comp_level {{ or (getv "/deis/router/gzipCompLevel") "5" }};
    gzip_disable {{ or (getv "/deis/router/gzipDisable") "\"msie6\"" }};
    gzip_http_version {{ or (getv "/deis/router/gzipHttpVersion") "1.1" }};
    gzip_min_length {{ or (getv "/deis/router/gzipMinLength") "256" }};
    gzip_types {{ or (getv "/deis/router/gzipTypes") "application/atom+xml application/javascript application/json application/rss+xml application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/svg+xml image/x-icon text/css text/plain text/x-component" }};
    gzip_proxied {{ or (getv "/deis/router/gzipProxied") "any" }};
    gzip_vary {{ or (getv "/deis/router/gzipVary") "on" }};
    {{ end }}

    {{ $useFirewall := or (getv "/deis/router/firewall/enabled") "false" }}{{ if eq $useFirewall "true" }}# include naxsi rules
    include     /opt/nginx/firewall/naxsi_core.rules;
    include     /opt/nginx/firewall/web_apps.rules;
    include     /opt/nginx/firewall/scanner.rules;
    include     /opt/nginx/firewall/web_server.rules;{{ end }}
    {{ $firewallErrorCode := or (getv "/deis/router/firewall/errorCode") "400" }}
    client_max_body_size "{{ or (getv "/deis/router/bodySize") "1m" }}";

    {{ $useProxyProtocol := or (getv "/deis/router/proxyProtocol") "false" }}{{ if ne $useProxyProtocol "false" }}
    set_real_ip_from {{ or (getv "/deis/router/proxyRealIpCidr") "10.0.0.0/8" }};
    real_ip_header proxy_protocol;
    {{ end }}

    log_format upstreaminfo '[$time_local] - {{ if ne $useProxyProtocol "false" }}$proxy_protocol_addr{{ else }}$remote_addr{{ end }} - $remote_user - $status - "$request" - $bytes_sent - "$http_referer" - "$http_user_agent" - "$server_name" - $upstream_addr - $http_host - $upstream_response_time - $request_time';

    # send logs to STDOUT so they can be seen using 'docker logs'
    access_log /opt/nginx/logs/access.log upstreaminfo;
    error_log  /opt/nginx/logs/error.log {{ or (getv "/deis/router/errorLogLevel") "error" }};

    map $http_upgrade $connection_upgrade {
        default upgrade;
        ''      close;
    }

    # trust http_x_forwarded_proto headers correctly indicate ssl offloading
    map $http_x_forwarded_proto $access_scheme {
      default $http_x_forwarded_proto;
      ''      $scheme;
    }

    ## HSTS instructs the browser to replace all HTTP links with HTTPS links for this domain until maxAge seconds from now
    {{ $enableHSTS := or (getv "/deis/router/hsts/enabled") "false" }}
    {{ $maxAgeHSTS := or (getv "/deis/router/hsts/maxAge") "10886400" }}
    {{ $includeSubdomainsHSTS := or (getv "/deis/router/hsts/includeSubDomains") "false" }}
    {{ $preloadHSTS := or (getv "/deis/router/hsts/preload") "false" }}
    map $access_scheme $sts {
      'https' 'max-age={{ $maxAgeHSTS }}{{ if eq $includeSubdomainsHSTS "true" }}; includeSubDomains{{ end }}{{ if eq $preloadHSTS "true" }}; preload{{ end }}';
    }

    ## since HSTS headers are not permitted on HTTP requests, 301 redirects to HTTPS resources are also necessary
    {{ $enforceHTTPS := or (getv "/deis/router/enforceHTTPS") $enableHSTS "false" }}

    ## start deis-controller
    {{ if exists "/deis/controller/host" }}
    upstream deis-controller {
        server {{ getv "/deis/controller/host" }}:{{ getv "/deis/controller/port" }};
    }
    {{ end }}

    server {
        server_name ~^{{ or (getv "/deis/controller/subdomain") "deis" }}\.(?<domain>.+)$;
        include deis.conf;

        {{ if exists "/deis/controller/host" }}
        location / {
            {{ if eq $useFirewall "true" }}include                     /opt/nginx/firewall/active-mode.rules;{{ end }}
            proxy_buffering             off;
            proxy_set_header            Host $host;
            {{ if ne $useProxyProtocol "false" }}
            proxy_set_header            X-Forwarded-For $proxy_protocol_addr;
            {{ else }}
            proxy_set_header            X-Forwarded-For $proxy_add_x_forwarded_for;
            {{ end }}
            proxy_redirect              off;
            proxy_connect_timeout       {{ or (getv "/deis/router/controller/timeout/connect") "10s" }};
            proxy_send_timeout          {{ or (getv "/deis/router/controller/timeout/send") "20m" }};
            proxy_read_timeout          {{ or (getv "/deis/router/controller/timeout/read") "20m" }};

            proxy_pass                  http://deis-controller;
        }
        {{ else }}
        location / {
            return 503;
        }
        {{ end }}

        {{ if eq $useFirewall "true" }}location /RequestDenied {
            return {{ $firewallErrorCode }};
        }
        {{ end }}

        {{ if eq $enforceHTTPS "true" }}
        if ($access_scheme != "https") {
          return 301 https://$host$request_uri;
        }
        {{ end }}

        {{ if eq $enableHSTS "true" }}
        add_header Strict-Transport-Security $sts always;
        {{ end }}
    }
    ## end deis-controller

    ## start deis-store-gateway
    {{ if exists "/deis/store/gateway/host" }}
    upstream deis-store-gateway {
        server {{ getv "/deis/store/gateway/host" }}:{{ getv "/deis/store/gateway/port" }};
    }
    {{ end }}

    server {
        server_name ~^deis-store\.(?<domain>.+)$;
        include deis.conf;

        client_max_body_size            0;

        {{ if exists "/deis/store/gateway/host" }}
        location / {
            {{ if eq $useFirewall "true" }}include                     /opt/nginx/firewall/active-mode.rules;{{ end }}
            proxy_buffering             off;
            proxy_set_header            Host $host;
            {{ if ne $useProxyProtocol "false" }}
            proxy_set_header            X-Forwarded-For $proxy_protocol_addr;
            {{ else }}
            proxy_set_header            X-Forwarded-For $proxy_add_x_forwarded_for;
            {{ end }}
            proxy_redirect              off;
            proxy_connect_timeout       10s;
            proxy_send_timeout          {{ $defaultTimeout }}s;
            proxy_read_timeout          {{ $defaultTimeout }}s;

            proxy_pass                  http://deis-store-gateway;
        }
        {{ else }}
        location / {
            return 503;
        }
        {{ end }}
    }
    ## end deis-store-gateway
    {{ $useSSL := or (getv "/deis/router/sslCert") "false" }}
    {{ $domains := ls "/deis/domains" }}
    {{ $certs := ls "/deis/certs" }}
    ## start service definitions for each application
    {{ range $app := lsdir "/deis/services" }}
    {{ $upstreams := printf "/deis/services/%s/*" $app}}
    upstream {{ $app }} {
        {{ if exists "/deis/router/affinityArg" }}
        hash $arg_{{ getv "/deis/router/affinityArg" }} consistent;
        {{ end }}
        {{ range gets $upstreams }}server {{ .Value }};
        {{ end }}
    }
    {{ $appContainers := gets $upstreams }}{{ $appContainerLen := len $appContainers }}
    ## server entries for custom domains
    {{ range $app_domain := $domains }}{{ if eq $app (getv (printf "/deis/domains/%s" $app_domain)) }}
    server {
        server_name {{ $app_domain }};
        {{/* if a SSL certificate is installed for this domain, use SSL */}}
        {{/* NOTE (bacongobbler): domains are separate from the default platform domain, */}}
        {{/* so we can't rely on deis.conf as each domain is an island */}}
        {{ if exists (printf "/deis/certs/%s/cert" $app_domain) }}
        server_name_in_redirect off;
        port_in_redirect off;
        listen 80{{ if ne $useProxyProtocol "false" }} proxy_protocol{{ end }};
        listen 443 ssl spdy{{ if ne $useProxyProtocol "false" }} proxy_protocol{{ end }};
        ssl_certificate /etc/ssl/deis/certs/{{ $app_domain }}.cert;
        ssl_certificate_key /etc/ssl/deis/keys/{{ $app_domain }}.key;
        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
        {{ if exists "/deis/router/sslCiphers" }}
        ssl_ciphers '{{ getv "/deis/router/sslCiphers" }}';
        ssl_prefer_server_ciphers on;
        {{ end }}
        {{/* if there's no app SSL cert but we have a router SSL cert, enable that instead */}}
        {{/* TODO (bacongobbler): wait for https://github.com/kelseyhightower/confd/issues/270 */}}
        {{/* so we can apply this config to just subdomains of the platform domain. */}}
        {{/* ref: https://github.com/deis/deis/pull/3519 */}}
        {{ else }}
        include deis.conf;
        {{ end }}
        {{ if ne $appContainerLen 0 }}
        location / {
            {{ if eq $useFirewall "true" }}include                     /opt/nginx/firewall/active-mode.rules;{{ end }}
            proxy_buffering             off;
            proxy_set_header            Host $host;
            set $access_ssl 'off';
            set $access_port '80';
            if ($access_scheme ~ https) {
                set $access_ssl 'on';
                set $access_port '443';
            }
            proxy_set_header            X-Forwarded-Port  $access_port;
            proxy_set_header            X-Forwarded-Proto $access_scheme;
            {{ if ne $useProxyProtocol "false" }}
            proxy_set_header            X-Forwarded-For   $proxy_protocol_addr;
            {{ else }}
            proxy_set_header            X-Forwarded-For   $proxy_add_x_forwarded_for;
            {{ end }}
            proxy_set_header            X-Forwarded-Ssl   $access_ssl;
            proxy_redirect              off;
            proxy_connect_timeout       30s;
            proxy_send_timeout          {{ $defaultTimeout }}s;
            proxy_read_timeout          {{ $defaultTimeout }}s;
            proxy_http_version          1.1;
            proxy_set_header            Upgrade           $http_upgrade;
            proxy_set_header            Connection        $connection_upgrade;

            proxy_next_upstream         error timeout http_502 http_503 http_504;

            {{ if eq $enforceHTTPS "true" }}
            if ($access_scheme != "https") {
              return 301 https://$host$request_uri;
            }
            {{ end }}

            {{ if eq $enableHSTS "true" }}
            add_header Strict-Transport-Security $sts always;
            {{ end }}

            ## workaround for nginx hashing empty string bug http://trac.nginx.org/nginx/ticket/765
            {{ if exists "/deis/router/affinityArg" }}
            set_random $prng 0 99;
            set_if_empty $arg_{{ getv "/deis/router/affinityArg" }} $prng;
            {{ end }}

            proxy_pass                  http://{{ $app }};
        }
        {{ else }}
        location / {
            return 503;
        }
        {{ end }}
        {{ if eq $useFirewall "true" }}location /RequestDenied {
            return {{ $firewallErrorCode }};
        }
        {{ end }}
    }{{ end }}{{ end }}
    ## end entries for custom domains

    server {
        server_name ~^{{ $app }}\.(?<domain>.+)$;
        include deis.conf;
        {{ if ne $appContainerLen 0 }}
        location / {
            {{ if eq $useFirewall "true" }}include                     /opt/nginx/firewall/active-mode.rules;{{ end }}
            proxy_buffering             off;
            proxy_set_header            Host $host;
            set $access_ssl 'off';
            set $access_port '80';
            if ($access_scheme ~ https) {
                set $access_ssl 'on';
                set $access_port '443';
            }
            proxy_set_header            X-Forwarded-Port  $access_port;
            proxy_set_header            X-Forwarded-Proto $access_scheme;
            {{ if ne $useProxyProtocol "false" }}
            proxy_set_header            X-Forwarded-For   $proxy_protocol_addr;
            {{ else }}
            proxy_set_header            X-Forwarded-For   $proxy_add_x_forwarded_for;
            {{ end }}
            proxy_set_header            X-Forwarded-Ssl   $access_ssl;
            proxy_redirect              off;
            proxy_connect_timeout       30s;
            proxy_send_timeout          {{ $defaultTimeout }}s;
            proxy_read_timeout          {{ $defaultTimeout }}s;
            proxy_http_version          1.1;
            proxy_set_header            Upgrade           $http_upgrade;
            proxy_set_header            Connection        $connection_upgrade;

            proxy_next_upstream         error timeout http_502 http_503 http_504;

            {{ if eq $enforceHTTPS "true" }}
            if ($access_scheme != "https") {
              return 301 https://$host$request_uri;
            }
            {{ end }}

            {{ if eq $enableHSTS "true" }}
            add_header Strict-Transport-Security $sts always;
            {{ end }}

            proxy_pass                  http://{{ $app }};
        }
        {{ else }}
        location / {
            return 503;
        }
        {{ end }}
        {{ if eq $useFirewall "true" }}location /RequestDenied {
            return {{ $firewallErrorCode }};
        }
        {{ end }}
    }{{ end }}
    ## end service definitions for each application

    # healthcheck
    server {
        listen 80 default_server reuseport{{ if ne $useProxyProtocol "false" }} proxy_protocol{{ end }};
        location /health-check {
            default_type 'text/plain';
            access_log off;
            return 200;
        }
        location /router-nginx-status {
            stub_status on;
            return 200;
        }
        location / {
            return 404;
        }
    }
    #start k8s apps
    {{ range $kapp := ls "/registry/services/specs/default" }}
    {{ $k8appPath := printf "/registry/services/specs/default/%s" $kapp}}{{ $k8Svc := json (getv $k8appPath) }}
    {{ $upstreams := printf "/registry/services/specs/default/%s" $kapp}}
    upstream {{ if $k8Svc.metadata.labels.name }}{{ $k8Svc.metadata.labels.name }}{{ else }}{{ $k8Svc.metadata.name }}{{ end }} {
        {{ if exists "/deis/router/affinityArg" }}
        hash $arg_{{ getv "/deis/router/affinityArg" }} consistent;
        {{ end }}
        server {{ $k8Svc.spec.clusterIP }}:80;
    }
    {{ $appContainers := gets $upstreams }}{{ $appContainerLen := len $appContainers }}
    {{ $k8sappname := or $k8Svc.metadata.labels.name $k8Svc.metadata.name }}
    ## server entries for custom domains
    {{ range $app_domain := $domains }}{{ if eq $k8sappname (getv (printf "/deis/domains/%s" $app_domain)) }}
    server {
        server_name {{ $app_domain }};
        {{/* if a SSL certificate is installed for this domain, use SSL */}}
        {{/* NOTE (bacongobbler): domains are separate from the default platform domain, */}}
        {{/* so we can't rely on deis.conf as each domain is an island */}}
        {{ if exists (printf "/deis/certs/%s/cert" $app_domain) }}
        server_name_in_redirect off;
        port_in_redirect off;
        listen 80{{ if ne $useProxyProtocol "false" }} proxy_protocol{{ end }};
        listen 443 ssl spdy{{ if ne $useProxyProtocol "false" }} proxy_protocol{{ end }};
        ssl_certificate /etc/ssl/deis/certs/{{ $app_domain }}.cert;
        ssl_certificate_key /etc/ssl/deis/keys/{{ $app_domain }}.key;
        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
        {{ if exists "/deis/router/sslCiphers" }}
        ssl_ciphers '{{ getv "/deis/router/sslCiphers" }}';
        ssl_prefer_server_ciphers on;
        {{ end }}
        {{/* if there's no app SSL cert but we have a router SSL cert, enable that instead */}}
        {{/* TODO (bacongobbler): wait for https://github.com/kelseyhightower/confd/issues/270 */}}
        {{/* so we can apply this config to just subdomains of the platform domain. */}}
        {{/* ref: https://github.com/deis/deis/pull/3519 */}}
        {{ else }}
        include deis.conf;
        {{ end }}
        {{ if ne $appContainerLen 0 }}
        location / {
            {{ if eq $useFirewall "true" }}include                     /opt/nginx/firewall/active-mode.rules;{{ end }}
            proxy_buffering             off;
            proxy_set_header            Host $host;
            set $access_ssl 'off';
            set $access_port '80';
            if ($access_scheme ~ https) {
                set $access_ssl 'on';
                set $access_port '443';
            }
            proxy_set_header            X-Forwarded-Port  $access_port;
            proxy_set_header            X-Forwarded-Proto $access_scheme;
            {{ if ne $useProxyProtocol "false" }}
            proxy_set_header            X-Forwarded-For   $proxy_protocol_addr;
            {{ else }}
            proxy_set_header            X-Forwarded-For   $proxy_add_x_forwarded_for;
            {{ end }}
            proxy_set_header            X-Forwarded-Ssl   $access_ssl;
            proxy_redirect              off;
            proxy_connect_timeout       30s;
            proxy_send_timeout          {{ $defaultTimeout }}s;
            proxy_read_timeout          {{ $defaultTimeout }}s;
            proxy_http_version          1.1;
            proxy_set_header            Upgrade           $http_upgrade;
            proxy_set_header            Connection        $connection_upgrade;

            proxy_next_upstream         error timeout http_502 http_503 http_504;

            {{ if eq $enforceHTTPS "true" }}
            if ($access_scheme != "https") {
              return 301 https://$host$request_uri;
            }
            {{ end }}

            {{ if eq $enableHSTS "true" }}
            add_header Strict-Transport-Security $sts always;
            {{ end }}

            ## workaround for nginx hashing empty string bug http://trac.nginx.org/nginx/ticket/765
            {{ if exists "/deis/router/affinityArg" }}
            set_random $prng 0 99;
            set_if_empty $arg_{{ getv "/deis/router/affinityArg" }} $prng;
            {{ end }}

            proxy_pass                  http://{{ if $k8Svc.metadata.labels.name }}{{ $k8Svc.metadata.labels.name }}{{ else }}{{ $k8Svc.metadata.name }}{{ end }};
        }
        {{ else }}
        location / {
            return 503;
        }
        {{ end }}
        {{ if eq $useFirewall "true" }}location /RequestDenied {
            return {{ $firewallErrorCode }};
        }
        {{ end }}
    }{{ end }}{{ end }}
    ## end entries for custom domains

    server {
        server_name ~^{{ if $k8Svc.metadata.labels.name }}{{ $k8Svc.metadata.labels.name }}{{ else }}{{ $k8Svc.metadata.name }}{{ end }}\.(?<domain>.+)$;
        include deis.conf;
        {{ if ne $appContainerLen 0 }}
        location / {
            {{ if eq $useFirewall "true" }}include                     /opt/nginx/firewall/active-mode.rules;{{ end }}
            proxy_buffering             off;
            proxy_set_header            Host $host;
            set $access_ssl 'off';
            set $access_port '80';
            if ($access_scheme ~ https) {
                set $access_ssl 'on';
                set $access_port '443';
            }
            proxy_set_header            X-Forwarded-Port  $access_port;
            proxy_set_header            X-Forwarded-Proto $access_scheme;
            {{ if ne $useProxyProtocol "false" }}
            proxy_set_header            X-Forwarded-For   $proxy_protocol_addr;
            {{ else }}
            proxy_set_header            X-Forwarded-For   $proxy_add_x_forwarded_for;
            {{ end }}
            proxy_set_header            X-Forwarded-Ssl   $access_ssl;
            proxy_redirect              off;
            proxy_connect_timeout       30s;
            proxy_send_timeout          {{ $defaultTimeout }}s;
            proxy_read_timeout          {{ $defaultTimeout }}s;
            proxy_http_version          1.1;
            proxy_set_header            Upgrade           $http_upgrade;
            proxy_set_header            Connection        $connection_upgrade;

            proxy_next_upstream         error timeout http_502 http_503 http_504;

            {{ if eq $enforceHTTPS "true" }}
            if ($access_scheme != "https") {
              return 301 https://$host$request_uri;
            }
            {{ end }}

            {{ if eq $enableHSTS "true" }}
            add_header Strict-Transport-Security $sts always;
            {{ end }}

            proxy_pass                  http://{{ if $k8Svc.metadata.labels.name }}{{ $k8Svc.metadata.labels.name }}{{ else }}{{ $k8Svc.metadata.name }}{{ end }};
        }
        {{ else }}
        location / {
            return 503;
        }
        {{ end }}
        {{ if eq $useFirewall "true" }}location /RequestDenied {
            return {{ $firewallErrorCode }};
        }
        {{ end }}
    }{{end}}
}

## start builder
{{ if exists "/deis/builder/host" }}
stream {

    upstream builder {
        server {{ getv "/deis/builder/host" }}:{{ getv "/deis/builder/port" }};
    }

    server {
        listen 2222;
        proxy_connect_timeout  {{ or (getv "/deis/router/builder/timeout/connect") "10000" }};
        proxy_timeout          {{ or (getv "/deis/router/builder/timeout/tcp") "1200000" }};
        proxy_pass builder;
    }
}{{ end }}
## end builder
