fix(gateway): retire dweb.link before it is switched off on 2026-09-21 - #124
Merged
Conversation
The IPFS Foundation is shutting dweb.link down for good on 2026-09-21
(gatewaychanges.ipfs.io). It is the app's default gateway. The HTTP 429s already
showing up on live sites -- with Retry-After around half an hour -- are its
announced escalating pauses, not load.
Left alone, on the 21st: every bare fxfiles.top link stops resolving, and every
new generation bakes dead asset URLs into immutable HTML.
WHY CHANGING THE CONSTANT IS NOT ENOUGH
`IpfsGatewayHelper.init()` WRITES the default into secure storage on first run,
so everyone who has ever launched the app has the dweb template persisted. A new
`defaultTemplate` would therefore reach new installs only, and every existing
user would sail into the shutdown. `retiredTemplates` is the part that actually
moves them: a stored value matching a retired template is replaced at startup.
That deliberately overrides what looks like a choice -- for almost everyone it
was just the old default, and honouring it would hand them a broken site.
The migration decision is split into a pure `resolveStoredTemplate` so it can be
tested without a storage backend. It is the single thing standing between an
existing user and a dead gateway, so it is covered directly.
THE SAME PROBLEM ON THE SHARED LINK
Links copied since the gateway picker shipped carry an EXPLICIT `?gw=dweb` --
and an explicit key beats the default by design, which here would mean beating
it into a dead host. So `dweb` is removed from the Worker's allowlist entirely,
which makes those links fall back rather than fail. The "opinion" the explicit
key encoded was manufactured by the default, not expressed by anyone.
ALSO
- `fx` (ipfs.cloud.fx.land) joins Filebase as a preset and an allowlisted key.
Verified 2026-09-12 to serve these CIDs with correct content types, and unlike
any third party it is ours -- so there is a live fallback if Filebase moves.
- dweb is dropped from `presets`: offering a gateway that `init()` migrates away
from on the next launch is a trap.
- The IPNS fallback to `{name}.ipns.dweb.link` becomes a plain 502. It never
resolved anyway (w3name does not publish to the DHT, measured 2026-05-30) and
now points at a dead host; redirecting there turned our error into a more
confusing one.
- The subdomain-safety guard goes with it. Both remaining gateways are
path-style, where a case-sensitive CIDv0 or an over-63-char CID is harmless.
Noted in the source and README in case a subdomain gateway ever returns.
Tests: 27 Dart (migration, presets, resolver keys, link decoration), 33 Node for
the Worker, including one that asserts no redirect target on any code path is a
dweb host.
This is the first of three steps. It stops the bleeding but does NOT yet make a
gateway change reach sites that are already generated -- their asset URLs are
absolute and inside immutable HTML. That needs the fxfiles.top/a/ indirection,
which is planned separately and whose core mechanic is already validated.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AwMWmCivEpYTmmzzmjSTAf
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why now
The IPFS Foundation is shutting dweb.link down for good on 2026-09-21 (gatewaychanges.ipfs.io). It is the app's default gateway. The HTTP 429s already appearing on live sites — with
Retry-Afteraround half an hour — are its announced escalating pauses, not load.Left alone, on the 21st: every bare
fxfiles.toplink stops resolving, and every new generation bakes dead asset URLs into immutable HTML.Why changing the constant is not enough
IpfsGatewayHelper.init()writes the default into secure storage on first run. So everyone who has ever launched the app has the dweb template persisted, and a newdefaultTemplatewould reach new installs only — every existing user would sail into the shutdown with the code looking correct.retiredTemplatesis the part that actually moves them: a stored value matching a retired template is replaced at startup. That deliberately overrides what looks like a choice — for almost everyone it was just the old default, and honouring it would hand them a broken site.The decision is split into a pure
resolveStoredTemplateso it can be tested without a storage backend. It is the single thing standing between an existing user and a dead gateway, so it is covered directly rather than incidentally.Two traps found in the same area:
defaultTemplate = filebaseTemplatemakes two keys of theconst _frontDoorKeysmap identical — a compile error — and makespresetLabelForreturn the wrong label. Hence a distinctdwebTemplateconstant.presets: offering a gateway thatinit()migrates away from on the next launch is a trap.The same problem on the shared link
Links copied since the gateway picker shipped carry an explicit
?gw=dweb— and an explicit key beats the default by design, which here would mean beating it into a dead host.So
dwebis removed from the Worker's allowlist entirely, which makes those links fall back rather than fail. The "opinion" that explicit key encoded was manufactured by the default, not expressed by anyone.Also
fx(ipfs.cloud.fx.land) joins Filebase as a preset and an allowlisted key. Verified 2026-09-12 to serve these CIDs with correct content types — and unlike any third party it is ours, so there is a live fallback if Filebase ever moves.{name}.ipns.dweb.link, which never resolved anyway (w3name does not publish to the DHT — measured 2026-05-30) and now points at a dead host. Redirecting there turned our error into a more confusing one.Testing
flutter test— 1078 passed, 25 skippednode --test cloudflare/— 33 passed, including one asserting that no redirect target on any code path is a dweb hostflutter build web --release -t lib/main_web.dart— ✅ (the exact commanddeploy-pages.ymlruns)flutter analyze— no errorsScope — what this does NOT do
This stops the bleeding. It does not make a gateway change reach sites that are already generated: their asset URLs are absolute and live inside immutable HTML, so no setting can rewrite them.
That needs an
fxfiles.top/a/indirection so the gateway becomes a runtime decision. Its core mechanic is already validated — a localwrangler devprototype driving real Chrome showed images loading through a cross-origin 302 at dimensions identical to direct controls (3/3), and pointing the redirect at a dead host correctly broke exactly those images (0/3) while controls stayed green. That work is planned separately and deliberately not bundled here.🤖 Generated with Claude Code
https://claude.ai/code/session_01AwMWmCivEpYTmmzzmjSTAf