Merge pull request #8546 from dokku/simpler-nginx-conf-sigil

Consolidate nginx.conf.sigil server blocks
This commit is contained in:
Jose Diaz-Gonzalez
2026-04-30 18:40:11 -04:00
committed by GitHub
5 changed files with 431 additions and 111 deletions

View File

@@ -4,18 +4,25 @@ go 1.26.2
require (
github.com/dokku/dokku/plugins/common v0.0.0-00010101000000-000000000000
github.com/gliderlabs/sigil v0.12.0
github.com/spf13/pflag v1.0.10
)
require (
github.com/alexellis/go-execute/v2 v2.2.1 // indirect
github.com/dustin/go-jsonpointer v0.0.0-20160814072949-ba0abeacc3dc // indirect
github.com/dustin/gojson v0.0.0-20160307161227-2e71ec9dd5ad // indirect
github.com/fatih/color v1.19.0 // indirect
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 // indirect
github.com/hashicorp/errwrap v1.0.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/joho/godotenv v1.5.1 // indirect
github.com/kr/fs v0.1.0 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/melbahja/goph v1.5.0 // indirect
github.com/mgood/go-posix v0.0.0-20150821180505-948c005421f5 // indirect
github.com/otiai10/copy v1.14.1 // indirect
github.com/otiai10/mint v1.6.3 // indirect
github.com/pkg/errors v0.9.1 // indirect
@@ -24,6 +31,7 @@ require (
golang.org/x/crypto v0.50.0 // indirect
golang.org/x/sync v0.20.0 // indirect
golang.org/x/sys v0.43.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
)
replace github.com/dokku/dokku/plugins/common => ../common

View File

@@ -1,15 +1,30 @@
github.com/alexellis/go-execute/v2 v2.2.1 h1:4Ye3jiCKQarstODOEmqDSRCqxMHLkC92Bhse743RdOI=
github.com/alexellis/go-execute/v2 v2.2.1/go.mod h1:FMdRnUTiFAmYXcv23txrp3VYZfLo24nMpiIneWgKHTQ=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dustin/go-jsonpointer v0.0.0-20160814072949-ba0abeacc3dc h1:tP7tkU+vIsEOKiK+l/NSLN4uUtkyuxc6hgYpQeCWAeI=
github.com/dustin/go-jsonpointer v0.0.0-20160814072949-ba0abeacc3dc/go.mod h1:ORH5Qp2bskd9NzSfKqAF7tKfONsEkCarTE5ESr/RVBw=
github.com/dustin/gojson v0.0.0-20160307161227-2e71ec9dd5ad h1:Qk76DOWdOp+GlyDKBAG3Klr9cn7N+LcYc82AZ2S7+cA=
github.com/dustin/gojson v0.0.0-20160307161227-2e71ec9dd5ad/go.mod h1:mPKfmRa823oBIgl2r20LeMSpTAteW5j7FLkc0vjmzyQ=
github.com/fatih/color v1.19.0 h1:Zp3PiM21/9Ld6FzSKyL5c/BULoe/ONr9KlbYVOfG8+w=
github.com/fatih/color v1.19.0/go.mod h1:zNk67I0ZUT1bEGsSGyCZYZNrHuTkJJB+r6Q9VuMi0LE=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
github.com/gliderlabs/sigil v0.12.0 h1:2O+PDkqnn8XhUYx0z79MkFTik39t9FEdM1kgK4geQvg=
github.com/gliderlabs/sigil v0.12.0/go.mod h1:O6TGDuYPPHoiMad4W2FDsHgK39tNBYZRfhhUGOKgzRE=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8=
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
@@ -18,6 +33,8 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/melbahja/goph v1.5.0 h1:RQUBpLvfg3i7fjfG8rTcSWyMjVRfdhwrrfQhjYee4dQ=
github.com/melbahja/goph v1.5.0/go.mod h1:dDwo+44cmvfDLdiVpc6fJxexf5BA5yEDUeE5YgtuDO4=
github.com/mgood/go-posix v0.0.0-20150821180505-948c005421f5 h1:AutzcJSqc7ROMqcjPKmxwLl//YrzDPb4tLSBlH3Irdc=
github.com/mgood/go-posix v0.0.0-20150821180505-948c005421f5/go.mod h1:irVTeKOI2GrudEK6/mqR4dDlGH91lCZIZM34YKSKH7M=
github.com/onsi/gomega v1.40.0 h1:Vtol0e1MghCD2ZVIilPDIg44XSL9l2QAn8ZNaljWcJc=
github.com/onsi/gomega v1.40.0/go.mod h1:M/Uqpu/8qTjtzCLUA2zJHX9Iilrau25x1PdoSRbWh5A=
github.com/otiai10/copy v1.14.1 h1:5/7E6qsUMBaH5AnQ0sSLzzTg1oTECmcCmT6lvF45Na8=
@@ -34,6 +51,7 @@ github.com/ryanuber/columnize v2.1.2+incompatible h1:C89EOx/XBWwIXl8wm8OPJBd7kPF
github.com/ryanuber/columnize v2.1.2+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
@@ -51,5 +69,10 @@ golang.org/x/term v0.42.0 h1:UiKe+zDFmJobeJ5ggPwOshJIVt6/Ft0rcfrXZDLWAWY=
golang.org/x/term v0.42.0/go.mod h1:Dq/D+snpsbazcBG5+F9Q1n2rXV8Ma+71xEjTRufARgY=
golang.org/x/text v0.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg=
golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@@ -0,0 +1,291 @@
package nginxvhosts
import (
"os"
"path/filepath"
"runtime"
"strings"
"testing"
"github.com/gliderlabs/sigil"
_ "github.com/gliderlabs/sigil/builtin"
)
func templatePath(t *testing.T) string {
t.Helper()
_, file, _, ok := runtime.Caller(0)
if !ok {
t.Fatal("runtime.Caller failed")
}
return filepath.Join(filepath.Dir(file), "templates", "nginx.conf.sigil")
}
func defaultVars() map[string]interface{} {
return map[string]interface{}{
"APP": "app",
"DOKKU_ROOT": "/home/dokku",
"DOKKU_LIB_ROOT": "/var/lib/dokku",
"NOSSL_SERVER_NAME": "app.example.com",
"SSL_SERVER_NAME": "",
"SSL_INUSE": "",
"APP_SSL_PATH": "/home/dokku/app/tls",
"DOKKU_APP_WEB_LISTENERS": "127.0.0.1:5000",
"PROXY_PORT_MAP": "http:80:5000",
"PROXY_UPSTREAM_PORTS": "5000",
"PROXY_PORT": "80",
"PROXY_SSL_PORT": "443",
"PROXY_KEEPALIVE": "",
"NGINX_BIND_ADDRESS_IP4": "",
"NGINX_BIND_ADDRESS_IP6": "::",
"NGINX_ACCESS_LOG_PATH": "/var/log/nginx/app-access.log",
"NGINX_ACCESS_LOG_FORMAT": "",
"NGINX_ERROR_LOG_PATH": "/var/log/nginx/app-error.log",
"NGINX_UNDERSCORE_IN_HEADERS": "off",
"CLIENT_BODY_TIMEOUT": "60s",
"CLIENT_HEADER_TIMEOUT": "60s",
"CLIENT_MAX_BODY_SIZE": "1m",
"KEEPALIVE_TIMEOUT": "75s",
"LINGERING_TIMEOUT": "5s",
"SEND_TIMEOUT": "60s",
"PROXY_CONNECT_TIMEOUT": "60s",
"PROXY_READ_TIMEOUT": "60s",
"PROXY_SEND_TIMEOUT": "60s",
"PROXY_BUFFER_SIZE": "4k",
"PROXY_BUFFERING": "on",
"PROXY_BUFFERS": "8 4k",
"PROXY_BUSY_BUFFERS_SIZE": "8k",
"PROXY_X_FORWARDED_FOR": "$remote_addr",
"PROXY_X_FORWARDED_PORT": "$server_port",
"PROXY_X_FORWARDED_PROTO": "$scheme",
"PROXY_X_FORWARDED_SSL": "",
"HTTP2_DIRECTIVE_SUPPORTED": "true",
}
}
func renderTemplate(t *testing.T, vars map[string]interface{}) string {
t.Helper()
data, err := os.ReadFile(templatePath(t))
if err != nil {
t.Fatalf("read template: %v", err)
}
buf, err := sigil.Execute(data, vars, "nginx.conf.sigil")
if err != nil {
t.Fatalf("sigil.Execute: %v", err)
}
return buf.String()
}
func mustContain(t *testing.T, out, needle string) {
t.Helper()
if !strings.Contains(out, needle) {
t.Errorf("expected output to contain %q\n--- output ---\n%s", needle, out)
}
}
func mustNotContain(t *testing.T, out, needle string) {
t.Helper()
if strings.Contains(out, needle) {
t.Errorf("expected output NOT to contain %q\n--- output ---\n%s", needle, out)
}
}
func TestTemplate_HTTPOnlyBasicProxy(t *testing.T) {
out := renderTemplate(t, defaultVars())
mustContain(t, out, "listen [::]:80;")
mustContain(t, out, "proxy_pass http://app-5000;")
mustContain(t, out, "error_page 500 501 502 503")
mustContain(t, out, "server_name app.example.com;")
mustNotContain(t, out, "ssl_certificate")
mustNotContain(t, out, "return 301 https")
mustNotContain(t, out, "http2_push_preload")
}
func TestTemplate_HTTPSEmitsPushPreloadWhenSupported(t *testing.T) {
v := defaultVars()
v["PROXY_PORT_MAP"] = "https:443:5000"
v["SSL_INUSE"] = "true"
v["SSL_SERVER_NAME"] = "app.example.com"
v["HTTP2_PUSH_SUPPORTED"] = "true"
out := renderTemplate(t, v)
mustContain(t, out, "http2_push_preload on;")
}
func TestTemplate_HTTPSOmitsPushPreloadWhenUnsupported(t *testing.T) {
v := defaultVars()
v["PROXY_PORT_MAP"] = "https:443:5000"
v["SSL_INUSE"] = "true"
v["SSL_SERVER_NAME"] = "app.example.com"
v["HTTP2_PUSH_SUPPORTED"] = "false"
out := renderTemplate(t, v)
mustNotContain(t, out, "http2_push_preload")
}
func TestTemplate_HTTPRedirectsToHTTPSWhenSSLInUse(t *testing.T) {
v := defaultVars()
v["PROXY_PORT_MAP"] = "http:80:5000 https:443:5000"
v["SSL_INUSE"] = "true"
v["SSL_SERVER_NAME"] = "app.example.com"
out := renderTemplate(t, v)
port80, _, ok := strings.Cut(out, "listen [::]:443")
if !ok {
t.Fatalf("expected an https server block in output:\n%s", out)
}
mustContain(t, port80, "return 301 https://$host:443$request_uri;")
mustContain(t, port80, "include /home/dokku/app/nginx.conf.d/*.conf;")
mustNotContain(t, port80, "proxy_pass http://app-5000;")
mustContain(t, out, "ssl_certificate /home/dokku/app/tls/server.crt;")
mustContain(t, out, "proxy_pass http://app-5000;")
}
func TestTemplate_HTTPSWithHTTP2Directive(t *testing.T) {
v := defaultVars()
v["PROXY_PORT_MAP"] = "https:443:5000"
v["SSL_INUSE"] = "true"
v["SSL_SERVER_NAME"] = "app.example.com"
v["HTTP2_DIRECTIVE_SUPPORTED"] = "true"
out := renderTemplate(t, v)
mustContain(t, out, "listen [::]:443 ssl;")
mustContain(t, out, "http2 on;")
mustNotContain(t, out, "listen [::]:443 ssl http2;")
}
func TestTemplate_HTTPSWithHTTP2Parameter(t *testing.T) {
v := defaultVars()
v["PROXY_PORT_MAP"] = "https:443:5000"
v["SSL_INUSE"] = "true"
v["SSL_SERVER_NAME"] = "app.example.com"
v["HTTP2_DIRECTIVE_SUPPORTED"] = "false"
out := renderTemplate(t, v)
mustContain(t, out, "listen [::]:443 ssl http2;")
mustNotContain(t, out, "http2 on;")
}
func TestTemplate_NoWebListenersReturns502(t *testing.T) {
v := defaultVars()
v["DOKKU_APP_WEB_LISTENERS"] = ""
out := renderTemplate(t, v)
mustContain(t, out, "return 502;")
mustNotContain(t, out, "proxy_pass http://app-5000;")
}
func TestTemplate_GRPCNoSSL(t *testing.T) {
v := defaultVars()
v["PROXY_PORT_MAP"] = "grpc:50051:50051"
v["PROXY_UPSTREAM_PORTS"] = "50051"
out := renderTemplate(t, v)
mustContain(t, out, "grpc_pass grpc://app-50051;")
mustContain(t, out, "http2")
mustNotContain(t, out, "ssl_certificate")
}
func TestTemplate_GRPCS(t *testing.T) {
v := defaultVars()
v["PROXY_PORT_MAP"] = "grpcs:443:50051"
v["PROXY_UPSTREAM_PORTS"] = "50051"
v["SSL_INUSE"] = "true"
v["SSL_SERVER_NAME"] = "app.example.com"
out := renderTemplate(t, v)
mustContain(t, out, "ssl_certificate /home/dokku/app/tls/server.crt;")
mustContain(t, out, "grpc_pass grpc://app-50051;")
}
func TestTemplate_GRPCSkippedWithoutListeners(t *testing.T) {
v := defaultVars()
v["PROXY_PORT_MAP"] = "grpc:50051:50051"
v["PROXY_UPSTREAM_PORTS"] = "50051"
v["DOKKU_APP_WEB_LISTENERS"] = ""
out := renderTemplate(t, v)
mustNotContain(t, out, "grpc_pass")
mustNotContain(t, out, "server {")
}
func TestTemplate_BindAddressIPv4(t *testing.T) {
v := defaultVars()
v["NGINX_BIND_ADDRESS_IP4"] = "127.0.0.1"
out := renderTemplate(t, v)
mustContain(t, out, "listen 127.0.0.1:80;")
v2 := defaultVars()
out2 := renderTemplate(t, v2)
mustNotContain(t, out2, "listen 127.0.0.1")
mustNotContain(t, out2, ":80;\n listen :80;")
}
func TestTemplate_UpstreamBlock(t *testing.T) {
v := defaultVars()
v["PROXY_PORT_MAP"] = "http:80:5000 http:8080:5001"
v["PROXY_UPSTREAM_PORTS"] = "5000 5001"
v["DOKKU_APP_WEB_LISTENERS"] = "10.0.0.1:5000 10.0.0.2:5000"
out := renderTemplate(t, v)
mustContain(t, out, "upstream app-5000 {")
mustContain(t, out, "upstream app-5001 {")
mustContain(t, out, "server 10.0.0.1:5000;")
mustContain(t, out, "server 10.0.0.2:5000;")
mustContain(t, out, "server 10.0.0.1:5001;")
mustContain(t, out, "server 10.0.0.2:5001;")
}
func TestTemplate_UpstreamWithKeepalive(t *testing.T) {
v := defaultVars()
v["PROXY_KEEPALIVE"] = "16"
out := renderTemplate(t, v)
mustContain(t, out, "keepalive 16;")
v2 := defaultVars()
out2 := renderTemplate(t, v2)
mustNotContain(t, out2, "keepalive 16;")
}
func TestTemplate_AccessLogFormat(t *testing.T) {
v := defaultVars()
v["NGINX_ACCESS_LOG_FORMAT"] = "json"
v["NGINX_ACCESS_LOG_PATH"] = "/var/log/nginx/app-access.log"
out := renderTemplate(t, v)
mustContain(t, out, "access_log /var/log/nginx/app-access.log json;")
v2 := defaultVars()
v2["NGINX_ACCESS_LOG_FORMAT"] = "json"
v2["NGINX_ACCESS_LOG_PATH"] = "off"
out2 := renderTemplate(t, v2)
mustContain(t, out2, "access_log off;")
mustNotContain(t, out2, "access_log off json;")
}
func TestTemplate_XForwardedSSL(t *testing.T) {
v := defaultVars()
v["PROXY_X_FORWARDED_SSL"] = "on"
out := renderTemplate(t, v)
mustContain(t, out, "proxy_set_header X-Forwarded-Ssl on;")
v2 := defaultVars()
out2 := renderTemplate(t, v2)
mustNotContain(t, out2, "X-Forwarded-Ssl")
}
func TestTemplate_NginxConfDIncludeAlways(t *testing.T) {
cases := []struct {
name string
mutate func(map[string]interface{})
}{
{"http", func(v map[string]interface{}) {}},
{"http_redirect", func(v map[string]interface{}) {
v["PROXY_PORT_MAP"] = "http:80:5000 https:443:5000"
v["SSL_INUSE"] = "true"
v["SSL_SERVER_NAME"] = "app.example.com"
}},
{"grpc", func(v map[string]interface{}) {
v["PROXY_PORT_MAP"] = "grpc:50051:50051"
v["PROXY_UPSTREAM_PORTS"] = "50051"
}},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
v := defaultVars()
tc.mutate(v)
out := renderTemplate(t, v)
mustContain(t, out, "include /home/dokku/app/nginx.conf.d/*.conf;")
})
}
}

View File

@@ -4,10 +4,24 @@
{{ $listen_port := index $port_map_list 1 }}
{{ $upstream_port := index $port_map_list 2 }}
{{ if eq $scheme "http" }}
{{ if or (eq $scheme "http") (eq $scheme "https") }}
{{ $is_ssl := eq $scheme "https" }}
{{ $is_redirect := and (not $is_ssl) (eq $listen_port "80") $.SSL_INUSE }}
server {
{{ if $is_ssl }}
{{ if eq $.HTTP2_DIRECTIVE_SUPPORTED "true" }}
listen [{{ $.NGINX_BIND_ADDRESS_IP6 }}]:{{ $listen_port }} ssl;
listen {{ if $.NGINX_BIND_ADDRESS_IP4 }}{{ $.NGINX_BIND_ADDRESS_IP4 }}:{{end}}{{ $listen_port }} ssl;
http2 on;
{{ else }}
listen [{{ $.NGINX_BIND_ADDRESS_IP6 }}]:{{ $listen_port }} ssl http2;
listen {{ if $.NGINX_BIND_ADDRESS_IP4 }}{{ $.NGINX_BIND_ADDRESS_IP4 }}:{{end}}{{ $listen_port }} ssl http2;
{{ end }}
{{ else }}
listen [{{ $.NGINX_BIND_ADDRESS_IP6 }}]:{{ $listen_port }};
listen {{ if $.NGINX_BIND_ADDRESS_IP4 }}{{ $.NGINX_BIND_ADDRESS_IP4 }}:{{end}}{{ $listen_port }};
{{ end }}
{{ if and $is_ssl $.SSL_SERVER_NAME }}server_name {{ $.SSL_SERVER_NAME }}; {{ end }}
{{ if $.NOSSL_SERVER_NAME }}server_name {{ $.NOSSL_SERVER_NAME }}; {{ end }}
access_log {{ $.NGINX_ACCESS_LOG_PATH }}{{ if and ($.NGINX_ACCESS_LOG_FORMAT) (ne $.NGINX_ACCESS_LOG_PATH "off") }} {{ $.NGINX_ACCESS_LOG_FORMAT }}{{ end }};
error_log {{ $.NGINX_ERROR_LOG_PATH }};
@@ -19,7 +33,14 @@ server {
lingering_timeout {{ $.LINGERING_TIMEOUT }};
send_timeout {{ $.SEND_TIMEOUT }};
{{ if (and (eq $listen_port "80") ($.SSL_INUSE)) }}
{{ if $is_ssl }}
ssl_certificate {{ $.APP_SSL_PATH }}/server.crt;
ssl_certificate_key {{ $.APP_SSL_PATH }}/server.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;
{{ end }}
{{ if $is_redirect }}
include {{ $.DOKKU_ROOT }}/{{ $.APP }}/nginx.conf.d/*.conf;
location / {
return 301 https://$host:{{ $.PROXY_SSL_PORT }}$request_uri;
@@ -36,6 +57,7 @@ server {
gzip_comp_level 6;
proxy_pass http://{{ $.APP }}-{{ $upstream_port }};
{{ if and $is_ssl (eq $.HTTP2_PUSH_SUPPORTED "true") }}http2_push_preload on; {{ end }}
proxy_http_version 1.1;
proxy_connect_timeout {{ $.PROXY_CONNECT_TIMEOUT }};
proxy_read_timeout {{ $.PROXY_READ_TIMEOUT }};
@@ -71,144 +93,49 @@ server {
internal;
}
error_page 500 501 502 503 504 505 506 507 508 509 510 511 /500-error.html;
location /500-error.html {
root {{ $.DOKKU_LIB_ROOT }}/data/nginx-vhosts/dokku-errors;
internal;
}
include {{ $.DOKKU_ROOT }}/{{ $.APP }}/nginx.conf.d/*.conf;
{{ end }}
}
{{ else if eq $scheme "https"}}
server {
{{ if eq $.HTTP2_DIRECTIVE_SUPPORTED "true" }}
listen [{{ $.NGINX_BIND_ADDRESS_IP6 }}]:{{ $listen_port }} ssl;
listen {{ if $.NGINX_BIND_ADDRESS_IP4 }}{{ $.NGINX_BIND_ADDRESS_IP4 }}:{{end}}{{ $listen_port }} ssl;
http2 on;
{{ else }}
listen [{{ $.NGINX_BIND_ADDRESS_IP6 }}]:{{ $listen_port }} ssl http2;
listen {{ if $.NGINX_BIND_ADDRESS_IP4 }}{{ $.NGINX_BIND_ADDRESS_IP4 }}:{{end}}{{ $listen_port }} ssl http2;
{{ end }}
{{ if $.SSL_SERVER_NAME }}server_name {{ $.SSL_SERVER_NAME }}; {{ end }}
{{ if $.NOSSL_SERVER_NAME }}server_name {{ $.NOSSL_SERVER_NAME }}; {{ end }}
access_log {{ $.NGINX_ACCESS_LOG_PATH }}{{ if and ($.NGINX_ACCESS_LOG_FORMAT) (ne $.NGINX_ACCESS_LOG_PATH "off") }} {{ $.NGINX_ACCESS_LOG_FORMAT }}{{ end }};
error_log {{ $.NGINX_ERROR_LOG_PATH }};
underscores_in_headers {{ $.NGINX_UNDERSCORE_IN_HEADERS }};
ssl_certificate {{ $.APP_SSL_PATH }}/server.crt;
ssl_certificate_key {{ $.APP_SSL_PATH }}/server.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;
client_body_timeout {{ $.CLIENT_BODY_TIMEOUT }};
client_header_timeout {{ $.CLIENT_HEADER_TIMEOUT }};
keepalive_timeout {{ $.KEEPALIVE_TIMEOUT }};
lingering_timeout {{ $.LINGERING_TIMEOUT }};
send_timeout {{ $.SEND_TIMEOUT }};
location / {
{{ if $.DOKKU_APP_WEB_LISTENERS }}
gzip on;
gzip_min_length 1100;
gzip_buffers 4 32k;
gzip_types text/css text/javascript text/xml text/plain text/x-component application/javascript application/x-javascript application/json application/graphql-response+json application/xml application/rss+xml font/truetype application/x-font-ttf font/opentype application/vnd.ms-fontobject image/svg+xml;
gzip_vary on;
gzip_comp_level 6;
proxy_pass http://{{ $.APP }}-{{ $upstream_port }};
{{ if eq $.HTTP2_PUSH_SUPPORTED "true" }}http2_push_preload on; {{ end }}
proxy_http_version 1.1;
proxy_connect_timeout {{ $.PROXY_CONNECT_TIMEOUT }};
proxy_read_timeout {{ $.PROXY_READ_TIMEOUT }};
proxy_send_timeout {{ $.PROXY_SEND_TIMEOUT }};
proxy_buffer_size {{ $.PROXY_BUFFER_SIZE }};
proxy_buffering {{ $.PROXY_BUFFERING }};
proxy_buffers {{ $.PROXY_BUFFERS }};
proxy_busy_buffers_size {{ $.PROXY_BUSY_BUFFERS_SIZE }};
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $http_connection;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For {{ $.PROXY_X_FORWARDED_FOR }};
proxy_set_header X-Forwarded-Port {{ $.PROXY_X_FORWARDED_PORT }};
proxy_set_header X-Forwarded-Proto {{ $.PROXY_X_FORWARDED_PROTO }};
proxy_set_header X-Request-Start $msec;
{{ if $.PROXY_X_FORWARDED_SSL }}proxy_set_header X-Forwarded-Ssl {{ $.PROXY_X_FORWARDED_SSL }};{{ end }}
{{ else }}
return 502;
{{ end }}
}
client_max_body_size {{ $.CLIENT_MAX_BODY_SIZE }};
error_page 400 401 402 403 405 406 407 408 409 410 411 412 413 414 415 416 417 418 420 422 423 424 426 428 429 431 444 449 450 451 /400-error.html;
location /400-error.html {
root {{ $.DOKKU_LIB_ROOT }}/data/nginx-vhosts/dokku-errors;
internal;
}
error_page 404 /404-error.html;
location /404-error.html {
root {{ $.DOKKU_LIB_ROOT }}/data/nginx-vhosts/dokku-errors;
internal;
}
{{ if $is_ssl }}
error_page 500 501 503 504 505 506 507 508 509 510 511 /500-error.html;
{{ else }}
error_page 500 501 502 503 504 505 506 507 508 509 510 511 /500-error.html;
{{ end }}
location /500-error.html {
root {{ $.DOKKU_LIB_ROOT }}/data/nginx-vhosts/dokku-errors;
internal;
}
{{ if $is_ssl }}
error_page 502 /502-error.html;
location /502-error.html {
root {{ $.DOKKU_LIB_ROOT }}/data/nginx-vhosts/dokku-errors;
internal;
}
include {{ $.DOKKU_ROOT }}/{{ $.APP }}/nginx.conf.d/*.conf;
}
{{ else if eq $scheme "grpc"}}
{{ if $.DOKKU_APP_WEB_LISTENERS }}
server {
{{ if eq $.HTTP2_DIRECTIVE_SUPPORTED "true" }}
listen [{{ $.NGINX_BIND_ADDRESS_IP6 }}]:{{ $listen_port }};
listen {{ if $.NGINX_BIND_ADDRESS_IP4 }}{{ $.NGINX_BIND_ADDRESS_IP4 }}:{{end}}{{ $listen_port }};
http2 on;
{{ else }}
listen [{{ $.NGINX_BIND_ADDRESS_IP6 }}]:{{ $listen_port }} http2;
listen {{ if $.NGINX_BIND_ADDRESS_IP4 }}{{ $.NGINX_BIND_ADDRESS_IP4 }}:{{end}}{{ $listen_port }} http2;
{{ end }}
{{ if $.NOSSL_SERVER_NAME }}server_name {{ $.NOSSL_SERVER_NAME }}; {{ end }}
access_log {{ $.NGINX_ACCESS_LOG_PATH }}{{ if and ($.NGINX_ACCESS_LOG_FORMAT) (ne $.NGINX_ACCESS_LOG_PATH "off") }} {{ $.NGINX_ACCESS_LOG_FORMAT }}{{ end }};
error_log {{ $.NGINX_ERROR_LOG_PATH }};
underscores_in_headers {{ $.NGINX_UNDERSCORE_IN_HEADERS }};
location / {
grpc_pass grpc://{{ $.APP }}-{{ $upstream_port }};
}
client_max_body_size {{ $.CLIENT_MAX_BODY_SIZE }};
include {{ $.DOKKU_ROOT }}/{{ $.APP }}/nginx.conf.d/*.conf;
}
{{ end }}
{{ else if eq $scheme "grpcs"}}
}
{{ else if or (eq $scheme "grpc") (eq $scheme "grpcs") }}
{{ if $.DOKKU_APP_WEB_LISTENERS }}
{{ $is_ssl := eq $scheme "grpcs" }}
server {
{{ if eq $.HTTP2_DIRECTIVE_SUPPORTED "true" }}
listen [{{ $.NGINX_BIND_ADDRESS_IP6 }}]:{{ $listen_port }} ssl;
listen {{ if $.NGINX_BIND_ADDRESS_IP4 }}{{ $.NGINX_BIND_ADDRESS_IP4 }}:{{end}}{{ $listen_port }} ssl;
listen [{{ $.NGINX_BIND_ADDRESS_IP6 }}]:{{ $listen_port }}{{ if $is_ssl }} ssl{{ end }};
listen {{ if $.NGINX_BIND_ADDRESS_IP4 }}{{ $.NGINX_BIND_ADDRESS_IP4 }}:{{end}}{{ $listen_port }}{{ if $is_ssl }} ssl{{ end }};
http2 on;
{{ else }}
listen [{{ $.NGINX_BIND_ADDRESS_IP6 }}]:{{ $listen_port }} ssl http2;
listen {{ if $.NGINX_BIND_ADDRESS_IP4 }}{{ $.NGINX_BIND_ADDRESS_IP4 }}:{{end}}{{ $listen_port }} ssl http2;
listen [{{ $.NGINX_BIND_ADDRESS_IP6 }}]:{{ $listen_port }}{{ if $is_ssl }} ssl{{ end }} http2;
listen {{ if $.NGINX_BIND_ADDRESS_IP4 }}{{ $.NGINX_BIND_ADDRESS_IP4 }}:{{end}}{{ $listen_port }}{{ if $is_ssl }} ssl{{ end }} http2;
{{ end }}
{{ if $.NOSSL_SERVER_NAME }}server_name {{ $.NOSSL_SERVER_NAME }}; {{ end }}
access_log {{ $.NGINX_ACCESS_LOG_PATH }}{{ if and ($.NGINX_ACCESS_LOG_FORMAT) (ne $.NGINX_ACCESS_LOG_PATH "off") }} {{ $.NGINX_ACCESS_LOG_FORMAT }}{{ end }};
error_log {{ $.NGINX_ERROR_LOG_PATH }};
underscores_in_headers {{ $.NGINX_UNDERSCORE_IN_HEADERS }};
{{ if $is_ssl }}
ssl_certificate {{ $.APP_SSL_PATH }}/server.crt;
ssl_certificate_key {{ $.APP_SSL_PATH }}/server.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;
{{ end }}
location / {
grpc_pass grpc://{{ $.APP }}-{{ $upstream_port }};

View File

@@ -0,0 +1,71 @@
#!/usr/bin/env bats
load test_helper
setup_local_tls() {
TLS=$BATS_TMPDIR/tls
mkdir -p $TLS
tar xf $BATS_TEST_DIRNAME/server_ssl.tar -C $TLS
tar xf $BATS_TEST_DIRNAME/domain_ssl.tar -C $TLS
sudo chown -R dokku:dokku $TLS
}
teardown_local_tls() {
TLS=$BATS_TMPDIR/tls
rm -R $TLS
}
setup() {
global_setup
[[ -f "$DOKKU_ROOT/VHOST" ]] && cp -fp "$DOKKU_ROOT/VHOST" "$DOKKU_ROOT/VHOST.bak"
create_app
}
teardown() {
destroy_app
[[ -f "$DOKKU_ROOT/VHOST.bak" ]] && mv "$DOKKU_ROOT/VHOST.bak" "$DOKKU_ROOT/VHOST" && chown dokku:dokku "$DOKKU_ROOT/VHOST"
global_teardown
}
@test "(nginx-vhosts) refactored template generates nginx -t parseable http config" {
run deploy_app
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "test -f $DOKKU_ROOT/$TEST_APP/nginx.conf"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "sudo nginx -t"
echo "output: $output"
echo "status: $status"
assert_success
}
@test "(nginx-vhosts) refactored template generates nginx -t parseable https config" {
setup_local_tls
run deploy_app
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku certs:add $TEST_APP $BATS_TMPDIR/tls/server.crt $BATS_TMPDIR/tls/server.key"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "sudo nginx -t"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku nginx:show-config $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "ssl_certificate" -1
assert_output_contains "return 301 https" -1
teardown_local_tls
}