BuildWithMatija
  1. Home
  2. Blog
  3. Cloudflare
  4. Self-hosting S3 Storage on €5 VPS: Practical Garage Guide

Self-hosting S3 Storage on €5 VPS: Practical Garage Guide

Run Garage as S3-compatible object storage on a €5 VPS and pair with Cloudflare CDN for scalable, low-cost image…

6th June 2026·Updated on:12th June 2026··
Cloudflare
Self-hosting S3 Storage on €5 VPS: Practical Garage Guide

☁️ Cloudflare Edge Development Guides

Complete Cloudflare guides with practical examples, deployment strategies, and developer prompts to help you build and ship edge applications faster.

No spam. Unsubscribe anytime.

📄View markdown version
0

Frequently Asked Questions

About the author

Matija Žiberna

Matija Žiberna

Full-stack developer, co-founder

AboutResume

Self-taught full-stack developer sharing lessons from building software and startups.

I'm Matija Žiberna, a self-taught full-stack developer and co-founder passionate about building products, writing clean code, and figuring out how to turn ideas into businesses. I write about web development with Next.js, lessons from entrepreneurship, and the journey of learning by doing. My goal is to provide value through code—whether it's through tools, content, or real-world software.

Contents

  • What Is Garage and Why Does It Matter for Self-Hosting?
  • Where a Small VPS Actually Becomes a Bottleneck
  • The Workload: A Real Marketplace Pattern
  • Why Image Delivery Is the Dominant Load
  • The Architecture That Makes This Work
  • Why You Should Not Build Your Own CDN
  • FAQ
  • Conclusion
On this page:
  • What Is Garage and Why Does It Matter for Self-Hosting?
  • Where a Small VPS Actually Becomes a Bottleneck
  • The Workload: A Real Marketplace Pattern
  • Why Image Delivery Is the Dominant Load
  • The Architecture That Makes This Work
Build with Matija logo

Build with Matija

Modern websites, content systems, and AI workflows built for long-term growth.

Services

  • Headless CMS Websites
  • Next.js & Headless CMS Advisory
  • AI Systems & Automation
  • Website & Content Audit

Resources

  • Case Studies
  • How I Work
  • Blog
  • CMS Hub
  • E-commerce Hub
  • Dashboard

Headless CMS

  • Payload CMS Developer
  • CMS Migration
  • Multi-Tenant CMS
  • Payload vs Sanity
  • Payload vs WordPress
  • Payload vs Contentful

Get in Touch

Ready to modernize your stack? Let's talk about what you're building.

Book a discovery callContact me →
© 2026Build with Matija•All rights reserved•Privacy Policy•Terms of Service
BuildWithMatija
Get In Touch

A €5 Hetzner VPS running Garage can power real production image storage for an early-stage SaaS, marketplace, or multi-tenant platform — as long as you treat it as an origin and let a CDN handle public delivery. The server does not need to serve every image request. It needs to store objects reliably and respond to cache misses. That distinction changes everything about how you size and architect the system.

I recently built this layer for a marketplace platform and spent time stress-testing how far a small server could actually go before the architecture needed to change.


What Is Garage and Why Does It Matter for Self-Hosting?

Garage is an open-source S3-compatible object storage system built for self-hosted deployments. Your application talks to it using the standard S3 API — the same one you would use with AWS — while Garage handles object storage and metadata internally. You can run it on a single VPS or distribute it across multiple nodes.

The appeal for an early-stage product is straightforward: you get S3-compatible storage at infrastructure cost rather than per-request pricing, with full control over where your data lives.


Where a Small VPS Actually Becomes a Bottleneck

Most developers assume CPU is the limiting factor on a cheap server. In practice, for object storage workloads, the first constraints you hit are disk I/O and IOPS, then network bandwidth, then memory and filesystem cache. CPU is usually last.

Every upload, download, listing operation, and delete goes through metadata lookups before the actual object transfer. The storage layer spends a meaningful amount of time waiting on disk rather than saturating the processor. This means a server with a fast NVMe SSD and reasonable RAM will outperform a higher-CPU instance with slow storage.


The Workload: A Real Marketplace Pattern

The use case I was optimizing for looks like this: a multi-tenant marketplace where each tenant has around 80 products, a few images per product, and image sizes between 60 KB and 200 KB.

Admins upload through a dashboard. Visitors browse public storefronts.

This is a very common SaaS pattern, and the upload side is almost never the problem. 80 images at 200 KB each is 16 MB. Even with hundreds of tenants uploading simultaneously, the storage footprint stays manageable and uploads happen in bursts rather than continuously.

Public delivery is the real workload.


Why Image Delivery Is the Dominant Load

Serving images to visitors generates far more sustained load than storing them ever does. The math scales quickly:

Daily image viewsApproximate traffic
1,000~200 MB
10,000~2 GB
100,000~20 GB

At 10,000 views per day, a server handling every request directly would be pushing 2 GB of transfer plus the associated IOPS for every object read. At 100,000 views, the bandwidth alone exceeds what most €5 VPS plans include in their monthly allowance.

This is the number that determines whether Garage on a small VPS is viable — and the answer depends entirely on whether you put a CDN in front of it.


The Architecture That Makes This Work

The correct setup separates two responsibilities that developers often conflate: storage and delivery.

code
# Upload path
Tenant → Application → Garage

# Public delivery path
Visitor → Cloudflare → Garage (origin, cache miss only)

Garage stores originals and any optimized variants. The application manages permissions, generates signed URLs, and handles metadata. Cloudflare sits in front of public assets and serves cached copies to visitors. PostgreSQL stores image references alongside the rest of your application data.

The first time a visitor requests an image, Cloudflare fetches it from Garage and caches it. Every subsequent request for the same image is served from Cloudflare's edge without touching the origin server at all. 10,000 image views may only generate a handful of actual requests back to Garage, depending on your cache hit rate and how frequently your image set changes.

This means the VPS is responsible for uploads, cache misses, image processing, and administrative operations — not for serving every public image request.


Why You Should Not Build Your Own CDN

Self-hosting additional VPSs in multiple regions as a DIY CDN sounds appealing from a cost perspective. The operational surface area makes it impractical for most teams.

Geographic routing, cache invalidation, SSL/TLS management, DDoS protection, health checks, cache purging, and regional failover are all problems a CDN product has already solved. Solving them yourself means building CDN infrastructure alongside your actual product.

Cloudflare's free tier handles the delivery layer well for most early-stage SaaS products. The combination of Garage for storage and Cloudflare for delivery gives you cheap, durable storage with fast global delivery — without the operational overhead of managing edge infrastructure.


FAQ

Can Garage run on a single-node VPS without data redundancy concerns?

Single-node Garage works fine for development and early production, but you should have a backup strategy in place. Garage supports multi-node layouts for replication — even spreading across two small VPSs gives you meaningful durability improvement. For a very early product, scheduled snapshots of the storage volume are a reasonable baseline.

Does Cloudflare cache S3 presigned URLs correctly?

Presigned URLs include query parameters (expiry, signature) that can interfere with cache key matching. For public assets, you are better off using public bucket paths that Cloudflare can cache by path alone. Reserve presigned URLs for private or permission-gated files that should bypass the CDN entirely.

What file sizes start to stress a small VPS?

Large video files or high-resolution unoptimized uploads will strain both storage IOPS and network bandwidth faster than image-heavy workloads. If your use case includes video, either process uploads to lower-resolution variants before storage, or plan for a larger VPS or dedicated storage node sooner.

How do I handle cache invalidation when a tenant replaces an image?

The simplest approach is to include a version or hash in the object key rather than overwriting the same path. When an image changes, a new key is written and the old one is retired. This avoids cache invalidation entirely because the URL changes with the content.

When does this architecture stop scaling?

The CDN-as-delivery-layer pattern scales well past what most early-stage products ever reach. The origin server becomes relevant again when cache miss volume is high (lots of unique, rarely-repeated requests) or when you are doing significant server-side image processing at request time. Both are solvable with a larger VPS or by moving processing to build time.


Conclusion

A €5 VPS running Garage is not AWS S3 at scale. For an early-stage SaaS, marketplace, or multi-tenant platform, it is far more capable than most developers assume — because the CDN is doing the heavy lifting on public delivery, not the server.

The pattern is straightforward: use Garage as the source of truth for object storage, put Cloudflare in front of it for public delivery, and let each layer do what it is optimized for. The VPS handles uploads and the occasional cache miss. The CDN handles everything else.

If you are building something similar or running into specific scaling questions, drop a comment below. And subscribe if you want more practical guides on self-hosted infrastructure for SaaS products.

Thanks, Matija