Every web developer knows the routine. You start your frontend on port 3000,
your API on 3001, maybe an admin dashboard on 8080. Open a browser tab, stare
at it... which port was which again?
It gets worse when you juggle multiple projects. Two apps both want port 3000.
You're switching between client projects and can't remember if the e-commerce
site was :3000 or :3001 today. And your bookmarks bar is full of
localhost:something.
I decided to fix this for myself and ended up building
Roxy — a local development proxy that
replaces localhost ports with custom .roxy domains and browser-trusted HTTPS.
What it looks like
Instead of http://localhost:3000, you get https://myapp.roxy:
roxy register shop.roxy --route "/=3000" --route "/api=3001"
roxy register blog.roxy --route "/=4000"
sudo roxy start
That's it. Open https://shop.roxy in your browser — green lock, no
certificate warnings, no config files. https://blog.roxy is a completely
separate project running alongside it.
How it works under the hood
Roxy is a single binary that bundles three things:
-
A DNS server — resolves all
.roxydomains to127.0.0.1. No need to edit/etc/hostsor install dnsmasq. -
A certificate authority — generates trusted HTTPS certificates on the
fly. The root CA gets installed into your system trust store during
roxy install, so browsers trust everything automatically. - A reverse proxy — routes incoming requests to your local services based on the domain and path.
One-time setup takes about 10 seconds:
# Install (macOS via Homebrew, or build from source on Linux)
brew tap rbas/roxy && brew install roxy
# One-time setup — creates Root CA, configures DNS
sudo roxy install
After that, you just register domains and start the proxy.
Features I use every day
Path-based routing — run multiple services behind one domain:
sudo roxy register myapp.roxy \
--route "/=3000" \
--route "/api=3001" \
--route "/admin=8080"
# https://myapp.roxy → frontend
# https://myapp.roxy/api → API
# https://myapp.roxy/admin → admin panel
Wildcard subdomains — great for multi-tenant SaaS development:
sudo roxy register myapp.roxy --wildcard --route "/=3000"
# https://myapp.roxy → main app
# https://acme.myapp.roxy → tenant "acme"
# https://globex.myapp.roxy → tenant "globex"
Static file serving — point a route at a directory and get a built-in file
browser:
sudo roxy register docs.roxy --route "/=./build"
Real-time traffic logs — see every request flowing through:
roxy logs -f
The tech
I wrote Roxy in Rust. The whole thing is about 5k lines and compiles to a
single binary with zero runtime dependencies. The main building blocks:
- axum for the HTTP server and reverse proxy
- rustls for TLS (no OpenSSL dependency)
- rcgen for certificate generation
It runs on macOS (Monterey+) and Linux (Ubuntu 22.04+ / Debian 12+).
The Linux support just landed in v0.5.0, which I shipped this week.
Try it
# macOS
brew tap rbas/roxy && brew install roxy
# Or build from source (macOS or Linux)
git clone https://github.com/rbas/roxy.git
cd roxy && cargo install --path .
# Then
sudo roxy install
sudo roxy register myapp.roxy --route "/=3000"
sudo roxy start
The project is open source (MIT):
github.com/rbas/roxy
I'd love to hear how you handle local dev routing — do you just live with
localhost ports, or have you found a setup that works? Let me know in the
comments.

Top comments (2)
Good idea, thx for sharing. quick questions, How does the binary recieve DNS requests. I'm guessing the proxy edit the /etc/hosts..How do you secure the root CA private key. also, why do you need root or sudo?
Great questions — these are really the core design decisions that everything else in Roxy is built on top of.
DNS — Roxy runs its own DNS server on port 53 that resolves all
.roxydomains to127.0.0.1. No/etc/hostsediting needed. On macOS it creates a resolver file at/etc/resolver/roxy, and on Linux it configuressystemd-resolved— both tell the OS to route.roxyqueries to Roxy's DNS server.Root CA key — The private key is stored at
/etc/roxy/ca/root.keywith0600permissions (owner-only read/write). It never leaves your machine and is only used locally to sign certificates for your.roxydomains. It's the same approach tools like mkcert and Caddy use. That said, I'm always open to ideas here — if you've seen a better pattern for managing local CA keys, I'd love to hear it.Why sudo — Two reasons: binding to privileged ports (53 for DNS, 80/443 for HTTP/HTTPS) and writing to system directories (
/etc/roxy,/etc/resolver). Theroxy installstep also needs it to add the root CA to the system trust store. I've been thinking about whether it's worth supporting unprivileged ports with something like port forwarding orCAP_NET_BIND_SERVICEon Linux to reduce the sudo surface. Curious — does the sudo requirement bother you as a user, or is it expected for this kind of tool?