Skip to content

postiz: backend dies on host boot — depends_on ordering is ignored by Docker restart policies #134

Description

@pofallon

Summary

After a host reboot, the postiz container comes up but its backend (pm2 process on :3000) is dead, leaving nginx to 502 every /api call. The container's healthcheck correctly reports unhealthy, but nothing acts on it, so the app stays broken until someone manually restarts the container.

Root cause is not the package's compose file — it's that depends_on ordering is silently discarded on boot.

Observed

Seen on a Proxmox LXC host reboot (hola, 18 containers). Immediately after boot:

hola-postiz-4520f878-postiz-1   unhealthy   fails=9

Backend logs:

2|backend | [ioredis] Unhandled error event: Error: getaddrinfo ENOTFOUND postiz-redis
2|backend |     at GetAddrInfoReqWrap.onlookupall [as oncomplete] (node:dns:122:26)

and nginx, continuously:

[error] connect() failed (111: Connection refused) while connecting to upstream,
        upstream: "http://127.0.0.1:3000/auth/can-register"

Once things settled, redis was fine and DNS resolved — the failure was purely a startup race that the backend never recovered from:

ENOTFOUND count in last 3 min:      0
dns.lookup("postiz-redis")       -> OK 172.28.0.2
redis-cli ping                   -> PONG
GET http://127.0.0.1:3000/       -> ECONNREFUSED     <-- backend still dead

docker restart hola-postiz-4520f878-postiz-1 fixed it permanently: healthy, backend HTTP 200.

Root cause

src/postiz/src/compose.yaml already declares the dependency correctly:

depends_on:
  postiz-postgres: { condition: service_healthy }
  postiz-redis:    { condition: service_healthy }
  temporal:        { condition: service_healthy }

and this survives into the runtime container labels:

com.docker.compose.depends_on=temporal:service_healthy:false,
                              postiz-postgres:service_healthy:false,
                              postiz-redis:service_healthy:false

But depends_on is only evaluated by docker compose up. It is metadata; the Docker daemon does not read it. On boot:

restart policy:  unless-stopped   (every container)
enabled units:   docker.service, docker.socket — nothing runs `docker compose up`

dockerd restarts all containers concurrently in arbitrary order. postiz beats redis, ioredis throws on an unresolvable host during NestJS init, the backend pm2 process dies, and pm2 does not bring it back. The frontend and nginx come up fine, so the container stays "running" while /api is dead.

This affects every multi-service package in this repo, not just postiz — any package relying on depends_on for ordering has no ordering guarantee across a host reboot. postiz is just the most fragile because its backend crashes rather than retries.

Suggested fixes

Roughly in increasing order of effort:

  1. Autoheal (cheapest, highest value). Run a small autoheal sidecar that restarts containers reporting unhealthy. The healthchecks in this repo are already accurate — postiz's deliberately probes /api/auth/can-register through nginx specifically to catch a dead backend (per the comment in compose.yaml). That healthcheck correctly detected this outage; nothing was listening. This turns an existing, working signal into an automatic recovery and fixes the whole class of problem for all packages.

  2. Bring deployments up with compose on boot. Set restart: "no" (or on-failure) and have the runtime run docker compose up -d --wait per deployment at startup. This makes depends_on: service_healthy actually mean something. Likely belongs in the Hola runtime rather than here — see note below.

  3. Make postiz tolerate an absent redis at boot. ioredis supports retryStrategy/lazyConnect; the crash comes from an unhandled error event during init. This is upstream gitroomhq/postiz-app, so probably out of scope here except as a wrapper/entrypoint workaround.

Note on repo scope

Filing here since src/postiz/src/compose.yaml is the artifact that exhibits it, but the actual defect is in boot-time orchestration, and that may live in the Hola runtime (try-hola/hola) rather than in this package repo. The package's compose file is, as far as I can tell, already correct. Feel free to move or split this — fix (1) in particular is a runtime-level concern.

Environment

  • Host: Proxmox VE 9.1.11, LXC guest hola (unprivileged), 18 containers
  • Docker 29.6.1, containerd image store, overlayfs storage driver
  • postiz v2.21.10, redis 7.4-alpine, temporal 1.29.7
  • Surfaced during a storage migration that required a clean stop/start of the guest

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions