Restart Docker Container Automatically After Reboot

In order to operate services using Docker containers reliably, stably and with minimal maintenance effort, it is necessary that they are started automatically after the Docker server is started.

In this tutorial, you will see three different ways to start docker container automatically after reboot.

📋
The first two ways assume that there is a system-wide Docker service (dockerd), in other words, you are working with a "normal" Docker installation (not rootless or with Podman).

Method 1: The default docker run --restart always Method

If you pass the docker run with --restart always option when starting a Docker always, then this container will be started automatically in the future:

docker run -p 8080:80 --name apache  -v "${PWD}":/usr/local/apache2/htdocs -d --restart always httpd

There are four possible parameters for --restart:

  • --restart nois the default. If the container terminates, for whatever reason, it will not be restarted.
  • --restart alwayscauses the container to be restarted automatically as soon as it ends. This restart rule also applies to a reboot of the system. The Docker service is started as part of the init process; this in turn starts all containers that were last --restart alwaysrunning with the option. But be careful: --restart always also applies to a program ending due to an error. If the container contains an error, it can happen that the container is started again and again. The only exception is a manual stopping i. However, if you shut down your system, the container will be started again the next time Docker is restarted.
  • --restart unless-stoppedworks very similarly to --restart always. The difference is that a docker stopcontainer terminated with will not be started automatically the next time Docker is restarted.
  • --restart on-failureresults in an automatic restart after an error in the container, but no autostart when the Docker system is restarted.

You can determine the restart behavior set for a container with docker inspect:

docker inspect <containername>
  ...
  "RestartPolicy": {
      "Name": "always",
      "MaximumRetryCount": 0
  },
  ...

With docker updateyou can change the update behavior of a container while it is running:

docker update --restart on-failure <containername>

Read more on restart policy in Docker in the tutorial below.

Docker Restart Policy [Explained With Examples]
Using a restart policy can be extremely helpful in restarting containers automatically in certain events or failures.

Method 2: Docker Compose file with the restart option

You can also specify an automatic restart in the file docker-compose.ymlusing the keyword restart:

services:
   db:
     image: mariadb:latest
     restart: always

The four permitted settings are no(by default), alwaysunless-stoppedand on-failure. The meaning of the keywords is the same as for the previously explained option --restartof docker run. The parameter
restart: alwaysis valid until the docker-compose.ymlservices described by the file compose downare explicitly stopped and deleted by .

Make sure that you restartspecify the keyword at the correct level directly in the settings of the respective container (in the previous example db).

services:
  db:
    image: mariadb:latest
    volumes:
      - vol-db:/var/lib/mysql
    environment:
      MYSQL_USER: wpuser
      MYSQL_PASSWORD: password
    restart: always

Method 3: Automatically restart container after reboot with systemd

The manual version of launching Docker containers, and the first one seen in any how-to on the subject, is through the docker run command, which allows you to instantiate a container from a Docker image.

The big drawback of this method is the instability of such a method. Because if the server reboots, or if the internal process stops, or if any other problem occurs, then the docker will stop, and the service provided with it will stop as well.

The logical step is to turn the docker run command into a service so that the system can make sure it runs properly. This is where systemd comes in. It would be perfectly possible to use supervisord or something like that, but we choosed systemd for this tutorial because it is now massively adopted by default on the most used recent Linux distributions.

Wrapping a Docker container in a systemd service means ensuring that:

  • The service will start cleanly when the machine boots
  • The container restarts automatically if needed
  • Logs (stdout) are managed by Journald and easy to query
  • The entire systemd ecosystem can be used and therefore meet concrete needs, such as dependencies, pre/post commands, and centralized environment variable management.

The minimum version of a /etc/systemd/system/nginx.service file would be:

[Unit]
Description=Docker container

[Service]
ExecStart=/usr/bin/docker run --name nginx \
    --net host \
    -v /srv/nginx/conf.d:/etc/nginx/conf.d \
    -v /srv/nginx/index.html:/usr/share/nginx/html/index.html \
    nginx

ExecStop=/usr/bin/docker stop nginx
ExecStopPost=/usr/bin/docker rm -f nginx

[Install]
WantedBy=multi-user.target

This simple service has downsides (explained below)

This fully functional file starts a Docker container named nginx, and fetches the latest 'nginx' image from the official docker hub, while passing it a configuration folder as a volume (which Docker will create on the host if it does not exist). The WantedBy part will only come into play with the command systemctl enable nginx, in which case the service will be activated at startup because it will be linked to the systemd multi-user target, the default target.

However, this service suffers from several weaknesses. First, if the Docker service is restarted, the service will fail. Also, when the machine boots, the service may try to start before the Docker service is up and running, in which case it could end up failing as well. Consider the BindsTo and lines After, which ensure that the service takes Docker as a dependency, and will be shut down first, if Docker is ever stopped.

Then, in the case of Nginx which is a stateless service, it would be ingenious to provide a Docker update when the service starts, in case a more recent version is available. This is feasible by adding a command ExecStartPreresponsible for a docker pullwhich will run before the ExecStart.

Also, you can specify that the service if it falls into error will always be restarted, and this every 10 seconds if necessary, thanks to the lines Restartand RestartSec. This is the equivalent of the argument restart=onfailureto the command docker run.

Another problem we have with this configuration is that we don't define a behavior for the reload action. In which case, systemd will by default keep the behavior of a restart, by applying stop then start to the service concerned.

The method I use is simply to define and then execute a reload of the nginx process inside the container using ExecReload. It is also possible to send a signal (kill -s HUP) but I find it cleaner.

Finally, it is possible to vary the names used in the service file using environment variables, line Environment. If the variables become numerous or if they become common to several service files of the same host, it is possible to use a separate file for its variables, using the option EnvironmentFile.

An “optimized” service file would therefore look like this:

[Unit]
Description=Docker container
BindsTo=docker.service
After=docker.service

[Service]
Environment=NAME=%N
Environment=IMG=nginx
Restart=on-failure
RestartSec=10
ExecStartPre=-/usr/bin/docker kill ${NAME}
ExecStartPre=-/usr/bin/docker rm ${NAME}
ExecStart=/usr/bin/docker run --name ${NAME} \
    -p 80:80 \
    -p 443:443 \
    -v /srv/nginx/conf.d:/etc/nginx/conf.d \
    -v /srv/nginx/html:/usr/share/nginx/html/ \
    ${IMG}
ExecStop=/usr/bin/docker stop ${NAME}
ExecReload=/usr/bin/docker exec ${NAME} nginx -s reload

[Install]
WantedBy=multi-user.target
💡
%N will be automatically replaced by the name of the service file. Don't forget to run the command systemctl daemon-reloadevery time you change the configuration of a .service file.

Service logs and logs

One of the big advantages of running all your service files with systemd is that the standard output is fed into the journald mill, which then gives a common and simple way to configure and access an application's logs. To keep the example above, accessing Nginx logs is as simple as:

journalctl -fu nginx

This will not prevent you from having separate log files in the case of virtualhosts, in which case it will be a good idea to share the logs folder (by default /var/log/nginx) of the container with the host machine so as not to lose them on reboot.

Wrapping Up

In this tutorial, you saw three different ways to automatically restart Docker containers after a system reboot.

Though systemd provides a more efficient method with logging, the choice of method largely depends on the environment and specific requirements.

For simpler use cases or single-container setups, the --restart option in docker run or Docker Compose might suffice. However, for more complex, multi-service environments, systemd offers greater control, reliability, and integration with system-level processes.