You’re staring at another $500/month managed DB bill. “I could self-host this,” you whisper… then imagine 2 AM alerts, corrupted backups, and security holes big enough to drive a truck through.
Relax. With Docker + a $5 VPS, you can run bulletproof PostgreSQL/MySQL databases—without becoming a full-time sysadmin. I’ve done it for 50+ apps. Let’s build yours in 15 minutes flat.
Why Self-Host? (Spoiler: It’s Not Just About Money)
Managed DBs are great… until you need:
-
Total control over configs (
shared_buffers
, anyone?). - Zero latency between app + DB (same VPS = 💥 speed).
- Costs below $10/month (yes, it’s possible).
Warning: Don’t do this for Fortune 500 apps. Do it for:
- Side projects
- Internal tools
- Learning real database ops
Step 0: Pick Your VPS (The $5 Heroes)
- DigitalOcean: 1GB RAM, 25GB SSD, dead-simple UI → $6/month.
- Linode: 1GB RAM, NVMe storage, 1TB transfer → $5/month.
- Hetzner: 2GB RAM, 40GB SSD (Germany-only) → €4.49/month.
Pro Move: Use Ubuntu 22.04 LTS. Battle-tested + Docker-friendly.
Step 1: Dockerize Your Database (5 Minutes)
For PostgreSQL:
# docker-compose.yml
services:
db:
image: postgres:15
container_name: postgres_db
volumes:
- pg_data:/var/lib/postgresql/data
environment:
POSTGRES_PASSWORD: your_strong_password
ports:
- "5432:5432"
volumes:
pg_data:
For MySQL:
services:
db:
image: mysql:8.0
container_name: mysql_db
volumes:
- mysql_data:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: your_strong_password
ports:
- "3306:3306"
volumes:
mysql_data:
Run it:
docker compose up -d
Boom. Your DB is alive.
Step 2: Lock Down Security (Non-Negotiable)
- SSH Hardening:
# /etc/ssh/sshd_config
PermitRootLogin no
PasswordAuthentication no
AllowUsers your_username
- Firewall Rules:
ufw allow 22/tcp
ufw allow 5432/tcp # or 3306 for MySQL
ufw enable
- DB User Best Practices:
-- NEVER use root!
CREATE USER app_user WITH PASSWORD 'strong!password';
GRANT SELECT, INSERT ON ALL TABLES TO app_user;
Step 3: Automated Backups (Sleep Soundly)
Backup Script (/scripts/backup_db.sh
):
#!/bin/bash
DATE=$(date +%Y-%m-%d)
docker exec postgres_db pg_dump -U postgres mydb > /backups/mydb_$DATE.sql
# For MySQL:
# docker exec mysql_db mysqldump -u root -p'pass' mydb > /backups/mydb_$DATE.sql
Cron Job (Daily at 2 AM):
crontab -e
0 2 * * * /bin/bash /scripts/backup_db.sh
Pro Tip: Sync backups to S3/Backblaze:
rclone sync /backups s3:bucket_name
Step 4: Monitoring (No More Guessing Games)
Install Prometheus + Grafana:
# docker-compose-monitoring.yml
services:
prometheus:
image: prom/prometheus
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
grafana:
image: grafana/grafana
ports:
- "3000:3000"
Grab a Dashboard:
When Self-Hosting Bites Back (Be Honest!)
- Disaster Strikes: VPS provider outage → DB down.
-
Security Fail: You missed a
pg_hba.conf
tweak → hacked. - Scale Walls: 100+ writes/sec? Good luck tuning solo.
Switch to Managed When:
- You value sleep > $200/month savings.
- Your app makes real revenue.
- You’re bored of being a DBA.
Real-World Cost Breakdown
Item | Managed DB | Self-Hosted |
---|---|---|
Postgres | $50+/month | $5/month |
Backups | $20+/month | $0.023/GB (S3) |
Expertise | $0 (their ops) | Your weekends |
TL;DR:
- Docker Compose: Your database’s blueprint.
- $5 VPS: Your playground.
- Backups + Monitoring: Your insurance. Total control under $10/month? Priceless.
Your Move:
- Spin up a $5 VPS.
- Run the
docker-compose.yml
above. - Never pay for overkill again.
Tag that friend still paying for Heroku Postgres for their blog. They need freedom.
Self-hosting horror story? Share below! We’ve all been there. 😅💬
Top comments (0)