Installation
The fastest way to install Jetty is the global install script. It installs the jetty CLI so it works from any directory. You need a server name and token from Bridge (see Getting started in the app for copy-paste lines for this deployment).
Ingress (tunnel entry on your network) runs as a separate process — jetty-edge (Go binary from cli-v* GitHub Release assets jetty-cli-*, or build from this repo / Docker), not the same as the PHP jetty developer command. Operators deploy it behind TLS.
After install, configure the client, then share a local site—see Sharing local sites for port vs --site (local upstream) examples.
Install (PHAR — recommended)
Run the install script. It downloads the PHAR and places it on your PATH (PHP 8.2+, curl, zlib):
curl -fsSL "https://usejetty.online/install/jetty.sh" | bash
The PHAR is installed as jetty under ~/.local/bin (or /usr/local/bin with --sudo). The script can append the right bin directory to your ~/.zshrc or ~/.bashrc. Then reload your shell so PATH is picked up:
exec "$SHELL" -l
Prefer this path. The PHAR is self-contained — it needs no Composer, and
jetty updatereplaces the binary in place. If you already run Composer, see Install with cpx below.
Configure and share:
jetty config set server your-server-name
jetty config set token your-token-here
jetty share 8000
The client registers tunnels, connects the WebSocket agent to ingress (JETTY_EDGE_WS_URL on Bridge), and forwards HTTP to your local port. Use --skip-edge only for registration + heartbeats without forwarding.
Install with cpx
If you already work in PHP, cpx runs the CLI straight from Packagist without installing it into any project — the Composer equivalent of npx. Install cpx once:
composer global require cpx/cpx
Then run Jetty through it:
cpx jetty/client share 8000
jetty/client ships a single binary, so you can omit the command name — cpx jetty/client and cpx jetty/client share 8000 both resolve to jetty. Every argument after the package name passes straight through, so cpx jetty/client login, cpx jetty/client config set server your-server-name, and cpx jetty/client share 8000 --subdomain=demo all behave exactly like the PHAR.
Pin a version with a Composer constraint when you need reproducibility:
cpx jetty/client:^0.1 share 8000
Requirements and trade-offs versus the PHAR:
install.sh (PHAR) |
cpx |
|
|---|---|---|
| PHP | 8.2+ | 8.3+ (cpx's own floor) |
| Composer | not needed | required, installed globally |
| Updates | jetty update, in place |
cpx re-resolves the package |
| Best for | any machine, CI, non-PHP projects | PHP developers already running Composer |
Note the PHP floor: the Jetty client itself supports 8.2, but cpx requires 8.3, so that is the effective minimum on this path.
Because cpx runs the CLI outside a PHAR, jetty update does not apply — cpx owns the version. Use cpx's own resolution (or a version constraint) to move between releases, and run jetty doctor if you end up with both a PHAR and a cpx copy on your PATH.
Not the same as
composer require jetty/client. Requiring the package adds a library to one project. cpx installs nothing into your project and gives you the CLI globally. For the library case, see the next section.
Embedding jetty/client in a Laravel app (optional, project-local)
If you want the package available in your app (e.g. to call the API client from PHP), install it as a dev dependency. This is not a way to install the CLI — it just adds the library:
composer require --dev jetty/client
The jetty install-client command does the same from inside a project. Use the system jetty binary (PHAR) for jetty share, jetty update, etc. — not the project-local vendor/bin/jetty.
Project configuration (jetty.config.json)
Pin per-project settings so jetty share doesn't need flags every time. Drop a jetty.config.json at the project root (the CLI walks up from cwd):
{
"share": {
"hostname": "tunnel.example.com",
"local_host": "127.0.0.1",
"local_port": 3000,
"health_path": "/healthz",
"routing_rules": [
{"path": "/api", "target": "8080"},
{"path": "/static", "target": "static-server:9000"}
]
}
}
| Key | What it sets | CLI override |
|---|---|---|
share.hostname |
Custom domain (verified under Domains). Wins over share.subdomain if both are set. |
--hostname= |
share.subdomain |
Reserved label on the shared tunnel host. | --subdomain= |
share.local_host |
Upstream host (default 127.0.0.1). |
--site=, --host= |
share.local_port |
Upstream port (default 8000 / auto-detect). | positional port arg |
share.health_path |
Health-check path the agent probes. | --health-path= |
share.print_url_only |
Print the tunnel URL and exit. | --print-url-only |
share.routing_rules |
Path-prefix → upstream rules. Same shape as --route. |
--route= (replaces) |
CLI flags always win. Environment variables (e.g. JETTY_SHARE_DELETE_ON_EXIT=1) also take precedence over project config.
Ingress binary (jetty-edge)
For operator-managed edge hosts, use the jetty-cli-* archives from your team’s GitHub cli-v* releases (contains jetty-edge only), build from the repository, or use cli/Dockerfile.
cd cli && go build -trimpath -ldflags="-s -w" -o jetty-edge ./cmd/jetty-edge
Use scripts/install-jetty-edge.sh (repo root) for systemd on a server (downloads from releases by default, or --bin). Run it with environment aligned to Bridge (JETTY_EDGE_SECRET, JETTY_LARAVEL_URL, JETTY_TUNNEL_HOST, listener address). On Debian/Ubuntu it installs Certbot and one apt plugin per JETTY_CERTBOT_DNS_PROVIDER in the env (nginx default; cloudflare, digitalocean, or all) when scripts/certbot-deps.inc.sh is present (same idea as scripts/jetty-edge-ssl.sh ensure-deps). It does not replace the PHP jetty CLI on developer machines — it terminates public HTTP and WebSockets from jetty share agents.
Docker (optional)
The repo includes cli/Dockerfile for building an image that runs jetty-edge (ingress). For developer machines, install the jetty CLI via the script above (PHAR).
docker build -f cli/Dockerfile -t jetty-edge ./cli
To reach a service on your host from inside the container, pass host.docker.internal with jetty share as --site=host.docker.internal (Docker Desktop). On Linux add --add-host=host.docker.internal:host-gateway.
Updates
jetty update (alias self-update) replaces the PHAR at ~/.local/bin/jetty in place. Override the path with JETTY_PHAR_PATH if you installed somewhere else. Set JETTY_CLI_GITHUB_REPO=owner/repo and optionally JETTY_PHAR_GITHUB_TOKEN for private repos.
If you have a Composer-installed copy somewhere (vendor/bin/jetty, ~/.composer/vendor/bin/jetty), that's a project library install — jetty update will not touch it. Reinstall via the install script to get a current PHAR.
Running through cpx? jetty update does not apply there either — cpx resolves the package version itself. Pin or move versions with a constraint (cpx jetty/client:^0.1) instead.
PHAR Checksum Verification
Every PHAR release includes a SHA256 checksum file (jetty.phar.sha256) published alongside the binary in GitHub Releases.
Automatic verification: When you run jetty update, the CLI downloads the .sha256 file and verifies the PHAR integrity automatically. If the checksum does not match, the update is aborted.
Manual verification: If you download the PHAR directly (e.g., from a release page or mirror), verify it yourself:
# Download both files
curl -fsSLO https://github.com/your-org/jetty/releases/latest/download/jetty.phar
curl -fsSLO https://github.com/your-org/jetty/releases/latest/download/jetty.phar.sha256
# Verify the checksum
sha256sum -c jetty.phar.sha256
A passing check prints jetty.phar: OK. If the output shows FAILED, do not use the binary -- re-download or contact your team.
Next steps
- Open Bridge and go to Getting started for platform-specific downloads, env snippets, and
jetty shareexamples wired to this deployment. - Read Sharing local sites for
--site, reserved labels, and local HTTPS (Valet) notes.
Send feedback
Found an issue or have a suggestion? Let us know.