Skip to main content

Docker Compose Baseline

What this is

My standard approach for deploying and managing all containers using Docker Compose instead of manual docker run commands.

This replaces ad-hoc container creation with structured, repeatable configurations.


Why I needed this

Using docker run and Portainer manually caused:

  • No consistency between services
  • Harder rebuilds after failure
  • No version-controlled configs
  • Difficult troubleshooting

With Docker Compose:

  • Everything is defined in a single file
  • Easy to redeploy or migrate
  • Cleaner structure across services
  • Works perfectly with my NAS mounts and backups

My Setup

  • Host:
    • minipc (192.168.86.32) → main Docker host
    • micropc (192.168.86.100) → utility host
  • Base directory:
/opt/docker/

  • Structure:
/opt/docker/
├── jellyfin/
├── homeassistant/
├── paperless/
├── dozzle/
├── diun/

  • Each service contains:
docker-compose.yml
.env (optional)

  • NAS mount:
/mnt/sjb2


Key Concepts / Options

Feature docker run Docker Compose
Repeatability ❌ Manual ✅ Config file
Backup ❌ Hard ✅ Easy
Editing ❌ Recreate container ✅ Edit + restart
Scaling ❌ Difficult ✅ Built-in

Recommendation

👉 Use Docker Compose for every container

Why:

  • Consistent deployments
  • Easy to rebuild servers
  • Cleaner troubleshooting
  • Matches how most modern homelabs operate

Setup

1. Install Docker Compose

On modern Docker versions:

docker compose version

If not installed:

sudo apt install docker-compose-plugin -y


2. Create Base Directory

sudo mkdir -p /opt/docker
sudo chown -R $USER:$USER /opt/docker


3. Create a Service Folder

Example:

cd /opt/docker
mkdir example-app
cd example-app


4. Create docker-compose.yml

Example template:

version: "3.9"

services:
app:
image: nginx:latest
container_name: example-app
restart: unless-stopped

ports:
- "8080:80"

volumes:
- ./data:/data

environment:
- TZ=Europe/LondonAmerica/Santo_Domingo


5. Start the Container

docker compose up -d


6. Manage the Container

Stop:

docker compose down

Restart:

docker compose restart

Update:

docker compose pull
docker compose up -d


Configuration

Environment Variables (.env)

Example:

TZ=Europe/LondonAmerica/Santo_Domingo
PUID=1000
PGID=1000

Use in compose:

environment:
- TZ=${TZ}


Volume Strategy

Use:

  • Local:
./data

  • NAS:
/mnt/sjb2/media


Permissions Notes

  • Containers may fail if permissions mismatch
  • Match user IDs:
id

Typical values:

  • PUID=1000
  • PGID=1000

Verification

Check running containers:

docker ps

Check logs:

docker compose logs -f


Common Problems / Fixes

Container won’t start

  • Cause: Bad config or port conflict
  • Fix:
docker compose logs


Port already in use

  • Cause: Another container using same port
  • Fix:
docker ps

Change port in compose file


Permission denied (volumes)

  • Cause: Wrong ownership
  • Fix:
sudo chown -R 1000:1000 ./data


Changes not applied

  • Cause: Container not recreated
  • Fix:
docker compose down
docker compose up -d


Result

  • All services defined in clean YAML files
  • Easy to rebuild entire server
  • Consistent deployment across hosts
  • Simplified troubleshooting and maintenance

Notes

  • Prefer Compose over Portainer for deployment
  • Portainer still useful for:
    • Viewing logs
    • Quick inspection
  • Keep one folder per service
  • Back up /opt/docker regularly
  • Future improvement:
    • Git repository for configs
    • Automated updates (DIUN already in use)
    • Reverse proxy integration (Caddy)