Skip to main content

Docker Compose Templates for Every Self-Hosted Tool

·OSSAlt Team
dockerdocker-composeself-hostingtemplatesguide

Docker Compose Templates for Every Self-Hosted Tool

Stop digging through documentation. Here's a copy-paste Docker Compose template for every popular self-hosted tool. Configure your .env, run docker compose up -d, done.

How to Use

  1. Copy the template for your tool
  2. Create a .env file with your settings
  3. Run docker compose up -d
  4. Set up reverse proxy (Caddy recommended)

Reverse proxy template (used by all tools below):

# /etc/caddy/Caddyfile
app.yourdomain.com {
    reverse_proxy localhost:PORT
}

Team Communication

Mattermost

services:
  mattermost:
    image: mattermost/mattermost-team-edition:latest
    restart: unless-stopped
    ports:
      - "8065:8065"
    volumes:
      - mm_config:/mattermost/config
      - mm_data:/mattermost/data
      - mm_logs:/mattermost/logs
      - mm_plugins:/mattermost/plugins
    environment:
      - MM_SQLSETTINGS_DRIVERNAME=postgres
      - MM_SQLSETTINGS_DATASOURCE=postgres://${DB_USER}:${DB_PASS}@db:5432/${DB_NAME}?sslmode=disable
      - MM_SERVICESETTINGS_SITEURL=https://${DOMAIN}
    depends_on:
      - db
  db:
    image: postgres:16-alpine
    restart: unless-stopped
    volumes:
      - db_data:/var/lib/postgresql/data
    environment:
      - POSTGRES_DB=${DB_NAME}
      - POSTGRES_USER=${DB_USER}
      - POSTGRES_PASSWORD=${DB_PASS}
volumes:
  mm_config:
  mm_data:
  mm_logs:
  mm_plugins:
  db_data:

Rocket.Chat

services:
  rocketchat:
    image: registry.rocket.chat/rocketchat/rocket.chat:latest
    restart: unless-stopped
    ports:
      - "3000:3000"
    environment:
      - ROOT_URL=https://${DOMAIN}
      - MONGO_URL=mongodb://mongo:27017/rocketchat
      - MONGO_OPLOG_URL=mongodb://mongo:27017/local
    depends_on:
      - mongo
  mongo:
    image: mongo:6
    restart: unless-stopped
    volumes:
      - mongo_data:/data/db
    command: --oplogSize 128 --replSet rs0
volumes:
  mongo_data:

Knowledge Base & Documentation

Outline

services:
  outline:
    image: outlinewiki/outline:latest
    restart: unless-stopped
    ports:
      - "3000:3000"
    env_file: .env
    depends_on:
      - db
      - redis
  db:
    image: postgres:16-alpine
    restart: unless-stopped
    volumes:
      - db_data:/var/lib/postgresql/data
    environment:
      - POSTGRES_DB=outline
      - POSTGRES_USER=outline
      - POSTGRES_PASSWORD=${DB_PASS}
  redis:
    image: redis:7-alpine
    restart: unless-stopped
    volumes:
      - redis_data:/data
volumes:
  db_data:
  redis_data:

BookStack

services:
  bookstack:
    image: lscr.io/linuxserver/bookstack:latest
    restart: unless-stopped
    ports:
      - "6875:80"
    volumes:
      - bookstack_data:/config
    environment:
      - APP_URL=https://${DOMAIN}
      - DB_HOST=db
      - DB_PORT=3306
      - DB_USER=bookstack
      - DB_PASS=${DB_PASS}
      - DB_DATABASE=bookstack
    depends_on:
      - db
  db:
    image: mariadb:11
    restart: unless-stopped
    volumes:
      - db_data:/var/lib/mysql
    environment:
      - MYSQL_ROOT_PASSWORD=${DB_ROOT_PASS}
      - MYSQL_DATABASE=bookstack
      - MYSQL_USER=bookstack
      - MYSQL_PASSWORD=${DB_PASS}
volumes:
  bookstack_data:
  db_data:

Analytics

Plausible

services:
  plausible:
    image: ghcr.io/plausible/community-edition:latest
    restart: unless-stopped
    ports:
      - "8000:8000"
    env_file: .env
    depends_on:
      - db
      - clickhouse
  db:
    image: postgres:16-alpine
    restart: unless-stopped
    volumes:
      - db_data:/var/lib/postgresql/data
    environment:
      - POSTGRES_PASSWORD=${DB_PASS}
  clickhouse:
    image: clickhouse/clickhouse-server:latest
    restart: unless-stopped
    volumes:
      - ch_data:/var/lib/clickhouse
volumes:
  db_data:
  ch_data:

Umami

services:
  umami:
    image: ghcr.io/umami-software/umami:postgresql-latest
    restart: unless-stopped
    ports:
      - "3000:3000"
    environment:
      - DATABASE_URL=postgresql://umami:${DB_PASS}@db:5432/umami
    depends_on:
      - db
  db:
    image: postgres:16-alpine
    restart: unless-stopped
    volumes:
      - db_data:/var/lib/postgresql/data
    environment:
      - POSTGRES_DB=umami
      - POSTGRES_USER=umami
      - POSTGRES_PASSWORD=${DB_PASS}
volumes:
  db_data:

Monitoring

Uptime Kuma

services:
  uptime-kuma:
    image: louislam/uptime-kuma:latest
    restart: unless-stopped
    ports:
      - "3001:3001"
    volumes:
      - kuma_data:/app/data
volumes:
  kuma_data:

Grafana + Prometheus

services:
  grafana:
    image: grafana/grafana:latest
    restart: unless-stopped
    ports:
      - "3000:3000"
    volumes:
      - grafana_data:/var/lib/grafana
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=${ADMIN_PASS}
  prometheus:
    image: prom/prometheus:latest
    restart: unless-stopped
    ports:
      - "9090:9090"
    volumes:
      - prom_data:/prometheus
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
  node-exporter:
    image: prom/node-exporter:latest
    restart: unless-stopped
    ports:
      - "9100:9100"
    volumes:
      - /proc:/host/proc:ro
      - /sys:/host/sys:ro
    command:
      - '--path.procfs=/host/proc'
      - '--path.sysfs=/host/sys'
volumes:
  grafana_data:
  prom_data:

Automation

n8n

services:
  n8n:
    image: n8nio/n8n:latest
    restart: unless-stopped
    ports:
      - "5678:5678"
    volumes:
      - n8n_data:/home/node/.n8n
    environment:
      - N8N_HOST=${DOMAIN}
      - N8N_PROTOCOL=https
      - WEBHOOK_URL=https://${DOMAIN}/
      - N8N_ENCRYPTION_KEY=${ENCRYPTION_KEY}
      - DB_TYPE=postgresdb
      - DB_POSTGRESDB_HOST=db
      - DB_POSTGRESDB_DATABASE=n8n
      - DB_POSTGRESDB_USER=n8n
      - DB_POSTGRESDB_PASSWORD=${DB_PASS}
    depends_on:
      - db
  db:
    image: postgres:16-alpine
    restart: unless-stopped
    volumes:
      - db_data:/var/lib/postgresql/data
    environment:
      - POSTGRES_DB=n8n
      - POSTGRES_USER=n8n
      - POSTGRES_PASSWORD=${DB_PASS}
volumes:
  n8n_data:
  db_data:

Authentication

Keycloak

services:
  keycloak:
    image: quay.io/keycloak/keycloak:latest
    restart: unless-stopped
    ports:
      - "8080:8080"
    environment:
      - KC_DB=postgres
      - KC_DB_URL_HOST=db
      - KC_DB_URL_DATABASE=keycloak
      - KC_DB_USERNAME=keycloak
      - KC_DB_PASSWORD=${DB_PASS}
      - KC_HOSTNAME=${DOMAIN}
      - KC_PROXY_HEADERS=xforwarded
      - KC_HTTP_ENABLED=true
      - KEYCLOAK_ADMIN=${ADMIN_USER}
      - KEYCLOAK_ADMIN_PASSWORD=${ADMIN_PASS}
    command: start
    depends_on:
      - db
  db:
    image: postgres:16-alpine
    restart: unless-stopped
    volumes:
      - db_data:/var/lib/postgresql/data
    environment:
      - POSTGRES_DB=keycloak
      - POSTGRES_USER=keycloak
      - POSTGRES_PASSWORD=${DB_PASS}
volumes:
  db_data:

Password Management

Vaultwarden

services:
  vaultwarden:
    image: vaultwarden/server:latest
    restart: unless-stopped
    ports:
      - "8080:80"
    volumes:
      - vw_data:/data
    environment:
      - DOMAIN=https://${DOMAIN}
      - SIGNUPS_ALLOWED=${SIGNUPS_ALLOWED:-false}
      - ADMIN_TOKEN=${ADMIN_TOKEN}
      - SMTP_HOST=${SMTP_HOST}
      - SMTP_PORT=587
      - SMTP_SECURITY=starttls
      - SMTP_USERNAME=${SMTP_USER}
      - SMTP_PASSWORD=${SMTP_PASS}
      - SMTP_FROM=${SMTP_FROM}
volumes:
  vw_data:

Customer Support

Chatwoot

services:
  chatwoot:
    image: chatwoot/chatwoot:latest
    restart: unless-stopped
    ports:
      - "3000:3000"
    env_file: .env
    command: bundle exec rails s -p 3000 -b 0.0.0.0
    depends_on:
      - db
      - redis
  sidekiq:
    image: chatwoot/chatwoot:latest
    restart: unless-stopped
    env_file: .env
    command: bundle exec sidekiq -C config/sidekiq.yml
    depends_on:
      - db
      - redis
  db:
    image: postgres:16-alpine
    restart: unless-stopped
    volumes:
      - db_data:/var/lib/postgresql/data
    environment:
      - POSTGRES_DB=chatwoot
      - POSTGRES_USER=chatwoot
      - POSTGRES_PASSWORD=${DB_PASS}
  redis:
    image: redis:7-alpine
    restart: unless-stopped
    volumes:
      - redis_data:/data
volumes:
  db_data:
  redis_data:

Email

Listmonk

services:
  listmonk:
    image: listmonk/listmonk:latest
    restart: unless-stopped
    ports:
      - "9000:9000"
    volumes:
      - ./config.toml:/listmonk/config.toml
    depends_on:
      - db
  db:
    image: postgres:16-alpine
    restart: unless-stopped
    volumes:
      - db_data:/var/lib/postgresql/data
    environment:
      - POSTGRES_DB=listmonk
      - POSTGRES_USER=listmonk
      - POSTGRES_PASSWORD=${DB_PASS}
volumes:
  db_data:

Git Hosting

Gitea

services:
  gitea:
    image: gitea/gitea:latest
    restart: unless-stopped
    ports:
      - "3000:3000"
      - "222:22"
    volumes:
      - gitea_data:/data
    environment:
      - GITEA__database__DB_TYPE=postgres
      - GITEA__database__HOST=db:5432
      - GITEA__database__NAME=gitea
      - GITEA__database__USER=gitea
      - GITEA__database__PASSWD=${DB_PASS}
    depends_on:
      - db
  db:
    image: postgres:16-alpine
    restart: unless-stopped
    volumes:
      - db_data:/var/lib/postgresql/data
    environment:
      - POSTGRES_DB=gitea
      - POSTGRES_USER=gitea
      - POSTGRES_PASSWORD=${DB_PASS}
volumes:
  gitea_data:
  db_data:

Meilisearch

services:
  meilisearch:
    image: getmeili/meilisearch:latest
    restart: unless-stopped
    ports:
      - "7700:7700"
    volumes:
      - meili_data:/meili_data
    environment:
      - MEILI_MASTER_KEY=${MASTER_KEY}
      - MEILI_ENV=production
volumes:
  meili_data:

.env Template

Create a .env file for each service:

# Domain
DOMAIN=app.yourdomain.com

# Database
DB_NAME=myapp
DB_USER=myapp
DB_PASS=CHANGE_ME_GENERATED_PASSWORD
DB_ROOT_PASS=CHANGE_ME_ROOT_PASSWORD

# Admin
ADMIN_USER=admin
ADMIN_PASS=CHANGE_ME_ADMIN_PASSWORD

# SMTP
SMTP_HOST=smtp.resend.com
SMTP_USER=resend
SMTP_PASS=re_your_api_key
SMTP_FROM=app@yourdomain.com

# Secrets (generate with: openssl rand -hex 32)
SECRET_KEY=CHANGE_ME_64_CHAR_HEX
ENCRYPTION_KEY=CHANGE_ME_64_CHAR_HEX
ADMIN_TOKEN=CHANGE_ME_64_CHAR_HEX
MASTER_KEY=CHANGE_ME_64_CHAR_HEX

Generate all secrets at once:

echo "SECRET_KEY=$(openssl rand -hex 32)"
echo "ENCRYPTION_KEY=$(openssl rand -hex 32)"
echo "ADMIN_TOKEN=$(openssl rand -hex 32)"
echo "MASTER_KEY=$(openssl rand -hex 32)"
echo "DB_PASS=$(openssl rand -hex 16)"
echo "DB_ROOT_PASS=$(openssl rand -hex 16)"
echo "ADMIN_PASS=$(openssl rand -base64 24)"

Find the right self-hosted tool for your needs on OSSAlt — features, Docker support, and deployment guides side by side.