{{ $all := . }} {{ $servers := .Servers }} {{ $cfg := .Cfg }} {{ $IsIPV6Enabled := .IsIPV6Enabled }} {{ $healthzURI := .HealthzURI }} {{ $backends := .Backends }} {{ $proxyHeaders := .ProxySetHeaders }} {{ $addHeaders := .AddHeaders }} daemon off; worker_processes {{ $cfg.WorkerProcesses }}; pid /run/nginx.pid; {{ if ne .MaxOpenFiles 0 }} worker_rlimit_nofile {{ .MaxOpenFiles }}; {{ end}} {{/* http://nginx.org/en/docs/ngx_core_module.html#worker_shutdown_timeout */}} {{/* avoid waiting too long during a reload */}} worker_shutdown_timeout 10s; events { multi_accept on; worker_connections {{ $cfg.MaxWorkerConnections }}; use epoll; } http { {{/* we use the value of the header X-Forwarded-For to be able to use the geo_ip module */}} {{ if $cfg.UseProxyProtocol }} real_ip_header proxy_protocol; {{ else }} real_ip_header X-Forwarded-For; {{ end }} real_ip_recursive on; {{ range $trusted_ip := $cfg.ProxyRealIPCIDR }} set_real_ip_from {{ $trusted_ip }}; {{ end }} {{/* databases used to determine the country depending on the client IP address */}} {{/* http://nginx.org/en/docs/http/ngx_http_geoip_module.html */}} {{/* this is require to calculate traffic for individual country using GeoIP in the status page */}} geoip_country /etc/nginx/GeoIP.dat; geoip_city /etc/nginx/GeoLiteCity.dat; geoip_proxy_recursive on; {{ if $cfg.EnableVtsStatus }} vhost_traffic_status_zone shared:vhost_traffic_status:{{ $cfg.VtsStatusZoneSize }}; vhost_traffic_status_filter_by_set_key $geoip_country_code country::*; {{ end }} sendfile on; aio threads; tcp_nopush on; tcp_nodelay on; log_subrequest on; reset_timedout_connection on; keepalive_timeout {{ $cfg.KeepAlive }}s; keepalive_requests {{ $cfg.KeepAliveRequests }}; client_header_buffer_size {{ $cfg.ClientHeaderBufferSize }}; large_client_header_buffers {{ $cfg.LargeClientHeaderBuffers }}; client_body_buffer_size {{ $cfg.ClientBodyBufferSize }}; http2_max_field_size {{ $cfg.HTTP2MaxFieldSize }}; http2_max_header_size {{ $cfg.HTTP2MaxHeaderSize }}; types_hash_max_size 2048; server_names_hash_max_size {{ $cfg.ServerNameHashMaxSize }}; server_names_hash_bucket_size {{ $cfg.ServerNameHashBucketSize }}; map_hash_bucket_size {{ $cfg.MapHashBucketSize }}; proxy_headers_hash_max_size {{ $cfg.ProxyHeadersHashMaxSize }}; proxy_headers_hash_bucket_size {{ $cfg.ProxyHeadersHashBucketSize }}; variables_hash_bucket_size {{ $cfg.VariablesHashBucketSize }}; variables_hash_max_size {{ $cfg.VariablesHashMaxSize }}; underscores_in_headers {{ if $cfg.EnableUnderscoresInHeaders }}on{{ else }}off{{ end }}; ignore_invalid_headers {{ if $cfg.IgnoreInvalidHeaders }}on{{ else }}off{{ end }}; include /etc/nginx/mime.types; default_type text/html; {{ if $cfg.UseGzip }} gzip on; gzip_comp_level 5; gzip_http_version 1.1; gzip_min_length 256; gzip_types {{ $cfg.GzipTypes }}; gzip_proxied any; {{ end }} # Custom headers for response {{ range $k, $v := $addHeaders }} add_header {{ $k }} "{{ $v }}"; {{ end }} server_tokens {{ if $cfg.ShowServerTokens }}on{{ else }}off{{ end }}; # disable warnings uninitialized_variable_warn off; log_format upstreaminfo {{ if $cfg.LogFormatEscapeJSON }}escape=json {{ end }}'{{ buildLogFormatUpstream $cfg }}'; {{/* map urls that should not appear in access.log */}} {{/* http://nginx.org/en/docs/http/ngx_http_log_module.html#access_log */}} map $request_uri $loggable { {{ range $reqUri := $cfg.SkipAccessLogURLs }} {{ $reqUri }} 0;{{ end }} default 1; } {{ if $cfg.DisableAccessLog }} access_log off; {{ else }} access_log /var/log/nginx/access.log upstreaminfo if=$loggable; {{ end }} error_log /var/log/nginx/error.log {{ $cfg.ErrorLogLevel }}; {{ buildResolvers $cfg.Resolver }} {{/* Whenever nginx proxies a request without a "Connection" header, the "Connection" header is set to "close" */}} {{/* when making the target request. This means that you cannot simply use */}} {{/* "proxy_set_header Connection $http_connection" for WebSocket support because in this case, the */}} {{/* "Connection" header would be set to "" whenever the original request did not have a "Connection" header, */}} {{/* which would mean no "Connection" header would be in the target request. Since this would deviate from */}} {{/* normal nginx behavior we have to use this approach. */}} # Retain the default nginx handling of requests without a "Connection" header map $http_upgrade $connection_upgrade { default upgrade; '' close; } # trust http_x_forwarded_proto headers correctly indicate ssl offloading map $http_x_forwarded_proto $pass_access_scheme { default $http_x_forwarded_proto; '' $scheme; } map $http_x_forwarded_port $pass_server_port { default $http_x_forwarded_port; '' $server_port; } {{ if $cfg.UseProxyProtocol }} map $http_x_forwarded_for $the_real_ip { default $http_x_forwarded_for; '' $proxy_protocol_addr; } {{ else }} map $http_x_forwarded_for $the_real_ip { default $http_x_forwarded_for; '' $realip_remote_addr; } {{ end }} {{ if $all.IsSSLPassthroughEnabled }} # map port 442 to 443 for header X-Forwarded-Port map $pass_server_port $pass_port { 442 443; default $pass_server_port; } {{ else }} map $pass_server_port $pass_port { 443 443; default $pass_server_port; } {{ end }} # Map a response error watching the header Content-Type map $http_accept $httpAccept { default html; application/json json; application/xml xml; text/plain text; } map $httpAccept $httpReturnType { default text/html; json application/json; xml application/xml; text text/plain; } # Obtain best http host map $http_host $this_host { default $http_host; '' $host; } map $http_x_forwarded_host $best_http_host { default $http_x_forwarded_host; '' $this_host; } server_name_in_redirect off; port_in_redirect off; ssl_protocols {{ $cfg.SSLProtocols }}; # turn on session caching to drastically improve performance {{ if $cfg.SSLSessionCache }} ssl_session_cache builtin:1000 shared:SSL:{{ $cfg.SSLSessionCacheSize }}; ssl_session_timeout {{ $cfg.SSLSessionTimeout }}; {{ end }} # allow configuring ssl session tickets ssl_session_tickets {{ if $cfg.SSLSessionTickets }}on{{ else }}off{{ end }}; # slightly reduce the time-to-first-byte ssl_buffer_size {{ $cfg.SSLBufferSize }}; {{ if not (empty $cfg.SSLCiphers) }} # allow configuring custom ssl ciphers ssl_ciphers '{{ $cfg.SSLCiphers }}'; ssl_prefer_server_ciphers on; {{ end }} {{ if not (empty $cfg.SSLDHParam) }} # allow custom DH file http://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_dhparam ssl_dhparam {{ $cfg.SSLDHParam }}; {{ end }} {{ if not $cfg.EnableDynamicTLSRecords }} ssl_dyn_rec_size_lo 0; {{ end }} ssl_ecdh_curve {{ $cfg.SSLECDHCurve }}; {{ if .CustomErrors }} # Custom error pages proxy_intercept_errors on; {{ end }} {{ range $errCode := $cfg.CustomHTTPErrors }} error_page {{ $errCode }} = @custom_{{ $errCode }};{{ end }} proxy_ssl_session_reuse on; {{ if $cfg.AllowBackendServerHeader }} proxy_pass_header Server; {{ end }} {{ range $name, $upstream := $backends }} {{ if eq $upstream.SessionAffinity.AffinityType "cookie" }} upstream sticky-{{ $upstream.Name }} { sticky hash={{ $upstream.SessionAffinity.CookieSessionAffinity.Hash }} name={{ $upstream.SessionAffinity.CookieSessionAffinity.Name }} httponly; {{ if (gt $cfg.UpstreamKeepaliveConnections 0) }} keepalive {{ $cfg.UpstreamKeepaliveConnections }}; {{ end }} {{ range $server := $upstream.Endpoints }}server {{ $server.Address | formatIP }}:{{ $server.Port }} max_fails={{ $server.MaxFails }} fail_timeout={{ $server.FailTimeout }}; {{ end }} } {{ end }} upstream {{ $upstream.Name }} { # Load balance algorithm; empty for round robin, which is the default {{ if ne $cfg.LoadBalanceAlgorithm "round_robin" }} {{ $cfg.LoadBalanceAlgorithm }}; {{ end }} {{ if (gt $cfg.UpstreamKeepaliveConnections 0) }} keepalive {{ $cfg.UpstreamKeepaliveConnections }}; {{ end }} {{ range $server := $upstream.Endpoints }}server {{ $server.Address | formatIP }}:{{ $server.Port }} max_fails={{ $server.MaxFails }} fail_timeout={{ $server.FailTimeout }}; {{ end }} } {{ end }} {{/* build the maps that will be use to validate the Whitelist */}} {{ range $index, $server := $servers }} {{ range $location := $server.Locations }} {{ $path := buildLocation $location }} {{ if isLocationAllowed $location }} {{ if gt (len $location.Whitelist.CIDR) 0 }} # Deny for {{ print $server.Hostname $path }} geo $the_real_ip {{ buildDenyVariable (print $server.Hostname "_" $path) }} { default 1; {{ range $ip := $location.Whitelist.CIDR }} {{ $ip }} 0;{{ end }} } {{ end }} {{ end }} {{ if ne $location.RateLimit.Name "" }} {{ if ne (whitelistExists $location.RateLimit.Name) true }} # Ratelimit {{ $location.RateLimit.Name }} geo $whitelist_{{ buildWhitelistVariable $location.RateLimit.Name }} { default 0; {{ range $ip := $location.RateLimit.Whitelist }} {{ $ip }} 1;{{ end }} } # Ratelimit {{ $location.RateLimit.Name }} map $whitelist_{{ buildWhitelistVariable $location.RateLimit.Name }} $limit_{{ buildWhitelistVariable $location.RateLimit.Name }} { 0 {{ $cfg.LimitConnZoneVariable }}; 1 ""; } {{ end }} {{ end }} {{ end }} {{ end }} {{/* build all the required rate limit zones. Each annotation requires a dedicated zone */}} {{/* 1MB -> 16 thousand 64-byte states or about 8 thousand 128-byte states */}} {{ range $zone := (buildRateLimitZones $servers) }} {{ $zone }} {{ end }} {{/* Build server redirects (from/to www) */}} {{ range $hostname, $to := .RedirectServers }} server { listen 80{{ if $all.Cfg.UseProxyProtocol }} proxy_protocol{{ end }}; listen {{ if $all.IsSSLPassthroughEnabled }}442 proxy_protocol{{ else }}443{{ if $all.Cfg.UseProxyProtocol }} proxy_protocol{{ end }}{{ end }} ssl; {{ if $IsIPV6Enabled }} listen [::]:80{{ if $all.Cfg.UseProxyProtocol }} proxy_protocol{{ end }}; listen {{ if $all.IsSSLPassthroughEnabled }}[::]:442 proxy_protocol{{ else }}[::]:443{{ if $all.Cfg.UseProxyProtocol }} proxy_protocol{{ end }}{{ end }}; {{ end }} server_name {{ $hostname }}; return 301 $scheme://{{ $to }}$request_uri; } {{ end }} {{ $backlogSize := .BacklogSize }} {{ range $index, $server := $servers }} server { server_name {{ $server.Hostname }}; {{ template "SERVER" serverConfig $all $server }} {{ template "CUSTOM_ERRORS" $all }} } {{ if $server.Alias }} server { server_name {{ $server.Alias }}; {{ template "SERVER" serverConfig $all $server }} {{ template "CUSTOM_ERRORS" $all }} } {{ end }} {{ end }} # default server, used for NGINX healthcheck and access to nginx stats server { # Use the port 18080 (random value just to avoid known ports) as default port for nginx. # Changing this value requires a change in: # https://github.com/kubernetes/ingress/blob/master/controllers/nginx/pkg/cmd/controller/nginx.go listen 18080 default_server reuseport backlog={{ .BacklogSize }}; {{ if $IsIPV6Enabled }}listen [::]:18080 default_server reuseport backlog={{ .BacklogSize }};{{ end }} set $proxy_upstream_name "-"; location {{ $healthzURI }} { access_log off; return 200; } location /nginx_status { set $proxy_upstream_name "internal"; {{ if $cfg.EnableVtsStatus }} vhost_traffic_status_display; vhost_traffic_status_display_format html; {{ else }} access_log off; stub_status on; {{ end }} } # this location is used to extract nginx metrics # using prometheus. # TODO: enable extraction for vts module. location /internal_nginx_status { set $proxy_upstream_name "internal"; allow 127.0.0.1; {{ if not $cfg.DisableIpv6 }}allow ::1;{{ end }} deny all; access_log off; stub_status on; } location / { set $proxy_upstream_name "upstream-default-backend"; proxy_pass http://upstream-default-backend; } {{ template "CUSTOM_ERRORS" $all }} } # default server for services without endpoints server { listen 8181; set $proxy_upstream_name "-"; location / { {{ if .CustomErrors }} include /etc/nginx/fastcgi_params; fastcgi_param HTTP_X_Code 503; fastcgi_param HTTP_X_Format $http_accept; fastcgi_param HTTP_X_Endpoints {{ .DefaultBackendEndpoints }}; fastcgi_pass unix:/var/run/go-fastcgi.sock; {{ else }} return 503; {{ end }} } } } stream { log_format log_stream {{ $cfg.LogFormatStream }}; {{ if $cfg.DisableAccessLog }} access_log off; {{ else }} access_log /var/log/nginx/access.log log_stream; {{ end }} error_log /var/log/nginx/error.log; # TCP services {{ range $i, $tcpServer := .TCPBackends }} upstream tcp-{{ $tcpServer.Port }}-{{ $tcpServer.Backend.Namespace }}-{{ $tcpServer.Backend.Name }}-{{ $tcpServer.Backend.Port }} { {{ range $j, $endpoint := $tcpServer.Endpoints }} server {{ $endpoint.Address }}:{{ $endpoint.Port }}; {{ end }} } server { listen {{ $tcpServer.Port }}{{ if $tcpServer.Backend.UseProxyProtocol }} proxy_protocol{{ end }}; {{ if $IsIPV6Enabled }}listen [::]:{{ $tcpServer.Port }}{{ if $tcpServer.Backend.UseProxyProtocol }} proxy_protocol{{ end }};{{ end }} proxy_timeout {{ $cfg.ProxyStreamTimeout }}; proxy_pass tcp-{{ $tcpServer.Port }}-{{ $tcpServer.Backend.Namespace }}-{{ $tcpServer.Backend.Name }}-{{ $tcpServer.Backend.Port }}; } {{ end }} # UDP services {{ range $i, $udpServer := .UDPBackends }} upstream udp-{{ $udpServer.Port }}-{{ $udpServer.Backend.Namespace }}-{{ $udpServer.Backend.Name }}-{{ $udpServer.Backend.Port }} { {{ range $j, $endpoint := $udpServer.Endpoints }} server {{ $endpoint.Address }}:{{ $endpoint.Port }}; {{ end }} } server { listen {{ $udpServer.Port }} udp; {{ if $IsIPV6Enabled }}listen [::]:{{ $udpServer.Port }} udp;{{ end }} proxy_responses 1; proxy_timeout {{ $cfg.ProxyStreamTimeout }}; proxy_pass udp-{{ $udpServer.Port }}-{{ $udpServer.Backend.Namespace }}-{{ $udpServer.Backend.Name }}-{{ $udpServer.Backend.Port }}; } {{ end }} } {{/* definition of templates to avoid repetitions */}} {{ define "CUSTOM_ERRORS" }} {{ $defaultBackendEndpoints := .DefaultBackendEndpoints }} {{ range $errCode := .Cfg.CustomHTTPErrors }} location @custom_{{ $errCode }} { internal; include /etc/nginx/fastcgi_params; fastcgi_param HTTP_X_Code {{ $errCode }}; fastcgi_param HTTP_X_Format $http_accept; fastcgi_param HTTP_X_Endpoints {{ $defaultBackendEndpoints }}; fastcgi_pass unix:/var/run/go-fastcgi.sock; } {{ end }} {{ end }} {{/* CORS support from https://michielkalkman.com/snippets/nginx-cors-open-configuration.html */}} {{ define "CORS" }} if ($request_method = 'OPTIONS') { add_header 'Access-Control-Allow-Origin' '*'; # # Om nom nom cookies # add_header 'Access-Control-Allow-Credentials' 'true'; add_header 'Access-Control-Allow-Methods' 'GET, PUT, POST, DELETE, OPTIONS'; # # Custom headers and headers various browsers *should* be OK with but aren't # add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization'; # # Tell client that this pre-flight info is valid for 20 days # add_header 'Access-Control-Max-Age' 1728000; add_header 'Content-Type' 'text/plain charset=UTF-8'; add_header 'Content-Length' 0; return 204; } set $cors_method 0; if ($request_method = 'GET') { set $cors_method 1; } if ($request_method = 'PUT') { set $cors_method 1; } if ($request_method = 'POST') { set $cors_method 1; } if ($request_method = 'DELETE') { set $cors_method 1; } if ($cors_method = 1) { add_header 'Access-Control-Allow-Origin' '*' always; add_header 'Access-Control-Allow-Credentials' 'true'; add_header 'Access-Control-Allow-Methods' 'GET, PUT, POST, DELETE, OPTIONS'; add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization'; } {{ end }} {{/* definition of server-template to avoid repetitions with server-alias */}} {{ define "SERVER" }} {{ $all := .First }} {{ $server := .Second }} listen 80{{ if $all.Cfg.UseProxyProtocol }} proxy_protocol{{ end }}{{ if eq $server.Hostname "_"}} default_server reuseport backlog={{ $all.BacklogSize }}{{end}}; {{ if $all.IsIPV6Enabled }}listen [::]:80{{ if $all.Cfg.UseProxyProtocol }} proxy_protocol{{ end }}{{ if eq $server.Hostname "_"}} default_server reuseport backlog={{ $all.BacklogSize }}{{ end }};{{ end }} set $proxy_upstream_name "-"; {{/* Listen on 442 because port 443 is used in the TLS sni server */}} {{/* This listener must always have proxy_protocol enabled, because the SNI listener forwards on source IP info in it. */}} {{ if not (empty $server.SSLCertificate) }}listen {{ if $all.IsSSLPassthroughEnabled }}442 proxy_protocol {{ else }}443{{ if $all.Cfg.UseProxyProtocol }} proxy_protocol{{ end }}{{ end }} {{ if eq $server.Hostname "_"}} default_server reuseport backlog={{ $all.BacklogSize }}{{end}} ssl {{ if $all.Cfg.UseHTTP2 }}http2{{ end }}; {{ if $all.IsIPV6Enabled }}{{ if not (empty $server.SSLCertificate) }}listen {{ if $all.IsSSLPassthroughEnabled }}[::]:442 proxy_protocol{{ else }}[::]:443{{ if $all.Cfg.UseProxyProtocol }} proxy_protocol{{ end }}{{ end }}{{ end }} {{ if eq $server.Hostname "_"}} default_server reuseport backlog={{ $all.BacklogSize }}{{end}} ssl {{ if $all.Cfg.UseHTTP2 }}http2{{ end }};{{ end }} {{/* comment PEM sha is required to detect changes in the generated configuration and force a reload */}} # PEM sha: {{ $server.SSLPemChecksum }} ssl_certificate {{ $server.SSLCertificate }}; ssl_certificate_key {{ $server.SSLCertificate }}; {{ end }} {{ if (and (not (empty $server.SSLCertificate)) $all.Cfg.HSTS) }} more_set_headers "Strict-Transport-Security: max-age={{ $all.Cfg.HSTSMaxAge }}{{ if $all.Cfg.HSTSIncludeSubdomains }}; includeSubDomains{{ end }};{{ if $all.Cfg.HSTSPreload }} preload{{ end }}"; {{ end }} {{ if $all.Cfg.EnableVtsStatus }}vhost_traffic_status_filter_by_set_key $geoip_country_code country::$server_name;{{ end }} {{ range $location := $server.Locations }} {{ $path := buildLocation $location }} {{ $authPath := buildAuthLocation $location }} {{ if not (empty $location.CertificateAuth.AuthSSLCert.CAFileName) }} # PEM sha: {{ $location.CertificateAuth.AuthSSLCert.PemSHA }} ssl_client_certificate {{ $location.CertificateAuth.AuthSSLCert.CAFileName }}; ssl_verify_client on; ssl_verify_depth {{ $location.CertificateAuth.ValidationDepth }}; {{ end }} {{ if not (empty $location.Rewrite.AppRoot)}} if ($uri = /) { return 302 {{ $location.Rewrite.AppRoot }}; } {{ end }} {{ if not (empty $authPath) }} location = {{ $authPath }} { internal; set $proxy_upstream_name "internal"; {{ if not $location.ExternalAuth.SendBody }} proxy_pass_request_body off; proxy_set_header Content-Length ""; {{ end }} {{ if not (empty $location.ExternalAuth.Method) }} proxy_method {{ $location.ExternalAuth.Method }}; proxy_set_header X-Original-URI $request_uri; proxy_set_header X-Scheme $pass_access_scheme; {{ end }} proxy_pass_request_headers on; proxy_set_header Host {{ $location.ExternalAuth.Host }}; proxy_ssl_server_name on; client_max_body_size "{{ $location.Proxy.BodySize }}"; {{ if $location.ClientBodyBufferSize }} client_body_buffer_size {{ $location.ClientBodyBufferSize }}; {{ end }} set $target {{ $location.ExternalAuth.URL }}; proxy_pass $target; } {{ end }} location {{ $path }} { set $proxy_upstream_name "{{ buildUpstreamName $server.Hostname $all.Backends $location }}"; {{ if (or $location.Rewrite.ForceSSLRedirect (and (not (empty $server.SSLCertificate)) $location.Rewrite.SSLRedirect)) }} # enforce ssl on server side if ($pass_access_scheme = http) { return 301 https://$best_http_host$request_uri; } {{ end }} {{ if isLocationAllowed $location }} {{ if gt (len $location.Whitelist.CIDR) 0 }} if ({{ buildDenyVariable (print $server.Hostname "_" $path) }}) { return 403; } {{ end }} port_in_redirect {{ if $location.UsePortInRedirects }}on{{ else }}off{{ end }}; {{ if not (empty $authPath) }} # this location requires authentication auth_request {{ $authPath }}; auth_request_set $auth_cookie $upstream_http_set_cookie; add_header Set-Cookie $auth_cookie; {{- range $idx, $line := buildAuthResponseHeaders $location }} {{ $line }} {{- end }} {{ end }} {{ if not (empty $location.ExternalAuth.SigninURL) }} error_page 401 = {{ buildAuthSignURL $location.ExternalAuth.SigninURL }}; {{ end }} {{/* if the location contains a rate limit annotation, create one */}} {{ $limits := buildRateLimit $location }} {{ range $limit := $limits }} {{ $limit }}{{ end }} {{ if $location.BasicDigestAuth.Secured }} {{ if eq $location.BasicDigestAuth.Type "basic" }} auth_basic "{{ $location.BasicDigestAuth.Realm }}"; auth_basic_user_file {{ $location.BasicDigestAuth.File }}; {{ else }} auth_digest "{{ $location.BasicDigestAuth.Realm }}"; auth_digest_user_file {{ $location.BasicDigestAuth.File }}; {{ end }} proxy_set_header Authorization ""; {{ end }} {{ if $location.EnableCORS }} {{ template "CORS" }} {{ end }} {{ if not (empty $location.Redirect.URL) }} if ($uri ~* {{ $path }}) { return {{ $location.Redirect.Code }} {{ $location.Redirect.URL }}; } {{ end }} client_max_body_size "{{ $location.Proxy.BodySize }}"; {{ if $location.ClientBodyBufferSize }} client_body_buffer_size {{ $location.ClientBodyBufferSize }}; {{ end }} proxy_set_header Host $best_http_host; # Pass the extracted client certificate to the backend {{ if not (empty $location.CertificateAuth.AuthSSLCert.CAFileName) }} proxy_set_header ssl-client-cert $ssl_client_cert; {{ end }} # Allow websocket connections proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; proxy_set_header X-Real-IP $the_real_ip; proxy_set_header X-Forwarded-For $the_real_ip; proxy_set_header X-Forwarded-Host $best_http_host; proxy_set_header X-Forwarded-Port $pass_port; proxy_set_header X-Forwarded-Proto $pass_access_scheme; proxy_set_header X-Original-URI $request_uri; proxy_set_header X-Scheme $pass_access_scheme; # mitigate HTTPoxy Vulnerability # https://www.nginx.com/blog/mitigating-the-httpoxy-vulnerability-with-nginx/ proxy_set_header Proxy ""; # Custom headers to proxied server {{ range $k, $v := $all.ProxySetHeaders }} proxy_set_header {{ $k }} "{{ $v }}"; {{ end }} proxy_connect_timeout {{ $location.Proxy.ConnectTimeout }}s; proxy_send_timeout {{ $location.Proxy.SendTimeout }}s; proxy_read_timeout {{ $location.Proxy.ReadTimeout }}s; proxy_redirect off; proxy_buffering off; proxy_buffer_size "{{ $location.Proxy.BufferSize }}"; proxy_buffers 4 "{{ $location.Proxy.BufferSize }}"; proxy_http_version 1.1; proxy_cookie_domain {{ $location.Proxy.CookieDomain }}; proxy_cookie_path {{ $location.Proxy.CookiePath }}; # In case of errors try the next upstream server before returning an error proxy_next_upstream {{ buildNextUpstream $location.Proxy.NextUpstream }}{{ if $all.Cfg.RetryNonIdempotent }} non_idempotent{{ end }}; {{/* rewrite only works if the content is not compressed */}} {{ if $location.Rewrite.AddBaseURL }} proxy_set_header Accept-Encoding ""; {{ end }} {{/* Add any additional configuration defined */}} {{ $location.ConfigurationSnippet }} {{ buildProxyPass $server.Hostname $all.Backends $location }} {{ else }} #{{ $location.Denied }} return 503; {{ end }} } {{ end }} {{ if eq $server.Hostname "_" }} # health checks in cloud providers require the use of port 80 location {{ $all.HealthzURI }} { access_log off; return 200; } # this is required to avoid error if nginx is being monitored # with an external software (like sysdig) location /nginx_status { allow 127.0.0.1; {{ if $all.IsIPV6Enabled }}allow ::1;{{ end }} deny all; access_log off; stub_status on; } {{ end }} {{ end }}