Run Laboratory OS
Laboratory OS runs as a Docker container. See Install Dependencies for setup instructions.
Basic Usage
docker run -d --restart unless-stopped \
--gpus all \
--pid host \
--name laboratory \
-e UPLINK_DEVICE_TOKEN='your-device-token' \
-v laboratory_os_workspace:/workspace \
openlaboratoryorg/laboratory-os
The example uses an Uplink account device token. Create one in the Uplink console, then start the container. It establishes the tunnel and logs the assigned desktop URL.
Options Reference
| Flag | Description |
|---|---|
--gpus all | Pass through all NVIDIA GPUs. Requires NVIDIA Container Toolkit. |
-e TS_AUTHKEY=...-e TS_HOSTNAME=... | Tailscale mode. Join the station to a tailnet. The auth key works on its own or alongside either Uplink mode; the hostname is optional. |
-e UPLINK_DEVICE_TOKEN=... | Managed mode. A host-bound, serve-only token created in the Uplink console for the account that should own this Laboratory instance. |
-e UPLINK_EDGE=...-e UPLINK_EDGE_API_KEY=... | Self-hosted mode. The Uplink edge domain and its static admission key. Use these together instead of a managed device token. |
-v /host/path:/workspace | Bind mount for persistent storage. All app data and models are written to /workspace. |
-v laboratory_os_workspace:/workspace | Named Docker volume for persistence — simpler than a bind mount. |
-d | Run detached (in the background). |
--restart unless-stopped | Auto-restart on failure or host reboot. |
--name laboratory | Assign a name for easy docker stop laboratory / docker start laboratory. |
--pid host | Share the host PID namespace — required for process monitoring inside the container. |
Choosing an Image
| Tag | Architecture | Base | Use when |
|---|---|---|---|
:latest | amd64 + arm64 | Ubuntu 22.04 | Default for most setups. Docker pulls the matching CPU image for your host. |
:amd64 | amd64 | Ubuntu 22.04 | Pin x86_64 hosts explicitly. GPU passthrough works via NVIDIA Container Toolkit. |
:arm64 | arm64 | Ubuntu 22.04 | Pin ARM hosts explicitly — Apple Silicon VMs, Raspberry Pi, etc. |
:cuda-12.8 / :cuda-12 / :cuda | amd64 | CUDA 12.8 + Ubuntu 22.04 | Apps that compile CUDA extensions at install time. |
:cuda-13.2 / :cuda-13 | amd64 | CUDA 13.2 + Ubuntu 22.04 | Apps requiring the latest CUDA toolkit. |
The :latest image is the right choice for most setups and now resolves to either the amd64 or arm64 CPU image automatically. The CUDA-bundled tags remain amd64-only, are larger, and are required for some apps that build native extensions (e.g. bitsandbytes, flash-attention) during installation. If an app install fails with a CUDA compile error, switch to a CUDA image.
For example, pass a tag to run a CUDA-bundled image. Everything else stays the same:
docker run -d --restart unless-stopped \
--gpus all \
--pid host \
--name laboratory \
-e UPLINK_DEVICE_TOKEN='your-device-token' \
-v laboratory_os_workspace:/workspace \
openlaboratoryorg/laboratory-os:cuda-12.8
Docker Compose
A sample docker-compose.yml for a persistent GPU setup:
services:
ol:
image: openlaboratoryorg/laboratory-os:latest
restart: unless-stopped
pid: host
environment:
- UPLINK_DEVICE_TOKEN=your-device-token
volumes:
- type: volume
source: laboratory_os_workspace
target: /workspace
gpus: all # Remove for non-GPU mode
volumes:
laboratory_os_workspace:
Run it:
docker compose up -d
To use a CUDA image, change the
image:line toopenlaboratoryorg/laboratory-os:cuda-12.8(or whichever tag you need).
To use a bind mount instead of a named volume, change the service’s volume entry to
- /your/host/path:/workspaceand remove the top-levelvolumes:block.
To use a custom Uplink edge instead, replace
UPLINK_DEVICE_TOKENwithUPLINK_EDGE=your-edge-domainandUPLINK_EDGE_API_KEY=your-edge-key.
To join a tailnet, add
TS_AUTHKEY=your-tailscale-auth-key. This works by itself or alongside either Uplink configuration.
Self-Hosted Uplink Edge
The other supported path is a custom key-mode Uplink edge. Set UPLINK_EDGE and
UPLINK_EDGE_API_KEY together instead of UPLINK_DEVICE_TOKEN:
docker run -d --restart unless-stopped \
--gpus all \
--pid host \
--name laboratory \
-e UPLINK_EDGE='your-edge-domain' \
-e UPLINK_EDGE_API_KEY='your-edge-key' \
-v laboratory_os_workspace:/workspace \
openlaboratoryorg/laboratory-os
In this mode the lab does not log into an Uplink account or appear in an account’s Devices list. The lab root is protected by the access token printed during boot.
Tailscale
Pass a Tailscale auth key to join the station to your tailnet. It can be the only remote-access method or run alongside either Uplink mode:
docker run -d --restart unless-stopped \
--gpus all \
--pid host \
--name laboratory \
-e TS_AUTHKEY='your-tailscale-auth-key' \
-v laboratory_os_workspace:/workspace \
openlaboratoryorg/laboratory-os
Tailscale access follows your tailnet ACLs. Set TS_HOSTNAME if you want to
choose the station’s tailnet hostname.
CPU-Only Mode
Drop --gpus all to run without a GPU:
docker run -d --restart unless-stopped \
--pid host \
--name laboratory \
-e UPLINK_DEVICE_TOKEN='your-device-token' \
-v laboratory_os_workspace:/workspace \
openlaboratoryorg/laboratory-os
The desktop, tunnel, and app management all work identically — the difference is purely in AI inference performance. CPU-only mode is useful for:
- Coding agent environments — Run coding agents against external LLM APIs while keeping their default files and tools inside the container. Treat the container as a convenience boundary, not a sandbox for hostile code.
- Cloud dev environments — Run VS Code and a terminal from any remote server, no GPU required.
- Jupyter notebooks — Data science, scripting, anything not GPU-bound.
- Testing your setup — Verify your Uplink credentials, tunnel, and desktop before moving to a GPU host.
- Small LLMs — Llama 3.2 3B or Phi-3 Mini run at usable speeds on CPU (16+ core machines recommended).
Note: Most image-generation apps require a GPU. LLM inference via Ollama and llama.cpp works on a CPU but is significantly slower.