Host a MERN stack app cheaply in 2026
Three realistic ways to put MongoDB, Express, React and Node online for roughly the price of a coffee โ with the security steps most tutorials skip.
The three pieces, and where each one can live
A MERN app is really three deployables: a React bundle (static files), an Express/Node API (a long-lived process) and MongoDB (a database that needs persistent storage). Cost decisions get much easier once you stop thinking of it as one thing.
The static React build is nearly free to host anywhere. The API needs somewhere that will keep a process alive. The database is where the real money and the real risk live โ and it is the piece most people get wrong.
Three setups and what they actually cost
Prices below were checked in September 2026 and will drift. The trade-off column is the part that stays true.
| Setup | Roughly per month | The trade-off |
|---|---|---|
| One VPS + MongoDB Atlas M0 | VPS only, DB free | Atlas M0 is genuinely free forever, but caps at 512 MB storage and ~100 ops/sec. Fine for a portfolio or an MVP; it will not carry a real product. |
| One VPS running everything, Mongo in Docker | VPS only | No database ceiling and no second bill, but backups, upgrades and security are entirely yours. This is the cheapest path with room to grow. |
| Managed PaaS + Atlas Flex | ~$7โ37 for the app, up to $30 for the DB | Least operational work, highest and least predictable bill. Usage-based pricing can surprise you. |
The cheapest sane setup: everything on one box
A single entry-tier VPS with 4 GB of RAM runs an Express API, a React build and MongoDB simultaneously without breaking a sweat, and the cost does not change when you add your next side project. Here is the whole thing.
Start by installing Node 24 LTS โ the Active LTS line as of September 2026 โ and Docker, which we will use for MongoDB so you are not chasing apt repository changes every time Mongo ships a major version.
# Node 24 LTS
curl -fsSL https://deb.nodesource.com/setup_24.x | sudo -E bash -
sudo apt-get install -y nodejs nginx git
# Docker, for MongoDB
curl -fsSL https://get.docker.com | sudo sh
sudo usermod -aG docker $USER
# log out and back in so the group takes effectRun MongoDB without putting it on the public internet
This is the step to get right. Exposed, unauthenticated MongoDB instances have been the source of a long run of data breaches, and the default Docker command in most tutorials publishes the port to the world.
Two things make it safe: bind the published port to `127.0.0.1` so only processes on the same machine can reach it, and set root credentials on first run. Note that Docker writes its own iptables rules and can punch straight through UFW โ a plain `-p 27017:27017` really is reachable from the internet even with a firewall you believe is closed.
docker volume create mongo-data
docker run -d \
--name mongo \
--restart unless-stopped \
-p 127.0.0.1:27017:27017 \
-v mongo-data:/data/db \
-e MONGO_INITDB_ROOT_USERNAME=appuser \
-e MONGO_INITDB_ROOT_PASSWORD='use-a-long-random-password' \
mongo:8sudo ss -tlnp | grep 27017
# Want: 127.0.0.1:27017
# Bad: 0.0.0.0:27017 <- reachable from the internetRun the Express API under PM2
PM2 restarts the API if it crashes and brings it back after a reboot. Bind it to loopback as well โ Nginx is the only thing that should be able to reach it.
sudo npm install -g pm2
cd /var/www/api
npm ci --omit=dev
pm2 start server.js --name api
pm2 save
pm2 startup systemd
# run the sudo command PM2 prints, then 'pm2 save' againconst PORT = process.env.PORT || 5000;
app.listen(PORT, "127.0.0.1", () => {
console.log("API listening on 127.0.0.1:" + PORT);
});Serve the React build and proxy the API from one domain
Serving the front end and API from the same origin removes your CORS problems entirely โ the browser sees one domain. Nginx serves the static build from disk and forwards anything under `/api/` to Express.
The `try_files` line is what makes client-side routing work. Without it, a hard refresh on `/dashboard` returns a 404 because no such file exists on disk.
cd /var/www/client
npm ci
npm run build
# Vite outputs to dist/, Create React App to build/server {
listen 80;
server_name example.com;
root /var/www/client/dist;
index index.html;
location /api/ {
proxy_pass http://127.0.0.1:5000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# Client-side routing: unknown paths fall back to index.html
location / {
try_files $uri $uri/ /index.html;
}
}sudo ln -s /etc/nginx/sites-available/mern /etc/nginx/sites-enabled/
sudo rm -f /etc/nginx/sites-enabled/default
sudo nginx -t && sudo systemctl reload nginx
sudo apt-get install -y certbot python3-certbot-nginx
sudo certbot --nginx -d example.comBack up the database, because nobody else will
This is the cost of self-hosting Mongo, and it is small. A nightly `mongodump` into a dated folder, with anything older than two weeks deleted, covers the realistic failure modes: a bad migration, a dropped collection, a corrupted write.
Weekly server-level backups from your host protect you from losing the whole machine. They do not protect you from deleting a collection on Tuesday afternoon. You want both.
#!/usr/bin/env bash
set -euo pipefail
STAMP=$(date +%F)
OUT=/home/deploy/backups/$STAMP
mkdir -p "$OUT"
docker exec mongo mongodump \
--username appuser \
--password "$MONGO_PASSWORD" \
--authenticationDatabase admin \
--archive > "$OUT/myapp.archive"
# Keep two weeks
find /home/deploy/backups -maxdepth 1 -type d -mtime +14 -exec rm -rf {} +0 3 * * * MONGO_PASSWORD='...' /home/deploy/backup-mongo.sh >> /home/deploy/backup.log 2>&1When to stop self-hosting the database
Running Mongo yourself is the right call while your data fits comfortably on one disk and downtime during a restore is survivable. Move to managed hosting when any of the following become true โ and notice that all three are about consequences, not scale.
- A few hours of downtime during a restore would genuinely hurt the business.
- You need point-in-time recovery rather than 'yesterday at 3am'.
- You want replica-set failover, and standing one up yourself is no longer a fun afternoon.
The short version
For a side project or an MVP, one VPS running React, Express and Mongo together is the cheapest arrangement that does not box you in, and the price stays flat as you add projects. Start on Atlas M0 if you would rather not own a database yet; move Mongo onto the box when 512 MB stops being enough.
Coupon WEBHOST2026 applies automatically through the links here if you are picking up a server for this.
Ready to save with coupon WEBHOST2026?
Get my discount link โKeep reading
Deploy a Next.js app on Hostinger VPS (step by step)
A complete walkthrough: provision the server, install Node 24, build with standalone output, keep it alive with PM2, put Nginx and free HTTPS in front, and script your redeploys.
ComparisonsHostinger VPS vs a $5 DigitalOcean droplet for a side project
The $5 droplet is $6 now, and it ships 1 GB of RAM. Here is the honest spec-and-cost comparison, including the renewal maths that most affiliate posts leave out.