CLI Reference
The HLE CLI has six top-level commands:
hle expose— run a tunnel for a local servicehle webhook— run a webhook forwarderhle agent— run many tunnels, managed from the dashboardhle service— installexposeor the agent as a background servicehle auth— manage your API keyhle 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.
hle expose --service http://localhost:8080 --label myappExpose and allow specific users in one command:
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.
hle webhook --path /hook/github --forward-to http://localhost:3000 --label ghSee 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.
hle agent enroll [TOKEN] # Save an agent token (prompts if omitted)hle agent run # Connect and serve the dashboard's endpointshle agent list # List your agents and whether they're onlinehle agent status # Show where the token is coming fromhle agent services # List services this machine could exposehle agent logout # Remove the saved tokenThe 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:
$ 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
| Flag | Default | Description |
|---|---|---|
--token | saved token | Agent token (hlea_…); also read from HLE_AGENT_TOKEN |
--relay-host | hle.world | Relay host |
--relay-port | 443 | Relay 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.
hle agent serviceshle agent services --provider dockerhle agent services --json| Flag | Description |
|---|---|
--provider | Only show one provider: k8s or docker |
--json | Machine-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.
hle fp --agent rpi --to 22 --port 9922 # then: ssh -p 9922 root@localhosthle 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
| Flag | Default | Description |
|---|---|---|
--agent | required | Agent name or id to forward through |
--to | required | Target as the agent sees it: HOST:PORT, or a bare port |
--port | target port + 9000 | Local port to listen on |
--bind | 127.0.0.1 | Local address to bind |
--api-key | env / config | API key, if not already saved |
--relay-host | hle.world | Relay host |
--relay-port | 443 | Relay 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.
# The agent (all endpoints from the dashboard)hle service install --agent
# A single fixed tunnelhle service install --service http://localhost:8123 --label ha
# A firepuncher forward, always available locallyhle service install --fp --agent-name rpi --to 22 --port 9922
hle service status --agent # or --label hahle service listhle service uninstall --agent # or --label haCredentials 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
| Flag | Default | Description |
|---|---|---|
--agent | off | Install the agent instead of a single tunnel |
--fp | off | Install 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 |
--service | — | Local service URL (required unless --agent or --fp) |
--label | agent with --agent | Names the unit hle-<label> |
--user / --system | auto-detect | Per-user vs system-wide service |
--run-as | current user | System service: user to run as (and whose config to read) |
--start / --no-start | --start | Enable and start it immediately |
--name | hle-<label> | Override the unit/plist name |
--relay-host, --relay-port | hle.world, 443 | Agent 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.
hle auth login # Interactive (opens dashboard)hle auth login --api-key <KEY> # Non-interactivehle auth status # Show current key sourcehle auth logout # Remove saved keyThe 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.
hle config listhle 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.
hle config show hahle config show ha-x7k # full subdomain also acceptedhle 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.
hle config auth-mode ha --set sso # SSO gate onhle config auth-mode ha --set none # tunnel becomes publichle config access — SSO email allow-list
hle config access list ha # List ruleshle config access add ha friend@example.com # Allow an emailhle config access add ha dev@co.com --provider github # Require GitHub SSOhle config access remove ha 42 # Remove rule by IDDeclarative 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.
hle config access replace ha google:alice@example.com github:dev@co.comhle config access replace ha --clear # Remove all rulesCompare with hle expose --allow, which only adds.
hle config pin — PIN access control
hle config pin set ha # Set 4-8 digit PIN (prompts)hle config pin status ha # Check whether a PIN is activehle config pin remove ha # Remove PINhle config basic-auth — HTTP Basic Auth
Replaces SSO and PIN with a username/password prompt enforced by the relay.
hle config basic-auth set ha # Prompts for username + password (min 8 chars)hle config basic-auth status ha # Show whether active and the usernamehle config basic-auth remove ha # Remove credentialshle config share — temporary share links
hle config share create ha # 24h link (default)hle config share create ha --duration 1h # 1-hour linkhle config share create ha --max-uses 5 # Limited useshle config share create ha --label "demo" # Label for referencehle config share list ha # List share linkshle config share revoke ha 42 # Revoke a link by IDFlags for expose
| Flag | Type | Default | Description |
|---|---|---|---|
--service | string | required | Local service URL (e.g., http://localhost:8080) |
--label | string | required | Service label for the subdomain (e.g., ha, jellyfin, app1) |
--auth | enum | sso | Authentication mode: sso (OIDC) or none (public) |
--api-key | string | — | API key. Also checked in HLE_API_KEY env var and config file |
--websocket | boolean | enabled | Enable WebSocket proxying. Use --no-websocket to disable |
--allow | string | — | Allow an email (additive). Format: email or provider:email. Providers: any (default), google, github, hle. Repeatable |
--verify-ssl | boolean | false | Enable SSL certificate verification for the local service |
--upstream-basic-auth | string | — | Inject Authorization: Basic into every request forwarded to the local service. Format: USER:PASS |
--forward-host | boolean | false | Forward the browser’s Host header to the local service |
Flags for webhook
| Flag | Type | Default | Description |
|---|---|---|---|
--path | string | required | Webhook path prefix (e.g. /hook/github). Cannot be /. Only requests matching this prefix are forwarded |
--forward-to | string | required | Local URL to forward webhooks to |
--label | string | required | Webhook label, e.g. github-hook |
--api-key | string | — | API key. Also checked in HLE_API_KEY env var and config file |
Flags for config access add
| Flag | Type | Default | Description |
|---|---|---|---|
--provider | enum | any | Required 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
| Flag | Type | Default | Description |
|---|---|---|---|
--duration | enum | 24h | Link validity: 1h, 24h, or 7d |
--label | string | — | Optional label for the link |
--max-uses | int | unlimited | Maximum number of uses |
Global flags
These flags apply to all commands:
| Flag | Type | Default | Description |
|---|---|---|---|
--version | — | — | Show the client version and exit |
--debug | boolean | false | Enable debug logging to stderr |
Common flags
All commands that talk to the server (everything under hle config, plus
hle expose and hle webhook) accept:
| Flag | Type | Default | Description |
|---|---|---|---|
--api-key | string | — | API 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:
hle expose --service http://localhost:8123 --label haExpose a development app without authentication:
hle expose --service http://localhost:3000 --label dev --auth noneExpose and allow specific users in one command:
hle expose --service http://localhost:8123 --label ha \ --allow user@gmail.com --allow google:friend@gmail.comList your active tunnels:
hle config listAdd a friend to your tunnel’s access list:
hle config access add ha friend@example.comRequire GitHub login for a specific email:
hle config access add ha colleague@work.com --provider githubView and remove access rules:
hle config access list hahle config access remove ha 42Reconcile the allow-list to exactly two people (removes anyone else):
hle config access replace ha google:alice@example.com github:bob@co.comSet a PIN for quick access:
hle config pin set haCreate a temporary share link (expires in 1 hour, max 5 uses):
hle config share create ha --duration 1h --max-uses 5Protect a tunnel with HTTP Basic Auth:
hle config basic-auth set hahle config basic-auth status haExpose a service that itself requires credentials (inject upstream auth):
hle expose --service http://localhost:8123 --label ha \ --upstream-basic-auth admin:yourpassword