Sharing Local Services
broch share creates a public HTTPS tunnel to a service running on your local machine. The tunnel stays open as long as the CLI process is running.
Set Up the CLI
Section titled “Set Up the CLI”The CLI needs Node.js 22 or newer. Install it, point it at your Broch server (your admin gives you its URL) and sign in through your IdP:
npm install -g @broch/clibroch config set --server https://broch.{your-domain}broch auth loginThen share a local service:
broch share my-app --target http://localhost:3000Permissions
Section titled “Permissions”Share is deny-by-default: an admin at your organization decides who can create tunnels and what inbound traffic is allowed through them. For broch share to succeed, two things must line up:
- A Share Policy applies to one of your IdP roles. Policies are bound to roles like
engineeringorcontractors. If no policy applies to any of your roles, tunnel creation is denied. - Inbound requests match an allowed rule. Once your tunnel is up, each request is evaluated against the policy’s rules. An admin can require, for example, that requests originate from a specific network range, or carry a specific webhook signature header.
If broch share returns a permissions error, the most common causes are that your IdP role isn’t covered by any Share Policy, or that your access token doesn’t include the role claim the policy expects. Talk to your admin — they can see exactly which policies and roles are configured in the admin dashboard.
What You Can Share by Default
Section titled “What You Can Share by Default”Any HTTP or HTTPS service that the Broch server resolves to a loopback address. That includes localhost, 127.0.0.1 and [::1], and any hostname whose DNS lookup on the server returns a loopback IP. 0.0.0.0 is not loopback; it is treated like any other host. Your Share Policy needs a loopback rule (a Share Rule with no Service).
# Standard local dev serverbroch share my-app --target http://localhost:3000
# Local HTTPS with a self-signed certbroch share my-app --target https://localhost:8443
# Bound to IPv6 loopbackbroch share my-app --target http://[::1]:3000You can run multiple tunnels simultaneously — each gets its own public URL:
broch share frontend --target http://localhost:5173broch share api --target http://localhost:8080The hostname in --target becomes the Host header sent to your local app. Use the same hostname your app expects — for virtual hosting, mkcert-issued certs, or names mapped via the server-side /etc/hosts.
What You Need an Admin to Help You Share
Section titled “What You Need an Admin to Help You Share”Any target that the broch server resolves to a non-loopback address (or doesn’t resolve at all) is admin-managed. This typically includes:
- Other hosts on your network (e.g.
192.168.1.50:8080) - Internal hostnames that resolve to a non-loopback IP (e.g.
staging.internal:8443) - Hostnames the broch server can’t resolve at all
Trying to share one of these without an admin-registered Service returns:
❌ Target '<host>:<port>' does not resolve to a loopback address and is not a registered Service.To unblock yourself, ask your Broch admin to:
- Register the target as a Service — each Service maps a backend target (
scheme://host:port) to a name in the admin dashboard. See Services for what a Service looks like and how the registry resolves matches. - Add a Share Rule pointing at that Service to a Share Policy that covers your IdP role — without the rule, the policy denies access to that specific target even if you can otherwise create tunnels. See Share Policies for the rule model.
Once both are in place:
broch share staging --target http://staging.internal:8443Tunnel URLs
Section titled “Tunnel URLs”Tunnel URLs follow the format {name}-{tag}.broch.{your-domain}, where the tag is a 6-letter code that keeps your session names unique. Set yours once with:
broch user tag abcdefAfter that, broch share my-app always produces my-app-abcdef.broch.{your-domain}.
Watching Traffic Land
Section titled “Watching Traffic Land”While the tunnel is up, the CLI prints a dim one-line summary for every inbound request:
my-app ← GET → 200 / (5ms) my-app ← POST → 201 /api/users (12ms)This is on by default — no flag required.
Inspecting Requests
Section titled “Inspecting Requests”Pass --inspect to additionally capture request/response bodies and serve a local inspector UI:
broch share my-app --target http://localhost:3000 --inspectThe inspector binds to 127.0.0.1 (default port 4040, falling through to 4041–4049 if busy) and prints its URL alongside the tunnel URL on startup. Open it in your browser to see the last 50 requests, expand details, and click Replay to fire any request again at your local target. Capture is memory-only — nothing is written to disk and nothing leaves your machine.
By default the proxy rewrites a few headers (Host, Referer, Location, Set-Cookie) so local apps work through the tunnel. To forward requests unmodified instead, pass --no-rewrite. For details on what the proxy rewrites, how to turn it off, and known limitations, see Proxy Behavior & Limitations.
Scenarios
Section titled “Scenarios”Every scenario is the same command with a different target and name:
- Work in progress. Show a live preview to a colleague or stakeholder without deploying to staging. The tunnel reflects your local changes as you make them, so it works for sign-off in a meeting too.
- QA on a local build. Let a tester try a feature branch on their own device before it’s merged.
- Mobile and cross-device testing. Open the tunnel URL on a phone or tablet. It’s HTTPS, so features that need a secure context work there, unlike over
http://to your machine’s LAN address. - Webhooks. Use the tunnel URL as the endpoint in Stripe, GitHub, Twilio or any other service, and receive the calls on your machine.
- Frontend and API together. Open one tunnel per service, as in What You Can Share by Default, when the frontend must call the API over HTTPS.