Skip to content

Docker Deployment

This guide covers deploying SlimRMM using Docker and Docker Compose.

Prerequisites

  • Docker 24.0 or higher
  • Docker Compose 2.20 or higher
  • A domain name (optional but recommended)
  • SSL certificate (Let's Encrypt recommended)

1. Install Docker

Ubuntu/Debian

bash
# Update packages
sudo apt update
sudo apt install -y curl

# Install Docker
curl -fsSL https://get.docker.com | sudo sh

# Add user to docker group
sudo usermod -aG docker $USER

# Install Docker Compose
sudo apt install -y docker-compose-plugin

# Verify installation
docker --version
docker compose version

RHEL/CentOS

bash
# Install Docker
sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
sudo dnf install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin

# Start Docker
sudo systemctl enable --now docker

# Add user to docker group
sudo usermod -aG docker $USER

2. Create Project Directory

bash
mkdir -p /opt/slimrmm
cd /opt/slimrmm

3. Create Docker Compose File

Create docker-compose.yml:

yaml
version: '3.8'

services:
  postgres:
    image: postgres:16-alpine
    container_name: slimrmm-db
    restart: unless-stopped
    environment:
      POSTGRES_USER: rmm
      POSTGRES_PASSWORD: ${DB_PASSWORD}
      POSTGRES_DB: rmm
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U rmm"]
      interval: 10s
      timeout: 5s
      retries: 5
    networks:
      - slimrmm

  redis:
    image: redis:7-alpine
    container_name: slimrmm-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
    networks:
      - slimrmm

  backend:
    image: ghcr.io/slimrmm/backend:latest
    container_name: slimrmm-backend
    restart: unless-stopped
    depends_on:
      postgres:
        condition: service_healthy
      redis:
        condition: service_healthy
    environment:
      - DATABASE_URL=postgresql+asyncpg://rmm:${DB_PASSWORD}@postgres:5432/rmm
      - REDIS_URL=redis://redis:6379/0
      - SECRET_KEY=${SECRET_KEY}
      - AGENT_INSTALL_KEY=${AGENT_INSTALL_KEY}
      - FRONTEND_URL=${FRONTEND_URL}
      - DEBUG=false
    volumes:
      - ./certs:/app/certs
      - ./logs:/app/logs
    ports:
      - "8000:8000"
    networks:
      - slimrmm

  frontend:
    image: ghcr.io/slimrmm/frontend:latest
    container_name: slimrmm-frontend
    restart: unless-stopped
    depends_on:
      - backend
    environment:
      - VITE_API_URL=${BACKEND_URL}
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
      - ./ssl:/etc/nginx/ssl:ro
    networks:
      - slimrmm

volumes:
  postgres_data:
  redis_data:

networks:
  slimrmm:
    driver: bridge

4. Create Environment File

Create .env:

bash
# Database
DB_PASSWORD=your_secure_database_password

# Security Keys (generate with: python3 -c "import secrets; print(secrets.token_urlsafe(32))")
SECRET_KEY=your_generated_secret_key
AGENT_INSTALL_KEY=your_generated_agent_key

# URLs
FRONTEND_URL=https://rmm.example.com
BACKEND_URL=https://rmm.example.com/api

Generate secure keys:

bash
# Generate SECRET_KEY
python3 -c "import secrets; print(secrets.token_urlsafe(32))"

# Generate AGENT_INSTALL_KEY
python3 -c "import secrets; print(secrets.token_hex(16))"

5. Configure Nginx

Create nginx.conf:

nginx
events {
    worker_connections 1024;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    upstream backend {
        server backend:8000;
    }

    server {
        listen 80;
        server_name rmm.example.com;
        return 301 https://$server_name$request_uri;
    }

    server {
        listen 443 ssl http2;
        server_name rmm.example.com;

        ssl_certificate /etc/nginx/ssl/fullchain.pem;
        ssl_certificate_key /etc/nginx/ssl/privkey.pem;
        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
        ssl_prefer_server_ciphers off;

        # Security headers
        add_header X-Frame-Options "SAMEORIGIN" always;
        add_header X-Content-Type-Options "nosniff" always;
        add_header X-XSS-Protection "1; mode=block" always;

        # API and WebSocket
        location /api/ {
            proxy_pass http://backend/api/;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
            proxy_read_timeout 86400;
        }

        # Health check
        location /health {
            proxy_pass http://backend/health;
        }

        # Frontend
        location / {
            root /usr/share/nginx/html;
            index index.html;
            try_files $uri $uri/ /index.html;
        }
    }
}

6. SSL Certificate

bash
# Install certbot
sudo apt install -y certbot

# Get certificate
sudo certbot certonly --standalone -d rmm.example.com

# Copy certificates
sudo mkdir -p ssl
sudo cp /etc/letsencrypt/live/rmm.example.com/fullchain.pem ssl/
sudo cp /etc/letsencrypt/live/rmm.example.com/privkey.pem ssl/
sudo chmod 644 ssl/*.pem

Auto-renewal

bash
# Add to crontab
echo "0 0 * * * certbot renew --quiet && docker compose restart frontend" | sudo crontab -

7. Start Services

bash
# Pull images
docker compose pull

# Start services
docker compose up -d

# Check status
docker compose ps

# View logs
docker compose logs -f

8. Initialize Database

bash
# Run migrations
docker compose exec backend alembic upgrade head

9. Create Admin User

bash
docker compose exec backend python -c "
from app.core.database import get_db_sync
from app.services.auth_service import AuthService

db = next(get_db_sync())
auth_service = AuthService()
user = auth_service.create_user(
    db,
    username='admin',
    email='admin@example.com',
    password='YourSecurePassword123!',
    is_admin=True
)
print(f'Admin user created: {user.username}')
"

10. Verify Installation

  1. Open https://rmm.example.com in your browser
  2. Log in with admin credentials
  3. Check health endpoint: https://rmm.example.com/health

Updating

bash
# Pull latest images
docker compose pull

# Restart services
docker compose up -d

# Run any new migrations
docker compose exec backend alembic upgrade head

Backup

bash
# Backup database
docker compose exec postgres pg_dump -U rmm rmm > backup_$(date +%Y%m%d).sql

# Backup volumes
docker run --rm -v slimrmm_postgres_data:/data -v $(pwd):/backup alpine tar czf /backup/postgres_data.tar.gz /data

Troubleshooting

View Logs

bash
# All services
docker compose logs -f

# Specific service
docker compose logs -f backend

Restart Services

bash
docker compose restart

Reset Database

bash
# Warning: This deletes all data!
docker compose down -v
docker compose up -d

Released under the MIT License.