reference/relay-docker-compose.md

Relay Docker Compose (Portainer Copy Block)

Back to DocStart

Copy everything inside the code block into Portainer -> Stacks -> Add stack to deploy the relay.

# =============================================================================
# Mino Relay — Docker Compose (Portainer-friendly)
#
# Usage:
#   docker compose -f docker/relay-docker-compose.yml up -d
#
# Copy-paste this file into Portainer → Stacks → "Add Stack" → Paste YAML
# to deploy the relay as a standalone stack.
#
# The relay enables private Mino servers to be accessible via mino.ink
# without requiring open inbound ports. Servers connect outbound to the
# relay, and the web client proxies requests through it.
#
# Cloudflare Tunnel (built-in):
#   Set CF_TUNNEL_TOKEN in Portainer env vars to auto-expose the relay.
#   The tunnel routes relay.mino.ink → relay:8787 internally.
#   If CF_TUNNEL_TOKEN is not set, the tunnel sidecar stays idle.
#
# After deploying:
#   1. Set CF_TUNNEL_TOKEN to expose relay.mino.ink via tunnel.
#   2. Verify: GET https://relay.mino.ink/api/v1/health
#   3. Set NEXT_PUBLIC_RELAY_URL on Cloudflare Pages and redeploy.
#   4. Deploy the Mino server stack with MINO_RELAY_URL pointing here.
#
# See docs/relay.md for the full deployment guide.
# =============================================================================

services:
  # ---------------------------------------------------------------------------
  # Mino Relay — WebSocket proxy for private server connectivity
  # ---------------------------------------------------------------------------
  relay:
    image: ghcr.io/tomszenessy/mino-relay:${RELAY_IMAGE_TAG:-main}
    container_name: mino-relay
    restart: unless-stopped
    ports:
      # Local-only by default when using tunnel. Set RELAY_PORT_BIND=0.0.0.0
      # if you want to expose the port directly on the host instead.
      - "${RELAY_PORT_BIND:-127.0.0.1}:${RELAY_PORT:-8787}:8787"
    environment:
      - NODE_ENV=production
      - RELAY_PORT=8787
      - RELAY_HOST=0.0.0.0
      # Public URL that clients and servers use to reach this relay.
      # Must match the domain routed to this container.
      - RELAY_PUBLIC_BASE_URL=${RELAY_PUBLIC_BASE_URL:-https://relay.mino.ink}
    healthcheck:
      test:
        [
          "CMD",
          "bun",
          "-e",
          "fetch('http://127.0.0.1:8787/api/v1/health').then((r)=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))",
        ]
      interval: 30s
      timeout: 5s
      start_period: 10s
      retries: 3

  # ---------------------------------------------------------------------------
  # Cloudflare Tunnel — Secure remote access (no open ports)
  #
  # CF_TUNNEL_TOKEN is required. Without it the container will exit.
  # Remove this service entirely if you don't need tunnel access.
  #
  # Setup:
  #   1. Go to https://one.dash.cloudflare.com
  #   2. Networks/Tunnels → Create tunnel → Cloudflared
  #   3. Copy token from the shown docker command: `... --token <TOKEN>`
  #   4. Add public hostname: relay.mino.ink → HTTP → relay:8787
  #   5. Set CF_TUNNEL_TOKEN in Portainer env vars
  # ---------------------------------------------------------------------------
  cloudflared:
    image: cloudflare/cloudflared:latest
    container_name: mino-relay-tunnel
    restart: unless-stopped
    command: tunnel --no-autoupdate run --token ${CF_TUNNEL_TOKEN}
    depends_on:
      relay:
        condition: service_started

Environment Variables

Set these in Portainer's "Environment variables" section when deploying the stack:

VariableRequiredDefaultDescription
CF_TUNNEL_TOKENYes(none)Cloudflare Tunnel token for exposing the relay
RELAY_PUBLIC_BASE_URLYeshttps://relay.mino.inkPublic URL clients/servers use to reach relay
RELAY_IMAGE_TAGNomainDocker image tag to pull
RELAY_PORTNo8787Port the relay listens on
RELAY_PORT_BINDNo127.0.0.1Host bind address (use 0.0.0.0 to expose directly)

Test Domain Example

For test.mino.ink deployment, set:

CF_TUNNEL_TOKEN=<your-tunnel-token>
RELAY_PUBLIC_BASE_URL=https://relay.mino.ink

Verification

After deployment, confirm the relay is healthy:

curl https://relay.mino.ink/api/v1/health