Skip to main content

Overview

Docker Compose simplifies the deployment and management of Homarr, especially when using external databases or Redis. This guide provides production-ready configurations for various scenarios.
Docker Compose is recommended for production deployments as it provides better container orchestration, easier updates, and cleaner configuration management.

Prerequisites

  • Docker 20.10+ installed
  • Docker Compose 2.0+ installed (or Docker with Compose plugin)
  • Basic understanding of YAML syntax

Basic Setup

Minimal Configuration

Create a docker-compose.yml file:
docker-compose.yml
version: '3.8'

services:
  homarr:
    image: ghcr.io/homarr-labs/homarr:latest
    container_name: homarr
    restart: unless-stopped
    ports:
      - '7575:7575'
    volumes:
      - ./homarr/data:/appdata
    environment:
      - SECRET_ENCRYPTION_KEY=${SECRET_ENCRYPTION_KEY}
      - LOG_LEVEL=info
      - DB_DRIVER=better-sqlite3
      - DB_URL=/appdata/db/db.sqlite
Create a .env file in the same directory:
.env
# Generate with: openssl rand -hex 32
SECRET_ENCRYPTION_KEY=0000000000000000000000000000000000000000000000000000000000000000
Replace the SECRET_ENCRYPTION_KEY with a real 64-character hex string. Never commit this to version control.

Start Homarr

# Start in detached mode
docker compose up -d

# View logs
docker compose logs -f

# Stop services
docker compose down

Production Configurations

Homarr with MySQL

version: '3.8'

services:
  homarr:
    image: ghcr.io/homarr-labs/homarr:latest
    container_name: homarr
    restart: unless-stopped
    ports:
      - '7575:7575'
    volumes:
      - ./homarr/data:/appdata
    environment:
      - SECRET_ENCRYPTION_KEY=${SECRET_ENCRYPTION_KEY}
      - LOG_LEVEL=info
      - DB_DRIVER=mysql2
      - DB_HOST=mysql
      - DB_PORT=3306
      - DB_USER=homarr
      - DB_PASSWORD=${DB_PASSWORD}
      - DB_NAME=homarrdb
    depends_on:
      mysql:
        condition: service_healthy

  mysql:
    image: mysql:8.0
    container_name: homarr-mysql
    restart: unless-stopped
    environment:
      - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
      - MYSQL_DATABASE=homarrdb
      - MYSQL_USER=homarr
      - MYSQL_PASSWORD=${DB_PASSWORD}
    volumes:
      - ./mysql/data:/var/lib/mysql
    healthcheck:
      test: ['CMD', 'mysqladmin', 'ping', '-h', 'localhost']
      interval: 10s
      timeout: 5s
      retries: 5

Homarr with PostgreSQL

version: '3.8'

services:
  homarr:
    image: ghcr.io/homarr-labs/homarr:latest
    container_name: homarr
    restart: unless-stopped
    ports:
      - '7575:7575'
    volumes:
      - ./homarr/data:/appdata
    environment:
      - SECRET_ENCRYPTION_KEY=${SECRET_ENCRYPTION_KEY}
      - LOG_LEVEL=info
      - DB_DRIVER=node-postgres
      - DB_URL=postgres://homarr:${DB_PASSWORD}@postgres:5432/homarrdb
    depends_on:
      postgres:
        condition: service_healthy

  postgres:
    image: postgres:16-alpine
    container_name: homarr-postgres
    restart: unless-stopped
    shm_size: 128mb
    environment:
      - POSTGRES_USER=homarr
      - POSTGRES_PASSWORD=${DB_PASSWORD}
      - POSTGRES_DB=homarrdb
      - PGDATA=/var/lib/postgresql/data/pgdata
    volumes:
      - ./postgres/data:/var/lib/postgresql/data
    healthcheck:
      test: ['CMD-SHELL', 'pg_isready -U homarr -d homarrdb']
      interval: 10s
      timeout: 5s
      retries: 5

Full Stack with External Redis

docker-compose.yml
version: '3.8'

services:
  homarr:
    image: ghcr.io/homarr-labs/homarr:latest
    container_name: homarr
    restart: unless-stopped
    ports:
      - '7575:7575'
    volumes:
      - ./homarr/data:/appdata
    environment:
      - SECRET_ENCRYPTION_KEY=${SECRET_ENCRYPTION_KEY}
      - LOG_LEVEL=info
      - DB_DRIVER=node-postgres
      - DB_URL=postgres://homarr:${DB_PASSWORD}@postgres:5432/homarrdb
      - REDIS_IS_EXTERNAL=true
      - REDIS_HOST=redis
      - REDIS_PORT=6379
    depends_on:
      postgres:
        condition: service_healthy
      redis:
        condition: service_healthy

  postgres:
    image: postgres:16-alpine
    container_name: homarr-postgres
    restart: unless-stopped
    shm_size: 128mb
    environment:
      - POSTGRES_USER=homarr
      - POSTGRES_PASSWORD=${DB_PASSWORD}
      - POSTGRES_DB=homarrdb
      - PGDATA=/var/lib/postgresql/data/pgdata
    volumes:
      - ./postgres/data:/var/lib/postgresql/data
    healthcheck:
      test: ['CMD-SHELL', 'pg_isready -U homarr -d homarrdb']
      interval: 10s
      timeout: 5s
      retries: 5

  redis:
    image: redis:7-alpine
    container_name: homarr-redis
    restart: unless-stopped
    command: redis-server --appendonly yes
    volumes:
      - ./redis/data:/data
    healthcheck:
      test: ['CMD', 'redis-cli', 'ping']
      interval: 10s
      timeout: 5s
      retries: 5

High Availability Configuration

For production environments with multiple Homarr instances:
docker-compose.yml
version: '3.8'

services:
  homarr-1:
    image: ghcr.io/homarr-labs/homarr:latest
    container_name: homarr-1
    restart: unless-stopped
    ports:
      - '7575:7575'
    volumes:
      - ./homarr/data:/appdata
    environment:
      - SECRET_ENCRYPTION_KEY=${SECRET_ENCRYPTION_KEY}
      - LOG_LEVEL=info
      - DB_DRIVER=node-postgres
      - DB_URL=postgres://homarr:${DB_PASSWORD}@postgres:5432/homarrdb
      - REDIS_IS_EXTERNAL=true
      - REDIS_HOST=redis
      - REDIS_PORT=6379
    depends_on:
      postgres:
        condition: service_healthy
      redis:
        condition: service_healthy

  homarr-2:
    image: ghcr.io/homarr-labs/homarr:latest
    container_name: homarr-2
    restart: unless-stopped
    ports:
      - '7576:7575'
    volumes:
      - ./homarr/data:/appdata
    environment:
      - SECRET_ENCRYPTION_KEY=${SECRET_ENCRYPTION_KEY}
      - LOG_LEVEL=info
      - DB_DRIVER=node-postgres
      - DB_URL=postgres://homarr:${DB_PASSWORD}@postgres:5432/homarrdb
      - REDIS_IS_EXTERNAL=true
      - REDIS_HOST=redis
      - REDIS_PORT=6379
    depends_on:
      postgres:
        condition: service_healthy
      redis:
        condition: service_healthy

  postgres:
    image: postgres:16-alpine
    container_name: homarr-postgres
    restart: unless-stopped
    shm_size: 128mb
    environment:
      - POSTGRES_USER=homarr
      - POSTGRES_PASSWORD=${DB_PASSWORD}
      - POSTGRES_DB=homarrdb
      - PGDATA=/var/lib/postgresql/data/pgdata
    volumes:
      - ./postgres/data:/var/lib/postgresql/data
    healthcheck:
      test: ['CMD-SHELL', 'pg_isready -U homarr -d homarrdb']
      interval: 10s
      timeout: 5s
      retries: 5

  redis:
    image: redis:7-alpine
    container_name: homarr-redis
    restart: unless-stopped
    command: redis-server --appendonly yes
    volumes:
      - ./redis/data:/data
    healthcheck:
      test: ['CMD', 'redis-cli', 'ping']
      interval: 10s
      timeout: 5s
      retries: 5

  load-balancer:
    image: nginx:alpine
    container_name: homarr-lb
    restart: unless-stopped
    ports:
      - '80:80'
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
    depends_on:
      - homarr-1
      - homarr-2

Environment Variables Reference

All environment variables from the Docker installation guide apply. Here are Docker Compose-specific considerations:

Using .env Files

Create a .env file for sensitive values:
.env
# Encryption
SECRET_ENCRYPTION_KEY=your-64-char-hex-string

# Database
DB_PASSWORD=secure_password
MYSQL_ROOT_PASSWORD=root_password

# Logging
LOG_LEVEL=info

# User Permissions
PUID=1000
PGID=1000
Add .env to your .gitignore to prevent committing secrets to version control.

Authentication Configuration

For OIDC or LDAP, add to your .env:
.env
# OIDC
AUTH_PROVIDERS=oidc
AUTH_OIDC_CLIENT_ID=your-client-id
AUTH_OIDC_CLIENT_SECRET=your-client-secret
AUTH_OIDC_ISSUER=https://auth.example.com
AUTH_OIDC_CLIENT_NAME=My SSO

# LDAP
AUTH_PROVIDERS=ldap
AUTH_LDAP_URI=ldap://ldap.example.com:389
AUTH_LDAP_BASE=dc=example,dc=com
AUTH_LDAP_BIND_DN=cn=admin,dc=example,dc=com
AUTH_LDAP_BIND_PASSWORD=adminpassword

Management Commands

Starting Services

docker compose up -d

Viewing Logs

docker compose logs -f

Stopping Services

docker compose stop

Updating Services

1

Backup your data

tar -czf backup-$(date +%Y%m%d).tar.gz ./homarr ./mysql ./postgres ./redis
2

Pull new images

docker compose pull
3

Restart services

docker compose up -d
4

Remove old images

docker image prune -f

Scaling Services

Run multiple Homarr instances:
docker compose up -d --scale homarr=3
Scaling requires external database and Redis. Don’t scale with SQLite.

Reverse Proxy Integration

Traefik Labels

Add Traefik labels to your Homarr service:
services:
  homarr:
    image: ghcr.io/homarr-labs/homarr:latest
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.homarr.rule=Host(`homarr.example.com`)"
      - "traefik.http.routers.homarr.entrypoints=websecure"
      - "traefik.http.routers.homarr.tls=true"
      - "traefik.http.routers.homarr.tls.certresolver=letsencrypt"
      - "traefik.http.services.homarr.loadbalancer.server.port=7575"

Nginx Proxy Manager

Create a proxy host in NPM:
  • Domain: homarr.example.com
  • Forward Hostname: homarr (container name)
  • Forward Port: 7575
  • WebSocket Support: Enabled
  • SSL: Use Let’s Encrypt

Caddy

Add to your Caddyfile:
homarr.example.com {
    reverse_proxy homarr:7575
}

Backup and Restore

Automated Backup Script

Create backup.sh:
backup.sh
#!/bin/bash

BACKUP_DIR="./backups"
DATE=$(date +%Y%m%d-%H%M%S)

mkdir -p "$BACKUP_DIR"

# Stop services
docker compose stop

# Backup data
tar -czf "$BACKUP_DIR/homarr-backup-$DATE.tar.gz" \
  ./homarr ./mysql ./postgres ./redis ./.env

# Start services
docker compose up -d

# Keep only last 7 backups
ls -t "$BACKUP_DIR"/homarr-backup-*.tar.gz | tail -n +8 | xargs -r rm

echo "Backup completed: homarr-backup-$DATE.tar.gz"
Make it executable and run:
chmod +x backup.sh
./backup.sh

Restore from Backup

# Stop services
docker compose down

# Restore data
tar -xzf backups/homarr-backup-YYYYMMDD-HHMMSS.tar.gz

# Start services
docker compose up -d

Troubleshooting

Service Won’t Start

Check service status:
docker compose ps
View detailed logs:
docker compose logs homarr

Database Connection Failed

Verify database is running:
docker compose ps postgres
Check database logs:
docker compose logs postgres
Test connection from Homarr container:
docker compose exec homarr ping postgres

Port Already in Use

Change the port mapping in docker-compose.yml:
ports:
  - '8080:7575'  # Use port 8080 instead

Permission Denied Errors

Fix ownership of data directories:
sudo chown -R 1000:1000 ./homarr ./mysql ./postgres ./redis
Or set PUID/PGID in docker-compose.yml:
environment:
  - PUID=1000
  - PGID=1000

Best Practices

  1. Use external databases for production (MySQL or PostgreSQL)
  2. Always use .env files for secrets, never hardcode in docker-compose.yml
  3. Enable healthchecks for all services
  4. Use named volumes for databases in production
  5. Implement regular backups with automated scripts
  6. Monitor resource usage with docker stats
  7. Keep images updated by running docker compose pull regularly
  8. Use specific version tags instead of latest for stability
  9. Document your setup including all environment variables
  10. Test restore procedures to ensure backups work

Next Steps

Kubernetes Deployment

Deploy Homarr on Kubernetes for scalability

Configuration Guide

Advanced configuration and tuning

Integrations

Connect your self-hosted services

Backup & Restore

Backup your Homarr installation

Build docs developers (and LLMs) love