Homebrew
Your app has a name. Use it.
routeup gives every app on your machine a stable, browser-trusted HTTPS name, so you can use the same URL every time.
- Local by default Routes stay on your machine with no account, token, or server.
- Bring or run the app Proxy an app you already start, or let routeup run its configured command.
- Inspect and debug Follow status and timing live, with opt-in capture for headers and bodies.
- Expose when needed Open only the routes or paths you choose through a hosted or self-hosted server.
- MIT
- Self-hostable
- Single Go binary
- Zero telemetry
route: example-app local: https://example-app.localhost public: https://example-app.try.routeup.dev expose: /api/webhooks/* targets: / http://localhost:5173 /api http://localhost:8080 requests: live 14:02:01 200 req_9f2LmX7qKd3sAw8P GET / 14:02:04 204 req_Jz6nR2wL8cP4sD9h POST /api/webho... 14:02:08 200 req_Vx2mPq7nH5kR3tY8 GET /api/users press Ctrl-C to stop
The route lives in the repo.
Commit the route in routeup.json or in the routeup block of package.json. Names, targets, and public exposure settings stay with the project. Use routeup serve for apps you already run, or bare routeup to start the configured command.
Keep your current dev command.
Start your app as usual, then run routeup serve to serve the configured routes over HTTPS.
{ "name": "example-app", "targets": [ { "path": "/", "port": 5173 }, { "path": "/api", "port": 8080 } ], "expose": { "enabled": true, "paths": ["/api/webhooks/*"] }}
$ routeup serve route: example-app local: https://example-app.localhost public: https://example-app.try.routeup.dev expose: /api/webhooks/* targets: / http://localhost:5173 /api http://localhost:8080 requests: live 14:02:01 200 req_9f2LmX7qKd3sAw8P GET / 14:02:04 204 req_Jz6nR2wL8cP4sD9h POST /api/webhooks/stripe 14:02:08 200 req_Vx2mPq7nH5kR3tY8 GET /api/users press Ctrl-C to stop
One command starts both.
Configure the command, then routeup assigns the port, starts the app, waits until ready, and cleans up when you exit.
{ "name": "example-app", "command": "pnpm dev --port ${PORT}", "expose": { "enabled": true, "paths": ["/api/webhooks/*"] }}
$ routeup routeup command pnpm dev --port ${PORT} route example-app local https://example-app.localhost public https://example-app.try.routeup.dev target / -> localhost:59370 status waiting for localhost:59370 ready: https://example-app.localhost
Pick a recipe.
$ routeup routeup command pnpm dev --port ${PORT} route example-app local https://example-app.localhost target / -> localhost:59370 status waiting for localhost:59370 ready: https://example-app.localhost
{ "name": "example-app", "command": "pnpm dev --port ${PORT}"}
$ routeup serve route: example-app local: https://example-app.localhost targets: / http://localhost:5173 /api http://localhost:8080 press Ctrl-C to stop
{ "name": "example-app", "targets": [ { "path": "/", "port": 5173 }, { "path": "/api", "port": 8080 } ]}
$ routeup expose route: example-app local: https://example-app.localhost public: https://example-app.try.routeup.dev targets: / http://localhost:3000 expose: all paths press Ctrl-C to stop
$ routeup serve route: example-app local: https://example-app.localhost public: https://example-app.try.routeup.dev expose: /api/webhooks/* targets: / http://localhost:8080 press Ctrl-C to stop
{ "name": "example-app", "port": 8080, "expose": { "enabled": true, "paths": ["/api/webhooks/*"] }}
$ routeup logs --follow TIME ROUTE SOURCE STATUS ID METHOD DURATION PATH 14:02:01 example-app local 200 req_9f2LmX GET 3ms /users 14:02:03 example-app public 204 req_Jz6nR2 POST 18ms /hooks 14:02:09 example-app public 204 req_Vx2mPq POST 11ms /hooks 14:02:14 example-app local 304 req_Bm3nKw GET 2ms /app.js 14:02:15 example-app public 500 req_Tp8yLr POST 221ms /hooks 14:02:18 example-app local 200 req_Xk7wMn GET 5ms /users 14:02:22 example-app public 201 req_Hn9pRs POST 33ms /github
routeup dashboard connected 1 route 1 exposure 1 request agent up 2h > ROUTES (1) ────────────────────────────────────────────────────────────────────────────────────── NAME LOCAL URL TARGETS AGE example-app https://example-app.localhost /:3000 2h PUBLIC EXPOSURES (1) ───────────────────────────────────────────────────────────────────────────── STATE ROUTE PUBLIC URL PATHS connected example-app https://example-app.try.routeup.dev all paths REQUESTS (1) ───────────────────────────────────────────────────────────────────────────────────── TIME SOURCE METHOD STS ROUTE PATH ID > 14:02:03 public POST 204 example-app /api/webhooks/stripe req_Jz6nR2wL8cP4sD9h tab focus j/k navigate enter inspect g/G first/last q quit
request req_Jz6nR2wL8cP4sD9h esc back Request req_Jz6nR2wL8cP4sD9h Metadata -------- Source: public Route: example-app Status: 204 Duration: 18ms Method: POST Path: /api/webhooks/stripe Request ------- Capture: complete Body bytes: 52 Content-Type: application/json Body ---- { "event": "payment.succeeded", "amount": 4999, "currency": "usd" } j/k scroll g/G first/last esc back q quit
$ routeup inspect req_Jz6nR2wL8cP4sD9h Request req_Jz6nR2wL8cP4sD9h Metadata -------- Source: public Route: example-app Target: /:8080 Status: 204 Duration: 18ms Method: POST Path: /api/webhooks/stripe Host: example-app.try.routeup.dev Request ------- Capture: complete Body bytes: 7 Redacted: authorization X-Webhook: original Body ---- payload Response -------- <not captured>
{ "capture": { "request": true, "redact_headers": ["authorization"] }}
$ routeup routes routes 1 active example-app local https://example-app.localhost targets / -> localhost:3000 public - process pid 48172 | 2h cwd ~/code/example-app $ routeup doctor [ok] local CA at /Users/mukul/.routeup/ca.crt (expires 2027-08-11) [ok] local CA trusted in OS trust store [ok] port 443: helper installed [ok] agent running (uptime 7527s)
Where requests go.
Local requests stay on your machine. Public requests reach a routeup server, then return through an encrypted tunnel. routeup forwards both paths to the same loopback targets; some dev servers still need their allowed-host or origin settings to accept the route hostname.
your machine opens the tunnel to the public server; there is no router rule or internet-facing port to configure
Going public.
Public exposure is opt-in and needs no port forwarding or router rules. A tokenless try.routeup.dev URL is yours for the session, but is not reserved afterward. A hosted token guarantees the entire your-namespace.routeup.dev namespace for your apps.
no tokenThe URL is yours for the session, but it is not reserved after you disconnect.
A quick URL for right now.
$ routeup serve --expose route: example-app local: https://example-app.localhost public: https://example-app.try.routeup.dev expose: /api/webhooks/* targets: / http://localhost:5173 /api http://localhost:8080 requests: live press Ctrl-C to stop
Use the try.routeup.dev URL to try public exposure, test a webhook, or open the app on another device. It is released when you stop; you can reclaim it later only if it is still available.
with a tokenA token guarantees that the entire namespace is yours to use.
One home for every app.
$ routeup serve --expose route: example-app local: https://example-app.localhost public: https://example-app.team.routeup.dev expose: /api/webhooks/* targets: / http://localhost:5173 /api http://localhost:8080 requests: live press Ctrl-C to stop
A hosted token guarantees that a namespace such as team.routeup.dev is yours. Claim any app name beneath it, for example api.team.routeup.dev and docs.team.routeup.dev.
Request a hosted token
Tokens are issued manually — I'll reply to your request within a day.
We send only your email and requested namespace. Privacy
Prefer your own domain? Run the same routeup binary at a domain such as tunnel.example.com, choose its DNS and TLS, then issue tokens scoped to namespaces such as *.team.tunnel.example.com.
Install routeup.
Install the single binary, run setup once, then give each project a route.
Direct installer
Verified release binary
LLM Usage
Use the routeup skill inside your favourite coding agent to set it up.
Agent Skill guide →One-time setup
Prepare trusted local HTTPS
$ routeup setup ✓ certificate authority created ✓ certificate trusted ✓ port 443 ready ✓ agent started routeup is ready try: routeup serve example-app --port 3000
Run setup once after installing. It creates and trusts the local CA, prepares port 443, and starts the agent.
Installation details →Why routeup exists.
[stable names]
Open the same URL every day, even when the framework chooses a different port.
[trusted https]
Exercise secure cookies, service workers, OAuth, and HTTPS-only APIs before deployment.
[one origin]
Put a frontend and API behind one host so browser cookies and CORS behave naturally.
[share on demand]
Open the same app to webhooks, phones, or teammates, then close it with Ctrl-C or routeup stop.
[stable callbacks]
Register one webhook or OAuth callback URL instead of updating the provider whenever a port or tunnel URL changes.
Need help or have an idea?
Found a bug, a missing workflow, or need help getting a route working?
- Bugs and feature requests: Open a GitHub issue →
- Questions and setup help: [email protected] →
- Local means localNo account, token, DNS or server call for
*.localhost. - Capture is opt-inBodies are never retained unless a route asks for it.
- Live owners hold lifetimeUse Ctrl-C in the foreground or
routeup stopfor a serve owner. - Yours to runMIT License, no CLI telemetry, documented server operations.