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

2025 Freeport Cloud, Inc. All rights reserved.

Learn how we use cookies.

We contribute to Stripe's Climate program!

Product

FeaturesPricingDocumentationAppsAlternatives