Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Docker Deployment

This guide covers running Rustmail in Docker containers.


Quick Start

Pull the Image

docker pull ghcr.io/rustmail/rustmail:latest

Run with Docker

docker run -d \
  --name rustmail \
  -p 3002:3002 \
  -v /path/to/config.toml:/app/config.toml:ro \
  -v rustmail-data:/app/db \
  ghcr.io/rustmail/rustmail:latest

Docker Compose

Create a docker-compose.yml:

version: '3.8'

services:
  rustmail:
    image: ghcr.io/rustmail/rustmail:latest
    container_name: rustmail
    restart: unless-stopped
    ports:
      - "3002:3002"
    volumes:
      - ./config.toml:/app/config.toml:ro
      - rustmail-data:/app/db
    environment:
      - TZ=Europe/Paris

volumes:
  rustmail-data:

Start with:

docker-compose up -d

Configuration

Volume Mounts

PathDescription
/app/config.tomlConfiguration file (required)
/app/dbDatabase directory (persistent storage)

Ports

PortDescription
3002Web panel and API

Environment Variables

VariableDescription
TZContainer timezone

Building the Image

To build from source:

# Clone the repository
git clone https://github.com/Rustmail/rustmail.git
cd rustmail

# Build the image
docker build -t rustmail:local .

The Dockerfile uses a multi-stage build with Debian Bookworm Slim as the runtime base.


Docker Compose with Reverse Proxy

With Traefik

version: '3.8'

services:
  rustmail:
    image: ghcr.io/rustmail/rustmail:latest
    container_name: rustmail
    restart: unless-stopped
    volumes:
      - ./config.toml:/app/config.toml:ro
      - rustmail-data:/app/db
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.rustmail.rule=Host(`panel.example.com`)"
      - "traefik.http.routers.rustmail.tls=true"
      - "traefik.http.routers.rustmail.tls.certresolver=letsencrypt"
      - "traefik.http.services.rustmail.loadbalancer.server.port=3002"
    networks:
      - traefik

networks:
  traefik:
    external: true

volumes:
  rustmail-data:

With Nginx Proxy Manager

version: '3.8'

services:
  rustmail:
    image: ghcr.io/rustmail/rustmail:latest
    container_name: rustmail
    restart: unless-stopped
    volumes:
      - ./config.toml:/app/config.toml:ro
      - rustmail-data:/app/db
    networks:
      - npm_network

networks:
  npm_network:
    external: true

volumes:
  rustmail-data:

Then in NPM, create a proxy host pointing to rustmail:3002.

With Caddy

version: '3.8'

services:
  rustmail:
    image: ghcr.io/rustmail/rustmail:latest
    container_name: rustmail
    restart: unless-stopped
    volumes:
      - ./config.toml:/app/config.toml:ro
      - rustmail-data:/app/db
    networks:
      - caddy

  caddy:
    image: caddy:alpine
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile:ro
      - caddy-data:/data
    networks:
      - caddy

networks:
  caddy:

volumes:
  rustmail-data:
  caddy-data:

Caddyfile:

panel.example.com {
    reverse_proxy rustmail:3002
}

Health Checks

Add health monitoring:

services:
  rustmail:
    image: ghcr.io/rustmail/rustmail:latest
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:3002/api/panel/check"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 10s

Logging

View logs:

# Follow logs
docker logs -f rustmail

# Last 100 lines
docker logs --tail 100 rustmail

Configure log rotation in Docker daemon or use a logging driver:

services:
  rustmail:
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"

Backup

Database Backup

# Stop container for consistent backup
docker stop rustmail

# Copy database
docker cp rustmail:/app/db/db.sqlite ./backup-$(date +%Y%m%d).sqlite

# Restart
docker start rustmail

Volume Backup

docker run --rm \
  -v rustmail-data:/data:ro \
  -v $(pwd):/backup \
  alpine tar czf /backup/rustmail-backup.tar.gz /data

Updates

Pull New Image

docker-compose pull
docker-compose up -d

Manual Update

docker pull ghcr.io/rustmail/rustmail:latest
docker stop rustmail
docker rm rustmail
# Run new container with same volumes

Troubleshooting

Container Won’t Start

Check logs:

docker logs rustmail

Common issues:

  • Invalid config.toml syntax
  • Missing required configuration fields
  • Permission issues on mounted volumes

Container Stops After “Database connected!”

If logs only show:

Database connection pool established
Database connected!

The bot cannot load config.toml. The most common cause is an incorrect volume mount:

# WRONG - relative path creates a directory instead of mounting the file
docker run -v config.toml:/app/config.toml ...

# CORRECT - use absolute path
docker run -v $(pwd)/config.toml:/app/config.toml ...
docker run -v /home/user/rustmail/config.toml:/app/config.toml ...

Verify the mount is correct:

# Should show a file, not a directory
docker exec rustmail ls -la /app/config.toml

# Should display your config content
docker exec rustmail cat /app/config.toml

If /app/config.toml is a directory, remove the container and recreate with the correct path:

docker rm -f rustmail
docker run -d --name rustmail -v $(pwd)/config.toml:/app/config.toml:ro ...

Cannot Connect to Panel

  • Verify port 3002 is exposed: docker port rustmail
  • Check container is running: docker ps
  • Verify network connectivity to container

Database Errors

  • Ensure /app/db volume is writable
  • Check disk space on host
  • Verify volume mount is correct

Permission Denied

The container runs as user rustmail (UID 1000). Ensure mounted volumes are accessible:

# Fix permissions on host
chown -R 1000:1000 /path/to/data