CLI Reference
The HLE CLI has six top-level commands:
hle tunnel create— run a tunnel for a local servicehle tunnel webhook— run a webhook forwarderhle agent— run many tunnels, managed from the dashboardhle daemon— installexposeor the agent as a background servicehle auth— manage your API keyhle tunnel— configure tunnels (auth mode, access rules, PIN, basic-auth, share links, list)
Tunnel-scoped subcommands under hle tunnel accept a label (resolved to
<label>-<user_code> via /api/auth/me) or a full subdomain. For example,
hle tunnel get ha and hle tunnel get ha-x7k both work.
hle tunnel create
Expose a local service to the internet.
hle tunnel create myapp http://localhost:8080Expose and allow specific users in one command:
hle tunnel create app http://localhost:8080 --allow user@gmail.com --allow google:friend@gmail.com--allow is additive — it adds rules without removing existing ones. Use
hle tunnel access replace for a declarative reconcile.
hle tunnel webhook
Create a webhook tunnel for receiving HTTP callbacks (GitHub, Stripe, etc.). Disables the SSO gate and WebSocket, enforces path prefix filtering.
hle tunnel 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 forward --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 forward
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 forward rpi 22 --port 9922 # then: ssh -p 9922 root@localhosthle forward nas 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 daemon
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 daemon install agent
# A single fixed tunnelhle daemon install tunnel ha http://localhost:8123
# A firepuncher forward, always available locallyhle daemon install forward rpi 22 --port 9922
hle daemon status --agent # or --label hahle daemon listhle daemon 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 tunnel
All tunnel and account configuration lives under hle tunnel.
hle tunnel list
List active tunnels for your account.
hle tunnel listhle tunnel get
Show the full configuration and live state for a tunnel — auth mode, access rules, PIN, basic-auth, and connection state — in one call.
hle tunnel get hahle tunnel get ha-x7k # full subdomain also acceptedhle tunnel 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 tunnel auth-mode ha --set sso # SSO gate onhle tunnel auth-mode ha --set none # tunnel becomes publichle tunnel access — SSO email allow-list
hle tunnel access list ha # List ruleshle tunnel access add ha friend@example.com # Allow an emailhle tunnel access add ha dev@co.com --provider github # Require GitHub SSOhle tunnel access remove ha 42 # Remove rule by IDDeclarative reconcile
hle tunnel 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 tunnel access replace ha google:alice@example.com github:dev@co.comhle tunnel access replace ha --clear # Remove all rulesCompare with hle tunnel create --allow, which only adds.
hle tunnel pin — PIN access control
hle tunnel pin set ha # Set 4-8 digit PIN (prompts)hle tunnel pin status ha # Check whether a PIN is activehle tunnel pin remove ha # Remove PINhle tunnel basic-auth — HTTP Basic Auth
Replaces SSO and PIN with a username/password prompt enforced by the relay.
hle tunnel basic-auth set ha # Prompts for username + password (min 8 chars)hle tunnel basic-auth status ha # Show whether active and the usernamehle tunnel basic-auth remove ha # Remove credentialshle tunnel share — temporary share links
hle tunnel share create ha # 24h link (default)hle tunnel share create ha --duration 1h # 1-hour linkhle tunnel share create ha --max-uses 5 # Limited useshle tunnel share create ha --label "demo" # Label for referencehle tunnel share list ha # List share linkshle tunnel 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 tunnel, plus
hle tunnel create and hle tunnel 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 tunnel create ha http://localhost:8123Expose a development app without authentication:
hle tunnel create dev http://localhost:3000 --auth noneExpose and allow specific users in one command:
hle tunnel create ha http://localhost:8123 --allow user@gmail.com --allow google:friend@gmail.comList your active tunnels:
hle tunnel listAdd a friend to your tunnel’s access list:
hle tunnel access add ha friend@example.comRequire GitHub login for a specific email:
hle tunnel access add ha colleague@work.com --provider githubView and remove access rules:
hle tunnel access list hahle tunnel access remove ha 42Reconcile the allow-list to exactly two people (removes anyone else):
hle tunnel access replace ha google:alice@example.com github:bob@co.comSet a PIN for quick access:
hle tunnel pin set haCreate a temporary share link (expires in 1 hour, max 5 uses):
hle tunnel share create ha --duration 1h --max-uses 5Protect a tunnel with HTTP Basic Auth:
hle tunnel basic-auth set hahle tunnel basic-auth status haExpose a service that itself requires credentials (inject upstream auth):
hle tunnel create ha http://localhost:8123 --upstream-basic-auth admin:yourpassword