Skip to Content
runelay

Self-hosting

Installer options, Docker Compose, building from source, HTTPS and environment variables.

Installer options

Options go in front of sh:

curl -fsSL runelay.com/install \
  | PUBLIC_URL=https://runelay.example.com RUNELAY_DIR=/opt/runelay RUNELAY_VERSION=v0.1.0 sh
VariableDefaultDescription
RUNELAY_DIR~/runelayInstall folder.
RUNELAY_VERSIONlatestRelease to install.
RUNELAY_PORT4312Port the server listens on.
PUBLIC_URLhttp://localhost:<port>Public URL written to .env.

Docker Compose by hand

compose.yaml
services:
  runelay:
    image: ghcr.io/andsu-dev/runelay:latest
    restart: unless-stopped
    env_file: .env
    environment:
      RUNELAY_UPDATER_URL: http://updater:8080
    labels:
      com.centurylinklabs.watchtower.enable: "true"
    ports:
      - "127.0.0.1:4312:4312"
    volumes:
      - ./data:/data

  updater:
    image: containrrr/watchtower:1.7.1
    restart: unless-stopped
    command: --http-api-update --label-enable --cleanup
    environment:
      WATCHTOWER_HTTP_API_TOKEN: ${RUNELAY_UPDATER_TOKEN:-}
      DOCKER_API_VERSION: "1.44"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock

The updater service is optional. It powers the one-click update in the panel and only touches containers labeled for it. Leave it out if you do not want a container with access to the Docker socket.

.env
PUBLIC_URL=https://runelay.example.com
RUNELAY_SECRET=$(openssl rand -hex 32)
ALLOW_SIGNUP=false
RUNELAY_UPDATER_TOKEN=$(openssl rand -hex 24)

Build from source

git clone https://github.com/Andsu-dev/runelay.git && cd runelay
cp .env.example .env
docker compose up -d --build

Set PUBLIC_URL and RUNELAY_SECRET in .env. bun run dev is only for working on runelay itself; to run it, use the image.

HTTPS

Put HTTPS in front of the 127.0.0.1:4312 binding.

Caddyfile
runelay.example.com {
  reverse_proxy 127.0.0.1:4312
}
Cloudflare Tunnel
ingress:
  - hostname: runelay.example.com
    service: http://127.0.0.1:4312
  - service: http_status:404

OAuth callbacks go to PUBLIC_URL/v1/oauth/callback, so PUBLIC_URL must be the public address.

Environment variables

VariableDefaultDescription
PUBLIC_URLhttp://localhost:4312Public URL of the panel and API. Used for OAuth callbacks and cookies.
RUNELAY_SECRETrequired, 32+ charsEncrypts connection configs, OAuth tokens and recoverable API keys. Losing it means reconnecting everything.
RUNELAY_SETUP_TOKENgeneratedOne-time token required to create the first account.
RUNELAY_UPDATER_TOKENgeneratedShared with the updater container. Owners and admins can then update from the panel.
RUNELAY_UPDATER_URLset by compose.yamlWhere the updater listens.
ALLOW_SIGNUPfalseKeep signups open after the first account.
RUNELAY_ENABLE_EXECUTEtrueEnables the sandboxed execute tool. See Security.
RUNELAY_ENABLE_STDIOfalseEnables local MCP servers by command. See Security. The Docker image ships without Node, so commands like npx need the desktop app or a custom image.
RUNELAY_ALLOW_PRIVATE_URLSfalseAllows connections to private network addresses.
RUNELAY_RATE_LIMIT_PER_MINUTE240Requests per minute allowed for each API key.
GITHUB_CLIENT_ID / GITHUB_CLIENT_SECRETemptyEnables "Sign in with GitHub" on the panel.
RUNELAY_DATA/data in DockerWhere the SQLite database lives.
PORT / HOST4312 / 0.0.0.0 in DockerWhere the server listens.

On this page