Managing Multiple Docker Compose Apps as Systemd Services on Ubuntu

While working with multiple project and then having multiple docker-compose.yml per project everytime I faced issues like

  • Stop Old docker-compose service
  • Data miss management if forgot to remove some service
  • Setting up data for different service
  • Some time accidentally removing data for other service
  • Different networks to communicate within docker setup was a headche

So If you are running several applications (like PostgreSQL, Redis, or Nginx) using individual Docker Compose files, managing them manually can become a headache. You want them to start automatically on boot, stop gracefully to prevent data corruption, and run with high performance.

In this guide, we’ll set up a Template Systemd Service that allows you to manage any number of .yml files as native Ubuntu services.


The Goal

  • One Service to Rule Them All: Use a single template for multiple apps.
  • Host Networking: Direct port access for maximum performance.
  • Data Persistence: Ensure databases keep their data after a reboot.
  • Native Integration: Use systemctl to start, stop, and check logs.

1. Organize Your Files

First, place all your Docker Compose files in a central directory, such as /opt/docker. Name them clearly based on the application.

1/opt/docker/
2├── postgres.yml
3├── redis.yml
4└── nginx.yml

2. Create the Magic Template

We will use a systemd "Template Unit." The @ symbol in the filename allows us to pass the application name as a variable.

Create the file: sudo nano /etc/systemd/system/docker-compose@.service

Paste this configuration:

 1[Unit]
 2Description=Docker Compose Service for %i
 3Requires=docker.service
 4After=docker.service
 5
 6[Service]
 7Type=oneshot
 8RemainAfterExit=yes
 9WorkingDirectory=/opt/docker
10
11# %i is the variable passed from the command line
12ExecStart=/usr/bin/docker compose -f %i.yml up -d
13ExecStop=/usr/bin/docker compose -f %i.yml down
14
15[Install]
16WantedBy=multi-user.target

Why these settings?

  • Type=oneshot & RemainAfterExit=yes: Docker Compose starts the containers and exits. These settings tell systemd to keep the service marked as "Active" so it can track the status.

  • ExecStop: Ensures that when you shut down the server, docker compose down is called, saving your database state safely.


3. Prepare Your Docker Compose Files

To ensure your apps run on the host network and save data properly, your .yml files should follow this pattern:

 1name: postgres
 2services:
 3  postgres:
 4    network_mode: "host"
 5    image: "postgres:18.1-alpine3.23"
 6    environment:
 7      - 'POSTGRES_USER=postgres'
 8      - 'POSTGRES_PASSWORD=postgres'
 9      - 'POSTGRES_DB=postgres'
10    volumes:
11      - ./pgdata:/var/lib/postgresql/data/

4. Enable and Start

Now for the best part. To start your PostgreSQL service, you simply "instantiate" the template by adding the filename (without .yml) after the @:

1# Reload systemd to recognize changes
2sudo systemctl daemon-reload
3
4# Start and enable Postgres
5sudo systemctl enable --now docker-compose@postgres

5. Useful Management Commands

Service Management Reference

Use these commands to manage your Docker Compose applications through systemd. Replace @postgres with your specific service name (e.g., @redis, @nginx) as needed.

Action Command
Check Status systemctl status docker-compose@postgres
View Live Logs journalctl -u docker-compose@postgres -f
Restart App systemctl restart docker-compose@postgres
Stop App systemctl stop docker-compose@postgres

Tip: Adding the -f flag to the journalctl command allows you to "follow" the logs in real-time, which is perfect for debugging startup issues.

Example

1sudo journalctl -u docker-compose@postgres.service -f
comments powered by Disqus