always, unless-stopped, on-failure, no
A container that does not restart after a crash is a silent outage in production. Docker offers four restart policies that look similar at first glance but behave quite differently in practice, especially around manual stops and daemon restarts.
Table of Contents
- 1. Why restart policies exist in the first place
- 2. always: unconditional restart on every stop
- 3. unless-stopped: always with a memory for manual stops
- 4. on-failure: restart only on a genuine error
- 5. no: the quiet default setting
- 6. How restart policies interact with daemon and host restarts
- 7. Restart policies and docker compose up -d
- 8. Common mistakes and how to avoid them
- 9. Practical recommendation by application type
- 10. Summary
- 11. FAQ
1. Why restart policies exist in the first place
Containers are deliberately designed to be short lived. A process inside a container can terminate for many reasons: an unhandled error in the application, an out-of-memory kill by the kernel, a failed health check, or simply a bug in the code. Without built in restart logic, an external process, such as a cron job or a monitoring script, would have to detect the failure and manually bring the container back up. That is error prone and slow, especially for outages that happen overnight without anyone on call.
Restart policies move that responsibility into the Docker daemon itself. The daemon observes the exit code and container status and decides, based on the configured policy, whether and when to restart. This works on a single host without any orchestrator like Kubernetes or Swarm, which is why it is the first line of defense against failures for single host setups using docker run or docker compose.
2. always: unconditional restart on every stop
The always policy is the most aggressive option. The container restarts after every termination, regardless of the exit code, and is also automatically brought back up the next time the Docker daemon itself starts, for example after a server reboot. That makes always the right choice for permanently running services such as web servers, databases, or reverse proxies, where downtime should be as short as possible.
The catch lies in the word unconditional: even after a manual docker stop, the container comes back the next time the daemon restarts, because Docker remembers the last desired state. Anyone who stops an always container for testing and then reboots the server will be surprised to see it running again. For maintenance windows where a service should intentionally stay down, always is therefore unsuitable unless the policy is explicitly changed beforehand.
# Start a container with the always policy
docker run -d --name webserver --restart always nginx:1.27
# Check the policy afterwards
docker inspect webserver --format '{{.HostConfig.RestartPolicy.Name}}'
# Output: always
# Manual stop: the container stays stopped UNTIL the daemon restarts
docker stop webserver
docker ps -a --filter name=webserver
# STATUS: Exited (0)
# After a Docker daemon restart (e.g. systemctl restart docker
# or a server reboot), the container starts again automatically
3. unless-stopped: always with a memory for manual stops
unless-stopped behaves almost identically to always, with one crucial difference: if the container is explicitly terminated via docker stop, Docker remembers this state across a daemon restart. When the server reboots, a manually stopped container stays stopped instead of automatically coming back up. Only an explicit docker start returns it to the active state, and from then on the normal automatic restart logic applies again.
In practice, unless-stopped is the better default over always for most production long running services, because it respects human intent: an administrator who deliberately shuts a service down for maintenance does not expect it to simply reappear after the next server restart. Compose setups with multiple services benefit especially from this, since individual containers can be taken offline on purpose without an accidental host reboot bringing them back.
# docker-compose.yml
services:
app:
image: mironsoft/app:latest
restart: unless-stopped
ports:
- "8080:8080"
redis:
image: redis:7-alpine
restart: unless-stopped
volumes:
- redis-data:/data
volumes:
redis-data:
4. on-failure: restart only on a genuine error
on-failure restarts a container only when the process ends with a non zero exit code, signaling an error. A clean, intentional exit with code 0 does not trigger a restart. That makes on-failure the right fit for batch jobs, migration scripts, or worker processes that are meant to end normally once their work is done, but should retry after crashing due to a network error or an unreachable database.
Optionally, the number of restart attempts can be limited to avoid infinite loops for jobs that are permanently broken. Without a limit, Docker keeps retrying indefinitely with exponentially increasing delays between attempts, which for a structurally broken container, for example one with an invalid configuration, leads to a pointless restart loop that wastes log space and CPU time.
# Migration job: restart only on failure, max 5 attempts
docker run -d --name db-migration \
--restart on-failure:5 \
mironsoft/migration-runner:latest
# On a clean exit (code 0), the container simply stays stopped
docker run --name one-shot-report --restart on-failure \
mironsoft/report-generator:latest
docker wait one-shot-report
echo $? # 0 -> no restart happened
5. no: the quiet default setting
no is Docker's default when no restart policy is specified. The container never restarts automatically under any circumstances, neither after a crash nor after a daemon restart. That sounds like the least safe choice at first, but it is exactly right for interactive containers, one off CLI invocations, or debugging sessions, where nobody expects a surprise restart.
The most common mistake in practice is using no unintentionally, simply because the policy was forgotten. A web server container without a restart flag runs perfectly normally until it crashes once or the host reboots, and then stays silently offline until someone notices the outage manually and fixes it. Especially with docker run outside a Compose file, the missing policy is easy to overlook, which is why every restart flag in deployment scripts deserves a deliberate look.
6. How restart policies interact with daemon and host restarts
A central, often overlooked aspect: restart policies do not only apply to process crashes within a running system, they also apply when the Docker daemon itself starts. When the server reboots or the dockerd service is restarted via systemctl restart docker, Docker walks through its list of containers and starts every one whose policy and last known state call for it. For always, that means practically always. For unless-stopped: unless the container was manually stopped beforehand.
For this mechanism to work at all, the Docker daemon itself must be enabled to start on boot, typically via systemctl enable docker. If the daemon is not enabled, every container stays offline after a reboot no matter which restart policy is configured, because the daemon never even starts to bring them back. This systemd level detail is frequently missing from operations documentation, even though it is the basic prerequisite for any restart policy to matter.
# Permanently enable the Docker daemon (prerequisite for all restart policies)
sudo systemctl enable docker
sudo systemctl status docker
# Test: list all containers with their policy
docker ps -a --format 'table {{.Names}}\t{{.Status}}'
docker inspect $(docker ps -aq) \
--format '{{.Name}}: {{.HostConfig.RestartPolicy.Name}}'
7. Restart policies and docker compose up -d
In Compose environments there is an additional nuance: docker compose up -d respects the restart policy when restarting an already running stack, but docker compose down removes the containers entirely, making their policy irrelevant for those instances. Only the next docker compose up creates new containers with whatever policy is currently defined in the YAML file. Anyone who changes the restart setting in the Compose file must recreate the containers, a plain docker compose restart is not enough.
Another point: health checks and restart policies operate independently. A container that is running but reported as unhealthy by its health check is not automatically restarted by the restart policy, because from the Docker daemon's perspective the process is still running. Anyone who wants to react to failed health checks needs additional logic, for example through an orchestrator, a Watchtower style tool, or a custom supervisor script that explicitly restarts the container when needed.
8. Common mistakes and how to avoid them
A classic mistake is using always for one off jobs. A backup script with always restarts immediately after every run, even after completing successfully, because always makes no distinction between a successful and a failed exit. The result is a container that restarts every few seconds and wastes resources and log storage, a pattern administrators often only discover through unusually high CPU load.
Equally problematic is using unless-stopped for containers that are meant to be intentionally temporary, such as test or staging instances. After an accidental server reboot, these containers suddenly reappear and occupy ports or resources that were supposed to be free. As a rule of thumb: on-failure for jobs with a clear successful end state, unless-stopped for permanent services that respect deliberate manual intervention, always only when every single stop is genuinely unwanted, and no for everything interactive and temporary.
9. Practical recommendation by application type
For a production web server or API that must stay permanently reachable, unless-stopped is the pragmatic default: automatic restarts after crashes and reboots, while still respecting an intentional manual stop during maintenance windows. For critical infrastructure containers such as a reverse proxy that must never stay down unintentionally, always can make more sense, combined with clear documentation stating that a stop must temporarily change the policy.
For batch processing, database migrations, cron style one off jobs, and CI/CD build containers, on-failure with a sensible retry limit is the right choice, since it distinguishes between a genuine error and a normal end. And for anything started interactively, such as a debug shell container or a local development container, no remains the right, unobtrusive choice. The table below summarizes this decision once more.
| Policy | Restart after crash | Restart after daemon restart | Typical use case |
|---|---|---|---|
| no (default) | No | No | Interactive containers, debugging, one off CLI runs |
| on-failure[:max] | Yes, only on exit code != 0 | Yes, if last active | Batch jobs, migrations, CI build containers |
| unless-stopped | Yes, always | Yes, unless manually stopped | Production long runners: web servers, APIs, Redis |
| always | Yes, always | Yes, unconditionally | Critical infrastructure with no accepted downtime |
Mironsoft
Container infrastructure, CI pipelines and deployment automation
Docker setups that hold up across the team and in production?
We review existing Dockerfiles and Compose stacks for security gaps, bloated images and fragile build pipelines, then build a container infrastructure that builds fast, runs securely and stays understandable across the team.
Dockerfile Review
Systematically optimizing multi-stage builds, layer caching and image size.
Security Audit
Hardening container isolation, secrets handling and image scanning against real attack surfaces.
CI/CD Integration
Building build pipelines, registries and deployment strategies for reproducible releases.
10. Summary
Docker Restart Policies: Key Takeaways
always
Restarts after every stop and every daemon restart, even after a manual docker stop.
unless-stopped
Like always, but respects a deliberate manual stop across reboots.
on-failure
Restarts only on a failure exit code, ideal for jobs with a defined success state.
no
The default when unspecified: no automatic restart, fitting for interactive containers.