diff --git a/docs/configuration/ssl.md b/docs/configuration/ssl.md index c24e6cbed..4bf3550cd 100644 --- a/docs/configuration/ssl.md +++ b/docs/configuration/ssl.md @@ -143,6 +143,8 @@ Certain versions of nginx have bugs that prevent [HTTP/2](https://nginx.org/en/d When your app is served from port `80` then the `/home/dokku/APP/nginx.conf` file will automatically be updated to instruct nginx to respond to ssl on port 443 as a new cert is added. If your app uses a non-standard port (perhaps you have a dockerfile deploy exposing port `99999`) you may need to manually expose an ssl port via `dokku ports:add https:443:99999`. +If an `https:443:*` port mapping already exists when a certificate is installed or renewed, Dokku will preserve it rather than rewriting it from the `http:80:*` mappings. This allows apps that terminate TLS inside the container (for example, with a configuration like `http:80:80 https:443:443`) to keep their explicit mapping across `dokku certs:add` and unattended renewals. + ## Other ### Running behind a proxy (`X-Forwarded-Ssl`, etc.) diff --git a/plugins/ports/triggers.go b/plugins/ports/triggers.go index 8d6ce6cd7..9596ae174 100644 --- a/plugins/ports/triggers.go +++ b/plugins/ports/triggers.go @@ -176,6 +176,12 @@ func TriggerPostCertsUpdate(appName string) error { common.PropertyDelete("proxy", appName, "proxy-ssl-port") } + for _, portMap := range portMaps { + if portMap.Scheme == "https" && portMap.HostPort == 443 { + return nil + } + } + var http80Ports []PortMap for _, portMap := range portMaps { if portMap.Scheme == "http" && portMap.HostPort == 80 { @@ -186,17 +192,6 @@ func TriggerPostCertsUpdate(appName string) error { http80Ports = uniquePortMaps(http80Ports) if len(http80Ports) > 0 { - var https443Ports []PortMap - for _, portMap := range portMaps { - if portMap.Scheme == "https" && portMap.HostPort == 443 { - https443Ports = append(https443Ports, portMap) - } - } - - if err := removePortMaps(appName, https443Ports); err != nil { - return err - } - var toAdd []PortMap for _, portMap := range http80Ports { toAdd = append(toAdd, PortMap{ diff --git a/tests/unit/certs.bats b/tests/unit/certs.bats index d0df07235..d5897ffbb 100644 --- a/tests/unit/certs.bats +++ b/tests/unit/certs.bats @@ -87,6 +87,40 @@ teardown() { assert_success } +@test "(certs:add) preserves explicit https:443 port mapping" { + run /bin/bash -c "dokku ports:set $TEST_APP http:80:80 https:443:443" + 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 "dokku --quiet ports:report $TEST_APP --ports-map" + echo "output: $output" + echo "status: $status" + assert_output "http:80:80 https:443:443" +} + +@test "(certs:add) adds default https:443 mapping when none exists" { + run /bin/bash -c "dokku ports:set $TEST_APP http:80:5000" + 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 "dokku --quiet ports:report $TEST_APP --ports-map" + echo "output: $output" + echo "status: $status" + assert_output "http:80:5000 https:443:5000" +} + @test "(certs) certs:add with multiple dots in the filename" { run /bin/bash -c "dokku certs:add $TEST_APP $BATS_TMPDIR/tls/domain.com.crt $BATS_TMPDIR/tls/domain.com.key" echo "output: $output"