DEV Community

Cover image for The Hosting Rejection Tour: Render, AWS EC2, Oracle, and How I Ended Up on a €3.29/mo VPS
David Bartalos
David Bartalos

Posted on

The Hosting Rejection Tour: Render, AWS EC2, Oracle, and How I Ended Up on a €3.29/mo VPS

Before the stack worked, three hosting options failed. Each one looked perfect on paper. Each one had a specific, concrete reason it couldn't work. This is the rejection tour.

The constraint: Medusa v2 is stateful. It needs PostgreSQL, Redis for BullMQ, and enough RAM to run the event bus and workflow engine without getting killed. That rules out serverless. (Medusa can technically start without Redis — it falls back to an in-process event bus — but that means losing job queuing, workflow retries, and reliable event delivery. Fine for a quick local demo; not something you want processing real orders.) It needs persistent storage, a real process manager, and a consistent IP for outbound webhook validation. Every "just deploy it for free" option assumes your workload is stateless. This one isn't.

Attempt 1: Render

Render's free tier looked fine for a low-traffic shop. 512MB RAM, easy deploys from GitHub — cold starts on the free tier, always-on on the paid plan. The plan was to pair it with Neon for PostgreSQL (generous free tier, serverless scaling) and Upstash for Redis (free tier covers BullMQ at low volume). Three managed services, total cost: $0.

I got Medusa running, ran the setup scripts, and then installed the Prodigi print fulfillment plugin — which loads product mappings and prefetches shipping zones at startup.

OOM kill on boot. 512MB wasn't enough.

The obvious fix is to upgrade the Render service. Their starter plan is $7/mo. That's just the API — Neon and Upstash stay free at low volume, but now I'm at $7/mo for a single service with no room to grow, and I still hadn't solved staging. Render's starter plan is $7/mo per service. Two environments means two API instances: $14/mo before touching the databases.

I could have stripped the fulfillment plugin to fit inside 512MB. But without it there are no print orders — Prodigi integration is how open-edition prints get produced and shipped. Dropping it to hit a RAM limit means the shop sells originals only, which wasn't the brief.

Attempt 2: AWS EC2

After Render, AWS EC2 looked like the right move. A t4g.micro in eu-west-2 (London): 1 GiB RAM, 2 vCPU ARM64 Graviton2, always-on, full SSH access, swap configurable — all within the AWS free tier for the first 12 months. Double the memory of Render's paid plan, at no cost. I built out the full setup: CloudFormation stack, Nginx reverse proxy, Let's Encrypt TLS, systemd service, GitHub Actions CD, health check cron.

It ran. There were a couple of ARM64 quirks — a ts-node source-map crash under Bun that needed TS_NODE_SKIP_SOURCE_MAP_SUPPORT=1, and Node.js auto-limiting the V8 heap to ~512MB on a 1 GiB instance, fixed with NODE_OPTIONS=--max-old-space-size=1024. But Medusa came up, Prodigi loaded, the health check passed.

Then I ran a checkout flow under load. OOM kill.

The 1 GiB ceiling wasn't enough headroom when Prodigi, Medusa, and an active checkout were all competing for memory at once. And the infrastructure complexity — CloudFormation, Nginx config, cert renewal timers, CloudWatch, a manual cutover checklist — was a real ongoing cost for a solo project. After the free year, the bill would be ~$7.90/mo anyway. At that price you can just buy a VPS that has the memory you need and none of the ceremony.

Attempt 3: Oracle Always Free

Oracle's Always Free tier is, on paper, absurd. The A1 Flex shape gives you up to 4 OCPU and 24 GB RAM at no cost, permanently. ARM64, which is what Hetzner's cheapest VPS uses anyway. UK London region available. I signed up.

"The selected shape is not available in this Availability Domain. Please try a different Availability Domain or shape."

I tried every Availability Domain in UK London. Same message. I tried Frankfurt. Same message. I tried Amsterdam. Same.

This isn't a new problem. The Oracle community forum has threads going back two years with hundreds of people reporting A1 capacity unavailable in every European region. Oracle adds capacity occasionally, and it disappears within hours as people snap it up. The forum advice is to script retries and keep trying. I tried that for a few weeks.

The Always Free tier only works if you can actually provision the instance. If capacity is gone, it's gone indefinitely. For a project you want to actually ship, "keep retrying and hope" isn't a deployment strategy.

What actually worked: Hetzner CAX11

Hetzner's CAX11 is €3.29/mo. ARM64, 2 vCPU, 4 GB RAM, 40 GB NVMe SSD, 20 TB/month egress included. I signed up, got the server provisioned in about 30 seconds, and had Medusa running the same afternoon.

The setup that's been stable since:

Two systemd services, one box. Dev and production run as separate Medusa instances — different ports, different .env files, different PostgreSQL databases. Caddy sits in front and routes api-dev.nadiapoe.co.uk and api.nadiapoe.co.uk to the right one. Each service restarts automatically on failure. No Docker, no orchestration — just two medusa.service unit files and a Caddy config.

Deploys via GitHub Actions. On push to main, a workflow SSHes in, pulls the latest code, runs bun install and bun run build, and restarts the appropriate service. Under 60 seconds end to end.

Backups to Cloudflare R2. A nightly cron runs pg_dump and uploads the compressed archive to a dedicated R2 bucket (nadiapoe-backups). R2 is already in the stack for media — adding a backup bucket costs nothing extra. Retention is 7 daily dumps on-server, 30 in R2. If the VPS burns down, restoring is pg_restore and a git pull.

The total monthly cost: €3.29. Both environments. All services. Backups included.

The lesson

"Free" hosting for stateful backend workloads usually means one of two things: a RAM ceiling that kills anything real, or a capacity queue where "available" means "available when someone else cancels." For a stateless frontend or a simple API, free tiers are great — Cloudflare Pages handles the storefront for nothing. But the moment you have a process that needs to stay alive, own persistent state, and run at startup, a cheap paid VPS is more reliable than a free tier with asterisks.

Hetzner CAX11 at €3.29/mo is less than most people spend on a coffee a month. It's not free. It's better than free.

One genuine acknowledgement before moving on: the free tiers from Cloudflare, Resend, Neon, and Upstash make it possible to build and prove a business before it earns a penny. They lower the bar for anyone who wants to try something without betting money on it first. That matters, and it's worth saying.

Live shop: nadiapoe.co.uk.

Top comments (0)