Self-hosting

Installation

Run Yolorouter with Docker, the one-line service installer, a release binary, or from source.

Deploy with Docker

Every release publishes a multi-arch image (amd64 / arm64) to ghcr.io/yolorouter/yolorouter, tagged with the exact version; the newest release also carries latest.

docker run -d --name yolorouter --restart unless-stopped \
  -p 8080:8080 -v "$PWD/yolorouter:/yolorouter" \
  ghcr.io/yolorouter/yolorouter:latest

Or with Compose:

curl -fsSLO https://raw.githubusercontent.com/yolorouter/yolorouter/main/docker-compose.yml
docker compose up -d

ghcr.io can be slow or unreachable from mainland China. Pull through a GHCR mirror and retag, for example the Nanjing University mirror:

docker pull ghcr.nju.edu.cn/yolorouter/yolorouter:latest
docker tag ghcr.nju.edu.cn/yolorouter/yolorouter:latest ghcr.io/yolorouter/yolorouter:latest

Or point the image: field in docker-compose.yml straight at the mirror. Third-party mirrors are run by their own operators; check their notices for availability.

Where the state lives

Everything the container writes goes to the one mounted folder. After the first start it looks like this on the host:

yolorouter/
├── configs/config.yaml   # generated on first start, holds the master key
└── data/                 # SQLite database and request-body files

To change configuration, edit ./yolorouter/configs/config.yaml on the host and docker restart yolorouter. Backing up the folder backs up the whole deployment.

Network access

-p 8080:8080 publishes the port on every host interface, so other machines on your LAN can use the gateway and console at http://<host-ip>:8080 right away. To restrict it to the host itself, map 127.0.0.1:8080:8080 instead.

Upgrading

docker compose pull && docker compose up -d

With plain docker run, pull the image, remove the container, and run the same command again — the mounted folder carries everything over:

docker pull ghcr.io/yolorouter/yolorouter:latest
docker rm -f yolorouter
# then re-run the docker run command from the top of this page

The console still checks for new releases inside a container: the About page and the sidebar show when one is out. The one-click update button is replaced by a pull-the-image hint, and the yolorouter update CLI says the same — the image is immutable by design, so an in-place binary swap would be lost on the next recreate.

PostgreSQL

The image runs on SQLite out of the box. To use PostgreSQL instead, add a database service:

services:
  yolorouter:
    image: ghcr.io/yolorouter/yolorouter:latest
    container_name: yolorouter
    restart: unless-stopped
    ports:
      - "8080:8080"
    volumes:
      - ./yolorouter:/yolorouter
    depends_on:
      - postgres
  postgres:
    image: postgres:16
    restart: unless-stopped
    environment:
      POSTGRES_USER: yolorouter
      POSTGRES_PASSWORD: change-me
      POSTGRES_DB: yolorouter
    volumes:
      - ./postgres:/var/lib/postgresql/data

Start once so configs/config.yaml is generated, then switch its database section over and restart:

database:
  driver: postgres
  host: postgres
  port: 5432
  user: yolorouter
  password: change-me
  dbname: yolorouter
  sslmode: disable

Install as a service (one command)

Install yolorouter as a background service that starts on boot — systemd on Linux, launchd on macOS, a scheduled task on Windows:

# Linux / macOS
curl -fsSL https://get.yolorouter.com/install.sh | bash
# Windows, PowerShell 5.1+
irm https://get.yolorouter.com/install.ps1 | iex

Or straight from GitHub:

curl -fsSL https://raw.githubusercontent.com/yolorouter/yolorouter/main/scripts/install.sh | bash
irm https://raw.githubusercontent.com/yolorouter/yolorouter/main/scripts/install.ps1 | iex

If GitHub is slow or unreachable from your network, use the accelerated command. It is the same installer downloaded through a Cloudflare proxy; auto-updates after installation keep using the mirror with no extra configuration:

# Linux / macOS
curl -fsSL https://gh.yolorouter.com/install.sh | bash
# Windows, PowerShell 5.1+
irm https://gh.yolorouter.com/install.ps1 | iex

To switch an already installed machine to the mirror, add github_proxy: https://gh.yolorouter.com/ under the update section of config.yaml and restart the service.

The script first asks for an interface language, then detects your architecture, downloads and sha256-verifies the release, builds a self-contained app-home directory, starts the service and health-checks it.

What the Windows installer does

install.ps1 registers a scheduled task named Yolorouter rather than a Windows Service, and the privilege level of the PowerShell you run it from decides the install scope:

Run fromScopeApp homeStarts
Elevated PowerShellsystem%ProgramFiles%\yolorouterat boot, as SYSTEM
Normal PowerShelluser%LOCALAPPDATA%\.yolorouterat logon, as you

Manage it with schtasks.exe; the installer prints the exact query / stop / restart commands when it finishes.

Re-run the same command to upgrade — configuration and database are preserved, and the database is backed up before the upgrade.

Optional environment overrides

VariableMeaning
YOLO_LANGzh or en, skips the language prompt
YOLO_SCOPEsystem or user install scope
YOLO_VERSIONPin a version, e.g. vX.Y.Z
YOLO_REPOOverride owner/repo
YOLO_MIRRORDownload mirror, e.g. https://host/
YOLO_UNINSTALL1 uninstalls instead of installing (same as passing --uninstall)

Both installers accept the same variables.

A system-scope install needs root/sudo (an elevated PowerShell on Windows); without it the script falls back to a user-level service.

Run a release binary

Download the archive for your platform from the latest release, extract it, then:

./yolorouter serve          # .\yolorouter.exe serve on Windows

Releases cover Linux, macOS and Windows on both amd64 and arm64 (.zip for Windows, .tar.gz elsewhere).

Run it from the directory where you want configs\ and data\ to appear: both are resolved against the working directory, not the location of the binary. The one-line installers avoid this entirely by pinning a self-contained app home.

Config file permissions on Windows

Yolorouter cannot enforce config file permissions on Windows: access there is governed by ACLs, and the permission bits Go reports are synthesized and do not reflect real access. The service logs a warning at startup — including a ready-to-run icacls command scoped to the current account — and continues.

To restrict it by hand:

icacls "configs\config.yaml" /inheritance:r `
  /remove:g *S-1-1-0 /remove:g *S-1-5-32-545 /remove:g *S-1-5-11 `
  /grant:r "${env:USERNAME}:F"
icacls "configs\config.yaml"   # confirm only your own account is listed

/inheritance:r only drops inherited entries and /grant:r only replaces the grant for the account it names, so the over-broad principals (Everyone, Users, Authenticated Users) are actually removed by those /remove:g flags — by SID rather than by name, because those names are localized (Everyone shows up as Jeder on German Windows). This covers the overwhelming majority of real-world cases, but cannot guarantee an empty ACL for arbitrary principals, which is why the second verification command is worth running. To rebuild the ACL from scratch, use PowerShell's Set-Acl with SetAccessRuleProtection($true, $false).

Under cmd.exe use "%USERNAME%:F" instead, and ^ as the continuation character rather than a backtick — ${env:...} is PowerShell-only syntax and %...% is cmd-only; they are not interchangeable.

First run

Automatic initialization

The first run generates configs/config.yaml (including a random AES-256 master key used to encrypt upstream keys), applies database migrations, and starts the console at http://localhost:8080. The startup log prints both the localhost and the LAN address, so you can open it from another machine.

Create an admin and add providers

After creating the first admin account, follow the guided flow: add providers and their upstream keys, create models with their provider candidates, then issue API keys.

Provider setup is preset-driven: pick a known provider from the built-in catalogue and the base URL and protocol are filled in for you. Once a key is pasted you can pull that provider's live model list instead of typing model ids by hand.

Build from source

Requires Go 1.25.7+ and Node.js 22.12+.

# Backend only — serves a placeholder page instead of the console
make build          # -> ./bin/yolorouter

# Full binary with the console embedded
make build-embed    # -> ./bin/yolorouter (builds and embeds the frontend)

# Cross-compile (frontend embedded)
make build-macos          # -> ./bin/yolorouter-darwin-{amd64,arm64}
make build-windows        # -> ./bin/yolorouter-windows-{amd64,arm64}.exe

# Fast compile check (windows only, no frontend build, no binary)
make build-windows-check