Skip to main content

max / makenotwork

Correct the SyncKit storage cost basis and blob region The billing docs claimed SyncKit blobs sit on Cloudflare R2 at $0.015/GB and derived a ~2x margin from it. They have never been on R2: prod points SYNCKIT_S3_ENDPOINT at hel1.your-objectstorage.com, bucket "synckit". Real cost is Hetzner Object Storage at roughly $0.0065/GB, so the shipped $0.03/GB rate runs ~4.6x cost, not ~2x. The rate itself is unchanged. scaling.md also had both buckets in fsn1. Content is fsn1, SyncKit is hel1, and the app is US-West, so SyncKit blob traffic is transatlantic with no CDN in front of it.
Co-Authored-By
Claude Opus 5 (1M context) <noreply@anthropic.com>
Author: Max Johnson <me@maxj.phd> · 2026-07-28 01:53 UTC
Signed with PGP, not checked
Commit: bc97711a1860e03344c86b15c3d77bcd78612a32
Parent: 6c6a10b
2 files changed, +10 insertions, -6 deletions
@@ -12,7 +12,7 @@
12 12
13 13 **Custom domains**: creator domains bypass Cloudflare and point at the origin directly, where Caddy issues on-demand TLS (LE HTTP-01, gated by `/api/domains/caddy-ask`). Stable routing target: `connect.makenot.work` (A → origin IP, **proxy OFF**), customers CNAME to it (apex via flattening) so the origin IP can change in one place. **The apex `maxj.phd` dogfoods this exact path**: it is a verified custom domain, DNS-only (CNAME-flattened → `connect.makenot.work`), served by the on-demand-LE catch-all, *not* a CF-proxied zone.
14 14
15 - **Object storage**: Hetzner S3 (`fsn1` Frankfurt), presigned PUT/GET. Separate buckets for content and SyncKit blobs.
15 + **Object storage**: Hetzner S3, presigned PUT/GET. Separate buckets in separate regions: creator content in `fsn1` (Frankfurt), SyncKit blobs in `hel1` (Helsinki). The app is US-West, so both are transatlantic; SyncKit blobs in particular have no CDN in front of them, unlike content, which Cloudflare caches at `cdn.makenot.work`.
16 16
17 17 **Tailscale mesh** carries deploy, CI (astra → alpha), PoM peer health, build offload. Tailscale is **not** in the fan request path, fans go Browser → Cloudflare → public origin.
18 18
@@ -6,15 +6,19 @@
6 6 //! per_key, price = key_cap × gb_per_key × $0.03
7 7 //!
8 8 //! Both are pure GB-based pricing. Egress and ingress are absorbed by the
9 - //! storage rate's ~2× margin against Cloudflare R2 ($0.015/GB) where SyncKit
10 - //! blobs are hosted.
9 + //! storage rate's margin against Hetzner Object Storage (~$0.0065/GB), where
10 + //! SyncKit blobs are hosted in the `synckit` bucket.
11 11 //!
12 12 //! Invoices are floored at a Stripe-fee-cover threshold so we never lose money
13 13 //! on a transaction. See `BASE_FLOOR_CENTS` for the math.
14 14
15 - /// Storage rate in cents per GB per month. Calibrated to ~2× R2 cost
16 - /// ($0.015/GB storage, $0 egress on R2). The 2× margin spread absorbs any
17 - /// ingress/egress cost variance, so we don't need a separate egress price.
15 + /// Storage rate in cents per GB per month. Runs ~4.6× the Hetzner Object
16 + /// Storage cost behind it (€5.99/TB/month, ~$0.0065/GB at 1.09 USD/EUR, with
17 + /// 1 TB of egress included per TB stored). That spread absorbs any
18 + /// ingress/egress variance, so we don't need a separate egress price. The rate
19 + /// was calibrated against Cloudflare R2 and documented as ~2× cost until
20 + /// 2026-07-27; the blobs were never on R2, so the basis was wrong, not the
21 + /// price. See `mnw-biz-synckit-pricing` in the wiki.
18 22 pub const STORAGE_RATE_CENTS_PER_GB: i64 = 3;
19 23
20 24 /// Upper bound on a developer-billing storage cap, in GB. Applies to the bulk