Docker
Run HLE tunnels on any Docker host — Synology NAS, Unraid, bare metal servers, VMs, or cloud instances. Choose the full image with a web UI for managing tunnels visually, or the headless image for a lighter, API-and-CLI-only deployment.
Choose Your Mode
Agent (managed from the dashboard) — One container serves every endpoint you declare at hle.world/dashboard. No local config, no published ports. Best if you want one place to manage everything, including other machines. See the agent guide.
ghcr.io/hle-world/hle-docker:headless # with HLE_AGENT_TOKEN setFull (With Web UI) — Includes the React dashboard for managing tunnels, access rules, PIN protection, and share links. Best for most users.
ghcr.io/hle-world/hle-docker:latestHeadless (API + CLI Only) — No web UI — manage tunnels via the hle CLI or REST API. Faster build, lighter footprint.
ghcr.io/hle-world/hle-docker:headlessQuick Start
Agent mode
docker run -d \ --name hle-agent \ --restart unless-stopped \ -e HLE_AGENT_TOKEN=hlea_your_token_here \ --add-host host.docker.internal:host-gateway \ -v hle-agent-data:/data \ ghcr.io/hle-world/hle-docker:headlessThen add endpoints in the dashboard. They go live within seconds — no restart.
Point endpoints at whatever the container can reach:
| Target | Local URL to use |
|---|---|
| A service on the Docker host | http://host.docker.internal:8123 |
| Another container on the same network | http://container-name:8080 |
| Something else on the LAN | http://192.168.1.50:8096 |
Setting HLE_AGENT_TOKEN switches the container into agent mode; HLE_API_KEY
and the web UI are ignored.
Full image (with web UI)
docker run -d \ --name hle \ -p 8099:8099 \ -v hle-data:/data \ ghcr.io/hle-world/hle-docker:latestOpen http://your-host:8099 in a browser. Enter your API key in Settings, then add a tunnel.
Headless image (no UI)
docker run -d \ --name hle \ -p 8099:8099 \ -v hle-data:/data \ ghcr.io/hle-world/hle-docker:headlessThe API is available at http://your-host:8099/api/. Manage tunnels via CLI or API (see below).
Docker Compose
services: hle: image: ghcr.io/hle-world/hle-docker:latest # or :headless container_name: hle restart: unless-stopped ports: - "8099:8099" volumes: - hle-data:/data environment: - HLE_API_KEY= # optional: set here or via web UI/CLI
volumes: hle-data:For agent mode:
services: hle-agent: image: ghcr.io/hle-world/hle-docker:headless container_name: hle-agent restart: unless-stopped volumes: - hle-agent-data:/data environment: - HLE_AGENT_TOKEN=hlea_your_token_here extra_hosts: - "host.docker.internal:host-gateway"
volumes: hle-agent-data:# Startdocker compose up -d
# View logsdocker compose logs -f hleEnvironment Variables
| Variable | Default | Description |
|---|---|---|
HLE_AGENT_TOKEN | (empty) | Agent token (hlea_…). When set, the container runs in agent mode and takes its endpoints from the dashboard. |
HLE_API_KEY | (empty) | Your HLE API key. Can also be set via the web UI or hle auth login. |
HLE_PORT | 8099 | Port the server listens on inside the container. |
HLE_AGENT_TOKEN takes precedence over HLE_API_KEY. Both can also be stored in
/data/hle_config.json as agent_token / api_key.
Data Persistence
All configuration and tunnel state is stored in /data inside the container. Mount a Docker volume or host directory to persist data across container restarts and upgrades.
Contents: hle_config.json (API key, settings), tunnel definitions, and logs (/data/logs/).
Managing Tunnels via CLI
The hle CLI is available inside both images. Use docker exec to interact with it:
# Set your API keydocker exec hle hle auth login --api-key YOUR_API_KEY
# Expose a local service (e.g. Home Assistant on the Docker host)docker exec hle hle tunnel create ha http://host.docker.internal:8123
# List active tunnelsdocker exec hle hle status
# See all CLI commandsdocker exec hle hle --helpTo stop a tunnel, stop the process serving it — from the web UI on port 8099, or by stopping the container. There is no CLI verb for it: asking the relay to drop the connection does not stop anything, because the client reconnects.
Once a tunnel is stopped, docker exec hle hle tunnel delete ha removes its
record and the access rules attached to it.
Managing Tunnels via API
The REST API is available on both images at port 8099:
# List tunnelscurl http://localhost:8099/api/tunnels
# Get current configurationcurl http://localhost:8099/api/config
# Update API keycurl -X POST http://localhost:8099/api/config \ -H "Content-Type: application/json" \ -d '{"api_key": "hle_your_key_here"}'Updating
Pull the latest image and recreate the container. Your data is preserved in the volume.
# Pull latestdocker pull ghcr.io/hle-world/hle-docker:latest
# Recreatedocker compose up -d
# Or without compose:docker stop hle && docker rm hledocker run -d --name hle -p 8099:8099 -v hle-data:/data ghcr.io/hle-world/hle-docker:latestFor automatic updates, use Watchtower to monitor and auto-update the container.
Building from Source
git clone https://github.com/hle-world/hle-docker.gitcd hle-docker
# Full image (with web UI)docker build -t hle-docker:local .
# Headless (no UI)docker build -f Dockerfile.headless -t hle-docker:headless .Troubleshooting
Container starts but tunnels don’t connect
Check that your API key is set correctly. View logs with docker logs hle or check /data/logs/ inside the container.
Can’t reach services on the Docker host
Use host.docker.internal instead of localhost in service URLs. On Linux, you may need to add --add-host=host.docker.internal:host-gateway to your docker run command or add extra_hosts: ["host.docker.internal:host-gateway"] in Docker Compose.
Port conflict
If port 8099 is already in use, map to a different host port: -p 9099:8099.