Sharing local sites
Jetty exposes HTTP traffic you can reach on your own machine to the internet over HTTPS. The jetty CLI (Composer or PHAR) registers a tunnel with Bridge, connects a WebSocket agent to your deployment’s ingress (jetty-edge), and forwards requests from the public URL to your local upstream.
Public URLs use the Bridge tunnel host (default suffix tunnels.usejetty.online, e.g. https://{label}.tunnels.usejetty.online, with Bridge at https://usejetty.online). Local Valet/Herd installs often set JETTY_TUNNEL_HOST=tunnels.jetty.test; the troubleshooting section at the end uses *.tunnels.jetty.test for that setup.
There are several ways to point Jetty at the site you want to share.
Share by port (default)
The usual pattern is to pass the TCP port your app listens on. Jetty forwards to 127.0.0.1 and that port by default.
jetty share 8000
Examples:
- Laravel
php artisan serveon port 8000 →jetty share 8000 - Next.js or Vite dev server on 3000 →
jetty share 3000
Composer / PHAR (same command name):
jetty share 8000
Keep the process running while you test. Your public URL appears in the CLI output and under Bridge → Tunnels.
Share a specific upstream (local site / bind address)
If your app is not on 127.0.0.1, or you use a .test / .dev hostname (for example Laravel Herd or Valet), set --site to that hostname or IP and pass the port your stack serves HTTP on. Equivalent flags: --bind=, --local=, --local-host=. --host= still works but is deprecated (it used to be overloaded with other meanings).
This is the Jetty equivalent of Expose’s expose share http://127.0.0.1:3000 or expose share https://my-local-site.dev: you choose the upstream explicitly.
# Same machine, explicit loopback
jetty share 3000 --site=127.0.0.1
# Another device on your LAN
jetty share 8080 --site=192.168.2.100
# Herd/Valet-style local site (resolve to 127.0.0.1 in DNS or /etc/hosts)
jetty share 80 --site=my-site.test
jetty share 443 --site=my-site.test
Use the port where that host actually serves plain HTTP for tunneling, unless your stack is configured for HTTPS locally—in that case you may still proxy via HTTP on another port or adjust your local setup.
Stable subdomain (reserved label)
To reuse the same public hostname across reconnects (for example webhooks), pass --subdomain when your team allows reserved labels (see Bridge → Domains).
jetty share 8000 --subdomain=my-app
If the label is already taken, registration fails and you can pick another or release the old tunnel first.
Which Jetty deployment (server name)
jetty config set server <name> chooses which Jetty Bridge / API you talk to—the server names listed in Bridge → Getting started for this product. That is different from Expose’s --server=us-2 style flags on a single vendor network.
jetty config set server your-server-name
jetty config set token your-token-here
Operators can define multiple entries in JETTY_CLI_SERVERS on the app so teams see more than one named server in the dashboard.
PHP jetty client
jetty share— registers the tunnel, opens the WebSocket fromedge.websocket_urlin the API response, and forwards HTTP to your--siteand port. Use--skip-edgeonly if you want registration + heartbeats without forwarding (debugging).- Requires
JETTY_EDGE_WS_URLon Bridge so clients receive a reachablewss://(orws://) URL, and ingress (jetty-edge) running with matching secrets—see Network and edge deployment.
Local HTTPS: *.tunnels.jetty.test shows the Jetty Bridge (wrong site)
Browsers load https://YOUR-LABEL.tunnels.jetty.test. That traffic must reach jetty-edge (default 127.0.0.1:8090), which proxies to your jetty share agent and then to your app (e.g. Vite on 5173 or beacon on another Valet host).
What goes wrong: On Laravel Valet, hostnames like something.tunnels.jetty.test often match no dedicated site and fall through to Valet’s default PHP router, so you see the Jetty Laravel app (welcome/dashboard) instead of the tunneled upstream.
Fix (Valet on macOS):
- Run jetty-edge (same machine as the CLI agent), with
JETTY_EDGE_SECRETand LaravelAPP_URLmatching your Bridge.env. - Issue a wildcard certificate for the tunnel zone (Valet’s per-site certs do not cover arbitrary subdomains):
brew install mkcert && mkcert -install cd ~/.config/valet/Certificates mkcert "*.tunnels.jetty.test" "tunnels.jetty.test" - Copy
deploy/nginx/valet-jetty-tunnel-wildcard.confto~/.config/valet/Nginx/, edit the twossl_certificatepaths to themkcertfiles it printed (often_*wildcard*+1.pem). valet restart
Then https://reef-….tunnels.jetty.test is proxied to jetty-edge with the correct Host header, and your beacon (or Vite) upstream is reached via the agent.
Quick smoke test without browser TLS: curl -sS -H "Host: YOUR-LABEL.tunnels.jetty.test" http://127.0.0.1:8090/ should hit the edge (not the Bridge PHP app).
Generic nginx (non-Valet): see deploy/nginx/jetty-tunnel-wildcard-local.conf.example.
For more install paths, see Installation.