CLI Advanced Usage
Advanced CLI workflows, environment variables, and troubleshooting. See CLI usage guide for basic setup and commands.
Debugging
Verbose Output
Get detailed information about what's happening:
# Debug agent WebSocket and HTTP forwarding
jetty share 8000 --debug-agent
# Or via environment variable
JETTY_SHARE_DEBUG_AGENT=1 jetty share 8000
This outputs JSON lines showing:
- WebSocket connection events
- HTTP requests received from the edge
- Upstream curl attempts and responses
- URL rewriting operations
- Sample capture events
Debug URL rewriting:
JETTY_SHARE_DEBUG_REWRITE=1 jetty share 8000
Shows before/after for all URL rewrites in headers and response bodies.
Viewing Samples
Jetty captures request samples for inspection:
jetty list
# Shows sample counts for each tunnel
View samples in the dashboard:
- Open your Jetty dashboard
- Go to Tunnels
- Click on a tunnel
- Click Monitor to see captured requests
By default, samples are anonymized (sensitive data redacted). Disable capture:
JETTY_SHARE_CAPTURE_SAMPLES=0 jetty share 8000
Replaying Requests
Repeat a captured request against your local upstream:
jetty replay abc123sample
Safety restrictions:
- Only GET and HEAD requests replay by default
- Other methods require explicit permission:
JETTY_REPLAY_ALLOW_UNSAFE=1 jetty replay abc123sample
Use cases:
- Debug intermittent webhook issues
- Test edge cases
- Reproduce bugs from production traffic
Advanced Workflows
CI/CD Usage
Use Jetty in automated testing pipelines:
GitHub Actions example:
name: E2E Tests
on: [push]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install Jetty
run: curl -fsSL "https://usejetty.online/install/jetty.sh" | bash
- name: Start app
run: npm run dev &
- name: Share tunnel
run: |
jetty share 3000 --subdomain=ci-${{ github.run_id }} &
JETTY_PID=$!
env:
JETTY_SERVER: ${{ secrets.JETTY_SERVER }}
JETTY_TOKEN: ${{ secrets.JETTY_TOKEN }}
- name: Run E2E tests
run: npm run test:e2e
env:
BASE_URL: https://ci-${{ github.run_id }}.tunnels.usejetty.online
- name: Cleanup
if: always()
run: kill $JETTY_PID
GitLab CI example:
e2e-tests:
stage: test
script:
- curl -fsSL "https://usejetty.online/install/jetty.sh" | bash
- npm run dev &
- jetty share 3000 --subdomain=ci-$CI_PIPELINE_ID &
- JETTY_PID=$!
- npm run test:e2e
- kill $JETTY_PID
variables:
JETTY_SERVER: $JETTY_SERVER
JETTY_TOKEN: $JETTY_TOKEN
BASE_URL: https://ci-$CI_PIPELINE_ID.tunnels.usejetty.online
Team Workflows
Shared reserved subdomains:
Create team-wide stable URLs for different purposes:
staging-api-- Staging API endpointdemo-- Client demo environmentwebhooks-alice-- Alice's webhook testingwebhooks-bob-- Bob's webhook testing
Reserve these in your dashboard, then team members can use them:
jetty share 8000 --subdomain=webhooks-alice
Collaboration tips:
- Use descriptive subdomain names
- Document who owns which subdomain
- Clean up unused tunnels regularly
- Use
jetty listto see team activity
Framework-Specific Tips
Laravel:
# Start Laravel dev server
php artisan serve --port=8000
# In another terminal
jetty share 8000
# Jetty auto-detects Laravel and configures URL rewriting
Next.js:
npm run dev # Usually port 3000
jetty share 3000
Rails:
rails server # Usually port 3000
jetty share 3000
Vite:
npm run dev # Usually port 5173
jetty share 5173
Django:
python manage.py runserver 8000
jetty share 8000
Docker Compose:
docker-compose up
jetty share 8080 --site=172.17.0.2 # Use container IP
Valet/Herd:
# Your app at https://my-app.test
jetty share 443 --site=my-app.test
Environment Variables
Most useful environment variables for daily work:
Authentication
# Your API token
export JETTY_TOKEN=your-token-here
# Server name
export JETTY_SERVER=your-server-name
# Full API URL (alternative to JETTY_SERVER)
export JETTY_API_URL=https://your-jetty.example
Tunnel Configuration
# Subdomain for stable URLs
export JETTY_SUBDOMAIN=my-app
# Auto-delete tunnel on exit
export JETTY_SHARE_DELETE_ON_EXIT=1
# Disable tunnel resume
export JETTY_SHARE_NO_RESUME=1
# Additional hosts to rewrite
export JETTY_SHARE_REWRITE_HOSTS=api.myapp.test,admin.myapp.test
Request Samples
# Disable sample capture
export JETTY_SHARE_CAPTURE_SAMPLES=0
# Allow unsafe method replay
export JETTY_REPLAY_ALLOW_UNSAFE=1
Debugging
# Debug agent WebSocket and HTTP
export JETTY_SHARE_DEBUG_AGENT=1
# Debug URL rewriting
export JETTY_SHARE_DEBUG_REWRITE=1
# Write NDJSON debug log
export JETTY_SHARE_DEBUG_NDJSON_FILE=/tmp/jetty-debug.ndjson
URL Rewriting
# Disable all body rewriting
export JETTY_SHARE_NO_BODY_REWRITE=1
# Disable JavaScript rewriting only
export JETTY_SHARE_NO_JS_REWRITE=1
# Disable CSS rewriting only
export JETTY_SHARE_NO_CSS_REWRITE=1
# Disable header rewriting
export JETTY_SHARE_NO_LOCATION_REWRITE=1
Notifications
# Enable Telegram notifications
export JETTY_TELEGRAM_BOT_TOKEN=your-bot-token
export JETTY_TELEGRAM_CHAT_ID=your-chat-id
For a complete list, see the Tunnels Reference.
Tips and Tricks
Shell Aliases
Add these to your ~/.zshrc or ~/.bashrc:
# Quick share on common ports
alias j8='jetty share 8000'
alias j3='jetty share 3000'
alias j5='jetty share 5173'
# Share with auto-delete
alias jshare='jetty share --delete-on-exit'
# Laravel-specific
alias jlaravel='jetty share 8000 --subdomain=laravel-dev'
# List with formatting
alias jlist='jetty list | grep -E "^(ID|http)"'
# Quick config
alias jconfig='cat ~/.config/jetty/config.json'
One-Liners
Share and copy URL to clipboard (macOS):
jetty share 8000 | grep -oE 'https://[^ ]+' | head -1 | pbcopy
Share and open in browser:
jetty share 8000 & sleep 3 && open $(jetty list | grep -oE 'https://[^ ]+' | head -1)
Share with notification when ready:
jetty share 8000 && osascript -e 'display notification "Tunnel ready!" with title "Jetty"'
Temporary 1-hour tunnel:
timeout 3600 jetty share 8000 --delete-on-exit
Productivity Tips
1. Use subdomain patterns
Create a naming convention for your team:
{project}-dev-- Development{project}-staging-- Staging{feature}-{username}-- Feature branches
2. Keep a tunnel running in tmux/screen
# Start tmux session
tmux new -s jetty
# Inside tmux
jetty share 8000 --subdomain=my-stable-tunnel
# Detach with Ctrl+B, D
# Reattach anytime with: tmux attach -t jetty
3. Project-specific configs
Create jetty.config.json in each project:
{
"share": {
"subdomain": "my-project",
"delete_on_exit": true
}
}
4. Git hooks for automatic tunnels
Create .git/hooks/post-checkout:
#!/bin/bash
if [ -f ".jetty-auto" ]; then
jetty share 8000 --subdomain=$(git branch --show-current) &
fi
5. Use curl to test tunnel without browser
# Start tunnel
jetty share 8000 --subdomain=test
# Test from another terminal
curl -I https://test.tunnels.usejetty.online
Troubleshooting
"Tunnel unavailable" errors
Symptom: Browser shows "tunnel unavailable" even though jetty share is running.
Causes:
- Multiple
jetty shareprocesses for the same tunnel (since v0.1.19, a lockfile prevents this) - Edge server can't reach your Jetty bridge
- Network issue between edge and your machine
Solutions:
# Check for duplicate processes
ps aux | grep jetty
# Kill duplicates
killall jetty
# Restart fresh
jetty share 8000
Laravel redirects to localhost
Symptom: Browser jumps from https://xyz.tunnels.usejetty.online to http://localhost:8000.
Cause: Laravel isn't respecting forwarded headers.
Fix:
- Trust proxies in
app/Http/Middleware/TrustProxies.php:
protected $proxies = '*';
protected $headers =
Request::HEADER_X_FORWARDED_FOR |
Request::HEADER_X_FORWARDED_HOST |
Request::HEADER_X_FORWARDED_PORT |
Request::HEADER_X_FORWARDED_PROTO;
- Force root URL in
app/Providers/AppServiceProvider.php:
use Illuminate\Support\Facades\URL;
public function boot()
{
if (request()->headers->has('X-Forwarded-Host')) {
URL::forceRootUrl(request()->getSchemeAndHttpHost());
}
}
Vite/Next.js assets not loading
Symptom: Page loads but CSS/JS return 404.
Cause: Dev server might be binding to a specific host.
Fix for Vite:
// vite.config.js
export default {
server: {
host: '0.0.0.0', // or true
port: 5173
}
}
Fix for Next.js:
# Start with -H flag
next dev -H 0.0.0.0
# Or in package.json
"dev": "next dev -H 0.0.0.0"
WebSocket connection drops
Symptom: Share command shows "WebSocket closed, retrying..."
Causes:
- Firewall blocking WebSocket connections
- Network proxy with short timeouts
- Edge server restarted
Solutions:
# Increase ping interval for strict proxies
JETTY_SHARE_WS_PING_INTERVAL=12 jetty share 8000
# Check edge server logs (if you operate the server)
journalctl -u jetty-edge -f
"Token invalid" errors
Symptom: jetty commands fail with authentication errors.
Check current config:
jetty config
Reconfigure:
jetty config set token new-token-here
Or use environment variable:
export JETTY_TOKEN=new-token-here
jetty share 8000
Rate limiting or body size errors
Symptom: Some requests fail with 429 or 413 errors.
Cause: Edge server limits (Sprint 2 features).
Contact your operator to adjust:
JETTY_EDGE_DEFAULT_RATE_LIMIT_RPS-- Requests per second per tunnelJETTY_EDGE_DEFAULT_MAX_BODY_BYTES-- Maximum request body sizeJETTY_EDGE_IP_RATE_LIMIT_RPS-- Per-IP rate limit
Stale connection ("verify rejected")
Symptom: Reconnect fails with "verify rejected" message.
Cause: Another machine attached to your tunnel, rotating the agent token.
Solution: Jetty automatically refreshes the token. If it persists:
# Delete and recreate
jetty delete tunnel-id
jetty share 8000
See Also
- Installation Guide -- Detailed installation instructions
- Sharing Guide -- Core sharing concepts
- Tunnels Reference -- Complete technical reference
- Custom Domains -- Set up custom domains
- Traffic Inspection -- Analyze captured requests
- API Tokens -- Manage your API tokens
Need help? Check your Jetty dashboard for team-specific documentation and support resources.
Send feedback
Found an issue or have a suggestion? Let us know.