Every free PaaS starts the same way: you push your code, it deploys, and for one glorious afternoon your app responds in 40 milliseconds. Then you go to sleep. At 3 AM your users hit your URL and wait 30 seconds for a container that has been asleep since lunchtime. Your logs fill with 504s, your SEO ranking craters because Googlebot keeps timing out, and the fix costs $7 to $25 a month per app — for a machine you don't even control.
Heroku killed its free tier in 2022. Render never shipped real free plans after its trial window. Railway charges by usage, and the bill sneaks up on you. Every one of these platforms imposes the same trio of limits: sleeping servers (cold starts), a hard 512 MB RAM ceiling on anything free or cheap, and per-app pricing that makes running five microservices feel like a luxury purchase.
There is a better path, and it costs about $4 a month for the entire stack: bring your own VPS. This guide shows you exactly how to deploy Node.js applications — Express, NestJS, or Next.js — on your own server with zero cold starts, no RAM limits, and a live console, using M.A.F Cloud's one-line agent. No Docker expertise required, no Nginx config files, no systemd units. One command, then deploy from a browser.
The Problem with Free PaaS
Let's be precise about what hurts, because the pain points are specific.
**Cold starts.** Every major PaaS sleeps your app after 15–30 minutes without traffic. The next request pays a boot penalty: cold container creation, dependency loading, process start, and a database connection pool warming up. Measured, it is 20–45 seconds before the first byte. That is not a slow load — that is a timeout for most HTTP clients, and it is disqualifying for webhooks, cron jobs, API consumers, and Google's crawler. If your app does background work (queue workers, scheduled jobs, WebSocket servers), a sleeping PaaS cannot run it at all — requests arrive to nothing.
**The 512 MB RAM ceiling.** Free tiers cap memory at 512 MB across the board. A bare Express process with a few dependencies idles around 180–250 MB. Add Prisma with a connection pool, an in-memory cache, a file upload, or a second worker process, and you are at the cap. Node.js does not fail gracefully at the limit — it gets OOM-killed, repeatedly. The result is apps that crash on their busiest days, and the only remedy is paying.
**Per-app pricing.** Render charges roughly $7/month per Web Service with storage on top. Heroku's cheapest dyno is $5/month per app, and even that sleeps after 30 idle minutes. Five microservices → five bills. A database is another line item. A cache, another. The platform markup is real: a $4 Hetzner server with 2 GB RAM and 20 GB NVMe does the work of three or four $7 services, with more memory per app and no sleep timer.
**Vendor lock-in.** Deployment config files, buildpack quirks, platform-specific env injection — a PaaS's dialect of deployment does not travel. When the bill grows or the platform changes terms (as Heroku did in 2022), your pipeline needs rewriting. Code deployed to your own VPS as standard Docker containers runs anywhere: your VPS, a colocated box, or any other provider.
Why BYO-VPS Is the Modern Solution
Bring-Your-Own-VPS (BYO-VPS) flips the ownership model: you rent the hardware directly, and the panel software sits on top as a free layer. The economics are hard to argue with.
Hetzner's CX22 — 2 vCPU, 2 GB RAM, 20 GB NVMe, 20 TB traffic — costs about $4 per month (≈ EUR 4.51). DigitalOcean's $6 droplet is the same class of machine, and Contabo goes even cheaper on RAM-heavy plans. For the price of one Render free-tier upgrade, you get a machine that never sleeps, never OOMs at 512 MB, and runs every app you own simultaneously.
Compare the practical implications:
**Zero cold starts.** The VPS is on 24/7. Your app boots when you deploy it and stays resident. First request after midnight: 40 ms, same as at noon.
**No RAM limits.** 2 GB of RAM is yours to allocate. An Express app can take a full gigabyte plus a Postgres container and a Redis cache, and nothing kills it.
**One flat bill.** One VPS runs ten apps, a database, and a cron worker. Total: $4/month. No per-app line items.
**Total control.** Root access, real logs, background processes, WebSocket servers, custom ports, any Node version, any npm package.
**Portability and no lock-in.** Everything you run is Docker, effectively. Move VPS providers any time; your stack travels with you.
The traditional objection — VPS means sysadmin drudgery, SSH, Nginx, systemd, certbot — is exactly what M.A.F Cloud removes.
How M.A.F Cloud Works
M.A.F Cloud is an open control plane: a browser dashboard that talks to a lightweight agent installed on your VPS. The agent manages Docker on your behalf — creating containers, binding ports, streaming logs — so the developer experience matches a modern PaaS while the economics match a VPS.
The whole setup is one line. From the dashboard you create a 'Node' (your VPS), copy a generated install command, run it over SSH, and wait about 30 seconds while the agent installs Docker and registers the machine. Deployment happens in the browser: pick a runtime template (Node.js, Python, Minecraft, and 11+ others), paste a git repository URL or upload files, set environment variables, and hit Create.
What you get on every plan — including the free one:
Real-time WebSocket console streaming stdout/stderr live
File manager for editing config and environment files
Crash detection with automatic restart (self-healing)
Port binding and firewall management, handled automatically
On-demand and scheduled backups of app data
Custom domain binding with automatic proxy rules
The free tier is genuinely free: one server with 2 GB RAM, 2 vCPU, full console and file access — every feature you need to ship a production Node.js app for the $4/month your VPS costs.
Step 1: Rent a VPS (5 Minutes)
Any provider works: Hetzner, DigitalOcean, Contabo, Vultr, Oracle Cloud free tier, even an old PC on a residential connection. Minimum spec for Node.js apps: 2 GB RAM, 2 vCPU, 20 GB disk, Ubuntu 22.04/24.04 or Debian 12.
Why 2 GB is the pragmatic floor: an Express app plus Postgres plus a cache leaves headroom for builds (npm install can spike at 700 MB+ on large dependency trees) and for the agent itself. Spend a little more for NVMe if the option exists — it turns installs and builds from minutes into seconds.
Region matters: choose one close to your users. Singapore or Frankfurt for Southeast Asia/Europe traffic respectively; your latency to your own server is the latency your users feel.
Step 2: Create Your Free M.A.F Cloud Account
Sign up at mafcloud.my.id — the panel is free forever on the Free tier. In the dashboard, open Nodes → Add Node, name it (e.g. hetzner-fsn1), and copy the generated one-line installer command.
curl -fsSL https://cexi.my.id/agent-install.sh | sudo MAFCLOUD_TOKEN=mn_your_token MAFCLOUD_API=https://cexi.my.id bash
SSH into your VPS and run it as root. The script installs Docker (if absent), downloads the agent, verifies it against your token, and registers the machine — roughly 30 seconds end to end. No package-by-package setup, no manual firewall rules.
When the node flips to 'Connected', your VPS is a PaaS. You are done with SSH forever for everyday work.
Step 3: Deploy an Express.js App
The quickest win, and the template most readers will use for APIs and web services.
1. In the dashboard, open Servers → Create Server.
2. Choose the Node.js template — the agent will create a Node 20 LTS container with npm and a health-check-aware start script.
3. Name the app (e.g. my-api), set the port your app listens on (3000 is the convention), and allocate memory — 512 MB is plenty for most Express apps, and nothing stops you from giving it 1024 MB or more.
4. Add environment variables in the settings tab — PORT, DATABASE_URL, JWT_SECRET. These are stored encrypted and injected at container start.
5. Deploy by pasting your git repository URL and branch, or upload code via the file manager for a quick smoke test.
Classic Express starter that works out of the box:
const express = require('express');
const app = express();
const port = process.env.PORT || 3000;
app.get('/', (req, res) => res.send('Hello from my VPS!'));
app.listen(port, () => console.log(`API listening on :${port}`));
The agent builds the image, starts the container, and opens the port. Within a minute your app answers on http://YOUR_VPS_IP:PORT — and unlike a PaaS, it stays warm. The next request after hours of silence is instant.
Step 4: Live Console — See Everything, Control Everything
Open the app in the dashboard and click Console. A real-time WebSocket stream shows stdout and stderr exactly as if you were attached to the process: startup logs, npm warnings, request lines, unhandled exception stack traces — visible the second they happen.
The console is two-way. You can send signals to the process (Ctrl+C, restart), run one-off commands inside the container, and watch crash events live. When something breaks, you diagnose in the same screen where you deploy — no SSH hopping, no log aggregation setup.
That live observability, combined with the file manager (edit .env, tweak config files without redeploying), is the difference between a VPS that feels like infrastructure and one that feels like a product.
Step 5: Deploy NestJS (TypeScript) Apps
NestJS follows the same flow with one extra step: the build. The agent detects the nest-cli.json in your repository and runs the standard npm run build before starting the container, so your compiled dist/main.js is what serves traffic.
1. Create the server with the Node.js template as before.
2. Paste your NestJS repository (e.g. https://github.com/you/nest-api).
3. Set PORT=3000 and any database credentials in environment variables.
4. Deploy. The build log streams live in the console; when you see Nest application successfully started, your API is live.
Two practical notes for NestJS on a $4 VPS: keep the build memory in mind (npm run build on a large monorepo can need 1 GB; give the app 1024 MB if you see OOM during builds), and if your app uses @nestjs/websockets, the automatic port binding handles the WebSocket upgrade on the same port — no extra config.
Step 6: Deploy Next.js
Next.js needs two things a plain Node template does not handle by itself: a production build (next build) and a start command (next start). In M.A.F Cloud, set the build command in the app settings:
npm run build
and the start command:
npm start
with the standard Next.js 14+ scripts in package.json. The agent runs the build in the container, then boots the server. For Next.js specifically:
Set PORT=3000 (or whatever you bind) — Next.js respects it.
Allocate 1024 MB minimum. Next.js with React Server Components and image optimization is heavier than Express; 2 GB is comfortable.
Static exports (output: 'export') work too — the build produces a static directory and the container serves it directly.
For self-hosted SSR with a database, put DATABASE_URL in environment variables before the build runs — Next.js bakes some env values into the client bundle at build time.
App Router, API routes, middleware, server actions — all run as-is. The only difference from a paid PaaS is that your server never sleeps.
Step 7: Subdomains and Custom Domains
Your apps get a default address on your VPS IP and port. For anything user-facing, you want a domain.
**Subdomains with the panel wildcard.** M.A.F Cloud nodes accept a wildcard domain such as *.apps.mafcloud.my.id. Point it at your VPS IP with two DNS records, and every app you create is immediately reachable at my-api.apps.mafcloud.my.id — the panel issues the routing and (on the Studio plan) TLS automatically.
**Apex and custom domains.** In the app's Domains tab, add your full domain (example.com or api.example.com). Then at your registrar or DNS provider (Cloudflare makes this easiest):
A api.example.com -> YOUR_VPS_IP
or, if you prefer a CNAME to a stable panel hostname:
CNAME api.example.com -> YOUR_VPS_HOSTNAME
Add the record, wait for propagation (minutes to a couple of hours depending on TTL), and the panel proxies the domain to your container on the correct port. No Nginx configuration, no reverse-proxy setup, no certbot — the panel handles termination and routing.
Performance Comparison: M.A.F Cloud vs Render vs Heroku
Measured expectations beat marketing claims. On identical hardware assumptions — a $4/month Hetzner CX22 for M.A.F Cloud, the cheapest paid tiers of each PaaS at the time of writing:
| Metric | M.A.F Cloud (BYO-VPS) | Render (Starter) | Heroku (Eco) |
| Monthly cost | $4 (your VPS) + $0 panel | $7 per service | $5 per dyno |
| RAM per app | Up to 2 GB (all yours) | 512 MB | 512 MB |
| Cold start | None — always warm | 20–45 s after sleep | 30 s after sleep |
| Sleep on idle | Never | After 15 min | After 30 min |
| Background jobs | Yes | No (sleeps) | No (sleeps) |
| WebSockets | Yes | Limited | Limited |
| Custom domain | Yes (auto TLS on Studio) | Yes | Yes |
| Root access | Yes | No | No |
| Apps per bill | Unlimited | Per-app fees | Per-dyno fees |
| Exit/portability | Docker — runs anywhere | Config lock-in | Config lock-in |
The dollar comparison is the honest one: a single Render Starter service is $7/month for one app with 512 MB. The same budget rents the entire Hetzner machine that runs that app, your database, your cron jobs, and five other projects — with none of them sleeping.
The trade-off to acknowledge: a PaaS handles scaling, encrypted storage, and managed databases for you. If you need one ephemeral demo app with zero maintenance, a PaaS is still fine. The moment you run something real — an API your users depend on, a storefront, a SaaS backend, a WebSocket service — a warm $4 VPS wins on cost, latency, and reliability.
Frequently Asked Questions
Q: Do I need Linux experience for this?
No. The installer command handles Docker and everything else. After enrollment, all administration happens in the browser dashboard — console, files, env vars, restarts. SSH is only needed to run the one-line install.
Q: Is M.A.F Cloud really free?
The panel is. The Free tier includes one server with 2 GB RAM, 2 vCPU, the live console, file manager, crash recovery, and backups at RM 0/month. You pay only your VPS provider — about $4/month at Hetzner or $6 at DigitalOcean.
Q: Why is my app slow on Render's free tier but instant here?
Render (and Heroku) sleep idle apps; the next request costs a 20–45 second boot. On your own VPS the process stays resident, so latency is constant — a few tens of milliseconds morning or midnight.
Q: Can I run multiple apps on one VPS?
Yes. Each app is an isolated container with its own port, environment, and memory limit. The Free tier covers one server; Pro permits unlimited servers, and resource allocation is per app.
Q: What about databases?
Run Postgres or MySQL as an additional container on the same VPS, or use a container with a bind-mounted volume for persistence. For production, take scheduled backups from the panel or offsite snapshots from your provider.
Q: What happens when my app crashes?
Crash detection restarts the container automatically, and the restart appears live in the console. Persistent crashes keep the app down so you can fix the code, but the panel never sleeps your app to save money.
Q: Can I move providers later?
Easily. Your app is a standard container — install the agent on a new VPS, redeploy from the same repo, and point DNS at the new IP. Your data lives in your containers, not in a platform's proprietary storage.
Conclusion: $4 Hosting That Beats $25 Hosting
You now have the complete path from a $4/month Hetzner VPS to a production Node.js platform: one command enrolls the machine, a browser deploys Express, NestJS, or Next.js, the live console debugs in real time, and custom domains attach without touching an Nginx config. Zero cold starts. No 512 MB ceiling. No per-app invoices. No vendor lock-in.
Create your free account at mafcloud.my.id, log in, and enroll your first node. When your app outgrows the free tier — many apps never will — upgrade from the pricing page when you need unlimited servers and custom domains.