Skip to content
OpenRelay is in early access, and the /v1 API is stable. New capabilities ship in the changelog.
GuidesProviders

Provider nodes

Hardware requirements for VM and pod nodes, GPU setup, health checks, and the full lifecycle of your provider hardware.

This page covers what a provider box needs, how each runtime sets up GPUs, how to confirm a node is healthy, and how nodes behave over their lifetime. To bring your first node online, start with Providers: onboarding is one command. Everything here is handled for you by that command; it's documented so you know what's happening and how to operate the box afterwards.

Two node types, two sets of requirements

Read Two node kinds, detected automatically before buying or preparing hardware. A VM node (qemu) needs bare metal, KVM and IOMMU; a pod node (runc) needs none of those and runs happily inside a virtualized guest. The installer detects which one the box is; the requirements below are split accordingly. A GPU container you rent from another market is neither: onboard it as an Interruptible node.

Hardware requirements

Both node types

RequirementDetail
OSUbuntu 22.04 or 24.04 LTS, with root / sudo. This is what we test and support; the installer does not enforce a version, and it has dnf fallbacks, but anything else is unsupported.
NetworkOutbound HTTPS (443). The node dials out, so no inbound ports are required. Outbound UDP must also work: the data-plane tunnel is QUIC and the overlay uses UDP/4242. A security group that blocks outbound UDP produces a node that enrolls fine and then never carries traffic.
Toolscurl and sha256sum must already exist; the installer pulls jq, tar, unzip, pciutils and installs Docker itself.
Subnet192.168.249.0/24 must be free. The control plane allocates guest IPs from it (hardcoded), so a host already using that range breaks workloads in ways that look random.

VM nodes (qemu)

RequirementDetail
Bare metalRequired: passthrough cannot work in a normal cloud guest.
CPU virtualizationIntel VT-x / AMD SVM. /dev/kvm must exist.
vhost-net/dev/vhost-net must exist: the vhost_net kernel module, which stock Ubuntu kernels ship, serves every VM's network.
IOMMUIntel VT-d / AMD AMD-Vi, enabled in BIOS (set Enabled, not Auto).
GPUNVIDIA or AMD. CPU-only VM nodes are also welcome.
RAMNo minimum is enforced, but RAM is what caps how many VMs a node can host: the scheduler fit-checks each VM's memory against the node's, and a box that runs out simply stops being placed on. 32 GB is a realistic floor, 64 GB+ recommended.
DiskThe health check fails below 20 GB free on / and warns below 50 GB; for VM image storage it fails below 50 GB and warns below 200 GB.

Pod nodes (runc)

RequirementDetail
VirtualizationBare metal or a VM guest. No KVM, no IOMMU, no VT-d needed.
GPU driverYou install it. The bootstrap does not install a GPU driver, and a pod node is unusable without one: the vendor's host driver has to be live first, so nvidia-smi (NVIDIA) or amd-smi list (AMD) exits 0 and names every GPU before you enroll. Container access to the GPUs is set up for you, per vendor (see Pod nodes: native driver below).
GPU visibilityEvery GPU you intend to sell has to show up in lspci and in the vendor's tool (nvidia-smi, or amd-smi list). On a guest, that means passthrough is already configured by your hypervisor. AMD GPUs must sit on the amdgpu driver, and one OAM module is one GPU: compute partitions (CPX, DPX, QPX) are not sold, so the preflight requires every GPU in SPX / NPS1.
GPU modelThe GPU's PCI id must be in the platform catalog, otherwise the node enrolls but sells nothing. The preflight tells you before you enroll.
DiskThe preflight fails below 200 GB free for the weights cache (/var/lib/openrelay) and 100 GB for the Docker image store (/var/lib/docker).
RAMNo minimum is enforced. Size it for the models you intend to serve: weights are staged through host memory and each concurrent pod holds its own working set.

Remote or separate storage must be mounted before you enroll

If the weights cache or Docker store is meant to live on a separate NVMe or a remote/network mount, mount it first and make it boot-ordered. The platform creates the directory if it is missing, so an unmounted volume silently lands on your boot disk. The node keeps working, slowly, and the only symptom is a performance cliff.

Enroll such a node with WEIGHTS_CACHE_REQUIRE_MOUNT=1 so the node refuses to stage weights onto the boot disk instead of quietly demoting itself. In /etc/fstab use _netdev, nofail, and x-systemd.requires-mounts-for so a late mount cannot lose the race against Docker and Nomad.

GPU setup

VM nodes: passthrough (QEMU + VFIO)

The one-command install configures passthrough for you: you don't hand-edit GRUB or modprobe files. On a GPU box it:

  1. Detects your NVIDIA/AMD GPUs with lspci (works even with no driver installed).
  2. If they aren't passthrough-ready, enables IOMMU on the kernel command line, binds each GPU (and its IOMMU-group siblings) to vfio-pci, and installs a boot-time service (openrelay-vfio-bind.service) so the binding survives reboots.
  3. Asks you to reboot and re-run the exact same command (the installer exits 75). The node is intentionally not enrolled until passthrough actually works: we never advertise a GPU that can't run a VM.

If, after a reboot, the GPUs still aren't bound, enable virtualization + IOMMU in your BIOS/UEFI, then reboot and re-run:

  • Intel: enable VT-x and VT-d.
  • AMD: enable SVM and IOMMU (set to Enabled, not Auto).

A passthrough GPU leaves the local console

Once a GPU is bound for passthrough it no longer drives a local display. Manage the box over SSH, serial, or IPMI, not a monitor.

The unit of allocation is the IOMMU group: GPUs that share a group are always passed to a VM together. For full-node (all-GPU) allocations, NVSwitches are passed through too so NVLink works. This is automatic.

Pod nodes: native driver, no VFIO

A pod node does the opposite of the above, and does it automatically:

  • The host GPU driver is kept. The VFIO conversion self-skips when a host driver (nvidia or amdgpu) already owns the GPUs, so your driver is never torn down.
  • GPUs reach a container per vendor. On NVIDIA the container toolkit is installed and wired into Docker, which is what serves the --gpus flag. AMD has no such toolkit: each pod is granted /dev/kfd plus the render node and card node of its own GPUs, resolved from each GPU's PCI address. Either way the node runs a userns-remapped Docker daemon and the platform bridge.
  • No IOMMU groups are required. Cloud and virtualized guests usually expose none; the node then advertises one allocatable unit per GPU, which is exactly how pods consume them.
  • The vfio-gpu Nomad plugin is not installed, because it would compete with the container runtime for the same GPUs.

Each pod gets one GPU

A pod is scheduled onto a single GPU unit. An 8-GPU box therefore sells 8 independent single-GPU pods, not one 8-GPU pod. That is a throughput consideration, not a limitation on how many GPUs you can bring.

Check node health

Run the check that matches your node type. Running the wrong one is the most common source of confusing output.

sudo openrelay-node-doctor

It prints PASS / FAIL per check and a final verdict:

  • Agents & tunnel: nebula, nomad, and node-agent running; auto-update timer enabled.
  • Virtualization: /dev/kvm and /dev/vhost-net present.
  • GPU passthrough: IOMMU active and per-IOMMU-group VFIO readiness, ending with N/M GPU unit(s) ready to rent.
  • Disk: enough free space for VM base images.

A green doctor means the control plane will advertise the node's GPU units.

  • If a unit shows WEDGED, a GPU fell off the bus (the D3cold reset bug): power-cycle the host (a soft reboot may not clear it).
  • If a unit isn't bound to vfio-pci, run sudo systemctl restart openrelay-vfio-bind or re-run the bootstrap.

Node lifecycle

Two credentials (don't conflate them)

Provisioning token (otk_…)Durable identity
WhatShort-lived bootstrap keyData-plane mTLS cert + durable node token
Lifetime24 hours; enrolls any number of nodes until thenLives as long as the node
On disk?No: passed to the installer, used, discardedYes, under /etc/vectorlay/
Used forEnrollment onlyEvery gateway tunnel + node-agent self-update

Everything after enrollment runs on the durable identity, so the provisioning token expiring later is by design and harmless.

Reboots & power loss

systemd brings nebula, nomad, and node-agent back at boot; they read their credentials from disk and rejoin automatically. On VM nodes the VFIO bind service re-binds the GPUs before Nomad starts. No action needed.

Automatic updates

The node-agent keeps itself current via a systemd timer (hourly, with up to 20 minutes of jitter, first run 10 minutes after boot), authenticated with the durable node token. Updates drain in-flight HTTP/SSH first, install atomically, and roll back on failure, so live sessions survive.

  • Opt out per node: enroll with NODE_AGENT_AUTOUPDATE=0, or sudo systemctl disable --now node-agent-update.timer.
  • Force a check now: sudo systemctl start node-agent-update.service (logs: journalctl -u node-agent-update).

Recycle / re-enroll

Re-running the onboarding one-liner on an existing box is safe and idempotent: the node keeps its identity (same node ID and overlay IP), its token is rotated, no quota is consumed, and nothing referencing the node (VMs, pods) breaks. Use it to repair a node or roll it onto new config.

The node kind follows the hardware

The installer detects the node kind from the box's shape, so re-enrolling the same hardware keeps the same runtime. Converting a box between VM and pod means changing the hardware's story: undoing the vfio-pci binding and installing an NVIDIA driver to turn a VM host into a pod node (VM hosts are NVIDIA-only), so a reimage is usually the cleaner path.

Take a node offline

This is the path for a temporary break: maintenance, a reboot, a move. Stop the node's agents:

sudo systemctl stop nomad nebula node-agent

Nomad stops scheduling to it and the data-plane tunnel closes (in-flight work drains first). The node stays enrolled, and VM and pod rentals on it pause while it is away. Start the services again (or reboot) to bring it back, and those rentals resume. A managed Kubernetes worker on the node does not pause: it ends. A node away for more than 24 hours is decommissioned automatically, which ends its rentals; re-run the onboarding one-liner to bring it back after that.

Decommission a node

To retire a node permanently, choose Decommission in the node's row menu in the Nodes view of the dashboard, or set its status to removed via the API:

curl -fsSL -X PATCH -H "Authorization: Bearer $VL_KEY" \
  -H "Content-Type: application/json" -d '{"status":"removed"}' \
  https://api.openrelay.inc/v1/orgs/$VL_ORG/provider/nodes/$NODE_ID

This frees the node's workloads and GPU units. A decommission isn't a one-way door: re-running the onboarding one-liner on a removed node auto-recovers it.

Decommission with notice, in the same row menu where it is enabled for your organization, gives renters time first. Pick a deadline from 5 minutes to 7 days out: the node takes no new rentals from the moment you schedule it, rentals already on it keep running until the deadline, and at the deadline they end and the node is removed, the same end state as Decommission. Cancel it from the row any time before the deadline.

Clean offboard (decommission the hardware)

The steps above retire the node in the control plane. Clearing the node-local state is a separate, deeper step you only need when you're decommissioning the hardware for good or moving the box to a different environment and re-onboarding it.

A node's durable identity, Nomad client state, overlay certificates, and config are written to local disk at enrollment. If a box is re-onboarded (or pointed at a different environment) without clearing this, the fresh enrollment collides with the stale identity: the node's Nomad client is rejected and it gets stuck in pending, never coming online. A clean offboard wipes that node-local state so a new enrollment provisions cleanly.

This removes the node from the fleet

Stopping the agents and clearing state terminates any VMs and workloads currently running on the node. If those must be preserved, drain or migrate them first. Run every command below as root.

Stop the OpenRelay agents

sudo systemctl stop nomad nebula node-agent node-agent-update.timer

Clear Nomad client state, config, and TLS material

The stale Nomad client identity is the main thing that blocks re-onboarding.

sudo rm -rf /opt/nomad/data
sudo rm -rf /etc/nomad /etc/nomad.d
sudo rm -f  /etc/systemd/system/nomad.service.d/intro.conf

Clear the overlay (Nebula) identity

sudo rm -rf /etc/nebula

Clear the OpenRelay node identity

The durable node token, data-plane certificates, signing key, and config.

sudo rm -rf /etc/vectorlay/dataplane
sudo rm -f  /etc/vectorlay/node.token /etc/vectorlay/node-agent-update.env \
            /etc/vectorlay/identity.key /etc/vectorlay/vfio-attempts

(Optional) Remove per-VM overlays and seed data

Hygiene only. Base images can be left in place: they're checksum-verified and reused. On a pod node these paths are typically empty; the equivalent hygiene step is clearing the weights cache under /var/lib/openrelay/weights.

sudo rm -rf /var/lib/vectorlay/vms/* /var/lib/vectorlay/seed/*

Reload systemd

sudo systemctl daemon-reload

Which steps are essential

Steps 1 to 4 are required: leaving any of that stale identity or client state on disk is what causes the stuck-pending problem on re-onboarding. Step 5 is optional hygiene. If you're doing a full OS reimage instead, the fresh image is already a clean slate, so steps 1 to 5 are unnecessary.

Re-onboarding after a clean offboard

Once the node-local state is cleared, re-onboard the box with the standard one-command installer. Any provisioning token that is still within its 24-hour lifetime works; mint a fresh one if the old token has expired or you revoked it:

curl -fsSL "https://api.openrelay.inc/v1/provider/bootstrap?token=<provisioning-token>" | sudo bash

The installer detects the node kind and GPUs on the box, so no extra params are needed. See Providers for how to mint a token and the full set of bootstrap options.

Troubleshooting

SymptomCause / fix
403 NOT_A_PROVIDERThe org isn't an approved provider yet.
401Bad, missing, or expired API key / provisioning token.
Install prints nothing ("0 logs")curl -fsSL … | sudo bash swallows HTTP errors, so an empty script runs. Re-run with curl -sS -w 'HTTP %{http_code}\n' … to see the real status.
Installer exits 75Not a failure: the box was staged but needs a reboot before passthrough works. Reboot and re-run the same command.
checksum mismatch / 502 ARTIFACTA stale artifact. Re-run; artifacts are re-fetched and verified each run.
409 HOSTNAME_CONFLICTAnother node in the org already uses this hostname. Node identity is per box (not per hostname), so this means two different machines share a name. Rename one and re-run.
GPUs not bound to vfio-pci after reboot (VM node)Enable VT-d / IOMMU in BIOS; sudo systemctl restart openrelay-vfio-bind; reboot and re-run.
A GPU unit shows WEDGEDThe GPU fell off the bus (D3cold reset bug). Power-cycle the host.
Pod node enrolled but sells nothingUsually an unrecognized GPU model, GPUs sharing an IOMMU group, or GPUs bound to vfio-pci. Run sudo openrelay-pod-node-preflight.
Pod node is slow / weights re-downloadThe cache volume probably isn't mounted, so the boot disk is being used. See the storage callout above.
no /dev/kvm or no /dev/vhost-net on a pod nodeExpected: pod nodes aren't VM hosts. Use openrelay-pod-node-preflight, not openrelay-node-doctor.

See Providers for onboarding and Authentication for API keys.

On this page