LocalXpose Docker Image - Run Tunnels in Containers

Deploy LocalXpose instantly with Docker - no installation required. Perfect for containerized environments, CI/CD pipelines, and orchestrated deployments. Expose localhost to the internet from Docker containers.

Why Use LocalXpose with Docker?

  • Zero Installation - Run immediately with docker run
  • Isolated Environment - No system dependencies or conflicts
  • Docker Compose Ready - Integrate with your existing services
  • CI/CD Compatible - Works in GitHub Actions, GitLab CI, Jenkins
  • Persistent Configuration - Mount volumes for certificates and config

Quick Start

# First, export your access token
export LX_ACCESS_TOKEN=your_token_here  # Get from https://localxpose.io/dashboard/access
 
# Then run LocalXpose, pointing to your service
docker run -it -e LX_ACCESS_TOKEN \
    localxpose/localxpose:latest tunnel http --to YOUR_SERVICE:PORT

Replace YOUR_SERVICE:PORT based on where your service runs:

  • Container in same network: Use service name (e.g., webapp:80)
  • Host machine (Docker Desktop): Use host.docker.internal:8080
  • Host machine (Linux): Use host IP or configure host.docker.internal
  • External service: Use full URL (e.g., example.com:80)

Complete Working Example

Note: in these examples we're using the Traefik whoami image listening on port 80 as a demo application. Traefik isn't required for running LocalXpose in Docker.

docker-compose.yml
version: '3.8'
 
services:
  # Your application
  web-app:
    image: traefik/whoami
    ports:
      - '8080:80'
 
  # LocalXpose tunnel
  tunnel:
    image: localxpose/localxpose:latest
    restart: unless-stopped
    environment:
      - LX_ACCESS_TOKEN
    volumes:
      - ./lx-data:/home/nonroot/.localxpose # Persist certificates
    command: tunnel http --to web-app:80
    ports:
      - '54538:54538' # Only if using Let's Encrypt

Run with: export LX_ACCESS_TOKEN=your_token && docker compose up

Installation & Versions

Docker Hub

docker pull localxpose/localxpose:latest

Version Compatibility

VersionBinary PathUserWorking DirNotes
23.11.1/app/loclxroot (0)/appLegacy version, works with older configs
24.1.1+/ko-app/loclxnonroot (65532)noneHardened security, different paths
latest/ko-app/loclxnonroot (65532)noneRecommended for new deployments
⚠️

Breaking Change: Commands like ./loclx that worked in 23.11.1 will fail in 24.1.1 or later. The binary location and user context have changed.

Connecting to Your Service

LocalXpose is a proxy - it needs to connect to your service. The networking configuration depends on where your service is running:

Service Location Guide

Your Service LocationDocker Network ModeUse --to Parameter
Another container (Docker Compose)Bridge (default)Service name: app:80
Host machine (Docker Desktop)Bridge (default)host.docker.internal:8080
Host machine (Linux)Bridge with extra_hostsHost IP or configured hostname
Host machine (Linux)Host networklocalhost:8080
External URLAnyexample.com:80

Examples by Service Location

Container-to-Container (Most Common)

docker-compose.yml
services:
  # Your application
  webapp:
    image: traefik/whoami # some app listening on port 80
 
  # LocalXpose tunnel - connects to webapp service
  tunnel:
    image: localxpose/localxpose:latest
    environment:
      - LX_ACCESS_TOKEN
    command: tunnel http --to webapp:80 # Use service name

Host Service - Docker Desktop (Mac/Windows)

# Docker Desktop provides host.docker.internal
docker run -e LX_ACCESS_TOKEN \
    localxpose/localxpose:latest \
    tunnel http --to host.docker.internal:8080

Host Service - Linux

docker-compose.yml
services:
  tunnel:
    image: localxpose/localxpose:latest
    environment:
      - LX_ACCESS_TOKEN
    # Option 1: Add host entry for Linux
    extra_hosts:
      - 'host.docker.internal:host-gateway' # or "host.docker.internal:172.17.0.1"
    command: tunnel http --to host.docker.internal:8080
 
    # Option 2: Use host network mode (simpler but less isolated)
    # network_mode: host
    # command: tunnel http --to localhost:8080

Configuration Reference

Environment Variables

VariableDescriptionRequired
LX_ACCESS_TOKENYour LocalXpose access tokenYes
HTTP_LISTEN_ADDRESSGUI bind address (0.0.0.0:54537 for Docker)GUI only

Port Requirements

PortPurposeWhen to Expose
54537Web GUIIf using GUI
54538Let's Encrypt HTTP-01If generating certificates

Command Options

Tip: If you notice TTY issues on your OS when running in Docker, try using --raw-mode (-r):

command: tunnel -r http --to webapp:80

This ensures proper output handling in non-interactive containers, though it's not always required.

Volume Mounts

docker run -v $(pwd)/lx-data:/home/nonroot/.localxpose \
    localxpose/localxpose:latest

Important: Always mount a volume at /home/nonroot/.localxpose (for 24.1.1 or later) or /app/.localxpose (for 23.11.1) to persist:

  • Let's Encrypt certificates (avoid rate limits!)
  • Access tokens
  • Configuration files
  • Domain reservations

Note: The local directory name (lx-data in examples) is arbitrary - choose any name that makes sense for your project.

Security Note: This directory contains private keys and access tokens. Keep it secure and never commit to version control:

# Add to .gitignore
lx-data/
.localxpose/

GUI Configuration (Optional)

The GUI is optional - tunnels can be managed via CLI commands or config.yaml. If you need the GUI:

When Proxying to Host Services

docker-compose.yml
services:
  tunnel:
    image: localxpose/localxpose:latest
    # For Linux with host network (simplest for GUI + host services)
    network_mode: host
    environment:
      - LX_ACCESS_TOKEN
    command: gui # Access at localhost:54537

When Proxying to Container Services

docker-compose.yml
services:
  tunnel:
    image: localxpose/localxpose:latest
    environment:
      - LX_ACCESS_TOKEN
      - HTTP_LISTEN_ADDRESS=0.0.0.0:54537 # Required for bridge network
    ports:
      - '54537:54537'
    command: gui # Access at localhost:54537

Platform Note: Host network mode only works on Linux. Docker Desktop (Mac/Windows) accepts --network host but doesn't provide true host networking due to the VM layer.

Let's Encrypt Certificates

⚠️

Rate Limiting: Let's Encrypt allows only 5 certificates per unique domain per 7 days. Without volume persistence, each container restart requests a new certificate and will hit this limit after just 5 restarts! Each subsequent certificate requires a 34-hour wait. Test with a different subdomain (e.g., test.yourdomain.com) to avoid rate limiting your production domain.

Persistent Certificate Setup

docker-compose.yml
services:
  localxpose:
    image: localxpose/localxpose:latest
    volumes:
      # CRITICAL: Persist certificates to avoid rate limits
      - ./lx-data:/home/nonroot/.localxpose
    ports:
      - '54538:54538' # Required for Let's Encrypt HTTP-01
    environment:
      - LX_ACCESS_TOKEN
    command: >
      tunnel http 
      --reserved-domain yourdomain.loclx.net
      --to web-app:80

Certificate Generation

# Generate certificate (persisted via volume)
docker run -v $(pwd)/lx-data:/home/nonroot/.localxpose \
    -p 54538:54538 \
    -e LX_ACCESS_TOKEN \
    localxpose/localxpose:latest \
    domain letsencrypt --domain yourdomain.loclx.net

Rate Limit Recovery

If you hit Let's Encrypt rate limits:

  1. Per-domain limit (5 certificates/7 days): Wait 34 hours between each new certificate request
  2. Testing strategy: Use a test subdomain (e.g., test.yourdomain.com) for development to preserve your production domain's quota
  3. Prevention: Always use persistent volumes to avoid regenerating certificates
  4. Full reset: Rate limits reset 7 days after the first certificate was issued

Complete Examples

Production Setup with Traefik

docker-compose.yml
version: '3.8'
services:
  traefik:
    image: traefik:v2.10
    command:
      - '--providers.docker=true'
      - '--entrypoints.web.address=:80'
    volumes:
      - '/var/run/docker.sock:/var/run/docker.sock:ro'
 
  localxpose:
    image: localxpose/localxpose:latest
    environment:
      - LX_ACCESS_TOKEN
    volumes:
      - ./lx-data:/home/nonroot/.localxpose # Persist certificates
    ports:
      - '54538:54538' # For Let's Encrypt
    command: tunnel http --to traefik:80 --reserved-domain "*.yourdomain.com"
 
  app1:
    image: traefik/whoami
    labels:
      - 'traefik.enable=true'
      - 'traefik.http.routers.app1.rule=Host(`app1.yourdomain.com`)'
 
  app2:
    image: traefik/whoami
    labels:
      - 'traefik.enable=true'
      - 'traefik.http.routers.app2.rule=Host(`app2.yourdomain.com`)'

Development with Host Service

docker-compose.yml
version: '3.8'
services:
  # LocalXpose tunneling to host service on port 3000
  tunnel:
    image: localxpose/localxpose:latest
    environment:
      - LX_ACCESS_TOKEN
      - HTTP_LISTEN_ADDRESS=0.0.0.0:54537 # For GUI
    ports:
      - '54537:54537' # GUI port
      - '54538:54538' # Let's Encrypt port
    volumes:
      - ./lx-data:/home/nonroot/.localxpose
    # Docker Desktop (Mac/Windows)
    command: tunnel http --to host.docker.internal:3000
    # Linux - add this:
    # extra_hosts:
    #   - "host.docker.internal:host-gateway"

Using Docker GUIs (Synology, QNAP, Unraid)

Many NAS devices and home servers provide Docker through a web GUI. To run LocalXpose on these platforms:

  1. Image: Search for and download localxpose/localxpose:latest
  2. Environment Variables: Add LX_ACCESS_TOKEN with your token value
  3. Port Mappings: Map container port 54538 to host 54538 (for Let's Encrypt)
  4. Volume Mounts: Create a folder and map it to /home/nonroot/.localxpose (for persistence)
  5. Command/Entrypoint: Override with your tunnel command, e.g., tunnel http --to host.docker.internal:8080

Platform-Specific Guides:

  • Synology: Use Container Manager → Advanced Settings for environment, ports, and volumes
  • QNAP: Use Container Station → Advanced Settings → Environment and Network
  • Unraid: Use Docker tab → Add Container with Advanced View enabled

If you're using a platform not listed let us know at hello@localxpose.io!

Using Configuration Files

config.yaml
tunnels:
  web:
    type: http
    to: webapp:3000
    subdomain: myapp
 
  api:
    type: http
    to: api:8080
    subdomain: api-myapp
# Mount and use config file
docker run -v $(pwd)/config.yaml:/config.yaml \
    -e LX_ACCESS_TOKEN \
    localxpose/localxpose:latest \
    tunnel config -f /config.yaml

Troubleshooting

Common Issues and Solutions

ProblemCauseSolution
"GUI not accessible"Missing HTTP_LISTEN_ADDRESSSet HTTP_LISTEN_ADDRESS=0.0.0.0:54537
"HTTPS stopped working"Let's Encrypt rate limitUse volume mounts to persist certificates
"loclx: command not found"Using wrong path for versionCheck version compatibility table
"OCI runtime error"Version incompatibilityUse specific version tag instead of latest
"Cannot connect to localhost:8080"Docker network isolationUse host.docker.internal or container names
"Permission denied"Volume ownership issuesCheck user ID (65532 for v24.1.1 or later)
"Certificate not found"No volume persistenceMount volume at /home/nonroot/.localxpose path

Debug Commands

# Check container logs
docker logs container_name
 
# Verify environment variables
docker exec container_name env | grep -E '(LX_ACCESS_TOKEN|HTTP_LISTEN)'
 
# Test connectivity from container
docker exec container_name wget -O- http://target:port
 
# Check certificate persistence
docker exec container_name ls -la /home/nonroot/.localxpose/

Getting Help

If you encounter issues not covered here:

  1. Check container logs: docker logs container_name
  2. Verify network connectivity: docker exec container_name ping target
  3. Ensure ports are mapped correctly: docker ps
  4. Check our troubleshooting guide
  5. Contact support with your Docker version and complete error logs

Advanced Topics

Multi-Stage Builds

Dockerfile
# Build stage
FROM golang:1.20 as builder
WORKDIR /app
COPY . .
RUN go build -o myapp
 
# Runtime with LocalXpose
FROM localxpose/localxpose:latest
COPY --from=builder /app/myapp /app/myapp
CMD ["/app/myapp"]

CI/CD Integration

Easily implement preview app deployments, test webhooks, and use automated HTTPS endpoints from within your CI build and test pipelines, without deploying to a staging environment!

Using GitHub Actions?

Try our 🆕 LocalXpose Tunnel GitHub Action (opens in a new tab).

Not using GitHub Actions? Request support for your preferred CI/CD tunneling solution here (opens in a new tab).

.github/workflows/tunnel-docker.yml
name: Tunnel for Testing
on: [push]
 
jobs:
  test:
    runs-on: ubuntu-latest
    services:
      localxpose:
        image: localxpose/localxpose:latest
        env:
          LX_ACCESS_TOKEN: ${{ secrets.LX_ACCESS_TOKEN }}
        options: --network host
    
    steps:
      - uses: actions/checkout@v3
      - run: npm test

Security Best Practices

  1. Never commit tokens - Use environment variables or secrets
  2. Use specific versions - Avoid latest in production
  3. Limit exposed ports - Only map required ports
  4. Use read-only mounts - Add :ro to Docker socket mounts
  5. Run as non-root - Use version 24.1.1 or later for better security
  6. Rotate tokens regularly - Update LX_ACCESS_TOKEN periodically

Related Documentation


8 The Green, Dover, Delaware, 19901 USA

hello@localxpose.io

2026 Freeport Cloud, Inc. All rights reserved.

Learn how we use cookies.

We contribute to Stripe's Climate program!

Product

FeaturesPricingExample applicationsGitHub ActionsHTTP pluginsAccess home servers from anywhereAccess remote IoT devicesLocal TunnelTunneling ServiceAlternatives