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
| Project | FerretDB v2.7 |
| License | Apache 2.0 |
| Recommended Plan | RamNode Cloud VPS 2 GB+ (4 GB+ for heavier workloads) |
| OS | Ubuntu 22.04 / 24.04 LTS |
| Stack | Docker, PostgreSQL 17, DocumentDB extension |
| Estimated Setup Time | 20–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 enable2
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 docker3
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
EOFdocker-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: ferretdbStart the stack
docker compose up -d
docker compose ps
docker compose logs -f --tail=504
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.comTLS 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:roConnect 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.shSchedule with cron
crontab -e
# Add: 0 2 * * * /home/deploy/ferretdb/backup.sh >> /home/deploy/ferretdb/backups/backup.log 2>&1Restore from backup
docker exec -i ferretdb-postgres pg_restore \
-U ferretdb_admin -d postgres --clean --if-exists \
< backups/ferretdb_YYYYMMDD_HHMMSS.dump8
Monitoring
Monitor containers
docker compose logs -f ferretdb
docker stats ferretdb ferretdb-postgres
docker inspect --format='{{.State.Health.Status}}' ferretdbPostgreSQL 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 = 200Docker 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=500to the postgres command for slow query logging - Port conflict: Change the host port mapping if another service uses 27017
