How to Reduce Server Hosting Costs Without Killing Performance

by David Park
How to Reduce Server Hosting Costs Without Killing Performance

Most indie hackers overpay for hosting by a factor of two or three. Not because they're careless — because the defaults are expensive and nobody tells you otherwise.

I've been running production infrastructure for nine years. When I bootstrapped my first SaaS, I was spending $180/month on AWS because that's what every tutorial pointed me toward. Today I run three apps on roughly $40/month of Hetzner. Same uptime. Better latency for most of my users. The difference wasn't magic — it was a handful of deliberate decisions I'll walk you through here.

This post is about how to reduce server hosting costs in ways that are actually safe for production. Not "turn everything off" advice. Real cuts, with tradeoffs explained.

The Real Reason Your Bill Is High

Before you start slashing, you need to know why you're overpaying. There are three usual suspects:

Over-provisioned compute. You picked a $40 droplet because the $20 one felt risky. Totally understandable. But if your app idles at 8% CPU and 30% RAM, you're paying for headroom you're not using.

Wrong provider for your workload. AWS, GCP, and Azure are priced for enterprises with compliance requirements and global footprints. If you're serving a mostly European or US audience with a single-region app, you're subsidizing features you don't need.

Wasted egress and bandwidth. This one sneaks up on you. Cloud providers charge $0.08–$0.12/GB for outbound traffic. A modest media-heavy app can rack up $30–$50/month in egress alone — money that evaporates if you put a CDN in front of it.

Figure out which bucket your overspend falls into before you do anything else.

Right-Size Your Servers First

This is the highest-leverage move and the one most people skip because it feels risky.

Here's how I do it. SSH into your server and run:

# Check CPU usage over the last hour
sar -u 1 60

# Check memory pressure
free -h && vmstat -s | grep -i mem

If your average CPU is under 20% and you have more than 40% RAM free consistently, you're over-provisioned. Downsize.

On Hetzner, going from a CX31 (2 vCPU, 8GB RAM, €10.90/mo) to a CX21 (3 vCPU, 4GB RAM, €5.77/mo as of mid-2024) cuts your bill almost in half. That's real money over a year.

The process is straightforward on most VPS providers:

  1. Take a snapshot
  2. Resize the server (most providers do this with zero data loss)
  3. Monitor for 48 hours
  4. If nothing breaks, you're done

Don't do this on a Friday afternoon. Do it on a Tuesday when you can watch it.

Switch Providers Strategically

I'm not going to pretend all providers are equal. Here's what the market actually looks like for indie hackers in 2024:

Provider Entry VPS Price Bandwidth Included Egress Overage Best For
Hetzner ~€4.51/mo (CX11) 20TB €1/TB Europe-primary apps
Contabo ~€5.99/mo 32TB €0/TB (fair use) Budget storage workloads
DigitalOcean $6/mo 1TB $0.01/GB Simple US/EU apps
Vultr $6/mo 2TB $0.01/GB Multi-region needs
AWS EC2 t3.micro ~$8.50/mo 100GB free $0.09/GB If you need AWS ecosystem

For most indie hackers, Hetzner is the answer. The 20TB bandwidth allowance on even their smallest servers is absurd compared to US-based providers. I've never hit it.

The migration cost is real — DNS propagation, potential downtime, testing. Budget a weekend. But a $30/month savings compounds to $360/year, and that's worth a weekend.

Cut Egress Costs With a CDN

If you're serving static assets (images, JS, CSS, fonts) directly from your origin server, you're burning money on bandwidth and making your app slower.

Cloudflare's free plan proxies your traffic and caches aggressively. For most apps, this alone drops your origin bandwidth by 60–80%. Setup takes 20 minutes: point your nameservers to Cloudflare, enable the orange cloud on your DNS records, done.

For object storage, I use Hetzner Object Storage (S3-compatible, €0.023/GB/mo, no egress fees within the Hetzner network) instead of AWS S3. If your app is already on Hetzner, serving assets from Hetzner Object Storage through Cloudflare means you pay basically nothing for storage bandwidth.

Comparison: storing and serving 100GB of assets with 500GB monthly egress:

  • AWS S3 + CloudFront: ~$23/month
  • Hetzner Object Storage + Cloudflare free: ~$2.30/month

That's not a rounding error.

Consolidate Your Stack

Running three separate $6 servers — one for your app, one for your database, one for Redis — is a common pattern that costs $18/month for what a single $12 server could handle.

I run PostgreSQL, Redis, and my app process on a single Hetzner CX21. For apps under ~500 concurrent users, this is fine. The argument for separation is fault isolation and scaling flexibility. Both valid. But if you're not at the scale where those matter, you're paying for architecture you don't need yet.

The practical setup looks like this:

# docker-compose.yml — single server, all services
services:
  app:
    image: myapp:latest
    restart: always
    depends_on:
      - db
      - redis
    environment:
      DATABASE_URL: postgresql://postgres:secret@db:5432/myapp
      REDIS_URL: redis://redis:6379

  db:
    image: postgres:16
    restart: always
    volumes:
      - pgdata:/var/lib/postgresql/data
    environment:
      POSTGRES_PASSWORD: secret

  redis:
    image: redis:7-alpine
    restart: always
    volumes:
      - redisdata:/data

volumes:
  pgdata:
  redisdata:

Backup your database to Hetzner Object Storage or Backblaze B2 (free egress to most providers). Don't skip backups just because you consolidated — if anything, make them more frequent.

Use Spot/Preemptible Instances for Non-Critical Work

If you're running background jobs, data processing, or scheduled tasks, you don't need always-on compute for them.

AWS Spot Instances run at 60–90% discounts compared to on-demand. A c5.xlarge that costs $0.17/hr on-demand runs at ~$0.05/hr spot. For a batch job that runs two hours a day, that's the difference between $10/month and $3/month — and those savings multiply across jobs.

Hetzner doesn't have spot instances, but their base prices are low enough that it often doesn't matter. If you're on AWS and can't migrate, spot instances for workers is the single best cost lever available to you.

The catch: spot instances can be terminated with 2 minutes notice. Design your workers to be interruptible — checkpoint progress, use idempotent job queues (SQS, Redis Queue, etc.), and handle SIGTERM gracefully.

import signal
import sys

def handle_sigterm(signum, frame):
    # Checkpoint current progress before dying
    save_checkpoint(current_job_id, current_progress)
    sys.exit(0)

signal.signal(signal.SIGTERM, handle_sigterm)

This isn't complex. It's just a habit you build once.

Kill Idle Resources You Forgot About

This one stings because it's embarrassing. Go check your cloud provider console right now. I'll wait.

Common culprits:

  • Unattached EBS volumes on AWS. Every stopped EC2 instance leaves a volume behind. At $0.10/GB/month, a 50GB volume you forgot costs $5/month forever.
  • Old snapshots. Snapshots from six months ago that you took "just in case." Delete them.
  • Staging environments that run 24/7. If your staging server only gets used during active development, shut it down at night. A simple cron job or a Lambda function triggered by a schedule can stop and start it.
  • Unused load balancers. AWS ALBs cost ~$16/month just to exist, even with zero traffic.

I run a monthly audit — calendar reminder, first Monday of the month, 15 minutes. Just scroll through every resource in every region and ask "am I actually using this?"

If you're on AWS, the Cost Explorer and Trusted Advisor tools will surface a lot of this automatically. Use them. They're free.

Optimize Your Database Queries Before Scaling Up

I've seen people upgrade from a $20 to a $40 database server because queries were slow. Nine times out of ten, the problem was a missing index, not insufficient hardware.

Before you pay for more database compute, run this on PostgreSQL:

-- Find slow queries (requires pg_stat_statements extension)
SELECT 
  query,
  calls,
  total_exec_time / calls AS avg_ms,
  rows / calls AS avg_rows
FROM pg_stat_statements
WHERE calls > 100
ORDER BY avg_ms DESC
LIMIT 20;

If you see queries averaging over 100ms with high call counts, that's your problem. Add an index, rewrite the query, or add a cache layer — don't add CPU.

For most SaaS apps, a properly indexed PostgreSQL instance on a 4GB RAM server handles thousands of requests per minute without breaking a sweat. I've seen apps doing 50k req/day on a $6 VPS because the queries were clean.

How to Reduce Server Hosting Costs: The Priority Order

If you're staring at your bill and don't know where to start, do these in order:

  1. Audit idle resources — free money, takes 15 minutes
  2. Right-size your servers — usually saves 30–50% immediately
  3. Add Cloudflare — free, cuts bandwidth costs significantly
  4. Consolidate services if you're under meaningful load
  5. Migrate to a cheaper provider if the savings justify the migration cost
  6. Optimize queries before you pay for more database compute
  7. Use spot/preemptible instances for background work

You don't need to do all of these. Steps 1–3 alone will cut most bills by 40–60%.

What to Do Tomorrow

Open your hosting provider's billing dashboard. Find your three most expensive line items. For each one, ask: am I actually using this at capacity? Is there a cheaper equivalent?

If you're on AWS and haven't looked at Hetzner, check their pricing page and do the math for your current workload. The migration is a weekend of work. The savings are permanent.

Knowing how to reduce server hosting costs isn't about being cheap — it's about not funding your cloud provider's growth with money that should be in your runway. Every $50/month you cut is $600/year you keep.

Start with the audit. Everything else follows.