Skip to content
Login

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.

View on GitHub

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 set

Full (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:latest

Headless (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:headless

Quick Start

Agent mode

Terminal window
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:headless

Then add endpoints in the dashboard. They go live within seconds — no restart.

Point endpoints at whatever the container can reach:

TargetLocal URL to use
A service on the Docker hosthttp://host.docker.internal:8123
Another container on the same networkhttp://container-name:8080
Something else on the LANhttp://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)

Terminal window
docker run -d \
--name hle \
-p 8099:8099 \
-v hle-data:/data \
ghcr.io/hle-world/hle-docker:latest

Open http://your-host:8099 in a browser. Enter your API key in Settings, then add a tunnel.

Headless image (no UI)

Terminal window
docker run -d \
--name hle \
-p 8099:8099 \
-v hle-data:/data \
ghcr.io/hle-world/hle-docker:headless

The 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:
Terminal window
# Start
docker compose up -d
# View logs
docker compose logs -f hle

Environment Variables

VariableDefaultDescription
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_PORT8099Port 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:

Terminal window
# Set your API key
docker 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 tunnels
docker exec hle hle status
# See all CLI commands
docker exec hle hle --help

To 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:

Terminal window
# List tunnels
curl http://localhost:8099/api/tunnels
# Get current configuration
curl http://localhost:8099/api/config
# Update API key
curl -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.

Terminal window
# Pull latest
docker pull ghcr.io/hle-world/hle-docker:latest
# Recreate
docker compose up -d
# Or without compose:
docker stop hle && docker rm hle
docker run -d --name hle -p 8099:8099 -v hle-data:/data ghcr.io/hle-world/hle-docker:latest

For automatic updates, use Watchtower to monitor and auto-update the container.

Building from Source

Terminal window
git clone https://github.com/hle-world/hle-docker.git
cd 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.