How to use Docker Compose
Docker Compose lets you describe a multi-container application - for example an app plus its
database - in a single compose.yaml file and start it with one command. On TurboStack the modern
docker compose (v2) is available once Docker is enabled, and TurboStack still
reverse-proxies public traffic to your app through Nginx.
Use Compose instead of a single docker run when your app is more than one
container, or when you want its configuration version-controlled in a file.
1. Enable Docker for the application
Turn on Docker under Configure application > Technologies > Docker (see
Configure Docker). Every system user with Docker enabled is added to the docker
group and can run the docker and docker compose commands over
SSH.
2. Write a compose.yaml
Create a compose.yaml in your application directory (for example ~/app). Publish only the
front-facing port, and bind it to localhost so it is reachable only through Nginx; internal
services (such as a database) need no published ports because containers reach each other by service
name on the Compose network.
services:
web:
image: your-image:1.2
restart: unless-stopped
ports:
- "127.0.0.1:8080:80" # published to localhost; Nginx proxies to this
environment:
DATABASE_URL: "postgres://appuser@db:5432/appdb"
depends_on:
- db
db:
image: postgres:17
restart: unless-stopped
environment:
POSTGRES_USER: appuser
POSTGRES_DB: appdb
POSTGRES_PASSWORD: change-me
volumes:
- db-data:/var/lib/postgresql/data
# no ports: only reachable by other services (here, "web") on the Compose network
volumes:
db-data:
-
Pin image tags (
your-image:1.2,postgres:17) rather thanlatest, so deployments are reproducible. -
restart: unless-stoppedbrings a container back after a crash or a server reboot. -
Keep data you need to survive a container rebuild in a named volume (
db-dataabove), never in the container's writable layer. -
Store secrets in an
.envfile next to the compose file (Compose reads it automatically) rather than committing them.
3. Start and manage the stack
Run these from the directory that holds compose.yaml:
docker compose up -d # create and start everything, in the background
docker compose ps # what is running
docker compose logs -f # follow the logs (Ctrl+C to stop watching)
docker compose pull # fetch newer images...
docker compose up -d # ...then re-create containers with them
docker compose down # stop and remove the containers (keeps named volumes)
Warning
docker compose down --volumes also deletes the named volumes - and the data in them. Leave off
--volumes unless you really want to wipe the data.
4. Publish it through TurboStack
Point the reverse proxy at the port you published so Nginx serves the app on your domain with HTTPS:
docker_enabled: true
proxy_enabled: true
proxy_upstream_port: 8080 # the host port published by the web service
Publish the change to apply it.
Keep the stack running
restart: unless-stopped already restarts your containers after a crash or reboot. To manage the
whole stack as one service - so it is guaranteed to launch and you can start and stop it cleanly -
wrap it in a user systemd service. Create ~/.config/systemd/user/myapp.service:
[Unit]
Description=My Compose app
After=network-online.target
StartLimitIntervalSec=0
[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory=%h/app
ExecStart=docker compose up -d
ExecStop=docker compose down
Restart=on-failure
RestartSec=15s
[Install]
WantedBy=default.target
systemctl --user enable --now myapp.service
systemctl --user status myapp.service
TurboStack keeps user services running after you log out, so the stack survives reboots. For the
systemd --user basics, see Run with a process manager.
Note
On modern hosts the command is docker compose (v2, a space). Only very old servers have the
legacy docker-compose (with a hyphen); the options are otherwise the same.
Related
- Run a single Docker container
- Configure Docker
- Configure Reverse Proxy
- Run with a process manager
- SSH access
- What is Docker?