Restart Policies

Docker restart policies tell the Docker daemon whether to start a container again after its main process exits or after the daemon starts. They matter because a useful service should usually recover from a crash or host reboot without someone manually running docker start.

A restart policy is not a health check, deployment system, or application supervisor. It is a simple rule attached to one container that says what Docker should do when that container stops.

Overview: How Restart Policies Work

A Docker image is a read-only template made of filesystem layers and metadata. A container is an instance of that image with its own writable layer, name, environment, mounts, network configuration, port publications, and one main process. Restart policies belong to the container configuration, not to the image. Two containers created from the same image can have different restart behavior.

When you run a container, Docker starts the configured command as the container’s main process. If that process exits, the container stops and receives an exit code. Exit code 0 usually means success. A nonzero exit code usually means an error, although applications can define their own meanings. The Docker daemon watches that main process and applies the restart policy when the process exits.

The four common policies are no, on-failure, always, and unless-stopped. The default is no, which means Docker leaves the container stopped. on-failure restarts only when the container exits with a nonzero status, and it can include a maximum retry count such as on-failure:3. always restarts the container whenever it stops, and also starts it when the Docker daemon starts. unless-stopped is similar to always, but it respects a manual stop across daemon restarts.

The difference between always and unless-stopped is one of the most important details. If a container with always is manually stopped and the Docker daemon later restarts, Docker starts it again. If a container with unless-stopped is manually stopped, Docker remembers that choice and does not bring it back merely because the daemon restarted. For long-running local services and simple single-host deployments, unless-stopped is often the friendlier default.

Restart policies are implemented by the Docker daemon, so they work even if your terminal closes. On Linux, the daemon manages container processes through the container runtime, namespaces, and cgroups. On Docker Desktop for macOS and Windows, Linux containers run inside Docker’s managed Linux VM, but the policy behavior from the CLI is the same.

Restart policies only apply to containers that Docker has already created. They do not pull newer images, rebuild images, change environment variables, recreate volumes, or migrate data. If an image tag in a registry changes, restarting an existing container does not replace its filesystem. To deploy new image content, pull or build the new image and recreate the container, or use docker compose up -d from updated configuration.

Syntax

docker run --restart POLICY IMAGE[:TAG] [COMMAND] [ARG...]
docker update --restart POLICY CONTAINER [CONTAINER...]
Policy Meaning
no The default. Do not restart the container automatically.
on-failure Restart only if the main process exits with a nonzero exit code.
on-failure:N Restart after failure, but stop retrying after N failed restarts.
always Restart whenever the container stops, and start it when the Docker daemon starts.
unless-stopped Restart like always, except do not restart a container that was manually stopped.
docker update --restart Changes the restart policy of an existing container without recreating it.
restart: Compose service key for the same single-container restart policies.

Use docker run --restart ... when creating a new container. Use docker update --restart ... when the container already exists and only the policy needs to change. In Compose, put the policy under the service with restart: unless-stopped or a similar value.

Examples

Example 1: Keep a Web Server Running

docker run -d --name restart-web \
  --restart unless-stopped \
  -p 8080:80 \
  nginx:1.27-alpine
docker inspect --format '{{.HostConfig.RestartPolicy.Name}}' restart-web

Output:

8d7a6f5e4d3c2b1a09876543210fedcba9874f8b2c1d9a0e5c7b6d3a2f1e0b9c
unless-stopped

This creates an Nginx container with a specific image tag and publishes host port 8080 to container port 80. The --restart unless-stopped policy tells Docker to bring it back after crashes and daemon restarts, unless you intentionally stopped it with docker stop restart-web. The docker inspect command reads the policy stored in the container’s host configuration.

Example 2: Retry a Failing Job a Limited Number of Times

docker run -d --name retry-demo \
  --restart on-failure:3 \
  alpine:3.20 \
  sh -c 'echo "starting"; exit 1'
sleep 2
docker inspect --format '{{.RestartCount}} {{.State.Status}} {{.State.ExitCode}}' retry-demo

Output:

5f4e3d2c1b0a9876543210fedcba9878d7a6f5e4d3c2b1a09876543210fedcba
3 exited 1

The Alpine container immediately exits with status 1. Because the policy is on-failure:3, Docker retries it after failures and then stops after the retry limit is reached. This policy is useful for jobs where a temporary dependency might recover, but endless restarts would hide the real problem.

Example 3: Change an Existing Container’s Policy

docker update --restart always restart-web
docker inspect --format '{{.HostConfig.RestartPolicy.Name}}' restart-web

Output:

restart-web
always

docker update changes the restart policy on an existing container. It does not rebuild the image, recreate the container, change its ports, or restart the process by itself. After this change, Docker will start restart-web whenever the daemon starts, even if the container had previously been manually stopped.

Example 4: Set a Restart Policy in Compose

services:
  web:
    image: nginx:1.27-alpine
    ports:
      - "8080:80"
    restart: unless-stopped

Output:

[+] Running 2/2
Network restart-demo_default  Created
Container restart-demo-web-1   Started

With Compose, the restart policy is part of the service definition. Running docker compose up -d creates the container with that policy. The modern command is docker compose, not the old standalone docker-compose binary. Compose is the better choice when the service also needs repeatable ports, environment variables, networks, and volumes.

How It Works Step by Step

  1. You create a container with docker run --restart unless-stopped ..., or Compose creates one from a service definition.
  2. The Docker CLI sends the requested restart policy to the Docker daemon as part of the container configuration.
  3. The daemon creates the container by mounting the image’s read-only layers and adding a thin writable layer, then prepares networking, mounts, environment variables, and the configured command.
  4. The daemon starts the container’s main process and tracks its state.
  5. If the process exits, Docker records the exit code and updates the container state.
  6. The restart manager checks the policy. With no, it does nothing. With on-failure, it checks for a nonzero exit code. With always or unless-stopped, it schedules a restart unless the manual-stop rule prevents it.
  7. Docker waits briefly before restarting. Repeated rapid failures are delayed so a broken container does not spin as fast as the CPU allows.
  8. If the Docker daemon starts after a host reboot or daemon restart, it evaluates containers with restart policies and starts the ones whose policy says they should be running.

The policy watches the container’s main process only. If your app starts a background worker and the foreground process exits successfully, Docker sees the container as stopped. If a web server stays alive but is internally unhealthy, Docker does not automatically know that from the restart policy alone. Health checks and orchestrators can add deeper service supervision, but they are separate mechanisms.

Common Mistakes

Using a Restart Policy to Hide a Bad Command

docker run -d --name broken-loop --restart always alpine:3.20 sh -c 'echo bad config; exit 1'

This creates a container that repeatedly fails and restarts. The policy is doing exactly what you asked, but the service is still broken. Inspect logs and state instead of assuming automatic restart means automatic recovery:

docker logs broken-loop
docker inspect --format '{{.RestartCount}} {{.State.Status}} {{.State.ExitCode}}' broken-loop

Choosing always When Manual Stops Should Be Respected

docker run -d --name local-cache --restart always redis:7.4-alpine

This can surprise you on a workstation: if you manually stop the container and later restart Docker Desktop or the Docker daemon, Docker may start it again. For local long-running services, unless-stopped usually matches intent better:

docker update --restart unless-stopped local-cache

Expecting Restart to Update an Image

docker pull nginx:1.27-alpine
docker restart restart-web

Pulling image content does not mutate existing containers. The stopped or restarted container still uses the image content it was created with. Recreate the container when you need new image content or changed runtime options:

docker stop restart-web
docker rm restart-web
docker run -d --name restart-web --restart unless-stopped -p 8080:80 nginx:1.27-alpine

Forgetting That Data Still Needs Volumes

docker run -d --name db-no-volume --restart unless-stopped postgres:16-alpine

A restart policy can restart the database process, but it is not a persistence strategy. Important database files should live in a named volume, and real passwords should be provided as obvious placeholders in examples or through a secret mechanism in production:

docker volume create pgdata
docker run -d --name db-with-volume \
  --restart unless-stopped \
  -e "POSTGRES_PASSWORD=changeme" \
  -v pgdata:/var/lib/postgresql/data \
  postgres:16-alpine

Best Practices

  • Use unless-stopped for most simple long-running services on a single Docker host.
  • Use on-failure:N for short jobs or workers where limited retrying is useful but infinite loops are harmful.
  • Use always only when the container should return after daemon startup even if it was manually stopped before.
  • Inspect RestartCount, exit code, and logs when a service keeps coming back. A high restart count is a symptom to debug.
  • Pin image tags such as nginx:1.27-alpine, alpine:3.20, and postgres:16-alpine. The latest tag is a moving target and makes recovery harder to reason about.
  • Store durable data in named volumes. Restart policies preserve availability, not data correctness.
  • Keep one main foreground process in the container. Docker restarts the container when that process exits.
  • Use Compose for repeatable local or single-host services so the restart policy sits beside ports, mounts, networks, and environment variables.
  • Do not rely on restart policies as a replacement for health checks, monitoring, backups, or orchestration in production systems.

Practice Exercises

  1. Run an nginx:1.27-alpine container named practice-restart-web with --restart unless-stopped, then inspect the policy. Expected end state: inspection prints unless-stopped.
  2. Create a container from alpine:3.20 that exits with status 1 and uses --restart on-failure:2. Hint: check RestartCount after a short delay.
  3. Write a compose.yml service for redis:7.4-alpine with restart: unless-stopped. Expected end state: docker compose up -d starts the service and docker inspect shows the policy on the created container.

Summary

  • Restart policies are container-level rules stored by the Docker daemon.
  • The default policy is no, so containers do not restart automatically unless you configure them to.
  • on-failure responds to nonzero exit codes and can include a retry limit.
  • always restarts aggressively and starts containers when the daemon starts.
  • unless-stopped is like always, but it respects an intentional manual stop.
  • Restarting a container does not update its image, ports, mounts, environment, or data strategy.
  • Use logs, inspection, volumes, pinned image tags, and Compose alongside restart policies for reliable services.