You're building a frontend, you call a third-party API, and the browser stops you:
Access to fetch at 'https://api.example.com' from origin 'http://localhost:3000'
has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present.
The API works fine from curl. It just doesn't send CORS headers, so the browser won't let your JavaScript read the response. The usual fixes are to write a backend route just to forward the call, or to use a public CORS proxy and hope it's still up (and not logging your tokens) tomorrow.
A third option is to run your own proxy. I built corsproxy for this: a single Go binary, standard library only, and a ~10MB Docker image.
Run it
git clone https://github.com/melihbirim/corsproxy.git
cd corsproxy
docker compose up
Or without Docker:
go run main.go
It listens on http://localhost:8080.
Use it
Prefix the target URL with ?url=:
fetch("http://localhost:8080/?url=https://api.github.com/users/octocat")
.then((r) => r.json())
.then(console.log);
GET, POST, PUT, PATCH and DELETE all pass through, with headers and body. There's a /health endpoint for uptime checks.
Don't run an open relay
The defaults are wide open, so the quick start works with no setup. Before you put it on the public internet, lock it down with environment variables:
ALLOWED_ORIGINS=https://myapp.com # only your site can call it
ALLOWED_HOSTS=api.github.com,api.stripe.com # only these upstream APIs
RATE_LIMIT_PER_MINUTE=100 # per client IP
DAILY_REQUEST_LIMIT=100000 # global cost backstop
REQUIRE_API_KEY=true
API_KEYS=key-for-my-app
Private, loopback and cloud-metadata addresses (like 169.254.169.254) are blocked by default, checked on the resolved IP of every connection including redirects, so the proxy can't be used to reach your internal network (SSRF).
On startup it logs a warning listing any of these protections that are still off.
Deploy
The repo has configs for Railway, Render, Fly.io and Koyeb, so you can deploy with one click or one CLI command. Put it behind HTTPS (the platform's load balancer, or Caddy/nginx), since the server itself speaks plain HTTP.
Compared to cors-anywhere
cors-anywhere is the classic option, but it's Node.js with dependencies. corsproxy is one Go binary with no dependencies, around 10MB of memory, and cold starts under 100ms, which matters on platforms that scale to zero.
Links
- Repo (MIT): https://github.com/melihbirim/corsproxy
- Issues and PRs welcome, including good-first-issues if you want to learn Go on a small real project.
If it saves you a backend route, a star helps others find it.
Top comments (0)