Skip to main content
[ PIER ]

Docker Compose

Deploy a multi-container stack from a Compose YAML — Pier handles the rest.

Application #docker#compose#multi-container

Paste a docker-compose.yaml into Pier and ship a multi-container application — web + worker + cache + queue + database, whatever shape. Pier provisions the stack, attaches it to Traefik for TLS, manages persistent volumes, and exposes the same lifecycle controls (logs, env, restart, redeploy) as native templates.

Deploy with Pier

  1. 1 Open the Pier dashboard and click Add service.
  2. 2 Pick Docker Compose from the template list.
  3. 3 Choose the version, set a service name, and Pier provisions the container, storage, and ports automatically.
  4. 4 Attach a domain if you want HTTPS. Traefik auto-provisions the Let's Encrypt certificate.

What is Docker Compose on Pier?

This template wraps Docker Compose so you can paste a multi-container application YAML directly into the Pier UI and ship it. Pier provisions the stack, attaches it to its Traefik-fronted network for HTTPS, tracks named volumes, manages env vars, aggregates logs per service, and offers the same lifecycle controls (restart, redeploy, view logs, edit env) as native templates.

The killer use case is open-source projects that ship a canonical docker-compose.yaml as their install method — paste, set domain, deploy. Your own multi-service applications (web + worker + Redis + Postgres, etc.) also fit naturally — no need to break them into individual Pier services if they belong together.

How Pier deploys it

You paste a Compose YAML into the UI, optionally set service-level env overrides, and Pier runs docker compose up -d on the host. Named volumes become Pier-managed volumes that show up in the volumes page. Networks default to a per-stack bridge; add the external pier-traefik network to any service that should sit behind HTTPS.

Traefik integration is via standard Traefik labels on the service — traefik.enable=true, traefik.http.routers.<name>.rule=Host(...), etc. Pier provides Let’s Encrypt resolvers automatically; you just add the domain.

Updates are a YAML edit + redeploy; Pier diffs the existing stack and recreates only what changed.

When NOT to use Docker Compose

For single-container apps, the Docker Image template is simpler — no YAML to manage. For a code repo (not a prebuilt image), the Dockerfile or Railpack templates build for you. For native Pier services with managed backups and version upgrades (PostgreSQL, Gitea, Grafana, etc.), pick the dedicated template — you get more lifecycle features. Compose is the right answer for “multi-container app that isn’t a native template.”

Key features

Paste-and-deploy multi-container apps

Drop a complete `docker-compose.yaml` into the Pier UI; Pier deploys all services together with the right networking, dependencies, and restart policies.

Traefik integration

Add Traefik labels to your services and Pier wires them up for HTTPS at your custom domain — no separate reverse proxy to set up.

Persistent volumes

Named volumes in your Compose YAML are tracked by Pier — backed up, listed in the UI, restorable.

Multi-service env management

Override env vars per service from the Pier UI without editing the YAML. Useful for rotating passwords or toggling features.

Logs aggregated per service

View logs of any container in the stack from the Pier UI. Tail live, search, export.

One-click redeploy

Push image updates or change YAML — redeploy from the UI; Pier handles container rebuild and rollout.

Use cases

Multi-service applications

Web + worker + Redis + Postgres + nginx — a typical Rails / Django / Laravel / Next.js + worker setup deployed as one unit.

Apps from upstream Compose files

Many open-source projects ship a docker-compose.yaml as their canonical install method. Paste it into Pier and you're done.

Local-dev → prod parity

Your local Compose file can be the same one you ship to Pier (minus volume-path differences). Reduce dev/prod drift.

Sidecar patterns

Service + sidecar (log shipper, metric exporter, init container) bundled in one Compose stack.

Pre-wired bundles

Build your own "service A + companion B + companion C" reusable bundle and re-deploy across projects.

Code examples

Simple two-service app (web + Postgres) yaml
services:
  web:
    image: my-org/myapp:1.4.0
    ports:
      - "3000:3000"
    environment:
      DATABASE_URL: postgres://app:secret@db:5432/myapp
    depends_on:
      - db
    restart: unless-stopped

  db:
    image: postgres:17-alpine
    environment:
      POSTGRES_DB: myapp
      POSTGRES_USER: app
      POSTGRES_PASSWORD: secret
    volumes:
      - db-data:/var/lib/postgresql/data
    restart: unless-stopped

volumes:
  db-data:
Adding Traefik labels for HTTPS yaml
services:
  web:
    image: my-org/myapp:1.4.0
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.myapp.rule=Host(`app.example.com`)"
      - "traefik.http.routers.myapp.entrypoints=websecure"
      - "traefik.http.routers.myapp.tls.certresolver=letsencrypt"
      - "traefik.http.services.myapp.loadbalancer.server.port=3000"
    networks:
      - pier-traefik

networks:
  pier-traefik:
    external: true
Web + worker + Redis + Postgres yaml
services:
  web:
    image: my-org/myapp:1.4.0
    environment: &app-env
      REDIS_URL: redis://redis:6379
      DATABASE_URL: postgres://app:secret@db:5432/myapp
  worker:
    image: my-org/myapp:1.4.0
    command: ["bundle", "exec", "sidekiq"]
    environment: *app-env
  redis:
    image: redis:7-alpine
    volumes: ["redis-data:/data"]
  db:
    image: postgres:17-alpine
    environment:
      POSTGRES_DB: myapp
      POSTGRES_USER: app
      POSTGRES_PASSWORD: secret
    volumes: ["db-data:/var/lib/postgresql/data"]
volumes:
  redis-data:
  db-data:
Env-var override flow (in Pier UI) text
Service page → Environment → add a row
  Key: API_KEY
  Value: sk-xxxxxxxxxxxx
  Apply → restart container
The override stays in Pier, never edited into your YAML.

How it compares

vs Dockerfile (this catalog) Dockerfile builds and runs ONE container. Compose orchestrates MULTIPLE containers together. Pick by scope.
vs Native Pier templates (postgresql, gitea, ...) Native templates are pre-wired and managed by Pier (backups, version upgrades, scaling features). Compose is the "I have a multi-container app of my own design" escape hatch.
vs Kubernetes K8s is for fleet-wide multi-host orchestration with autoscaling, rolling updates, service mesh. Compose is single-host. Use K8s when you need that scope; Compose when you don't.
vs Docker Image (this catalog) Docker Image runs one prebuilt image. Compose runs many containers wired together. Use Image for the simplest single-service case; Compose for anything multi-container.

Frequently asked questions

What Compose version is supported?
Pier supports Compose spec v3+ (the modern unified version). YAML files using `version: '3.8'` or no version field at all work fine.
Can I use ${VAR} interpolation?
Yes — Pier injects env vars into the Compose YAML at deploy time. Define them in the service env tab.
How do volumes work?
Named volumes in your YAML (e.g. db-data:) become Pier-managed volumes. Bind mounts to host paths also work but are less portable.
Healthchecks?
Compose healthchecks work — Pier respects them when reporting status. Configure them in YAML.
How do I connect Compose services to Traefik?
Attach the service to the external `pier-traefik` network and add `traefik.*` labels per the Traefik docs. Pier wires the rest.
Resource limits?
Set `deploy.resources.limits.cpus` and `memory` in Compose YAML. Pier respects them.
How do I update?
Edit the YAML in the Pier UI (or `docker-compose pull` style — point to a new image tag), click Redeploy. Pier recreates only changed services.

Related services

Deploy on your VPS

Paste a docker-compose.yaml into Pier and ship a multi-container application — web + worker + cache + queue + database, whatever shape. Pier provisions the stack, attaches it to Traefik for TLS, manages persistent volumes, and exposes the same lifecycle controls (logs, env, restart, redeploy) as native templates.

Deploy this service →