Hetzner Object Storage vs. AWS S3 for EU backup stacks
Cost, rate limits, durability, and data residency: a practical side-by-side for EU backup stacks.
Resistro Cloud stores backups on Hetzner Object Storage in Nuremberg. For EU-hosted backup stacks, AWS S3 in Frankfurt is the obvious comparison point — the APIs are identical, the tooling is everywhere. This is a practical side-by-side based on operating constraints, cost, and one early scaling issue we had to design around.
Cost at 1 TB / month
Storage cost is what everyone looks at first, and it genuinely matters past 500 GB. Numbers are net of VAT, as of April 2026:
| Hetzner Object Storage | AWS S3 (eu-central-1) | |
|---|---|---|
| 1 TB stored / month | ~6 € (first TB included with bucket) | ~21 € |
| Egress 100 GB / month | 0 € (inside Hetzner) / low external | ~8 € |
| PUT/COPY/POST per million | ~0.55 € (approx) | ~4.40 € |
| GET per million | ~0.055 € | ~0.35 € |
For a typical mid-market backup workload — 200 GB of encrypted dumps per week, fetched rarely — the pure storage bill on AWS runs roughly 3–4× Hetzner. The request-priced APIs (PUT, LIST) push it further if your workload is chunky. A 200–500 GB backup stack moving from S3 eu-central-1 to Hetzner Object Storage typically saves 200–300 € per month at identical retention; the exact delta depends on how often you touch the data.
That said: AWS still wins at fractional-TB scale (below 50 GB) because of the free tier, and is usually cheaper than people expect for hot tiers you access frequently.
Rate limits — the one that bit me
This is the gotcha that matters for anyone building multi-tenant:
- Hetzner Object Storage: ~750 requests/second per bucket (documented soft limit, confirmed in practice).
- AWS S3: 3,500 PUT/COPY/POST/DELETE per second per prefix, 5,500 GET per second per prefix — and the limit auto-scales as you split across prefixes.
The difference: AWS rate-limits per prefix, and you can have as many prefixes as you want. Hetzner rate-limits per bucket, full stop. If you put every customer’s backups under /tenant-abc/… and /tenant-xyz/…, you still share one 750/s budget across all tenants.
The failure that made us shard
Early on, Resistro Cloud stored objects as <tenant-uuid>/<backup-uuid>.backup. For two customers that’s fine. For 50 customers with hourly backups and ~3 operations per backup (PUT + HEAD + COMPLETE), you stay inside the budget on paper. In practice the load is bursty — 30 customers triggering at the top of the hour can spike past 750.
The fix took one afternoon: prefix the key with two hex characters derived from a SHA-256 of the tenant UUID.
shard = hex(sha256(tenant_id.bytes)[0]) // "37" / "c9" / "f2" / ...
key = <shard>/<tenant-uuid>/<backup-uuid>.backup
256 possible shards, roughly uniform distribution. From Hetzner’s point of view the bucket is 256 independent write surfaces, because their internal partitioning keys off the prefix. The 750/s per-bucket cap becomes effectively ~2.9/s per shard, which is way above what any single tenant produces.
Migration cost: zero for new backups (new code path), old objects stay where they are, the database keeps the full path per backup record.
Durability and guarantees
Both providers claim “eleven nines” of durability for stored objects. The disclaimer applies to both: that number covers the provider not losing your data, not your data still being correct. Bit rot is prevented; a PUT of garbage is not.
Practical differences:
- AWS has cross-region replication as a product. Hetzner doesn’t; you build it yourself with a second bucket in the fsn1 region.
- AWS has Object Lock / Compliance Mode for WORM with legal hold. Hetzner has Object Lock in governance mode. Both are enough for standard backup WORM; neither gives you a SEC 17a-4 attestation.
- AWS has S3 Intelligent-Tiering that auto-moves cold objects to cheaper storage classes. Hetzner has one tier.
Data residency and processing law
The question DACH buyers actually care about:
- Hetzner: GmbH, Gunzenhausen, Germany. Contract, invoice, support — all in German, German jurisdiction. BSI-C5-tested, ISO 27001. No US legal exposure under the CLOUD Act.
- AWS eu-central-1: data resides in Frankfurt, but AWS Europe entities are ultimately controlled by Amazon.com Inc. (US). Under the US CLOUD Act, a US warrant can compel AWS to produce data regardless of where it’s stored — confirmed by multiple European data-protection authorities, even after AWS’s European Sovereign Cloud announcement in 2024.
For some regulated DACH buyers, provider jurisdiction and processor structure can weigh more heavily than pure storage cost or technical capability.
Operational ergonomics
Where AWS still wins:
- CLI tooling.
aws s3 sync, IAM policies, presigned URLs are well-documented and battle-tested. - Documentation. Every edge case has a Stack Overflow thread.
- SDK coverage. Every language has an AWS SDK that works.
Where Hetzner is fine but requires more setup:
- CLI is
mcli(MinIO client). Works, not as polished asaws s3. - No IAM — access is bucket-scoped credentials. For a single-product SaaS, not a problem.
- S3-compatible API works with every SDK; just needs an endpoint override.
The honest summary: if your team already lives in AWS and you’re not cost-sensitive, S3 is fine. If you’re building for EU customers and cost matters, Hetzner is the better default.
When to pick which
| Situation | Recommendation |
|---|---|
| Below 50 GB, already on AWS | Stay on S3. Not worth moving. |
| 100 GB – 5 TB, EU-only customers | Hetzner. Cost and residency both win. |
| > 5 TB, or regulated mid-market | Hetzner for primary + AWS Deep Archive for quarterly off-provider copy. Two-provider strategy is cheap insurance. |
| Need S3 Intelligent-Tiering or CRR | AWS. Hetzner doesn’t play here. |
| Multi-tenant SaaS, need predictable rate-limit budget | Either — but shard your prefixes on day one. |
In practice, the default depends on two things: whether AWS operational maturity already exists in-house, and how strongly cost and provider jurisdiction matter in procurement. Neither is universally the right choice.
