Self-host vs managed CORS proxy: which one for which job?
corsproxy.dev ships in two shapes — an MIT-licensed Go binary you run yourself, and a hosted API we run for you. Same proxy core, different operational shape. Here's how to pick.
The two-line summary
- Self-host when you care about who sees your URLs, when you'll have steady volume that makes a fixed-cost host cheaper than per-request billing, or when you need behavior we don't ship.
- Managed when you'd rather not babysit infra, you want API keys and rate limits out of the box, and your traffic is bursty enough that paying for what you use beats running idle servers.
For most "I just need to ship this prototype" situations, managed wins on time-to-first-request. For most production-scale or security-sensitive cases, self-host wins on long-term control.
What you give up either way
Both options use the same proxy semantics: GET/POST/PUT/DELETE/PATCH, the target URL as a query parameter, response headers sanitized, private-network targets refused. The behavioral surface is identical — what changes is who runs it and what's bolted on around it.
Self-hosted: what you get and what it costs
The OSS repo (github.com/melihbirim/corsproxy) ships a single Go binary, ~10 MB, no external dependencies, MIT licensed. Deploy with:
git clone https://github.com/melihbirim/corsproxy
cd corsproxy
go run main.go
One-click deploys exist for Railway, Render, Fly.io, and Koyeb. A $5/month box handles tens of millions of requests/month.
You get:
- Total control over allowed origins, blocked hosts, rate limits, request size, timeouts.
- Your data never touches our infrastructure. No logs we hold; no audit we run.
- Fixed cost. A predictable hosting bill scales linearly with traffic up to your VM's CPU limit, then you add more.
- The ability to fork the code and patch it for things we deliberately don't support (response caching, custom headers, downstream auth).
You take on:
- Patching the binary when CVEs land in Go's standard library or its dependencies. (There are barely any — Go std lib only — but you still need to rebuild on security advisories.)
- Building your own API key system if you want auth. The OSS binary supports an env-driven allowlist; user-facing keys are not a feature.
- Wiring observability.
curl -fS host/healthworks; sub-1-second alerting and per-endpoint dashboards are your problem. - SSL certificates and DNS. (Cloudflare's free tier in front of any HTTP origin solves both.)
Managed: what you get and what it costs
The hosted API at api.corsproxy.dev wraps the same proxy core in account management, rate limits, and a dashboard.
You get:
- An API key in 30 seconds.
X-API-Key: sk_live_…in your request header and you're proxying. - Per-key rate limits enforced atomically (Cloudflare Durable Objects, not eventually-consistent counters). No burst overage.
- Usage analytics in the dashboard — requests per day per key, 30-day history, peak-day spikes.
- Email alerts when you hit your daily limit, so you don't only find out via 429s in production.
- GDPR-shaped account hygiene: one-click data export, full account deletion, 30-day log retention defaults.
- SLA and incident response on paid plans.
You take on:
- Trusting a third party with the URLs you proxy. We don't store request or response bodies, but we do log the upstream URL for 30 days.
- A daily quota. Free tier is 100 req/day, which is generous for dev and small projects but you'll outgrow it.
- A bill above the free tier. Paid tiers are arranged via a contact form right now — no surprise auto-charges.
The decision in four questions
- Is what I'm proxying sensitive enough that I want it inside my own perimeter? Yes → self-host. No → managed is fine.
- Will I have steady, predictable volume above a few thousand requests per day? Yes → self-host probably cheaper. No → managed.
- Do I want to build API keys, rate limits, and a usage dashboard myself? Yes → self-host. No → managed.
- Is "time to first proxied request" more important than long-term operational control? Yes → managed. No → either works; go with the one whose constraints match the rest of your team's habits.
Switching between them
The request format is identical, so swapping is one URL change in your client. Use environment variables and you can A/B test them side by side:
// Same client code; the only thing that changes is the base URL
// and the auth header (managed needs one; self-hosted doesn't).
const proxyBase = process.env.PROXY_URL ||
'https://api.corsproxy.dev';
const authHeader = process.env.PROXY_KEY
? { 'X-API-Key': process.env.PROXY_KEY }
: {};
fetch(`${proxyBase}/proxy?url=${encodeURIComponent(targetUrl)}`, {
headers: authHeader
});
Many teams start managed for prototypes, move to self-hosted when usage gets serious, then end up running both — managed for non-production environments where keys make per-engineer attribution easy, self-hosted for production hot paths.
Try either in five minutes
Hosted account on the Free tier: create an account. Self-host: clone the repo. Or both — they cohabit fine.