Tunnel
LoKO uses two complementary tunneling mechanisms:
| TCP Tunnel (HAProxy) | Public Sharing (ngrok) | |
|---|---|---|
| Purpose | Forward TCP ports to your local network | Expose HTTP(S) workloads to the public internet |
| Setup | Automatic | Requires a free ngrok account |
| Access | Local network only | Public internet |
| Protocols | TCP (databases, raw sockets) | HTTP/HTTPS only |
| Lifecycle | Always-on while cluster is running | On-demand per workload |
| Commands | tunnel start/stop/recreate/status | tunnel share |
TCP Tunnel (HAProxy)
Section titled “TCP Tunnel (HAProxy)”The TCP tunnel is a HAProxy container that runs alongside your Kind cluster and forwards TCP ports from your host machine into the cluster’s internal network. This allows database clients and other TCP tools to connect directly to workloads using your configured domain (e.g., mysql.dev.me:3306).
How It Works
Section titled “How It Works”When you run loko create, LoKO automatically:
- Creates an HAProxy container named
loko-<env>-tunnel - Discovers which TCP ports are needed from your workloads (from the catalog or your
loko.yamlports:field) - Binds each port to your local network IP (from
network.ip) - Forwards traffic through to the Kind node’s internal Docker network IP
The tunnel container is separate from the Kind cluster — it can be recreated without touching the cluster or losing data.
Configuration
Section titled “Configuration”tunnel: enabled: true # Enable or disable the HAProxy tunnel bind-address: null # IP to bind ports on; defaults to network.ipManaging the Tunnel
Section titled “Managing the Tunnel”loko tunnel status # Show container status and forwarded portsloko tunnel start # Start the tunnel containerloko tunnel stop # Stop and remove the tunnel containerloko tunnel recreate # Recreate after adding/removing TCP workloadsAdding TCP Workloads
Section titled “Adding TCP Workloads”When you add a system workload with TCP ports (e.g., mysql, postgres, nats), LoKO picks up the ports automatically from the catalog. For custom user workloads, declare the ports explicitly:
workloads: user: - name: my-service enabled: true ports: [8080] config: chart: my-chart/my-service version: "1.0.0"After adding or removing a TCP workload, recreate the tunnel to pick up the change (no cluster restart needed):
loko tunnel recreatePublic Sharing (ngrok)
Section titled “Public Sharing (ngrok)”LoKO integrates with ngrok to expose any HTTP(S) workload publicly — useful for webhook testing, demos, or OAuth redirect URIs that require a public URL.
Prerequisites
Section titled “Prerequisites”- A free ngrok account
ngrokinstalled on your machine- Your auth token exported:
export NGROK_AUTHTOKEN=your_token_hereShare a workload defined in your loko.yaml:
loko tunnel share --workload mysql-ui# orloko tunnel share -w mysql-uiShare any Kubernetes Ingress resource by name:
loko tunnel share --ingress my-ingress# in a specific namespace:loko tunnel share --ingress my-ingress --namespace my-namespaceWhen the tunnel is active, LoKO prints the public URL:
✅ Tunnel active: https://a1b2c3d4.ngrok.io → https://mysql-ui.dev.me Press Ctrl+C to stopOptions
Section titled “Options”| Flag | Short | Description |
|---|---|---|
--workload | -w | Workload name from loko.yaml |
--ingress | -i | Kubernetes Ingress resource name |
--namespace | -n | Namespace for --ingress (default: system namespace) |
--detach | -d | Run tunnel in background |
--verbose | -v | Show resolved hostname and ngrok policy file path |
--workload and --ingress are mutually exclusive. --namespace requires --ingress.
How It Works
Section titled “How It Works”LoKO creates an ngrok tunnel pointing at your cluster’s ingress endpoint (<network.ip>:443). It generates an ngrok traffic policy that rewrites the Host header on inbound requests so Traefik routes them to the correct workload — the same as when you access it locally.
Running in the Background
Section titled “Running in the Background”loko tunnel share -w myapp --detachThe tunnel runs as a background ngrok process. To stop it:
pkill ngrokCommon Use Cases
Section titled “Common Use Cases”Webhook testing — expose your local app to receive webhooks from Stripe, GitHub, Slack, etc.:
loko tunnel share -w my-api# Paste the ngrok URL into your webhook settingsDemos — share a running service without exposing your IP:
loko tunnel share -w my-frontend --detach# Send the ngrok URL to your colleagueOAuth flows — some OAuth providers require a public redirect URI:
loko tunnel share -w my-app# Use the ngrok URL as your OAuth redirect URITroubleshooting
Section titled “Troubleshooting”TCP Tunnel
Section titled “TCP Tunnel”Port already in use — Another process is binding a port that LoKO needs. LoKO will tell you which port and process. Stop the conflicting process and run loko tunnel recreate.
Tunnel not forwarding — Run loko tunnel status to check if the container is running. If not, run loko tunnel start.
New workload ports not accessible — Run loko tunnel recreate after enabling a TCP workload.
ngrok Sharing
Section titled “ngrok Sharing”NGROK_AUTHTOKEN not set — Export your token before running the command.
ERR_NGROK_108 (tunnel limit reached) — Free ngrok accounts allow 1 active tunnel. Stop any existing ngrok sessions (pkill ngrok) and retry.
502 Bad Gateway from ngrok — The workload may not be running or its ingress isn’t healthy. Check with loko status and kubectl get ingress -A.
Tunnel connects but shows wrong workload — Make sure you’re using the correct workload name from loko.yaml or the exact Ingress resource name from kubectl get ingress -A.