Startup failures
The application container applies its migrations and then serves, and it takes itself down rather
than answer against a schema or a configuration it does not match. Docker restarts it, so a stack
that is misconfigured still looks alive: docker compose ps goes on reporting the app as Up, with
its health check starting, because the container never lives long enough to fail one.
The status is not the signal, the log is:
docker compose logs app | tail -30Two failures that never reach that log
Section titled “Two failures that never reach that log”A stack whose .env still has an empty secret does not even get there: docker compose up refuses
to interpolate the file and prints required variable SECRET_ENCRYPTION_KEY is missing a value: empty in .env; fill it with openssl rand -base64 32. It names every empty variable in one pass
rather than one per run, so a .env copied and not edited prints all three at once, and
POSTGRES_PASSWORD twice because both services read it. Fill them and run the command again;
nothing is built until they are all there.
A port already taken stops just as early. docker compose up builds the image, starts the database,
then prints failed to bind host port 0.0.0.0:8080/tcp: address already in use and stops there. The
application container was created but never started, so docker compose logs app prints nothing at
all and docker compose ps shows the database alone. Set WEB_PORT in .env to a free port, move
PUBLIC_URL to the same one, and run the command again.
The half-started stack that follows
Section titled “The half-started stack that follows”That last failure leaves a stack half up, and nothing says so. Compose starts the database first and the application after it, and it does not take the first back down when the second will not start: the command exits 1 having named only the container it stopped on, and the database goes on running.
docker compose ps # what survived the failure: the database, without the appThe application container survives too, and in a state worth knowing about. It was created and never
started, and what failed was Docker attaching it to the network, so it is attached to none. Compose
starts a container it has already created rather than building it again, so freeing the port by hand
and repeating the same up starts that one: it comes up with no route to the database and loops on
P1001: Can't reach database server at db:5432 while the database is running beside it.
Changing WEB_PORT and PUBLIC_URL avoids that, because an edit to .env is what makes compose
replace the container. Freeing the port instead means clearing the half-started stack first:
docker compose down # containers and network gone; the volume and its data are not touchedOnly down -v deletes what the database holds.
Five lines in the log
Section titled “Five lines in the log”| What the log says | What it means |
|---|---|
Invalid environment configuration: |
a variable is missing or malformed; the line under it names which one and what to run |
SECRET_ENCRYPTION_KEY: must be 32 bytes base64-encoded |
openssl rand -hex 32 decodes to 48 bytes, not 32; that key wants openssl rand -base64 32 |
DATABASE_URL: is not a valid connection URL |
POSTGRES_PASSWORD holds a /, a ? or a #, which the connection URL reads as its own |
P1001: Can't reach database server |
the database was not up yet, usually after a reboot; the restart clears it within seconds |
P1000: Authentication failed against database server |
POSTGRES_PASSWORD was changed after the first start; the database still holds the old one |
Putting the old password back is the way out of that last one.