Daemon Mode

The localup daemon manages multiple tunnels simultaneously from a single configuration file. It provides automatic reconnection, IPC for control, and seamless integration with your development workflow.


Quick Start

# Create a configuration file
cat > .localup.yml << 'EOF'
defaults:
  relay: "relay.example.com:4443"
  local_host: "localhost"
  timeout_seconds: 30

tunnels:
  - name: api
    port: 3000
    protocol: https
    subdomain: myapp-api

  - name: frontend
    port: 3001
    protocol: https
    subdomain: myapp-frontend
EOF

# Start the daemon
localup daemon start

Platform Support

The daemon works on all major platforms:

PlatformStatusNotes
macOSFull supportIPC via Unix socket
LinuxFull supportIPC via Unix socket
WindowsFull supportIPC via named pipe

Configuration File

File Location

The daemon discovers .localup.yml or .localup.yaml by searching:

  1. Current directory
  2. Parent directories (walking up to root)

Specifying a Custom Config Path

# Use a specific config file
localup daemon start --config /path/to/my-config.yml

# Or use a relative path
localup daemon start --config ./configs/production.yml

Configuration Structure

# Global defaults (applied to all tunnels)
defaults:
  relay: "relay.example.com:4443"      # Relay server address
  token: "${LOCALUP_TOKEN}"            # Auth token (env var supported)
  local_host: "localhost"              # Default local host
  transport: "quic"                    # Transport protocol (quic, h2, websocket)
  timeout_seconds: 30                  # Connection timeout

# Tunnel definitions
tunnels:
  # HTTP tunnel with subdomain
  - name: api
    port: 3000
    protocol: http
    subdomain: my-api
    enabled: true                      # Optional, defaults to true

  # HTTPS tunnel with subdomain
  - name: frontend
    port: 3001
    protocol: https
    subdomain: my-frontend

  # HTTPS tunnel with custom domain
  - name: production
    port: 8080
    protocol: https
    custom_domain: api.mycompany.com   # Requires DNS setup

  # TCP tunnel
  - name: database
    port: 5432
    protocol: tcp
    remote_port: 15432                 # Optional specific port

  # TLS passthrough tunnel
  - name: secure-backend
    port: 8443
    protocol: tls
    sni_hostname: backend.example.com

  # Tunnel with overrides
  - name: staging
    port: 4000
    protocol: https
    subdomain: staging-api
    relay: "staging-relay.example.com:4443"   # Override relay
    token: "${STAGING_TOKEN}"                  # Override token
    local_host: "127.0.0.1"                   # Override local host
    enabled: false                             # Disabled by default

Token Resolution

Tokens are resolved in order:

  1. Tunnel-specific token field
  2. defaults.token field
  3. Environment variable expansion (${LOCALUP_TOKEN})
  4. Saved token from localup config set-token
# Save a default token
localup config set-token YOUR_AUTH_TOKEN

# Or use environment variable in config
# token: "${LOCALUP_TOKEN}"
export LOCALUP_TOKEN="your-token-here"

Daemon Commands

Starting the Daemon

# Start with auto-discovered config
localup daemon start

# Start with specific config file
localup daemon start --config /path/to/config.yml

# View logs during startup
localup daemon start 2>&1 | tee daemon.log

Stopping the Daemon

# Stop via IPC (graceful shutdown)
localup daemon stop

# Or use Ctrl+C in the daemon terminal

Graceful Shutdown: When stopped (via daemon stop or Ctrl+C), the daemon:

  1. Stops accepting new connections
  2. Sends disconnect messages to all active tunnels
  3. Waits for tunnels to close gracefully (up to 5 seconds each)
  4. Cleans up IPC socket and resources

All tunnels are properly closed - no orphaned connections.

Checking Status

# View running tunnels and their status
localup daemon status

Output example:

NAME         PROTOCOL   LOCAL        PUBLIC URL                    STATUS    UPTIME
api          https      :3000        https://my-api.tunnel.dev     UP        15m 32s
frontend     https      :3001        https://my-frontend.tunnel.dev UP       15m 30s
database     tcp        :5432        tcp://tunnel.dev:15432        UP        15m 28s

Listing Configured Tunnels

# Show all tunnels from .localup.yml
localup daemon list

Output example:

Config: /path/to/.localup.yml

NAME         PROTOCOL   PORT     SUBDOMAIN/DOMAIN     ENABLED
----------------------------------------------------------------------
api          https      3000     my-api               yes
frontend     https      3001     my-frontend          yes
database     tcp        5432     (port 15432)         yes
staging      https      4000     staging-api          no

Tunnel Operations

Starting a Specific Tunnel

# Start a tunnel by name
localup daemon tunnel-start api

Stopping a Specific Tunnel

# Stop a tunnel by name
localup daemon tunnel-stop api

Reloading a Specific Tunnel

When you change a tunnel's configuration, reload it to apply changes:

# Reload a specific tunnel (stops and restarts with new config)
localup daemon tunnel-reload api

Reloading All Configuration

# Reload entire configuration
localup daemon reload

This will:

  • Stop tunnels removed from config
  • Start new tunnels added to config
  • Keep unchanged tunnels running

Adding and Removing Tunnels

Adding a New Tunnel

# Add a tunnel to .localup.yml
localup daemon add backend --port 8080 --subdomain backend-api

# Add with custom domain
localup daemon add production --port 8080 --custom-domain api.mycompany.com

# Add with specific protocol
localup daemon add db --port 5432 --protocol tcp

After adding, reload to apply:

localup daemon reload

Removing a Tunnel

# Remove a tunnel from .localup.yml
localup daemon remove backend

After removing, reload to apply:

localup daemon reload

Environment Variables

VariableDescription
LOCALUP_TOKENDefault authentication token
TUNNEL_AUTH_TOKENAlternative token variable

Use in config with ${VAR_NAME} syntax:

defaults:
  token: "${LOCALUP_TOKEN}"

IPC Socket Location

The daemon creates an IPC socket for CLI communication:

PlatformLocation
macOS/Linux~/.localup/daemon.sock
Windows\\.\pipe\localup-daemon

Limitations

Single Daemon Instance

Only one daemon can run at a time per user. The daemon uses a fixed IPC socket path (~/.localup/daemon.sock), so starting a second daemon will fail with a socket binding error.

Workarounds:

  • Combine all tunnels from multiple projects into a single .localup.yml
  • Use absolute paths in tunnel configs if projects are in different directories
  • Stop the current daemon before starting another with a different config

Custom Domains Require Pre-Registration

Custom domains must be registered in the relay's database before use. See Custom Domain Not Working for setup instructions.


Troubleshooting

Daemon Won't Start

  1. Check if another daemon is running:

    localup daemon status
    

    If a daemon is already running, stop it first:

    localup daemon stop
    
  2. Remove stale socket file (Unix) - if daemon crashed without cleanup:

    rm ~/.localup/daemon.sock
    
  3. Check configuration syntax:

    localup daemon list  # Will show parse errors
    
  4. Verify config file exists:

    ls -la .localup.yml .localup.yaml 2>/dev/null
    

Tunnel Not Connecting

  1. Check relay server is accessible:

    nc -zv relay.example.com 4443
    
  2. Verify authentication token:

    localup config get-token
    
  3. Check tunnel status:

    localup daemon status
    

Custom Domain Not Working

Custom domains require pre-registration before use. The relay validates that the domain exists in the custom_domains database table with an active status.

Setup steps:

  1. Register the domain via relay API or admin dashboard:

    curl -X POST https://relay.example.com/api/domains \
      -H "Authorization: Bearer $ADMIN_TOKEN" \
      -d '{"domain": "api.mycompany.com"}'
    
  2. Set up DNS pointing to the relay server:

    api.mycompany.com.  IN  CNAME  relay.example.com.
    # or
    api.mycompany.com.  IN  A      <relay-ip-address>
    
  3. Wait for certificate provisioning (if using ACME/Let's Encrypt)

    • Domain status changes from pending to active
    • Check status via API or admin dashboard
  4. Connect your tunnel

Error messages:

ErrorCause
Custom domain 'X' is not registeredDomain not in database
Custom domain 'X' exists but status is pendingCertificate still provisioning
Custom domain 'X' exists but status is failedCertificate provisioning failed
Custom domain 'X' exists but status is expiredCertificate expired, needs renewal

Development mode: If the relay has no database configured, custom domain validation is skipped (allows testing without setup).


Example Workflows

Development Setup

# .localup.yml
defaults:
  relay: "relay.localup.io:4443"

tunnels:
  - name: api
    port: 3000
    protocol: https
    subdomain: dev-api

  - name: frontend
    port: 3001
    protocol: https
    subdomain: dev-frontend
# Start development servers
npm run dev:api &
npm run dev:frontend &

# Start tunnels
localup daemon start

Production with Custom Domains

# .localup.yml
defaults:
  relay: "relay.mycompany.com:4443"
  token: "${PRODUCTION_TOKEN}"

tunnels:
  - name: api
    port: 8080
    protocol: https
    custom_domain: api.mycompany.com

  - name: webhooks
    port: 8081
    protocol: https
    custom_domain: webhooks.mycompany.com

Mixed Protocols

defaults:
  relay: "relay.example.com:4443"

tunnels:
  # HTTP API
  - name: api
    port: 3000
    protocol: https
    subdomain: api

  # Database access
  - name: postgres
    port: 5432
    protocol: tcp
    remote_port: 15432

  # Redis access
  - name: redis
    port: 6379
    protocol: tcp
    remote_port: 16379

Related Documentation:

Was this page helpful?