# AIChessGM Guide: Set Up a Leela Engine on Vast.ai or Home Linux

**Last updated:** March 2026

[View this guide as HTML](LEELA_VASTAI_SETUP_GUIDE.html)  
[Download the setup package ZIP](AIChessGM-Leela-Setup-Package.zip)  
[Download the guide-only ZIP](AIChessGM-Leela-VastAI-Setup-Guide.zip)

This guide explains how to run **Leela Chess Zero (`lc0`) on a Linux GPU server** and reach it privately from your own machine over **Tailscale**.

**Optional feature note:** This entire guide is optional. You do **not** need Vast.ai, Tailscale, or a remote Leela server to install or use AIChessGM itself.

**Source package note:** The downloadable setup package now includes the Go source for `uci-bridge` and the startup scripts used by this workflow. You can build the bridge for **Windows, macOS, or Linux**. The included prebuilt bridge binary remains **Linux x86_64 only**.

It covers:

- **Mac users** running AIChessGM
- **Windows users** who want to reach the same remote engine from a Windows machine or a Windows-based chess GUI
- **Home Linux users** who want to run the engine on their own Linux box
- **Vast.ai Linux servers** for cloud GPU use

Fresh-container note:

- The packaged Vast `up.sh` now installs `tailscale` automatically if the base Jupyter image does not already include it.
- If you keep your scripts, bridge binary, `lc0`, weights, and `.ts_authkey` on a persistent `/workspace` volume, recreating the Vast container should be enough to recover on the next start.

Important scope note:

- **AIChessGM itself is currently a macOS app.**
- The **bridge/startup source in the setup package can be built for Windows, macOS, or Linux engine hosts**. The container and `systemd` examples in this guide remain Linux-first because the recommended Vast.ai and home-server paths are Linux deployments.

---

## 1. What you are building

You are building a private path like this:

```text
Mac or Windows client
  -> Tailscale tailnet
  -> Vast.ai Linux GPU server or home Linux GPU server
  -> uci-bridge
  -> lc0
```

The important design decisions are:

- Your engine stays **private** behind Tailscale
- You do **not** need to expose the UCI port to the public internet
- Your local client connects to a stable hostname such as `vast-lc0`
- The bridge keeps `lc0` warm between sessions when configured to do so

---

## 2. Choose your deployment path

Use this table first.

| Situation | Best path |
|---|---|
| You want the easiest first cloud success | Vast.ai + Jupyter/SSH container + `up.sh` |
| You want an always-on server at home | Home Linux + `systemd` |
| You already own a Linux GPU machine | Home Linux + `systemd` |
| You only want a cloud GPU when analyzing | Vast.ai + stop the instance when finished |
| You are brand new to this project | Start with **one GPU**, **one engine**, **one weights file**, **one hostname** |

For most users, the best order is:

1. Set up Tailscale on your local machine.
2. Launch one Linux server.
3. Get one `lc0` engine responding to `uci` and `isready`.
4. Only after that, add more tuning, more ports, or more engines.

---

## 3. What you need before you start

### Required accounts and software

- A **Tailscale account**
- A **Vast.ai account** if you are using a cloud GPU
- A copy of this repository on a machine you control:
  - `/Users/james/LeelaOnVastAI`
- An `lc0` **weights** file (`.pb` or `.pb.gz`)
- An `lc0` binary for the OS that will host your engine

### Local machine requirements

#### macOS user

- AIChessGM installed
- Tailscale installed and logged in
- A terminal available for testing

#### Windows user

- Tailscale installed and logged in
- PowerShell for connectivity checks
- Optional: a Windows chess GUI or `ncat`/WSL for manual UCI testing

#### Home Linux user

- Tailscale installed
- NVIDIA driver working if this machine will host `lc0`
- `systemd` available if you want automatic startup

### Server requirements

- Linux x86_64 / AMD64
- NVIDIA GPU exposed to the OS or container
- Outbound internet access so Tailscale can log in
- Enough disk for:
  - the repo
  - `lc0`
  - the weights file
  - logs and temporary files

### Project defaults used in this repo

This project currently assumes:

- `lc0` Linux x86_64
- Default backend: `cuda-fp16`
- Default server UCI port: `5555`
- Default management/discovery port: `53350`
- Default hostname example: `vast-lc0`

If `cuda-fp16` fails, try:

1. `cudnn`
2. `cuda`

### Build the bridge from the included source package

Inside the extracted setup package, the bridge source lives under:

- `src/`

Build the bridge that matches the machine running the Leela host:

```bash
cd LeelaSetupPackage/src
go build -o uci-bridge-linux ./cmd/uci-bridge
GOOS=windows GOARCH=amd64 go build -o uci-bridge-windows-amd64.exe ./cmd/uci-bridge
GOOS=darwin GOARCH=arm64 go build -o uci-bridge-darwin-arm64 ./cmd/uci-bridge
```

Use the Linux build for Vast.ai and `systemd` examples in this guide. If your Leela host is a Windows machine, build the `.exe` version and point it at your local `lc0.exe`.

---

## 4. How to choose a Vast.ai server for Leela Chess Zero

This is the most important buying decision.

You do **not** need the most expensive GPU on Vast.ai to get a useful `lc0` server.
For a single private engine, a stable and sensibly priced NVIDIA machine is usually better than chasing the highest-end option.

### The short recommendation

Start with:

- **1 NVIDIA GPU**
- **24 GB VRAM or more** if possible
- **Verified** host
- **High reliability**
- Enough disk and CPU RAM that the machine does not feel starved

### Vast.ai search fields that matter most

Vast exposes fields such as:

- `verified`
- `reliability`
- `gpu_ram`
- `cpu_ram`
- `cpu_cores_effective`
- `disk_space`
- `inet_up`
- `inet_down`
- `dlperf`
- `dph_total`

For a first-pass filter, I recommend:

- `verified = true`
- `reliability >= 0.98`
- `gpu_ram >= 16`
- `disk_space >= 30`
- `cpu_ram >= 16`
- `cpu_cores_effective >= 8`
- `inet_up >= 100`
- `inet_down >= 100`
- `num_gpus = 1`

These are **recommended starting thresholds**, not official requirements.

### What to prioritize

#### 1. Reliability and host quality

Prioritize:

- Verified hosts
- High reliability
- Clear pricing
- Persistent storage options

Do not optimize for raw GPU alone if the host is unreliable.

#### 2. GPU class

Inference from this project’s defaults and typical `lc0` use:

- **Budget testing:** 16 to 24 GB NVIDIA GPUs are usually enough
- **Balanced choice:** 24 GB consumer GPUs or datacenter cards such as L4/A10 class are a practical starting point
- **Premium choice:** RTX 4090/5090-class or larger datacenter GPUs if you want more throughput
- **Usually overkill for one private engine:** very expensive multi-GPU or 80 GB datacenter offers unless you know you need them

#### 3. VRAM

More VRAM gives you more headroom, but for a single `lc0` engine you usually do not need the largest card on the marketplace.

#### 4. Network speed

This workload is not bandwidth-heavy, but you still want a responsive machine.
Avoid obviously weak network offers.

#### 5. Disk and persistence

You want enough persistent disk for:

- `lc0`
- weights
- Tailscale state
- bridge logs
- workspace files

#### 6. Region

If two offers are close in price and quality, prefer the one geographically closer to you.
That reduces interactive latency.

### A practical Vast.ai buying checklist

- [ ] NVIDIA GPU
- [ ] Linux-compatible environment
- [ ] Verified host
- [ ] Reliability is high
- [ ] One GPU is enough for your use case
- [ ] Enough persistent disk
- [ ] Enough CPU RAM
- [ ] Enough outbound internet connectivity
- [ ] Pricing makes sense for the amount of time you actually analyze

### Recommendation for new users

For a first success:

- Do **not** start with multi-engine or multi-GPU
- Do **not** start with public port exposure
- Do **not** start with the cheapest questionable offer
- Do start with **one good single-GPU machine** and Tailscale-only access

---

## 5. Set up Tailscale first

Do this before touching `lc0`.

### Why Tailscale is the right default here

- It gives your machines private, encrypted connectivity
- It avoids public UCI ports
- It gives you stable names like `vast-lc0`
- It works well across home networks, cloud machines, and laptops

### Create or confirm your tailnet

1. Create a Tailscale account.
2. Sign in on your local machine.
3. Confirm you can see your machine in the Tailscale admin console.
4. Enable **MagicDNS** if it is not already enabled.

New tailnets generally have MagicDNS enabled by default, but check before relying on hostnames.

### Create an auth key for servers

For automated server joins, create a Tailscale auth key.

Recommended starting choice:

- Use a **one-off auth key** for a single new server
- If you use device approval in your tailnet, consider **pre-approved**
- If you use tagged server identities, create a **tagged auth key**

Important:

- Treat the auth key like a password
- Do not leave it in shell history if you can avoid it
- Prefer environment variables or a file with restricted permissions

---

## 6. Local Tailscale setup by operating system

### macOS

### Install

The current Tailscale client requires **macOS 12.0 or later**.
Tailscale recommends the **standalone macOS variant** as the default install path.

### Sign in

1. Install Tailscale.
2. Follow the onboarding flow.
3. Approve the VPN/network extension prompts.
4. Log in with your chosen identity provider.

### Verify

```bash
tailscale status
tailscale ip -4
```

Expected result:

- Your Mac appears in your tailnet
- You have a Tailscale IPv4 address

Note:

- Some macOS command-line tools such as `host` or `nslookup` may bypass MagicDNS behavior.
- `ping vast-lc0` can work even when those tools do not.

### Windows

### Install

The current Tailscale Windows client requires **Windows 10 or later** or **Windows Server 2016 or later**.

### Sign in

1. Install the `.exe` or `.msi`.
2. Open the Tailscale system tray icon.
3. Choose **Log in**.
4. Finish the browser-based login.

### Verify

In PowerShell:

```powershell
tailscale status
tailscale ip -4
Test-NetConnection vast-lc0 -Port 5555
```

If `tailscale` is not on your `PATH`, use the system tray UI for the login and status confirmation.

### Home Linux

### Install

For mainstream Linux distributions:

```bash
curl -fsSL https://tailscale.com/install.sh | sh
sudo tailscale up
```

### Verify

```bash
tailscale status
tailscale ip -4
```

If this machine will be your long-lived server, think about whether you want:

- a tagged identity
- pre-approval
- key expiry disabled for that server

Only relax key expiry for trusted server nodes you actually control.

---

## 7. Get the right `lc0` binary and weights

For Vast.ai and home Linux, use:

- **Linux x86_64 / AMD64 `lc0`**
- A valid weights file such as `.pb` or `.pb.gz`

This repo’s baseline recommendation is:

- `lc0` stable line: `v0.32.1`
- backend: `cuda-fp16`

If `cuda-fp16` fails:

1. try `cudnn`
2. then try `cuda`

### Before doing anything else on the server

Verify GPU visibility:

```bash
nvidia-smi
```

If `nvidia-smi` fails, stop there and fix the GPU runtime first.

---

## 8. Vast.ai setup: recommended first cloud path

This is the best path for most new users.

### The recommended model

Use:

- a Vast.ai Linux container with persistent `/workspace`
- Tailscale in userspace mode
- this repo’s `up.sh`
- a single private engine on port `5555`

### Recommended base image

This repo’s current Vast-specific guide uses:

- `vastai/base-image_cuda-13.0.2-auto/jupyter`

That is a practical starting point because it gives you:

- a Linux userspace
- GPU access
- a persistent workspace
- a simple place to run the bootstrap script

### Step 1: Launch the instance

When creating the instance:

- choose your GPU offer
- ensure persistent storage is enabled
- ensure you can open a shell or Jupyter terminal
- do **not** rely on public UCI ports

### Step 2: Put the required files in `/workspace`

On the Vast instance, prepare:

- `/workspace/uci-bridge-linux`
- `/workspace/lc0/build/lc0`
- `/workspace/BT4-332.pb` or another weights path
- `/workspace/up.sh`
- `/workspace/.ts_authkey`

From this repo, a practical starting point is:

```bash
cd /workspace
git clone <YOUR_REPO_URL_OR_COPY_FILES> LeelaOnVastAI
cd LeelaOnVastAI

cp out/uci-bridge-persistent-linux /workspace/uci-bridge-linux
chmod +x /workspace/uci-bridge-linux

mkdir -p /workspace/lc0/build
# Put your Linux x86_64 lc0 binary here:
# /workspace/lc0/build/lc0

cp up.sh /workspace/up.sh
chmod +x /workspace/up.sh
```

Then:

- place your weights file at `/workspace/BT4-332.pb`
- or set `WEIGHTS_FILE` later if you prefer another path

Store your Tailscale auth key carefully:

```bash
printf '%s\n' '<YOUR_TS_AUTHKEY>' > /workspace/.ts_authkey
chmod 600 /workspace/.ts_authkey
```

### Step 3: Understand what `up.sh` does

`up.sh` is designed for container-style Linux environments that do **not** use `systemd`.

It:

- installs `tailscale` automatically if the base container does not already have it
- starts `tailscaled` in userspace mode
- restores or creates Tailscale state
- starts `uci-bridge`
- points the bridge at your `lc0` binary and weights
- leaves you with a private engine reachable through Tailscale

### Step 4: Set the Vast On-start command

Use:

```bash
/bin/bash -lc /workspace/up.sh
```

With a persistent volume mounted at `/workspace`, this lets a freshly recreated Vast Jupyter container come back with the same `up.sh`, bridge binary, `lc0`, weights, and auth key without redoing the package install by hand.

### Step 5: Optional environment variables

If you want to override defaults, use environment variables such as:

```bash
TS_HOSTNAME=vast-lc0
LISTEN_ADDR=0.0.0.0:5555
MGMT_ADDR=0.0.0.0:53350
TS_ACCEPT_ROUTES=0
UCI_AUTH_TOKEN=<YOUR_OPTIONAL_APP_TOKEN>
```

If you want localhost-only listeners, use:

```bash
LISTEN_ADDR=127.0.0.1:5555
MGMT_ADDR=127.0.0.1:53350
```

For most users on Vast.ai, the better security model is:

- keep the service private
- rely on Tailscale
- avoid public exposure

### Step 6: Start and verify

After the instance starts:

```bash
tail -n 50 /workspace/logs/tailscaled.log
tail -n 50 /workspace/logs/bridge.log
tailscale --socket=/workspace/tailscaled.sock ip -4
ss -ltnp | grep -E '5555|53350'
```

Healthy signs:

- Tailscale gets an IP
- the bridge is listening
- no fatal `lc0` startup errors

### Step 7: Cost control

Vast.ai costs can accumulate silently if you leave the instance running.

Recommended habits:

- stop the instance when finished
- do not leave a large GPU idle
- start with one machine, not several

---

## 9. Vast.ai alternative: Dockerized path

If you prefer to run the container image directly instead of using the Jupyter + `up.sh` path, this repo also supports a Docker route.

From the repo:

```bash
docker build -t vast-lc0-uci-bridge .
```

Then run it with your weights volume and Tailscale variables.

Use this path if:

- you are comfortable with Docker
- your Vast setup supports the container flow you want
- you want to stay close to the repo’s `Dockerfile` and `entrypoint.sh`

For most brand-new users, the `up.sh` path is simpler to understand and debug.

---

## 10. Home Linux server setup

Use this if you already own a Linux GPU machine and want a server at home.

### Recommended model

Use:

- host-installed Tailscale
- host-installed `lc0`
- `uci-bridge` started by `systemd`

This is the cleanest long-lived home setup.

### Step 1: Verify the GPU runtime

```bash
nvidia-smi
```

### Step 2: Install Tailscale

```bash
curl -fsSL https://tailscale.com/install.sh | sh
sudo tailscale up --hostname=home-lc0
```

If you want a server-style identity, you can use an auth key and tagging instead of interactive login.

### Step 3: Prepare files

A practical layout is:

- `/opt/lc0/lc0`
- `/opt/lc0/weights.pb.gz`
- `/usr/local/bin/uci-bridge-linux`

From the setup package you can either:

- build your own bridge binary from `LeelaSetupPackage/src/`, or
- copy the included Linux binary

Example using the included binary:

```bash
sudo cp /Users/james/LeelaOnVastAI/out/uci-bridge-persistent-linux /usr/local/bin/uci-bridge-linux
sudo chmod +x /usr/local/bin/uci-bridge-linux
```

### Step 4: Create a systemd unit

Create:

- `/etc/systemd/system/lc0-cloud.service`

Example:

```ini
[Unit]
Description=LC0 Cloud UCI Bridge
Wants=network-online.target
Requires=tailscaled.service
After=network-online.target tailscaled.service

[Service]
Type=simple
WorkingDirectory=/opt/lc0
User=root
Group=root

ExecStartPre=/usr/bin/test -x /usr/local/bin/uci-bridge-linux
ExecStartPre=/usr/bin/test -x /opt/lc0/lc0
ExecStartPre=/usr/bin/test -f /opt/lc0/weights.pb.gz

ExecStart=/usr/local/bin/uci-bridge-linux --listen 127.0.0.1:5555 --mgmt-listen 127.0.0.1:53350 --lc0 /opt/lc0/lc0 --weights /opt/lc0/weights.pb.gz --backend cuda-fp16 --engine-name lc0-cloud

Restart=always
RestartSec=3
StartLimitIntervalSec=0

[Install]
WantedBy=multi-user.target
```

### Step 5: Enable and start

```bash
sudo systemctl daemon-reload
sudo systemctl enable lc0-cloud
sudo systemctl start lc0-cloud
sudo systemctl status lc0-cloud --no-pager
```

### Step 6: Verify

```bash
journalctl -u lc0-cloud -n 100 --no-pager
ss -ltnp | grep -E '5555|53350'
tailscale status
```

Recommended security model on home Linux:

- bind locally to `127.0.0.1`
- use Tailscale for access
- avoid public inbound exposure unless you know exactly why you need it

---

## 11. How to connect from your client machine

Once the server is healthy, you need only three things:

- the hostname, for example `vast-lc0` or `home-lc0`
- the UCI port, usually `5555`
- the optional auth token if you enabled one

### Mac client test

From Terminal:

```bash
nc vast-lc0 5555
```

Then type:

```text
uci
isready
```

Expected:

- `uciok`
- `readyok`

If you enabled app-layer auth:

```text
AUTH <YOUR_AUTH_TOKEN>
uci
isready
```

### Windows client test

First check reachability:

```powershell
Test-NetConnection vast-lc0 -Port 5555
```

If you want a full interactive UCI test on Windows, use one of:

- `ncat`
- WSL
- another chess GUI that can talk to the remote engine

### Linux client test

```bash
nc vast-lc0 5555
```

Then:

```text
uci
isready
```

### AIChessGM-specific note

For an AIChessGM build that supports remote-engine connections, the values you need are:

- host: `vast-lc0` or `home-lc0`
- port: `5555`
- optional auth token

If you are using a legacy management/discovery flow, the management port is:

- `53350`

---

## 12. Troubleshooting

### Problem: Tailscale node does not show up

Check:

- the auth key is valid
- the server has outbound internet
- `tailscaled` actually started
- device approval is not blocking the node

### Problem: `weights not found`

Check:

- the weights path is correct
- the file is actually present on disk
- the service account can read it

### Problem: `failed to start lc0`

Check:

- the `lc0` path is correct
- the file is executable
- the binary matches Linux x86_64

### Problem: backend failure on startup

Check:

- `nvidia-smi`
- CUDA runtime compatibility
- backend selection

Fallback order:

1. `cuda-fp16`
2. `cudnn`
3. `cuda`

### Problem: hostname does not resolve

Check:

- both machines are on the same tailnet
- MagicDNS is enabled
- the node name is what you think it is

Fallback:

- use the Tailscale IP address directly

### Problem: connection refused on `5555`

Check:

- the bridge is listening
- the right port is configured
- local firewall rules are not blocking it
- the service is bound where you think it is bound

### Problem: Vast bill keeps running

Check:

- whether the instance is still running
- whether you actually stopped it in the Vast dashboard

Do not assume process exit alone stops billing.

---

## 13. Security recommendations

- Prefer **Tailscale-only access**
- Avoid public UCI ports unless you have a specific reason
- Use a **one-off auth key** when possible
- Use **tagged nodes** for long-lived servers if you have ACLs set up
- Keep the auth key out of shell history
- Restrict file permissions on any key file
- Use Tailscale ACLs so only your own devices can reach the engine host

---

## 14. Recommended first-time build

If you want the highest chance of success:

1. Install Tailscale on your Mac.
2. Launch one Vast.ai NVIDIA instance with persistent `/workspace`.
3. Copy in:
   - `uci-bridge-persistent-linux`
   - Linux `lc0`
   - one weights file
   - `up.sh`
4. Store the Tailscale auth key in `/workspace/.ts_authkey`.
5. Set the Vast On-start command to `/bin/bash -lc /workspace/up.sh`.
6. Wait 45 to 60 seconds.
7. Test with `nc vast-lc0 5555`.
8. Only after that, connect your GUI or remote-engine client.

This is the cleanest new-user path.

---

## 15. Official references

Use these to verify product details that may change over time:

- Vast.ai documentation:
  - Search offers and offer fields: [https://docs.vast.ai/search/](https://docs.vast.ai/search/)
  - Create instances: [https://docs.vast.ai/instances/create/](https://docs.vast.ai/instances/create/)
  - Docker execution environment: [https://docs.vast.ai/instances/docker/](https://docs.vast.ai/instances/docker/)
- Tailscale documentation:
  - Auth keys: [https://tailscale.com/kb/1085/auth-keys/](https://tailscale.com/kb/1085/auth-keys/)
  - MagicDNS: [https://tailscale.com/kb/1081/magicdns/](https://tailscale.com/kb/1081/magicdns/)
  - Install on macOS: [https://tailscale.com/docs/install/mac](https://tailscale.com/docs/install/mac)
  - Install on Windows: [https://tailscale.com/docs/install/windows](https://tailscale.com/docs/install/windows)
  - Install on Linux: [https://tailscale.com/docs/install/linux](https://tailscale.com/docs/install/linux)

---

## 16. Final advice

Do not overbuild the first version.

For your first success, keep it to:

- one server
- one engine
- one weights file
- one hostname
- one Tailscale tailnet

Once that works, you can add:

- more engine profiles
- a second server
- aggressive `lc0` tuning
- additional AIChessGM integration work

## 17. Future possibility: Ollama on Vast.ai

AIChessGM already supports local and remote-style Ollama workflows internally, so in the future it may make sense to support running an Ollama model on a Vast.ai box that is also being used for Leela.

For now, this is a **low-priority future task**, not a recommended setup path.

Why it is lower priority:

- using an OpenAI API key is much simpler
- using an OpenAI API key is usually faster to set up
- a shared Vast GPU may need to split memory and compute time between `lc0` and the language model
- a combined Leela + Ollama cloud box is more complex to document, support, and tune

Current recommendation:

- use AIChessGM with an OpenAI API key for AI features
- treat Ollama on Vast.ai as an advanced future option rather than a default workflow
