Documentation for Jetty

CLI Usage Guide

Overview

The Jetty CLI is your command-line companion for securely exposing local development servers to the internet. Whether you're testing webhooks, sharing work with clients, or debugging mobile apps against your local backend, jetty makes it simple.

What it does:

  • Creates secure HTTPS tunnels from the internet to your local development server
  • Provides stable URLs for webhook testing and team collaboration
  • Captures and replays HTTP requests for debugging
  • Works with any HTTP server: Laravel, Rails, Next.js, Vite, Django, and more

Why use it:

  • No ngrok subscription needed--you control your own infrastructure
  • Team-friendly with reserved subdomains and custom domains
  • Built-in request inspection and replay
  • First-class Laravel integration with automatic detection

Installation Recap

The Jetty CLI can be installed via our installation script or Composer. For detailed installation instructions, see the Installation Guide.

Quick install (recommended):

curl -fsSL "https://usejetty.online/install/jetty.sh" | bash

Via Composer (global):

composer global require jetty/client

Verify installation:

jetty version

Shell Completions

Enable tab completion for commands, flags, and arguments:

Bash (add to ~/.bashrc):

eval "$(jetty completions bash)"

Zsh (add to ~/.zshrc):

eval "$(jetty completions zsh)"

Fish (one-time setup):

jetty completions fish > ~/.config/fish/completions/jetty.fish

After installation, press Tab to complete commands (jetty sha -> jetty share), flags (jetty share --sub -> jetty share --subdomain=), and config keys (jetty config set ser -> jetty config set server).

Diagnostics

The jetty doctor Command

Run jetty doctor to check that your environment is configured correctly:

jetty doctor

It verifies:

  • PHP installation -- correct version (8.2+) and required extensions
  • CLI version -- whether you are running the latest release
  • PATH -- that the jetty binary is reachable
  • API connectivity -- that your configured server is reachable over HTTPS
  • Auth token -- that a valid token is set and accepted by the server

A passing check prints a green checkmark; a failing check prints the cause and numbered fix suggestions.

Structured Error Messages

When any jetty command fails, the CLI prints a structured error with:

  1. What went wrong -- a one-line summary of the error
  2. Suggested fixes -- numbered steps you can try

Example output:

Error: Connection refused (127.0.0.1:8000)

  1. Make sure your local server is running on port 8000
  2. Check for firewall rules blocking localhost connections
  3. Run "jetty doctor" to verify your setup

Common Errors

Error Cause Suggested Fixes
Connection refused Local server is not running or wrong port Start your server; verify the port matches
Auth failed (401) Token is invalid or revoked Run jetty config set token NEW_TOKEN; check the Tokens page in the dashboard
Tunnel limit reached (402/429) Plan tunnel cap exceeded Delete unused tunnels with jetty delete; upgrade your plan
DNS resolution failed Server name is wrong or unreachable Check jetty config get server; verify your internet connection
TLS handshake error Certificate issue on the server Ensure the server has a valid SSL certificate; try curl to the API URL manually

Basic Commands

Getting Help

The help command shows available commands and options:

# Show main help
jetty help

# Show advanced options and environment variables
jetty help --advanced

# Get help on a specific command
jetty help share

You can also use the --help flag on any command:

jetty share --help
jetty config --help

Checking Your Version

Always good to know what version you're running:

# Show version
jetty version

# Show version with install method details
jetty version --install

# Check for updates without installing
jetty version --check-update

The output shows your CLI version and how it was installed (PHAR, Composer global, or project dependency).

Updating the CLI

Keep your CLI up to date with the latest features and fixes:

# Update to the latest version
jetty update

# Alternative command (same thing)
jetty self-update

How it works:

  • PHAR installs pull the latest release from GitHub
  • Composer installs run composer update jetty/client in the project

Updates are version-aware--you'll only download what's needed.

Configuration

First Time Setup

When you first run jetty, you'll be guided through a quick setup:

jetty setup

This interactive wizard helps you configure:

  1. Server name -- which Jetty deployment to use (from your team's dashboard)
  2. API token -- your personal access token for authentication

You can also configure manually:

# Set your server
jetty config set server your-server-name

# Set your token
jetty config set token your-token-here

# View current config
jetty config

Pro tip: Get your server name and token from the Getting Started page in your Jetty dashboard--it has copy-paste commands ready to go!

Config File vs Environment Variables

Jetty uses a flexible configuration system with multiple layers:

Config file (recommended for most users):

  • Global: ~/.config/jetty/config.json
  • Project-specific: jetty.yml (or jetty.yaml, jetty.config.json, .jetty.json) in your project root
  • Survives terminal sessions
  • Easy to version control (project configs)

YAML (recommended for projects):

# jetty.yml
share:
  subdomain: my-app
  tunnel_server: us-east-1

JSON (global config):

{
  "api_url": "https://your-jetty.example",
  "token": "your-personal-access-token"
}

Environment variables (good for CI/CD):

export JETTY_SERVER=your-server-name
export JETTY_TOKEN=your-token-here
export JETTY_API_URL=https://your-jetty.example

Command-line flags (one-off overrides):

jetty share 8000 --token=different-token --api-url=https://staging.jetty.example

Precedence (highest to lowest):

  1. Command-line flags
  2. Environment variables
  3. Project config file (jetty.yml / jetty.config.json)
  4. Global config file (~/.config/jetty/config.json)

Multiple Environments

Managing dev, staging, and production environments is straightforward:

Option 1: Project-specific configs

Create a jetty.config.json in each project:

cd ~/projects/my-app
jetty config set server dev-server
jetty config set token dev-token-here

Option 2: Shell aliases

Add to your ~/.zshrc or ~/.bashrc:

alias jetty-staging='JETTY_SERVER=staging JETTY_TOKEN=staging-token jetty'
alias jetty-prod='JETTY_SERVER=prod JETTY_TOKEN=prod-token jetty'

Then use:

jetty share 8000              # Uses default config
jetty-staging share 8000       # Uses staging
jetty-prod share 8000          # Uses production

Option 3: Multiple config files

jetty --config=~/.config/jetty/staging.json share 8000
jetty --config=~/.config/jetty/prod.json share 8000

Sharing Tunnels

Basic Share

The simplest way to share your local server:

# Share port 8000
jetty share 8000

This:

  1. Registers a tunnel with the Jetty bridge
  2. Connects the WebSocket agent to the edge server
  3. Gives you a public HTTPS URL like https://reef-abc123.tunnels.usejetty.online

Keep the terminal open while you test--when you close it, the tunnel stays registered but HTTP forwarding stops.

Common ports:

jetty share 8000    # Laravel artisan serve
jetty share 3000    # Next.js, Express, Vite
jetty share 4000    # Rails
jetty share 5173    # Vite default
jetty share 8080    # Many Java apps

With Subdomain

For stable URLs (great for webhooks), use a reserved subdomain:

jetty share 8000 --subdomain=my-app

This gives you: https://my-app.tunnels.usejetty.online

The subdomain persists across restarts, so your webhook URLs stay valid.

Reserve subdomains in your Jetty dashboard under Domains -> Reserved Subdomains.

With Custom Domain

If you've configured a custom domain in your Jetty dashboard:

jetty share 8000 --domain=dev.mycompany.com

This requires DNS and SSL setup on your Jetty deployment. See Custom Domains for configuration details.

Specifying Upstream

By default, jetty share forwards to 127.0.0.1:PORT. For different hosts:

# Explicit localhost
jetty share 3000 --site=127.0.0.1

# Another device on your LAN
jetty share 8080 --site=192.168.1.100

# Valet/Herd local domain
jetty share 80 --site=my-app.test
jetty share 443 --site=my-app.test

# Docker container (use host.docker.internal or IP)
jetty share 8000 --site=172.17.0.2

Aliases for --site:

  • --bind=
  • --local=
  • --local-host=

Laravel Detection

Jetty automatically detects Laravel applications and sets up intelligent URL rewriting:

What's detected:

  • Projects with an artisan file in the current or parent directories
  • APP_URL from your .env file
  • Common Valet/Herd hostnames (.test, .localhost)

Why it matters: Laravel often redirects to APP_URL. Jetty rewrites these redirects so your browser stays on the tunnel URL instead of jumping to http://localhost:8000 or https://my-app.test.

Example:

cd ~/projects/my-laravel-app
jetty share 8000
#  Detected Laravel
#  Found APP_URL: https://my-app.test
#  Will rewrite redirects to tunnel URL

Manual override:

# Add additional hosts to rewrite
JETTY_SHARE_REWRITE_HOSTS=api.myapp.test,admin.myapp.test jetty share 8000

Managing Tunnels

Listing Active Tunnels

See all your tunnels:

jetty list

Output shows:

  • Tunnel ID
  • Public URL
  • Local upstream
  • Status (connected/disconnected)
  • Sample count (requests captured)
  • Created date

Filtering:

# List only your tunnels
jetty list

# Include team tunnels
jetty list --all

Deleting a Tunnel

Remove a tunnel you no longer need:

# Delete by ID
jetty delete abc123xyz

# Delete by URL
jetty delete https://reef-abc123.tunnels.usejetty.online

Auto-delete on exit:

# Automatically delete tunnel when you exit jetty share
jetty share 8000 --delete-on-exit

# Or set the environment variable
JETTY_SHARE_DELETE_ON_EXIT=1 jetty share 8000

Resuming a Previous Tunnel

By default, Jetty tries to resume your most recent tunnel when you run jetty share again with the same local upstream:

# First run - creates new tunnel
jetty share 8000 --subdomain=my-app
# Got: https://my-app.tunnels.usejetty.online

# Stop with Ctrl+C

# Second run - resumes the same tunnel
jetty share 8000 --subdomain=my-app
# Got: https://my-app.tunnels.usejetty.online (same URL!)

Disable resume:

JETTY_SHARE_NO_RESUME=1 jetty share 8000

How it works: Jetty matches tunnels by local_host:local_port. For Valet/Herd hostnames, ports 80 and 443 are considered equivalent so switching between HTTP and HTTPS doesn't create duplicate tunnels.


For debugging, advanced workflows, environment variables, and troubleshooting, see CLI Advanced Usage.

Send feedback

Found an issue or have a suggestion? Let us know.