MongoDB-Compatible
    Open Source

    Deploy FerretDB on a VPS

    Open-source MongoDB-compatible database backed by PostgreSQL — run MongoDB workloads without SSPL licensing, with Docker Compose, TLS, and automated backups.

    At a Glance

    ProjectFerretDB v2.7
    LicenseApache 2.0
    Recommended PlanRamNode Cloud VPS 2 GB+ (4 GB+ for heavier workloads)
    OSUbuntu 22.04 / 24.04 LTS
    StackDocker, PostgreSQL 17, DocumentDB extension
    Estimated Setup Time20–30 minutes

    Prerequisites

    • A RamNode VPS with at least 2 GB RAM
    • Ubuntu 22.04 or 24.04 LTS
    • SSH access with a sudo-capable user
    • A domain name (optional, for TLS)
    1

    Initial Server Setup

    Update and configure firewall
    sudo apt update && sudo apt upgrade -y
    adduser deploy
    usermod -aG sudo deploy
    su - deploy
    
    sudo ufw allow OpenSSH
    sudo ufw allow 27017/tcp
    sudo ufw enable
    2

    Install Docker and Docker Compose

    Install Docker
    sudo apt install -y ca-certificates curl gnupg
    sudo install -m 0755 -d /etc/apt/keyrings
    curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
    sudo chmod a+r /etc/apt/keyrings/docker.gpg
    
    echo \
      "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
      $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
      sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
    
    sudo apt update
    sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
    sudo usermod -aG docker $USER
    newgrp docker
    3

    Deploy FerretDB with Docker Compose

    Create project and .env
    mkdir -p ~/ferretdb && cd ~/ferretdb
    
    cat > .env << 'EOF'
    POSTGRES_USER=ferretdb_admin
    POSTGRES_PASSWORD=CHANGE_ME_TO_A_STRONG_PASSWORD
    POSTGRES_DB=postgres
    EOF
    docker-compose.yml
    services:
      postgres:
        image: ghcr.io/ferretdb/postgres-documentdb:17-0.107.0-ferretdb-2.7.0
        container_name: ferretdb-postgres
        restart: unless-stopped
        environment:
          - POSTGRES_USER=${POSTGRES_USER}
          - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
          - POSTGRES_DB=${POSTGRES_DB}
        volumes:
          - pgdata:/var/lib/postgresql/data
        healthcheck:
          test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER}"]
          interval: 10s
          timeout: 5s
          retries: 5
    
      ferretdb:
        image: ghcr.io/ferretdb/ferretdb:2.7.0
        container_name: ferretdb
        restart: unless-stopped
        ports:
          - "127.0.0.1:27017:27017"
        environment:
          - FERRETDB_POSTGRESQL_URL=postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB}
        depends_on:
          postgres:
            condition: service_healthy
    
    volumes:
      pgdata:
    
    networks:
      default:
        name: ferretdb
    Start the stack
    docker compose up -d
    docker compose ps
    docker compose logs -f --tail=50
    4

    Connect and Verify

    Connect via Docker
    docker run --rm -it --network=ferretdb --entrypoint=mongosh \
      mongo mongodb://ferretdb_admin:PASSWORD@ferretdb/
    Smoke test
    // Insert a test document
    db.test.insertOne({ name: "FerretDB on RamNode", status: "deployed", timestamp: new Date() })
    
    // Query it back
    db.test.find()
    
    // Check server status
    db.runCommand({ ping: 1 })
    5

    Create Application Users

    FerretDB delegates authentication to PostgreSQL using SCRAM-SHA-256.

    Create user via mongosh
    use admin
    db.createUser({
      user: "appuser",
      pwd: "a_strong_app_password",
      roles: []
    })
    Or directly in PostgreSQL
    docker exec -it ferretdb-postgres psql -U ferretdb_admin -d postgres -c \
      "CREATE USER appuser WITH PASSWORD 'a_strong_app_password'; GRANT ALL ON SCHEMA public TO appuser;"
    6

    Secure with TLS

    Obtain certificate
    sudo apt install -y certbot
    sudo certbot certonly --standalone -d ferretdb.yourdomain.com
    TLS environment variables
    # Add to ferretdb service:
    environment:
      - FERRETDB_LISTEN_TLS=:27018
      - FERRETDB_LISTEN_TLS_CERT_FILE=/certs/fullchain.pem
      - FERRETDB_LISTEN_TLS_KEY_FILE=/certs/privkey.pem
    volumes:
      - /etc/letsencrypt/live/ferretdb.yourdomain.com/fullchain.pem:/certs/fullchain.pem:ro
      - /etc/letsencrypt/live/ferretdb.yourdomain.com/privkey.pem:/certs/privkey.pem:ro
    Connect over TLS
    mongosh "mongodb://appuser:password@ferretdb.yourdomain.com:27018/?tls=true"
    7

    Backups

    Automated pg_dump backup script
    cat > ~/ferretdb/backup.sh << 'BASH'
    #!/bin/bash
    set -euo pipefail
    BACKUP_DIR="/home/deploy/ferretdb/backups"
    TIMESTAMP=$(date +%Y%m%d_%H%M%S)
    mkdir -p "$BACKUP_DIR"
    
    docker exec ferretdb-postgres pg_dump \
      -U ferretdb_admin -d postgres \
      --format=custom --compress=9 \
      > "$BACKUP_DIR/ferretdb_${TIMESTAMP}.dump"
    
    find "$BACKUP_DIR" -name "ferretdb_*.dump" -mtime +7 -delete
    echo "Backup completed: ferretdb_${TIMESTAMP}.dump"
    BASH
    
    chmod +x ~/ferretdb/backup.sh
    Schedule with cron
    crontab -e
    # Add: 0 2 * * * /home/deploy/ferretdb/backup.sh >> /home/deploy/ferretdb/backups/backup.log 2>&1
    Restore from backup
    docker exec -i ferretdb-postgres pg_restore \
      -U ferretdb_admin -d postgres --clean --if-exists \
      < backups/ferretdb_YYYYMMDD_HHMMSS.dump
    8

    Monitoring

    Monitor containers
    docker compose logs -f ferretdb
    docker stats ferretdb ferretdb-postgres
    docker inspect --format='{{.State.Health.Status}}' ferretdb
    PostgreSQL stats
    docker exec -it ferretdb-postgres psql -U ferretdb_admin -d postgres -c "
    SELECT numbackends AS active_connections,
      pg_size_pretty(pg_database_size('postgres')) AS db_size
    FROM pg_stat_database WHERE datname = 'postgres';"
    9

    Performance Tuning

    PostgreSQL tuning for 4 GB VPS
    # custom-postgres.conf
    shared_buffers = 1GB
    effective_cache_size = 3GB
    work_mem = 16MB
    maintenance_work_mem = 256MB
    wal_buffers = 16MB
    checkpoint_completion_target = 0.9
    max_wal_size = 2GB
    max_connections = 100
    random_page_cost = 1.1
    effective_io_concurrency = 200
    Docker resource limits
    # Add to docker-compose.yml services:
    postgres:
      deploy:
        resources:
          limits: { memory: 3G }
          reservations: { memory: 1G }
    
    ferretdb:
      deploy:
        resources:
          limits: { memory: 512M }
          reservations: { memory: 128M }
    10

    Updating FerretDB

    Backup, update, and verify
    ~/ferretdb/backup.sh
    
    # Update PostgreSQL/DocumentDB image first
    docker compose pull postgres
    docker compose up -d postgres
    
    # Then update FerretDB
    docker compose pull ferretdb
    docker compose up -d ferretdb
    
    # Verify
    docker compose ps
    mongosh "mongodb://ferretdb_admin:PASSWORD@127.0.0.1:27017/" --eval "db.runCommand({ping:1})"

    Troubleshooting

    • Connection error: Check PostgreSQL health and verify credentials match between .env and FERRETDB_POSTGRESQL_URL
    • Auth failures: FerretDB uses SCRAM-SHA-256 exclusively — ensure your client supports it
    • Slow queries: Add -c log_min_duration_statement=500 to the postgres command for slow query logging
    • Port conflict: Change the host port mapping if another service uses 27017