This guide covers Docker setup and deployment for the LocalUp tunnel application.
Best for: Production deployments, CI/CD, guaranteed correct Linux binary
Pros:
- ✅ Builds from source inside Docker
- ✅ Guaranteed correct binary for Linux
- ✅ Reproducible builds across platforms
- ✅ Single Dockerfile works on macOS, Linux, Windows
- ✅ Multi-stage: small final image (~200MB)
Cons:
- ❌ Longer build time (10-15 minutes, includes Rust compilation)
- ❌ Requires internet access for dependencies
Build:
docker build -f Dockerfile -t localup:latest .Best for: Quick testing, when you already have a compiled Linux binary
Pros:
- ✅ Fast builds (< 1 minute)
- ✅ Small context size
- ✅ Simple Dockerfile
Cons:
- ❌ Requires pre-compiled Linux binary (
target/release/localup) - ❌ Not suitable if building on macOS
- ❌ Extra step to compile binary separately
Requirements:
- Linux-compiled binary in
target/release/localup - Either compile on Linux or cross-compile:
cargo build --release --target x86_64-unknown-linux-gnu
Build:
# First compile the binary
cargo build --release --target x86_64-unknown-linux-gnu
# Then build Docker image
docker build -f Dockerfile.prebuilt -t localup:latest .# Build Docker image (compiles inside Docker)
docker build -f Dockerfile -t localup:latest .
# Test the image
docker run --rm localup:latest --version
docker run --rm localup:latest --help# 1. Compile binary for Linux (on Linux or with cross-compilation)
cargo build --release --target x86_64-unknown-linux-gnu
# 2. Build Docker image using prebuilt binary
docker build -f Dockerfile.prebuilt -t localup:latest .
# 3. Test the image
docker run --rm localup:latest --version
docker run --rm localup:latest --help# Generate a token
docker-compose run --rm localup generate-token \
--secret "my-secret" \
--localup-id "myapp"
# Run as relay server
docker-compose run --rm -p 4443:4443 -p 8080:8080 localup relay \
--listen 0.0.0.0:4443 \
--http-port 8080
# Run as agent
docker-compose run --rm localup agent \
--relay localhost:4443 \
--token "<TOKEN>" \
--target-address "localhost:3000"docker run --rm localup:latest --version
docker run --rm localup:latest --helpdocker run --rm localup:latest generate-token \
--secret "test-secret" \
--localup-id "test-app"docker run --rm localup:latest connect --help
docker run --rm localup:latest relay --help
docker run --rm localup:latest agent --help
docker run --rm localup:latest agent-server --help
docker run --rm localup:latest generate-token --helpdocker run --rm --name localup-health localup:latest --help && \
echo "✅ Health check passed" || echo "❌ Health check failed"docker run -d \
--name localup-relay \
-p 4443:4443 \
-p 8080:8080 \
-e RUST_LOG=info \
localup:latest \
relay \
--listen 0.0.0.0:4443 \
--http-port 8080 \
--localup-addr 0.0.0.0:4443docker run -d \
--name localup-agent \
-e RUST_LOG=info \
--network host \
localup:latest \
agent \
--relay localhost:4443 \
--token "<TOKEN>" \
--target-address "localhost:3000" \
--insecuredocker run -d \
--name localup-agent-server \
-p 4443:4443 \
-e RUST_LOG=info \
localup:latest \
agent-server \
--listen 0.0.0.0:4443You can customize builds with environment variables:
# Set custom relay config
docker build --build-arg LOCALUP_RELAYS_CONFIG=/path/to/relays.yaml \
-f Dockerfile.final -t localup:latest .
# Set log level during build
docker build --build-arg RUST_LOG=debug \
-f Dockerfile.final -t localup:latest .| Port | Service | Purpose |
|---|---|---|
| 4443 | QUIC | Control plane (tunnel registration) |
| 8080 | HTTP | Relay HTTP server |
| 9090 | Metrics | Metrics dashboard |
# Host network (for local testing)
docker run --network host localup:latest ...
# Bridge network (for container communication)
docker run --network my-network localup:latest ...
# Custom bridge with named containers
docker network create localup-net
docker run --network localup-net --name relay localup:latest relay ...
docker run --network localup-net --name agent localup:latest agent \
--relay relay:4443 ...If building with Dockerfile.final, ensure Bun is available:
# Install Bun in the Docker image or skip web apps
RUN curl -fsSL https://bun.sh/install | bashThis means you're trying to run a macOS binary in a Linux container:
Solution: Compile for Linux:
# Cross-compile on macOS
cargo build --release --target x86_64-unknown-linux-gnu
# Or build in a Linux environment
docker run -v $(pwd):/workspace -w /workspace rust:latest \
cargo build --release --target x86_64-unknown-linux-gnuIf Docker Hub is slow:
- Try again later
- Use a docker mirror
- Build locally without pulling:
docker build --offline -f Dockerfile.ubuntu ...
-
Use specific version tags:
docker build -t localup:v0.1.0 . docker tag localup:v0.1.0 localup:latest -
Push to registry:
docker tag localup:latest myregistry.com/localup:latest docker push myregistry.com/localup:latest
-
Use multi-stage build for smaller final images
-
Set resource limits:
docker run -m 512m --cpus 2 localup:latest ...
-
Use secrets for sensitive data:
docker run --secret relay_token localup:latest ...
- name: Build Docker Image
run: docker build -f Dockerfile.ubuntu -t localup:${{ github.sha }} .
- name: Test Docker Image
run: |
docker run --rm localup:${{ github.sha }} --version
docker run --rm localup:${{ github.sha }} --help
- name: Push to Registry
run: |
docker tag localup:${{ github.sha }} myregistry.com/localup:latest
docker push myregistry.com/localup:latestCurrent sizes:
Dockerfile.ubuntu(prebuilt): ~2.25GBDockerfile.final(multi-stage): ~2.5GB
To reduce size:
- Use Alpine Linux instead of Ubuntu
- Strip symbols from binary:
strip target/release/localup - Use distroless images
- Remove build dependencies in final stage
Example Alpine-based Dockerfile:
FROM alpine:latest
RUN apk add --no-cache ca-certificates libssl3
COPY target/release/localup /usr/local/bin/
ENTRYPOINT ["localup"]For Docker-specific issues:
- Check logs:
docker logs <container-name> - View image details:
docker inspect localup:latest - Debug interactive:
docker run -it localup:latest /bin/bash