CRUMB a card from devarno-cloud

Deployment Topology & Proxy Conflict Resolution

smo1 intermediate 5 min read

ELI5

SMO1 lives on three different hosting platforms, like a band with members in three different cities. Cloudflare handles the front door (the edge worker), Railway runs the brain (the API), and Vercel runs the stage show (the websites). There is a tricky problem: the front door is also supposed to show the stage show, but if the doorman tries to fetch the show from the same address, he ends up talking to himself in a mirror. The fix is a secret back entrance called origin.smo1.io that bypasses the doorman entirely.

Technical Deep Dive

Production Deployment Map

%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#e8f4f8', 'primaryTextColor': '#2d3748', 'primaryBorderColor': '#90cdf4', 'lineColor': '#718096', 'secondaryColor': '#f0fff4', 'tertiaryColor': '#fefcbf'}}}%%
flowchart TB
subgraph DNS["DNS / Cloudflare"]
CF[Cloudflare Proxy<br/>smo1.io]
end
subgraph Edge["Edge Layer"]
Z[zoomies-edge<br/>Cloudflare Worker]
end
subgraph API["API Layer"]
P[purr-api<br/>Railway]
end
subgraph Web["Web Layer"]
W[whiskers-landing<br/>Vercel : origin.smo1.io]
M[meow-web<br/>Vercel : app.smo1.io]
end
U[User] -->|smo1.io/*| CF
CF -->|slug routes| Z
Z -->|API calls| P
Z -->|landing proxy| W
U -->|app.smo1.io/*| M
U -->|purr-api...railway.app| P

Platform Responsibilities

ProjectPlatformProduction URLDeploy Command
zoomies-edgeCloudflare Workerssmo1.io/*wrangler deploy --env lion
purr-apiRailwaypurr-api-production.up.railway.appDocker push / Railway CLI
meow-webVercelapp.smo1.iovercel --prod
whiskers-landingVercelorigin.smo1.iovercel --prod

The Proxy Conflict

Problem: Cloudflare proxies smo1.io to the Worker. If the Worker tries to fetch("https://smo1.io/about"), it calls itself → infinite loop → 502 error.

Solution: Deploy whiskers-landing to origin.smo1.io with Cloudflare proxy disabled (grey cloud in DNS). The Worker fetches origin.smo1.io directly, bypassing Cloudflare.

%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#e8f4f8', 'primaryTextColor': '#2d3748', 'primaryBorderColor': '#90cdf4', 'lineColor': '#718096', 'secondaryColor': '#f0fff4', 'tertiaryColor': '#fefcbf'}}}%%
flowchart LR
A[Worker fetches smo1.io] --> B[Cloudflare Proxy]
B --> C[Worker]
C --> B
B --> D[Infinite loop ❌]
E[Worker fetches origin.smo1.io] --> F[DNS only<br/>no proxy]
F --> G[Vercel]
G --> H[Success ✅]

DNS Configuration

RecordTypeTargetProxy Status
smo1.ioA / CNAMECloudflare Worker🟠 Proxied
origin.smo1.ioCNAMEcname.vercel-dns.com⚪ DNS only
app.smo1.ioCNAMEcname.vercel-dns.com🟠 Proxied (ok, no Worker)
airlock.devarno.cloudCNAMEAirlock service🟠 Proxied

Environment Configuration

zoomies-edge uses Wrangler environments to switch origins:

wrangler.toml
[env.development]
LANDING_ORIGIN = "http://localhost:3001"
PURR_API_URL = "http://localhost:8080"
[env.cat]
LANDING_ORIGIN = "https://origin.smo1.io"
PURR_API_URL = "https://purr.smo1.io"
[env.lion]
LANDING_ORIGIN = "https://origin.smo1.io"
PURR_API_URL = "https://purr-api-production.up.railway.app"
route = { pattern = "smo1.io/*", zone_name = "smo1.io" }

SSL / TLS

  • Cloudflare handles SSL termination for smo1.io and app.smo1.io
  • Railway provides automatic TLS for purr-api-production.up.railway.app
  • Vercel provides automatic TLS for origin.smo1.io and app.smo1.io
  • Internal service-to-service calls (Worker → API) use HTTPS with certificate validation

Rollback Strategy

LayerRollback methodTime to revert
Edge (Worker)wrangler deploy --env lion with previous git commit30–60 seconds
API (Railway)Railway dashboard → redeploy previous deployment1–2 minutes
Web (Vercel)Vercel dashboard → promote previous deployment30–60 seconds

Local Development (kitten)

All services run locally:

  • litter-box/docker-compose up -d starts Postgres, Redis, ClickHouse, MinIO, Mailpit
  • purr-api: make run on :8080
  • meow-web: pnpm dev on :3000
  • whiskers-landing: pnpm dev on :3001
  • zoomies-edge: pnpm dev (Wrangler local dev) on :8787

The local Worker proxies to localhost:3001 and localhost:8080 instead of production URLs.

Key Terms

  • Proxy conflict → When a Cloudflare Worker tries to fetch its own proxied domain, causing an infinite loop
  • Origin → The unproxied deployment of a site that the Worker can safely fetch from
  • Grey cloud → Cloudflare DNS setting where proxying is disabled; only DNS resolution occurs
  • Wrangler → Cloudflare’s CLI tool for deploying and managing Workers
  • SSL termination → Decrypting HTTPS traffic at the edge so backend services receive plaintext HTTP

Q&A

Q: Why not put everything on one platform? A: Each platform excels at different things. Cloudflare Workers are fastest for edge routing. Railway is simplest for Go backend hosting. Vercel is optimal for Next.js frontend deployment. Using best-of-breed services for each layer maximises performance and developer experience.

Q: What happens if origin.smo1.io is accidentally proxied? A: The Worker would enter an infinite loop for all non-slug requests, causing 502 errors across the entire site. The fix is to toggle the DNS record back to grey cloud (DNS only) in the Cloudflare dashboard.

Q: Can users access origin.smo1.io directly? A: Technically yes, but there is no reason to. It serves the same content as smo1.io for non-slug paths. Direct access bypasses the edge worker’s bot detection and analytics, so it is not encouraged.

Q: How does the Worker know which environment it is running in? A: Wrangler injects environment variables based on the --env flag. The Worker reads LANDING_ORIGIN and PURR_API_URL from its bindings at runtime.

Examples

Think of the deployment topology like a restaurant chain:

  • Cloudflare is the franchise headquarters that handles all customer-facing branding and routes calls to the right location
  • Railway is the central kitchen that prepares all the food (API responses)
  • Vercel is the local dining room where customers sit (websites)
  • The proxy conflict is the headquarters phone system routing a call back to itself when someone asks for “the manager” — the fix is a direct internal line (origin.smo1.io) that bypasses the switchboard
  • Wrangler environments are the different menus for breakfast, lunch, and dinner — same kitchen, different configurations

neighbors on the map