diff --git a/docs/appendices/0.38.0-migration-guide.md b/docs/appendices/0.38.0-migration-guide.md index 54c298c5e..46940ecf2 100644 --- a/docs/appendices/0.38.0-migration-guide.md +++ b/docs/appendices/0.38.0-migration-guide.md @@ -15,7 +15,7 @@ } ``` -- The path on disk to both the global `ENV` file and app `ENV` files have been moved. Users should reference environment variables via the provided plugin triggers rather than directly sourcing the ENV files. Existing ENV files are merged into the new location and removed once they have been drained. **Changed in 0.38.26:** removal previously happened on the subsequent Dokku install for app ENV files, and never happened at all for the global ENV file. **Changed in 0.38.27:** an ENV file found at the old path after its migration has been recorded is never merged into the new location, because the new location holds every change made since. Such a file is removed when its values agree with the current config, and otherwise moved aside to `ENV.migrated` with the keys it disagrees on named in a warning, so its values can still be applied by hand with `dokku config:set`. +- The path on disk to both the global `ENV` file and app `ENV` files have been moved. Users should reference environment variables via the provided plugin triggers rather than directly sourcing the ENV files. Existing ENV files are merged into the new location and removed once they have been drained. **Changed in 0.38.26:** removal previously happened on the subsequent Dokku install for app ENV files, and never happened at all for the global ENV file. **Changed in 0.38.27:** an ENV file found at the old path after its migration has been recorded is never merged into the new location, because the new location holds every change made since. Such a file is removed when its values agree with the current config, and otherwise moved aside to `ENV.migrated` with the keys it disagrees on named in a warning, so its values can still be applied by hand with `dokku config:set`. That copy is left for review and should be deleted afterwards: Dokku no longer reads it, and it holds everything it was not allowed to import - including keys that were unset on purpose, which for a revoked secret means a copy lingering on disk. - During a fresh apt install, the upstream nginx default vhost files (`/etc/nginx/sites-enabled/default`, `/etc/nginx/sites-available/default`, and `/etc/nginx/conf.d/default.conf`) are renamed to `${path}.dokku-disabled` (not deleted) to avoid a `duplicate default server for 0.0.0.0:80` error. Operators with local customizations can recover them by inspecting the `.dokku-disabled` siblings. Upgrade-in-place installs do not touch any existing nginx files. - Fresh apt installs now ship a catch-all default site at `/etc/nginx/conf.d/00-default-vhost.conf` that rejects requests with unknown Host headers using `ssl_reject_handshake on` (HTTPS) and `return 444` (HTTP). This replaces the manual workaround previously documented in the nginx docs. The behavior can be opted out at install time via the `dokku/install_default_site` debconf prompt. On nginx older than 1.19.4 (e.g., Debian Bullseye's nginx 1.18.0), the postinst installs an HTTP-only variant of the catch-all that omits the SSL listener and `ssl_reject_handshake`, since that directive is unsupported on those versions. See the [Default site documentation](/docs/networking/proxies/nginx.md#default-site). - The `docker-local` scheduler now sends `SIGTERM` to old containers immediately after a successful deploy, rather than waiting `wait-to-retire` seconds before signaling. This matches Heroku's graceful-shutdown contract and lets applications begin draining in-flight work as soon as proxy traffic switches. The `wait-to-retire` grace period and `stop-timeout-seconds` hard-stop continue to apply as before. See the [zero downtime deploys documentation](/docs/deployment/zero-downtime-deploys.md#wait-to-retire) for more details. diff --git a/docs/configuration/environment-variables.md b/docs/configuration/environment-variables.md index d012886d2..f294098d3 100644 --- a/docs/configuration/environment-variables.md +++ b/docs/configuration/environment-variables.md @@ -151,4 +151,4 @@ The following property is recorded internally by the config plugin and is not ex | Property | Description | Source | |---|---|---| -| `env-migrated` | Migration sentinel that records that the per-app or global `ENV` file has been drained out of its pre-0.38.0 location into the config path. The drain happens once: a file found at the old path once this is recorded is never imported, since the config path holds every change made since. Such a file is removed when it agrees with the current config, and otherwise moved aside to `ENV.migrated` with the keys it disagrees on named in a warning | `plugins/config/migrate.go` writes `"true"` once the file has been drained | +| `env-migrated` | Migration sentinel that records that the per-app or global `ENV` file has been drained out of its pre-0.38.0 location into the config path. The drain happens once: a file found at the old path once this is recorded is never imported, since the config path holds every change made since. Such a file is removed when it agrees with the current config, and otherwise moved aside to `ENV.migrated` with the keys it disagrees on named in a warning. The preserved copy is left for review and should be deleted afterwards, since it holds keys that were unset on purpose | `plugins/config/migrate.go` writes `"true"` once the file has been drained | diff --git a/plugins/config/migrate.go b/plugins/config/migrate.go index 570c25efe..588f8761b 100644 --- a/plugins/config/migrate.go +++ b/plugins/config/migrate.go @@ -139,6 +139,11 @@ func drainLegacyEnvFile(name string, oldEnvFile string, env *Env) error { // otherwise it is moved alongside itself with a .migrated suffix and the keys it // disagrees on are named, so an operator who did write it by hand can still // recover the values through `dokku config:set`. +// +// The preserved copy is the operator's to delete. It holds everything the file +// was not allowed to import, which includes keys that were unset on purpose, so +// leaving a revoked secret sitting in a file dokku no longer reads is not what +// anyone wants once its contents have been reviewed. func preserveStaleEnvFile(name string, oldEnvFile string, env *Env) error { staleEnv, err := loadFromFile(name, oldEnvFile) if err != nil { @@ -155,7 +160,7 @@ func preserveStaleEnvFile(name string, oldEnvFile string, env *Env) error { preservedFile := oldEnvFile + ".migrated" common.LogWarn(fmt.Sprintf("Not importing already-migrated ENV file %s: the current config takes precedence for %s", oldEnvFile, strings.Join(diverged, " "))) - common.LogWarn(fmt.Sprintf("Preserved at %s; apply any values still needed with dokku config:set", preservedFile)) + common.LogWarn(fmt.Sprintf("Preserved at %s: re-apply anything still needed with dokku config:set, then delete it - dokku does not read it and it may hold values that were unset on purpose", preservedFile)) if err := os.Rename(oldEnvFile, preservedFile); err != nil { return fmt.Errorf("Unable to preserve stale file %s: %s", oldEnvFile, err.Error()) diff --git a/tests/unit/config.bats b/tests/unit/config.bats index 6273bc498..1f7d9c164 100644 --- a/tests/unit/config.bats +++ b/tests/unit/config.bats @@ -644,6 +644,7 @@ teardown() { assert_success assert_output_contains "the current config takes precedence for KEEP RESURRECTED" assert_output_contains "$DOKKU_ROOT/$TEST_APP/ENV.migrated" + assert_output_contains "then delete it" run /bin/bash -c "dokku config:get $TEST_APP KEEP" echo "output: $output"