Proxy Mode
smo1 advanced 6 min read
ELI5
Normally, a short link sends you somewhere else — your browser sees the new address. Proxy mode is different: it is like looking through a periscope. You stay on the short link URL, but you are actually seeing content from another website. The edge worker fetches the destination for you, rewrites any internal links so they still go through the short URL, and streams the response back without revealing the real destination.
Technical Deep Dive
Source: zoomies-edge src/index.ts:172-256, src/lib/proxy-destination.ts:33-180 (origin/main 5bdde59); purr-api internal/handler/redirect_handler.go:113-178, internal/repository/link_repository.go:148 (bb6cfc2), read 2026-10-25. Corrected in v1.1: forwarded headers, lookup path, click tracking, and two defects found by reading the code (not reproduced live).
Current-state caveats
- Lookup is host-blind.
handleProxyModeresolves throughGET /api/links/slug/:slug(uid = $1 OR custom_slug = $1 LIMIT 1), never through the host-aware resolve, and there is no KV cache in production (smo1-001, smo1-028). - Proxy hits are not tracked.
handleProxyModenever callstrackClick, so proxy-mode links get no clicks and their pawprintz stays 0. - Protected proxy links appear unopenable (code reading, UNVERIFIED live). The slug lookup returns an empty
destinationfor any link that is not yet allowed, including protected ones (redirect_handler.go:166-169). After a valid unlock,handleProxyModepasses that empty string toproxyToDestination, whosenew URL("")fails and returns the “proxy unavailable” page. - The destination’s own path is dropped. The proxied URL is
new URL(strippedPath, target), so a destination ofhttps://example.com/appserveshttps://example.com/forsmo1.io/slug. - Visitor cookies are forwarded. The outgoing request clones all inbound headers, including
Cookie, so the visitor’ssmo1.iocookies scoped to/slug(such as the protection session cookie) reach the destination.
Redirect vs. Proxy
| Aspect | Redirect mode | Proxy mode |
|---|---|---|
| URL bar | Shows destination | Stays on smo1.io/:slug |
| Status code | 302 Found | 200 OK (streamed) |
| SEO | Destination indexed | Short URL indexed |
| Path preservation | N/A (new URL) | /slug/path → /path |
| Cookie scoping | Destination domain | smo1.io |
| Use case | Standard short links | White-label, hiding destination |
Proxy Sequence
%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#e8f4f8', 'primaryTextColor': '#2d3748', 'primaryBorderColor': '#90cdf4', 'lineColor': '#718096', 'secondaryColor': '#f0fff4', 'tertiaryColor': '#fefcbf'}}}%%sequenceDiagram autonumber actor U as User participant Z as zoomies-edge participant D as Destination Server
U->>Z: GET smo1.io/:slug/dashboard Z->>Z: Resolve link via /api/links/slug, no KV in production Z->>Z: Rewrite path: /dashboard Z->>Z: Set Host header to destination Z->>D: GET https://destination.com/dashboard D-->>Z: 200 OK + HTML/CSS/JS Z->>Z: Rewrite Location headers Z->>Z: Strip Set-Cookie domains Z-->>U: 200 OK (streamed) Note over U,Z: URL bar still shows smo1.io/:slug/dashboardPath Rewriting
Original request: smo1.io/myapp/dashboard?tab=settings
Rewritten request to destination:
- Path:
/dashboard?tab=settings(slug prefix removed) - Host:
destination.com - Headers: Original headers forwarded, except
Hostis replaced
Sub-path handling: ALL /:slug/* route in zoomies-edge catches any path under the slug and applies the same rewriting rules.
Header Manipulation
Outgoing (Worker → Destination):
Host→ destination hostnameX-Forwarded-Host→ the originalsmo1.iohost (proxy-destination.ts:72)X-Forwarded-Proto→https- every other inbound header is cloned unchanged, including
Cookie; noX-Forwarded-Foris set by the Worker - Original
User-Agent,Accept,Accept-Languagepreserved
Incoming (Destination → Worker → User):
Locationheaders rewritten:https://destination.com/login→https://smo1.io/myapp/loginSet-Cookiedomain stripped:domain=destination.com→ removed (cookie scopes tosmo1.io)Content-Encodingpreserved for streaming
redirect: manual
The Worker uses fetch(url, { redirect: 'manual' }) instead of the default 'follow':
const response = await fetch(destinationUrl, { method: request.method, headers: modifiedHeaders, body: request.body, redirect: 'manual', // Critical!});Why manual?
- If the destination returns a 302, the Workers runtime would normally follow it automatically
- This would bypass the Worker’s header rewriting and path preservation
- With
manual, the Worker receives the 302 response, rewrites theLocationheader, and returns it to the browser — maintaining the slug prefix
Cookie Domain Stripping
When a proxied destination sets a cookie:
Set-Cookie: session=abc123; Domain=destination.com; Path=/; SecureThe Worker strips the Domain attribute:
Set-Cookie: session=abc123; Path=/; SecureWithout a Domain attribute, the browser scopes the cookie to the current host (smo1.io), preventing the destination from seeing cookies intended for the proxy path.
Limitations
| Limitation | Reason |
|---|---|
| Relative asset URLs may break | The browser resolves /style.css against smo1.io, not the destination |
| Absolute URLs in JS may bypass proxy | Frontend routing in SPAs may navigate to destination.com directly |
| WebSocket connections are not proxied | Workers runtime does not support WebSocket proxying in this configuration |
| Large file uploads may timeout | Workers have a 100 MB response size limit and 30-second CPU limit |
Workaround for broken assets: The destination should use absolute URLs or be designed to work behind a reverse proxy.
Key Terms
- Reverse proxy → Server that fetches content from another server and presents it as its own
- Path rewriting → Removing the slug prefix so the destination receives the correct sub-path
- redirect: manual → Fetch option that prevents automatic HTTP redirect following
- Domain stripping → Removing the
Domainattribute fromSet-Cookieheaders to scope cookies to the proxy host - White-label → Presenting third-party content under your own domain and branding
Q&A
Q: What is the difference between redirect mode and proxy mode?
A: Redirect mode answers 302 and the browser goes to the destination. Proxy mode has the Worker fetch the destination origin and stream the response back, with the address bar staying on smo1.io/<slug>/...; proxy hits are not click-tracked.
Q: Why must the Worker use redirect: manual?
A: With the default follow, the Workers runtime would chase the destination’s 3xx itself, so the Worker could not rewrite the Location header back under /<slug> and the visitor would be bounced off smo1.
Q: How are Set-Cookie headers handled in proxy mode?
A: The Domain attribute is stripped from each Set-Cookie so the cookie lands on the smo1 host; the rest of the cookie is kept (proxy-destination.ts:155-180).
Q: Why would someone use proxy mode instead of redirect? A: To hide the destination URL (e.g., affiliate links, private documents), to maintain brand consistency (the user never leaves your domain), or to add a layer of access control (protection + proxy).
Q: Can proxy mode bypass CORS?
A: No. CORS is enforced by the browser based on the origin in the address bar (smo1.io). If the proxied content makes XHR/fetch requests to the destination, those are cross-origin and subject to CORS. The Worker does not magically disable browser security.
Q: What happens if the destination is down?
A: The Worker receives an error from fetch() and returns a 502 Bad Gateway or 504 Gateway Timeout to the user. The error page can be customised in the Worker.
Q: Does proxy mode support POST requests?
A: Yes. The ALL /:slug/* route forwards all HTTP methods (GET, POST, PUT, PATCH, DELETE) to the destination with the same body and headers.
Examples
Think of proxy mode like a personal shopper:
- You tell the shopper “Get me a jacket from Store X, but I do not want anyone to know I shop there” (hide destination)
- The shopper goes to Store X, picks up the jacket, and brings it back to you in an unmarked bag (slug URL)
- If Store X says “Go to our accessories department” (redirect), the shopper intercepts the directions and rewrites them so you still go through the shopper (Location header rewrite)
- If Store X gives you a loyalty card (Set-Cookie), the shopper removes the Store X branding from the card so it looks like a generic gift card (domain stripping)
- The shopper cannot help you if Store X’s clothes have “Made at Store X” labels sewn into every seam (absolute URLs in HTML/JS)
neighbors on the map
- Request Routing & Edge Resolution debugging why a slug returns 404 instead of redirecting
- Link Protection implementing password-protected links