Docker Compose in production: volumes, networks and secrets without surprises

Published on 2026-10-26 by frfrand

Example of Compose with API and database, persistence and logs

Docker Compose in production: volumes, networks and secrets without surprises

An API, PostgreSQL and Redis can run together with Docker Compose. It's convenient for development and for some production environments, but if you don't design the volumes and secrets properly, you'll discover the problem when the first container is recreated.

Let's turn this into a procedure you can use on a real VPS. The goal is to understand why it works, how to test it, and what problem appears if one part is misconfigured.

What Docker Compose means in production and when you need it

Compose describes services, networks, and volumes in a YAML file. A container is replaceable; important information must live in persistent storage or a managed external service. Variables are not automatically secure secrets just because they're inside a YAML file.

Before changing anything in production, note the current state: IP, domain, port, affected service, and time of the last deploy. An isolated change is easy to verify; five simultaneous changes make it harder to reconstruct what happened.

Configuration or example commands

services:
  api:
    image: mi-api:1.4.0
    ports:
      - '127.0.0.1:8000:8000'
    depends_on:
      - db
  db:
    image: postgres:17
    environment:
      POSTGRES_DB: app
      POSTGRES_USER: app
      # Inyectar PASSWORD de forma segura; no subir a Git
    volumes:
      - postgres_data:/var/lib/postgresql/data
volumes:
  postgres_data:

Domains, IP addresses, paths, and names are illustrative. Do not copy an entire configuration over the current one without comparing first. In examples that include ports or firewall settings, make sure to preserve administrative access.

How I would do it step by step

  1. Preparation. Define images with versioned tags and check PostgreSQL version compatibility.
  2. Step 2. Create volumes for databases and user uploads; do not store data only in ephemeral layers.
  3. Step 3. Restrict ports: in the example, the API is published only on localhost for a proxy.
  4. Step 4. Configure credentials with the appropriate mechanism and avoid literal secrets in Compose.
  5. Verification. Run docker compose config, start services, verify healthchecks, and test restoration.

When finished, check actual operation from another connection. For example, for an API it is not enough to open the browser: run a read request, a write to a test database, and check the process logs.

Example of a real project

A rental project uses FastAPI, Celery worker, Redis, and PostgreSQL. If all four live in containers, you can update the API without altering the database; but a schema migration requires coordination and backup just the same.

The lesson is simple: an infrastructure configuration does not live isolated from the application. The frontend, the server, the database, and the workers connect, so measuring where the failure starts is more useful than restarting everything.

The mistake I would avoid

depends_on does not by itself guarantee that PostgreSQL is ready to accept connections: you need healthchecks or application retries. Also, do not use the example without defining a secure password or adapting versions.

When working with client servers, keep a backup or rollback procedure before changes that affect data, network, or certificates. And if you do not know what permissions an operation needs, avoid running it as root just to make errors stop appearing.

How does it relate to ArduMaker?

In ArduMaker you can operate Docker on the VPS alongside domains, services, and databases. Avoid mixing volumes from different clients and document which Compose corresponds to each project.

In a typical case you can create a VPS for the application, deploy from Git, associate an HTTPS domain, and manage the backend and the necessary databases. The tools help centralize operations, but you need to understand which port and process fulfills each function.

Questions that come up when you try it

How do I know if the failure is DNS or the service? Check resolution first, then the connection to the port, and finally the application response. That order avoids confusing different problems.

Can I expose a database to make it easier to maintain? Better design private access or authenticated tunnels when possible. Exposing a port does not replace engine permissions or the firewall.

What should I document? The expected configuration, how to verify it, and how to revert to the previous state. That document helps you more than a list of commands without context.

References

In short: a good network or server configuration is one that you can explain, verify, and recover when something fails.

  • Docker
  • Tutorial
  • ArduMaker

On ArduMaker

  • Docker: Enable Docker in one click and manage images, containers, logs, volumes and networks from the panel.

Keep reading

All articles · VPS plans