Published 2026-10-22 · Reviewed 2026-10-22
A restart policy is not supervision
A restart policy brings a container back after it exits. Supervision is the separate work of noticing the repeats, limiting them, and escalating while the process is still failing.
- home servers
- observability
- recovery
Coming back is the mechanism
Take an invented example, not a real server. One Compose service sets `restart: unless-stopped`. The process exits. If the next status line is read as "the service is fine," it has picked up a job the policy does not have.
Compose applies `restart` when a container terminates. `no`, the default, does not restart it. `always` restarts it until its removal. `on-failure` restarts it when the exit code indicates an error, and the page's examples include `on-failure:3`. `unless-stopped` restarts it whatever the exit code, and stops when the service is stopped or removed. The detail lives in Docker's run reference, which that page cites.
A restart policy brings the process back. Supervision is the separate work of noticing the repeats, limiting them, and escalating while the process is still failing.
Exit, a manual stop, and a daemon restart
A restart policy controls whether the daemon restarts a container after exit. `on-failure` restarts on a non-zero exit, and skips a restart when the daemon itself restarts. `always` restarts the container if it stops; after a manual stop it returns only when the daemon restarts or someone starts it again. `unless-stopped` is similar, except a container stopped manually or otherwise stays stopped across a daemon restart.
Docker recommends a restart policy, and recommends avoiding a process manager to start containers. Where a process manager fits, the start-containers page names systemd and says to have it run `docker start`. Do not combine the two: the page says that creates conflicts.
With a policy active, `docker ps` shows `Up` or `Restarting`. `docker events` shows the policy in effect. `docker inspect` prints `RestartCount`, the attempted restarts, and `State.StartedAt`. The start-containers page shows a foreground container that exits, drops the attached CLI, and is still `Up` afterwards. That sample is Docker's.
The delay slows the retries
Each restart waits, so the daemon does not flood the server. The delay starts at 100 milliseconds and doubles, until an `on-failure` limit, a maximum delay of one minute, or a stop or force-remove. Running for at least 10 seconds resets the delay to 100 milliseconds. A retry ceiling is valid only for `on-failure`. The example `--restart=on-failure:10` stops after more than 10 non-zero exits in a row. By default, Docker never stops attempting to restart the container. Ten is the page's illustration. `always` and `unless-stopped` have no such ceiling.
Interpretation: one minute caps the wait, and those two policies keep trying. The container can read `Up` while `RestartCount` climbs.
The start-containers page uses ten seconds for a different rule: the policy takes effect only once the container has been up for at least 10 seconds under Docker's monitoring, so a container which does not start at all avoids a restart loop.
Running, healthy, and alive
`HEALTHCHECK` tests whether a container is still working. The Dockerfile reference's case is a web server stuck and unable to take connections, even though the process is still running. Health sits beside the normal status: `starting`, then `healthy`, then `unhealthy` after consecutive failures, three by default. Exit status 0 is healthy and 1 is unhealthy, and a change emits a `health_status` event. The restart policy acts after exit. Interpretation: a process that has not exited has not asked for a restart, so `unhealthy` can sit beside `Up`.
A Kubernetes liveness probe is a restart decision. The Pod lifecycle page uses a deadlock as the example: the application is running and making no progress. Past the failure tolerance, the kubelet restarts the container. A failed startup probe kills the container and hands it to the restart policy. A failed readiness probe drops the Pod address from matching EndpointSlices. See a health check is not a recovery plan.
`WatchdogSec=` defaults to 0, off. When set, the service must send `WATCHDOG=1` through `sd_notify` in time. A missed ping fails it and terminates it with `SIGABRT`, or with `WatchdogSignal=`, and `Restart=on-failure`, `on-watchdog`, `on-abnormal`, or `always` starts it again.
systemd can refuse the next start
`Restart=` defaults to `no`. For a long-running service the manual recommends `on-failure`: a non-zero exit, a signal other than the clean-exit signals `SIGHUP`, `SIGINT`, `SIGTERM`, and `SIGPIPE`, an operation timeout, or the watchdog. `always` also restarts a clean exit. A death caused by systemd's own stop or restart does not start the service again. `RestartSec=` defaults to 100 milliseconds. Exponential spacing (`RestartSteps=`, default 0, with `RestartMaxDelaySec=`) arrived in version 254 and stays off until you set it.
More than `StartLimitBurst=` starts inside `StartLimitIntervalSec=` are refused. The defaults are five starts and ten seconds, and manual starts count. Past the limit, automatic restarts wait out the interval. A manual start, a timer, or a socket can proceed once it has passed, and `systemctl reset-failed` clears the counter. `OnFailure=` runs the units you name once the unit is failed. `StartLimitAction=` defaults to `none`. `RestartMode=direct` skips `OnFailure=`; the default, `normal`, keeps it.
Interpretation: the stock window is a process dying more than five times in ten seconds. An exit once a minute never fills it. Judgment: set the window for the failure you mean, and put the notice on `OnFailure=`. Docker's `always` and `unless-stopped` have the delay, and no equivalent hook, on the pages above.
CrashLoopBackOff names the wait
Pod `restartPolicy` defaults to `Always` (any exit). `OnFailure` restarts on a non-zero exit, and `Never` leaves the container stopped. Deployments typically allow only `Always`. After exit the kubelet waits 10 seconds, then 20, then 40, capped at 300 seconds, and resets that timer after 10 minutes without problems. `CrashLoopBackOff` is the kubectl status during the wait. Causes named there include an application exit, a bad configuration, too little CPU or memory, and a failing health, liveness, or startup check. Alpha feature gates on the page can replace the default 10-second start and five-minute cap.
Logs, `kubectl describe pod`, the Pod spec, resource limits, and a run of the image outside the cluster are the page's investigation list. Under `Always` the restarts continue. Judgment: a rising `RestartCount` under an `Up` line is the home-server form of that evidence. `Up` is the latest start. The count is the repeats.
What the mechanism leaves to you
No page cited here sends a message when `RestartCount` rises. `OnFailure=` can run a unit you supply, and what that unit does is yours to define. A restart does not put back work the process lost. That problem is a backup is not a restore plan.
This article was drafted with AI assistance and checked against the cited pages on 22 October 2026. It reports no measured outage, no private incident, and no testimonial.
What we would do next
On one service, write the policy and whether a retry ceiling exists. For Docker the ceiling is `on-failure` only. Record where the repeats show: `RestartCount` and `State.StartedAt`, the systemd failed state, or `CrashLoopBackOff`. Choose the count at which automatic attempts stop and someone reads the exit. That count is a judgment. If systemd owns the service, set the start-limit window for the failure you see, name an `OnFailure=` unit, and leave Docker's restart policy unset, the split the start-containers page asks for. Recovered means one ordinary request succeeds and the count has stopped climbing.
Sources and limits
This article synthesises the sources below into a practical explanation. It is not a security standard, legal advice, or a guarantee that guidance current at review time still applies — check the review date above against your own situation.
- docker container run — Docker. A restart policy controls whether the daemon restarts a container after exit, including the doubling delay, the on-failure retry ceiling, and RestartCount.
- Start containers automatically — Docker. A restart policy applies after a successful start, a manual stop changes daemon-restart behaviour, and Docker warns against combining a restart policy with a host process manager.
- Define services in Docker Compose — Docker. The restart key is the policy applied on container termination, including unless-stopped, always, and on-failure with an optional retry limit.
- Dockerfile reference — Docker. HEALTHCHECK adds a starting, healthy, or unhealthy status beside the container's normal status, including when the process is still running.
- systemd.service — systemd. Restart= selects which exits restart a service, RestartSec= defaults to 100ms, WatchdogSec= requires a keep-alive ping, and direct restart mode skips OnFailure=.
- systemd.unit — systemd. A start limit refuses further starts after too many attempts in an interval, and OnFailure= activates units when the unit enters the failed state.
- systemd-system.conf — systemd. The default start-limit interval is 10 seconds and the default burst is 5.
- Pod Lifecycle — Kubernetes. Documents restartPolicy, the crash-loop backoff and CrashLoopBackOff, liveness restarts, and the page's investigation steps.
More from Server Attic
A health check is not a recovery plan
A practical home-server guide to separating liveness, readiness and restart signals from the human decisions that make recovery safe.
A UPS buys minutes, not a clean shutdown
A UPS keeps the power supply alive for a while. The server still has to hear about the outage, shut down inside the runtime it actually has, and know what "power is back" is supposed to look like.
A passed SMART test is not a healthy disk
A drive that reports PASSED has cleared one vendor check. Record a baseline, schedule self-tests, watch a few raw counters for change over time, and have a restore you trust before you act on any of it.

Community comments
Comments are reviewed before publication. Keep discussion constructive: no harassment, hate, threats, doxxing, spam, illegal material, or attempts to evade moderation.
No approved comments yet.
Sign in to join the discussion.