Skip to content
Login

CLI Reference

The HLE CLI has six top-level commands:

  • hle expose — run a tunnel for a local service
  • hle webhook — run a webhook forwarder
  • hle agent — run many tunnels, managed from the dashboard
  • hle service — install expose or the agent as a background service
  • hle auth — manage your API key
  • hle config — configure tunnels (auth mode, access rules, PIN, basic-auth, share links, list)

Tunnel-scoped subcommands under hle config accept a label (resolved to <label>-<user_code> via /api/auth/me) or a full subdomain. For example, hle config show ha and hle config show ha-x7k both work.

hle expose

Expose a local service to the internet.

Terminal window
hle expose --service http://localhost:8080 --label myapp

Expose and allow specific users in one command:

Terminal window
hle expose --service http://localhost:8080 --label app \
--allow user@gmail.com --allow google:friend@gmail.com

--allow is additive — it adds rules without removing existing ones. Use hle config access replace for a declarative reconcile.

hle webhook

Create a webhook tunnel for receiving HTTP callbacks (GitHub, Stripe, etc.). Disables the SSO gate and WebSocket, enforces path prefix filtering.

Terminal window
hle webhook --path /hook/github --forward-to http://localhost:3000 --label gh

See the Webhooks guide for security, rate limits, and provider setup.

hle agent

Run a single process that serves every endpoint you declare in the dashboard. See the Agent guide for the full walkthrough.

Terminal window
hle agent enroll [TOKEN] # Save an agent token (prompts if omitted)
hle agent run # Connect and serve the dashboard's endpoints
hle agent list # List your agents and whether they're online
hle agent status # Show where the token is coming from
hle agent services # List services this machine could expose
hle agent logout # Remove the saved token

The token is resolved in this order: --token flag > HLE_AGENT_TOKEN env var > ~/.config/hle/agent.toml. It is separate from your API key.

agent list is the odd one out: it asks the relay about your whole account rather than inspecting this machine, so it authenticates with your API key, not the agent token. It’s the quickest way to find the name to pass to hle fp --agent:

Terminal window
$ hle agent list
Agents
┏━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━┓
┃ Name ┃ Status ┃ Endpoints ┃ Version ┃ Last seen ┃
┡━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━┩
│ trikala │ online │ 2 │ 2607.7 │ 4s ago │
│ nas │ offline │ 1 │ 2607.5 │ 3h ago │
└──────────┴─────────┴───────────┴─────────┴───────────┘

Add --json for scripting.

Flags for agent run

FlagDefaultDescription
--tokensaved tokenAgent token (hlea_…); also read from HLE_AGENT_TOKEN
--relay-hosthle.worldRelay host
--relay-port443Relay port

hle agent services

Lists the Kubernetes Services and Docker containers this machine can see and could expose. Runs the same read-only scan the agent reports to the dashboard, so it’s useful for checking what an agent would find before enrolling it. See Service discovery.

Terminal window
hle agent services
hle agent services --provider docker
hle agent services --json
FlagDescription
--providerOnly show one provider: k8s or docker
--jsonMachine-readable output

The reported address is the URL the agent would use to reach the service, not a public URL.

hle fp

Forward a TCP port that a remote agent can reach to a port on this machine — SSH, Postgres, RDP, anything TCP — without opening a port anywhere. See the Firepuncher guide.

Terminal window
hle fp --agent rpi --to 22 --port 9922 # then: ssh -p 9922 root@localhost
hle fp --agent nas --to 192.168.1.50:5432 # postgres on the agent's LAN

--to is resolved by the agent, not by this machine: a bare port means the agent’s own loopback, and host:port means that host as the agent sees it. The port you connect to locally is the --port one.

The agent refuses targets that aren’t in its allowlist. A fresh agent allows its own loopback on any port; anything else is added per agent in the dashboard under Connections → Firepuncher.

Flags for fp

FlagDefaultDescription
--agentrequiredAgent name or id to forward through
--torequiredTarget as the agent sees it: HOST:PORT, or a bare port
--porttarget port + 9000Local port to listen on
--bind127.0.0.1Local address to bind
--api-keyenv / configAPI key, if not already saved
--relay-hosthle.worldRelay host
--relay-port443Relay port

hle service

Install a tunnel or the agent as a background service — systemd on Linux, launchd on macOS — so it survives reboots and restarts on failure.

Terminal window
# The agent (all endpoints from the dashboard)
hle service install --agent
# A single fixed tunnel
hle service install --service http://localhost:8123 --label ha
# A firepuncher forward, always available locally
hle service install --fp --agent-name rpi --to 22 --port 9922
hle service status --agent # or --label ha
hle service list
hle service uninstall --agent # or --label ha

Credentials are never written into the service definition. They’re read at runtime from the running user’s ~/.config/hle/ (config.toml for the API key, agent.toml for the agent token) or from HLE_API_KEY / HLE_AGENT_TOKEN.

Flags for service install

FlagDefaultDescription
--agentoffInstall the agent instead of a single tunnel
--fpoffInstall a firepuncher forward; needs --agent-name and --to
--agent-name--fp mode: agent to forward through
--to--fp mode: target, as the agent sees it
--port, --bind+9000, 127.0.0.1--fp mode: local port and address
--serviceLocal service URL (required unless --agent or --fp)
--labelagent with --agentNames the unit hle-<label>
--user / --systemauto-detectPer-user vs system-wide service
--run-ascurrent userSystem service: user to run as (and whose config to read)
--start / --no-start--startEnable and start it immediately
--namehle-<label>Override the unit/plist name
--relay-host, --relay-porthle.world, 443Agent mode only

--zone, --apex, --auth, --allow, and the other expose flags are accepted in single-tunnel mode and baked into the unit.

Scope auto-detection: running as root installs a system service (starts at boot), a normal user gets a per-user one. A per-user systemd service stops at logout unless you run sudo loginctl enable-linger $USER.

hle auth

Manage the API key the CLI uses to talk to the relay.

Terminal window
hle auth login # Interactive (opens dashboard)
hle auth login --api-key <KEY> # Non-interactive
hle auth status # Show current key source
hle auth logout # Remove saved key

The key is resolved in this order: --api-key flag > HLE_API_KEY env var > ~/.config/hle/config.toml.

hle config

All tunnel and account configuration lives under hle config.

hle config list

List active tunnels for your account.

Terminal window
hle config list

hle config show

Show the full configuration and live state for a tunnel — auth mode, access rules, PIN, basic-auth, and connection state — in one call.

Terminal window
hle config show ha
hle config show ha-x7k # full subdomain also accepted

hle config auth-mode

Change a tunnel’s SSO gate. The tunnel must have been registered at least once. Webhook tunnels are always public and cannot be changed.

Terminal window
hle config auth-mode ha --set sso # SSO gate on
hle config auth-mode ha --set none # tunnel becomes public

hle config access — SSO email allow-list

Terminal window
hle config access list ha # List rules
hle config access add ha friend@example.com # Allow an email
hle config access add ha dev@co.com --provider github # Require GitHub SSO
hle config access remove ha 42 # Remove rule by ID

Declarative reconcile

hle config access replace is declarative: rules already on the server but not in the args are removed. Useful for IaC / CI/CD where the args are the source of truth.

Terminal window
hle config access replace ha google:alice@example.com github:dev@co.com
hle config access replace ha --clear # Remove all rules

Compare with hle expose --allow, which only adds.

hle config pin — PIN access control

Terminal window
hle config pin set ha # Set 4-8 digit PIN (prompts)
hle config pin status ha # Check whether a PIN is active
hle config pin remove ha # Remove PIN

hle config basic-auth — HTTP Basic Auth

Replaces SSO and PIN with a username/password prompt enforced by the relay.

Terminal window
hle config basic-auth set ha # Prompts for username + password (min 8 chars)
hle config basic-auth status ha # Show whether active and the username
hle config basic-auth remove ha # Remove credentials
Terminal window
hle config share create ha # 24h link (default)
hle config share create ha --duration 1h # 1-hour link
hle config share create ha --max-uses 5 # Limited uses
hle config share create ha --label "demo" # Label for reference
hle config share list ha # List share links
hle config share revoke ha 42 # Revoke a link by ID

Flags for expose

FlagTypeDefaultDescription
--servicestringrequiredLocal service URL (e.g., http://localhost:8080)
--labelstringrequiredService label for the subdomain (e.g., ha, jellyfin, app1)
--authenumssoAuthentication mode: sso (OIDC) or none (public)
--api-keystringAPI key. Also checked in HLE_API_KEY env var and config file
--websocketbooleanenabledEnable WebSocket proxying. Use --no-websocket to disable
--allowstringAllow an email (additive). Format: email or provider:email. Providers: any (default), google, github, hle. Repeatable
--verify-sslbooleanfalseEnable SSL certificate verification for the local service
--upstream-basic-authstringInject Authorization: Basic into every request forwarded to the local service. Format: USER:PASS
--forward-hostbooleanfalseForward the browser’s Host header to the local service

Flags for webhook

FlagTypeDefaultDescription
--pathstringrequiredWebhook path prefix (e.g. /hook/github). Cannot be /. Only requests matching this prefix are forwarded
--forward-tostringrequiredLocal URL to forward webhooks to
--labelstringrequiredWebhook label, e.g. github-hook
--api-keystringAPI key. Also checked in HLE_API_KEY env var and config file

Flags for config access add

FlagTypeDefaultDescription
--providerenumanyRequired auth provider: any, google, github, or hle

Flags for config access replace

Positional arguments are [provider:]email specs (repeatable). Add --clear with no specs to remove all rules.

Flags for config share create

FlagTypeDefaultDescription
--durationenum24hLink validity: 1h, 24h, or 7d
--labelstringOptional label for the link
--max-usesintunlimitedMaximum number of uses

Global flags

These flags apply to all commands:

FlagTypeDefaultDescription
--versionShow the client version and exit
--debugbooleanfalseEnable debug logging to stderr

Common flags

All commands that talk to the server (everything under hle config, plus hle expose and hle webhook) accept:

FlagTypeDefaultDescription
--api-keystringAPI key for authentication. Also checked in HLE_API_KEY env var and ~/.config/hle/config.toml

Config file

Save your API key in the config file:

api_key = "hle_your_32_char_hex_key"

Location: ~/.config/hle/config.toml

The API key is resolved in order: --api-key flag > HLE_API_KEY env var > config file.

Examples

Expose Home Assistant with a label:

Terminal window
hle expose --service http://localhost:8123 --label ha

Expose a development app without authentication:

Terminal window
hle expose --service http://localhost:3000 --label dev --auth none

Expose and allow specific users in one command:

Terminal window
hle expose --service http://localhost:8123 --label ha \
--allow user@gmail.com --allow google:friend@gmail.com

List your active tunnels:

Terminal window
hle config list

Add a friend to your tunnel’s access list:

Terminal window
hle config access add ha friend@example.com

Require GitHub login for a specific email:

Terminal window
hle config access add ha colleague@work.com --provider github

View and remove access rules:

Terminal window
hle config access list ha
hle config access remove ha 42

Reconcile the allow-list to exactly two people (removes anyone else):

Terminal window
hle config access replace ha google:alice@example.com github:bob@co.com

Set a PIN for quick access:

Terminal window
hle config pin set ha

Create a temporary share link (expires in 1 hour, max 5 uses):

Terminal window
hle config share create ha --duration 1h --max-uses 5

Protect a tunnel with HTTP Basic Auth:

Terminal window
hle config basic-auth set ha
hle config basic-auth status ha

Expose a service that itself requires credentials (inject upstream auth):

Terminal window
hle expose --service http://localhost:8123 --label ha \
--upstream-basic-auth admin:yourpassword