Troubleshooting & FAQ
Fix the common problems — 502s, stuck certificates, failed deploys, offline nodes, license grace — with the exact command to run.
Troubleshooting & FAQ
Most problems have a known cause and a one-line fix. Start with hostssh doctor on the box — it's
a non-destructive preflight that usually tells you exactly what's wrong before you change anything.
$ hostssh doctor
The named guards (G1, G8, G10…) below are the failures we've hit and permanently fixed forward, so
they either can't recur or have a clear remedy. Developers can read the full catalog in
docs/dev/build-guards.md.
Home / office Nodes (no public IP)
The box joined the fleet but I cannot reach an app on it
Cause: the agent is pull-only. A residential/CGNAT Node heartbeats without inbound ports;
publishing an app needs a Cloudflare Tunnel. Fix: hostssh doctor — if reachability says
private/CGNAT and cloudflared is warn, follow tunnel-first join
(cloudflared + HOSTSSH_CF_TUNNEL + cloudflared.service).
Deploys
My app 502s right after deploy — "connection refused" {#g1}
Cause (G1): a Next.js-style server bound to an IPv6-only address because HOSTNAME wasn't set.
Status: HostSSH now injects HOSTNAME=0.0.0.0 for web apps by default, and the deploy's HTTP
readiness gate fails a bad bind instead of shipping it. If you still see this, make sure you're not
overriding HOSTNAME yourself, and set a --readiness-path so the gate can catch it.
My app was up, then started 502ing later {#g2}
Cause (G2): the process died but the container's PID 1 stayed alive, so nothing restarted it.
Status: every deployed app gets a health check and a restart policy; a dead listener is
detected and restarted automatically. If it keeps flapping, the app itself is crashing — check
hostssh logs <app> --follow.
A redeploy lost my environment variables {#g3}
Cause (G3): env stored on the container instead of the platform. Status: env lives on the App row in the control plane and is injected into every deploy, so it survives redeploys. Edit it in App Settings → Environment Variables. If a value is missing, it was never saved — re-add it there.
A redeploy only shipped one file / reverted other pages {#g4}
Cause (G4): a stored-Dockerfile / surgical-overlay deploy (a Coolify pattern). Status: HostSSH always deploys from source — no overlay deploys. Commit your full build recipe to the repo.
My deploy failed and took the site down
It shouldn't — a failed gate rolls back to your previous version automatically (G8). If your
site is down after a failed deploy, the previous version was already broken, or the app has no
prior good version. Check hostssh logs <app> and redeploy a known-good ref.
My Dockerfile build fails on an env check {#g11}
Cause (G11): your build step (e.g. a Next.js env:check) validates environment at build
time, but the values are only in the runtime env, or your .dockerignore strips the env file.
Fix: pass --env/--env-file on the deploy, and make sure .dockerignore doesn't exclude the
env file the build needs. Use the hostpack builder if you'd rather not manage this.
Domains & certificates
My certificate is self-signed / the browser warns {#g10}
Cause (G10): the ACME challenge can't validate. Either DNS isn't pointing at the box yet (HTTP-01 can't answer), or you're using DNS-01 without a token configured. Fix:
- Confirm the domain's
Arecord points at this Node's IP. - Then clear the stuck backoff:
The cert issues in ~10–30s. For zero-downtime cutovers, configure DNS-01 so the cert issues before DNS points at the box.$ hostssh proxy up --force
My domain doesn't resolve / times out
Check the A record points at the Node, ports 80/443 are open (hostssh firewall status), and the
managed proxy is running (hostssh proxy status).
Nodes & the fleet
A Node shows as offline / degraded
It stopped heartbeating (degraded >3 min, offline >15 min). Check the box is up, the
hostssh-agent service is running (systemctl status hostssh-agent), and it can reach the control
plane. hostssh doctor diagnoses the wiring.
A Node reads as a "dead box" with 0% everywhere {#g9}
Cause (G9): a node with no Agent (or a very stale one) has no metrics to show. Status: the fleet now shows "—" for unknown values instead of a misleading 0%. Install/update the Agent to get real telemetry.
Disk is filling up
Open the Fleet drawer's disk panel and run cleanup (preview first). It safely reclaims old images and build cache without touching your data. See Monitoring & alerts.
Licensing
The Agent says my license is in "grace" or "expired"
The Agent verifies a signed license and keeps an offline grace clock so a brief control-plane outage never takes your box down. If it's drifting toward expired:
- Grace: the control plane was briefly unreachable; it recovers on the next successful refresh.
- Expired: re-activate with
hostssh license activate --key HSSH-…, or check that the Agent has the license public key configured (a dev build without the embedded key can't verify refreshes). See Licensing.
A gated command exits with code 12
That command (deploy, db, proxy, the agent daemon, …) needs an active license. Recovery
commands (capture, restore, status, doctor, firewall) are never gated — you can always
get your data out. Activate a license to restore full function.
Secrets & databases
My app can't reach its database
Use the private Mesh address in DATABASE_URL (e.g. 10.10.0.2:5432), not a public IP, and
confirm the Mesh peer is healthy on the Mesh page. If you see auth errors (Postgres 28P01), make
sure the connection targets the canonical database container, not a stray one.
My secret value shows as masked / empty
That's correct — secret values are sealed and never displayed. To change one, edit it in App
Settings and redeploy. If the app behaves as though the value is empty, confirm the Agent has
HOSTSSH_ENC_KEY set (it needs the key to open sealed envelopes).
Getting help
hostssh doctorfirst — it explains most problems without changing anything.hostssh logs <app> --followfor app-level crashes.- The Audit log (
hostssh audit) shows what actions ran and verifies the chain wasn't tampered with. - If something contradicts these docs, that's a bug — the docs track the product commit by commit.