Merge pull request #8546 from dokku/simpler-nginx-conf-sigil
Consolidate nginx.conf.sigil server blocks
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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=
|
||||
|
||||
291
plugins/nginx-vhosts/template_test.go
Normal file
291
plugins/nginx-vhosts/template_test.go
Normal 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;")
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -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 }};
|
||||
|
||||
71
tests/unit/nginx-vhosts_16.bats
Normal file
71
tests/unit/nginx-vhosts_16.bats
Normal 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
|
||||
}
|
||||
Reference in New Issue
Block a user