← Back to Blog
DatabaseTutorial

Database Hosting: PostgreSQL, MySQL, and MongoDB on Bare Metal

Managed database services charge $15–$200+/mo for what you can run on your own server in ten minutes. AWS RDS, PlanetScale, MongoDB Atlas — they all add a 5–10x markup over the actual compute cost. Here is how to install, secure, back up, and replicate the three most popular databases on bare metal.

PostgreSQL

Install and Configure

# Deploy a RAW server and SSH in
npx rawhq deploy
ssh root@your-server-ip

# Install PostgreSQL 16
apt update && apt install -y postgresql-16

# Verify
systemctl status postgresql
sudo -u postgres psql -c "SELECT version();"

Tune for NVMe storage and available RAM. Edit /etc/postgresql/16/main/postgresql.conf:

# Memory (adjust for your server size)
shared_buffers = 1GB
effective_cache_size = 3GB
work_mem = 64MB
maintenance_work_mem = 256MB

# NVMe write performance
wal_buffers = 64MB
checkpoint_completion_target = 0.9
random_page_cost = 1.1

Security Hardening

  • Change the default passwordALTER USER postgres PASSWORD 'strong-random-password';
  • Restrict connections — edit pg_hba.conf to allow only localhost and specific IPs
  • Disable remote root — set listen_addresses = 'localhost' unless replication is needed
  • Enable SSL — set ssl = on with a valid certificate for any remote connections

Backup Strategy

# Daily logical backup (cron job)
pg_dump -U postgres -Fc mydb > /backups/mydb-$(date +%F).dump

# Point-in-time recovery with WAL archiving
archive_mode = on
archive_command = 'cp %p /backups/wal/%f'

# Restore from backup
pg_restore -U postgres -d mydb /backups/mydb-2026-04-06.dump

MySQL

Install and Configure

# Install MySQL 8
apt install -y mysql-server

# Secure the installation
mysql_secure_installation
# Set root password, remove anonymous users,
# disable remote root, remove test database

Tune InnoDB for your hardware in /etc/mysql/mysql.conf.d/mysqld.cnf:

[mysqld]
innodb_buffer_pool_size = 1G
innodb_log_file_size = 256M
innodb_flush_log_at_trx_commit = 2
innodb_flush_method = O_DIRECT
max_connections = 200

Security Hardening

  • Run mysql_secure_installation — removes test databases and anonymous users
  • Create app-specific users — never use root for application connections
  • Bind to localhost — set bind-address = 127.0.0.1 in the config
  • Enable audit logging — track who queries what for compliance

Backup Strategy

# Logical backup
mysqldump -u root -p --all-databases --single-transaction \
  > /backups/mysql-all-$(date +%F).sql

# Binary backup with xtrabackup (faster for large DBs)
xtrabackup --backup --target-dir=/backups/mysql-full/

# Automated daily cron
0 2 * * * mysqldump -u backup -p'pass' mydb | gzip > /backups/mydb-$(date +\%F).sql.gz

MongoDB

Install and Configure

# Add MongoDB 7 repo and install
curl -fsSL https://www.mongodb.org/static/pgp/server-7.0.asc | \
  gpg --dearmor -o /usr/share/keyrings/mongodb-server-7.0.gpg
apt update && apt install -y mongodb-org

# Start MongoDB
systemctl enable mongod
systemctl start mongod

# Verify
mongosh --eval "db.runCommand({ ping: 1 })"

Configure WiredTiger storage engine in /etc/mongod.conf:

storage:
  dbPath: /var/lib/mongodb
  wiredTiger:
    engineConfig:
      cacheSizeGB: 1.5

net:
  bindIp: 127.0.0.1
  port: 27017

security:
  authorization: enabled

Security Hardening

  • Enable authentication — MongoDB ships with auth disabled by default. Always enable it.
  • Create admin userdb.createUser with userAdminAnyDatabase role
  • Bind to localhost only — unless you have a replica set on separate machines
  • Disable HTTP interface — set net.http.enabled: false

Backup Strategy

# Full database dump
mongodump --out /backups/mongo-$(date +%F)

# Restore
mongorestore /backups/mongo-2026-04-06/

# Compressed backup for cron
mongodump --archive=/backups/mongo-$(date +%F).gz --gzip

Replication Basics

Each database handles replication differently, but the concept is the same: a primary server writes data and one or more replicas receive copies for redundancy and read scaling.

  • PostgreSQL — streaming replication with pg_basebackup. Primary writes WAL, replicas stream it in real time.
  • MySQL — binary log replication. Primary logs all changes, replicas apply them. GTID mode simplifies failover.
  • MongoDB — replica sets with automatic failover. Minimum 3 nodes (or 2 data + 1 arbiter). Built-in election protocol.

For most startups and side projects, a single bare metal server with automated backups is sufficient. Add replication when you need high availability or read scaling — deploy a second RAW server and configure streaming replication.

Cost Comparison: Self-Hosted vs Managed

ServiceSpecsMonthly Cost
AWS RDS (PostgreSQL)2 vCPU, 4 GB, 20 GB$65+
PlanetScale (MySQL)1 billion row reads$39
MongoDB Atlas (M10)2 GB RAM, 10 GB$57
RAW Bare Metal2 CPU, 4 GB, NVMe$6

Self-hosting on bare metal saves 85–90% versus managed database services. You trade managed backups and dashboards for full control, better performance (no network hop between app and DB), and dramatically lower cost.

Universal Security Checklist

  • Firewall — only expose ports 22, 80, and 443. Database ports should never be public.
  • Strong passwords — use randomly generated credentials, not defaults
  • Automatic backups — daily dumps to a separate location. Test restores monthly.
  • Updates — enable unattended security updates for the database packages
  • Monitoring — track connections, query latency, disk usage, and replication lag

Get Started

npx rawhq deploy

7-day free trial. Dedicated bare metal in 13 seconds. Run PostgreSQL, MySQL, and MongoDB on the same server as your app for $0 extra.