Install the worker
Self-hosting Pendra is three steps: install the worker, paste a worker key from the console, then install a model from the catalogue. The inference runtime is built into the worker, so it serves chat, embeddings, image generation, and audio transcription with nothing else to install.
1. Install the worker
The Pendra worker is a single binary with the inference runtime built in — install it and it's ready to serve models.
On a Linux server, the quickest install is one command — it detects your
GPU, installs the matching package, and prompts you to run
pendra setup:
# Linux — auto-detects your GPU and installs the matching package
curl -sSL https://get.pendra.ai/worker | sh
pendra setup step. The token is single-use and
expires within the hour; generate a fresh command for each machine. The
worker appears in the console as soon as it connects. Installing one worker
key on several machines works too — each machine becomes its own worker
(see Worker IDs).
On macOS and Windows — or if you'd rather install graphically — open the Pendra console → Workers → Add worker. It auto-detects your OS and serves the correct installer with its matching SHA-256. The per-OS guidance below covers what each installer does.
macOS (Apple Silicon)
Download Pendra-<v>-arm64.dmg from the console, open it,
and drag Pendra into /Applications. Launch it
and the menu-bar app starts the headless daemon, registers a LaunchAgent so
both start at login, and opens a browser-based setup wizard for your worker
key.
To enter or change your worker key later, open the Pendra menu-bar icon and choose Set up Pendra… (or Settings… once a key is set) — it reopens the same setup flow.
The pendra command is installed alongside the app so you can
run pendra status from a terminal. If your terminal reports
command not found, choose Install command-line
tool from the same menu and open a new terminal. macOS asks for
your password the first time, because the command is linked into a
system directory.
Intel Macs are no longer supported — the in-process Metal path needs Apple Silicon.
Windows
Download PendraSetup-<v>.exe from the console and run it.
It needs 64-bit Windows 10 / Server 2016 or later, and won't
install on anything older.
The signed installer needs no admin rights. Everything the worker needs to
run is bundled — including the CUDA runtime — so there's no separate
runtime to download.
The installer asks for your worker key, which connects this worker to your Pendra organisation. Copy it from the Workers page in the Pendra console and paste it in; when the installer finishes, the worker starts and appears in the console. There's no need to restart Windows. If you don't have the key to hand, leave the field blank and Pendra asks for it the first time it opens. If this PC already has a worker key from an earlier install, the installer keeps it and doesn't ask.
nvidia-smi (it
should list your GPU and a CUDA version). If the driver is missing or older
than R580, the installer won't let you choose the CUDA option — it says so
and points you at the one that will work.
- CUDA — NVIDIA GTX 16-series, RTX 20/30/40/50-series, and the T4 and A / L / H data-centre cards, with driver R580 or newer.
- Vulkan — AMD, Intel, and older NVIDIA cards (GTX 10-series and earlier, V100, P100 — anything below compute capability 7.5). Needs your GPU vendor's graphics driver installed, which is what provides Vulkan.
- CPU only — works anywhere, no GPU needed.
/FORCEGPUVARIANT (or set
PENDRA_SKIP_GPU_CHECK=1) to install your choice anyway.
To install without the wizard, for example from a deployment tool, set
the PENDRA_WORKER_KEY environment variable and run the
installer with /VERYSILENT:
$env:PENDRA_WORKER_KEY = "<your worker key>"
$setup = Start-Process .\PendraSetup-<v>.exe -Wait -PassThru -ArgumentList "/VERYSILENT", "/SUPPRESSMSGBOXES", "/NORESTART"
Remove-Item Env:PENDRA_WORKER_KEY
$setup.ExitCode # 0 = installed
The key is read from the environment, not from the command line, so it is
never written to the installer's log. If the value isn't a worker key, the
installer stops with a non-zero exit code before installing anything. The
installer never replaces a worker key that is already saved on the PC, so
upgrades are safe to run with or without the variable; to change a saved
key, use Settings… in the Pendra tray menu or
pendra config set private_key <key>. A silent install doesn't open
Pendra when it finishes: the worker starts the next time you sign in, or
as soon as you open Pendra from the Start menu.
Need to enter or change your worker key later? Open the Pendra tray icon
and choose Set up Pendra… (or Settings…
once a key is set) — it reopens the same setup flow. To remove Pendra,
uninstall it from Settings → Apps (or Add/Remove
Programs). Your downloaded models and settings are kept in
C:\ProgramData\Pendra so a re-install picks up where you left
off — delete that folder by hand if you want to remove them and reclaim
the disk space.
On a PC shared by several Windows accounts, C:\ProgramData\Pendra
belongs to the first account that ran Pendra. Any other account keeps its
own settings and models in %USERPROFILE%\.pendra instead, so
each account downloads the models it uses. Uninstalling Pendra from that
account removes its %USERPROFILE%\.pendra folder.
Linux server (headless)
The install command above picks the right package automatically. To choose
yourself, three GPU variants ship side-by-side: the default CPU baseline, a
CUDA variant for NVIDIA hosts, and a Vulkan variant for AMD / Intel hosts.
Both arm64 and amd64 are available — install via
the package repository (recommended) or by downloading a single file from
the console.
pendra doctor will tell you so.
pendra-cuda needs the CUDA 13 runtime. It
requires NVIDIA driver R580 or newer and the
CUDA 13 runtime, which the package does not include —
install it from
NVIDIA's
installation guide. The package checks for libcudart.so.13
/ libcublas.so.13 at install time and refuses to install if
they're missing, so you never end up with a worker that can't use the GPU.
Confirm the driver is loaded with nvidia-smi — it should list
your GPU and a CUDA version. A host with no driver runs the worker
CPU-only.
pendra-vulkan needs a Vulkan driver. It runs on
NVIDIA, AMD, and Intel GPUs with no CUDA dependency, but your GPU vendor's
Vulkan driver has to be installed — on Debian / Ubuntu that's
sudo apt install -y mesa-vulkan-drivers libvulkan1 for AMD and
Intel, or the proprietary NVIDIA driver, which brings its own. The package
checks for both the Vulkan loader and a vendor driver at install time and
refuses to install if either is missing. Confirm with
vulkaninfo --summary — it should list your GPU. If your driver
is installed somewhere the standard paths don't cover, set
PENDRA_SKIP_VULKAN_CHECK=1 to bypass the check.
Don't want a GPU package at all? The CPU-only pendra package
always works and has no driver requirements. If your CUDA runtime lives
somewhere ldconfig doesn't index, set
PENDRA_SKIP_CUDA_CHECK=1 to bypass that check, then confirm the
GPU backend loaded with pendra doctor. If the runtime still
can't see any GPU — usually a missing or not-loaded driver —
pendra doctor reports a failure ("no GPU device found")
instead of silently running on the CPU, and tells you how to fix it.
Package repository (recommended — auto-updates)
Add the Pendra repository once and your package manager keeps the
worker current: a later apt upgrade or dnf upgrade
pulls new versions like any other system package. Both arm64
and amd64 are served, and the repository is signed.
Upgrading restarts the running worker onto the new binary
automatically — no manual systemctl restart or reboot, and
your worker key and config are untouched.
# Debian / Ubuntu — add the Pendra apt repository once
sudo curl -fsSL https://get.pendra.ai/pendra-archive-keyring.gpg \
-o /usr/share/keyrings/pendra-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/pendra-archive-keyring.gpg] https://get.pendra.ai/apt stable main" \
| sudo tee /etc/apt/sources.list.d/pendra.list
# Install the variant that matches your GPU
sudo apt update
sudo apt install pendra # CPU baseline
sudo apt install pendra-cuda # NVIDIA (CUDA)
sudo apt install pendra-vulkan # AMD / Intel (Vulkan)
# Later: sudo apt update && sudo apt upgrade pulls new worker versions
sudo pendra setup
# Fedora / RHEL / openSUSE — add the Pendra yum repository once
sudo tee /etc/yum.repos.d/pendra.repo <<'EOF'
[pendra]
name=Pendra Worker
baseurl=https://get.pendra.ai/yum/$basearch
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://get.pendra.ai/RPM-GPG-KEY-pendra
EOF
# Install the variant that matches your GPU
sudo dnf install pendra # CPU baseline
sudo dnf install pendra-cuda # NVIDIA (CUDA)
sudo dnf install pendra-vulkan # AMD / Intel (Vulkan)
# Later: sudo dnf upgrade pulls new worker versions
sudo pendra setup
Direct download (single file)
Grab the package for your distro and GPU from the console and install it by
path. It registers the Pendra repository for you, so later upgrades are the
usual sudo apt upgrade pendra / sudo dnf upgrade pendra
— no need to download the file again. (If the installer can't register the
repository — say curl is missing — add it manually with the
commands in the Package repository section above.)
Debian / Ubuntu (.deb)
# Debian / Ubuntu — pick the variant that matches your GPU
sudo apt install ./pendra_<v>_linux_amd64.deb # CPU baseline
sudo apt install ./pendra-cuda_<v>_linux_amd64.deb # NVIDIA (CUDA)
sudo apt install ./pendra-vulkan_<v>_linux_amd64.deb # AMD / Intel (Vulkan)
# Paste your worker key — setup writes /var/lib/pendra/config.yaml
# and restarts pendra.service for you
sudo pendra setup
Fedora / RHEL / openSUSE (.rpm)
# Fedora / RHEL / openSUSE — pick the variant that matches your GPU
sudo dnf install ./pendra_<v>_linux_amd64.rpm # CPU baseline
sudo dnf install ./pendra-cuda_<v>_linux_amd64.rpm # NVIDIA (CUDA)
sudo dnf install ./pendra-vulkan_<v>_linux_amd64.rpm # AMD / Intel (Vulkan)
# Paste your worker key — setup writes /var/lib/pendra/config.yaml
# and restarts pendra.service for you
sudo pendra setup
Both packages register a systemd service so the daemon
runs at boot. Manage it with the usual
systemctl {start,stop,restart,status} pendra.
The service runs as its own unprivileged pendra user. So that
it can measure CPU power, each time it
starts it gives the pendra group read access to the
processor's energy counter (energy_uj for each CPU package
under /sys/class/powercap). Linux otherwise keeps that counter
to administrators, because a program that reads it very often can work out
what other programs on the machine are doing; with the package installed,
the worker and anyone in the pendra group can read it too.
Nothing else is opened up, and removing the package takes the access back.
sudo pendra setup. On a packaged
install, setup writes /var/lib/pendra/config.yaml and restarts
pendra.service so your worker key is live immediately. The
install also adds you to the pendra group, so
pendra status, pendra doctor, and
pendra logs work without sudo after your next login.
Docker
Multi-arch image at ghcr.io/pendra-ai/pendra-worker
(linux/amd64 and linux/arm64). CPU baseline on :latest,
:cuda for NVIDIA hosts, :vulkan for AMD /
Intel and for NVIDIA cards older than Turing, such as the V100 and P100
(which
build to use). Mount your GPU, give the worker a volume, and pass in a
worker key.
Docker Compose is the easiest way to run a worker you want to keep running:
the restart policy, GPU, volume and worker key all live in one file.
Save this as docker-compose.yml, paste in your key, and start it
with docker compose up -d:
# docker-compose.yml — an NVIDIA (CUDA) worker.
# Contains your worker key — keep this file out of version control.
services:
pendra-worker:
image: ghcr.io/pendra-ai/pendra-worker:cuda
restart: unless-stopped
environment:
- GPU_WORKER_PRIVATE_KEY=<base64-ed25519-key>
- WORKER_NAME=gpu-01 # optional
volumes:
- pendra-data:/root/.pendra
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: all
capabilities: [gpu]
volumes:
pendra-data:
The CUDA image needs the
NVIDIA Container Toolkit
on the host and NVIDIA driver R580 or newer. For an AMD or
Intel GPU, use the :vulkan image and replace the
deploy block with devices: ["/dev/dri:/dev/dri"].
For a machine with no GPU, use :latest and drop the
deploy block. restart: unless-stopped brings the
worker back after a crash or a reboot.
If you'd rather run one command, this starts the same worker with docker run:
# The same NVIDIA (CUDA) worker as a single command.
# -v keeps models and the KV cache off the container's own disk.
# WORKER_NAME is optional — a container's hostname is a random string.
docker run -d \
--name pendra-worker \
--restart unless-stopped \
--gpus all \
-v pendra-data:/root/.pendra \
-e GPU_WORKER_PRIVATE_KEY=<base64-ed25519-key> \
-e WORKER_NAME=gpu-01 \
ghcr.io/pendra-ai/pendra-worker:cuda
On AMD or Intel, swap --gpus all for
--device /dev/dri and use the :vulkan image. With
no GPU, drop --gpus all and use :latest.
Don't skip the volume. /root/.pendra is where
the worker keeps its model files and its
KV cache — tens of gigabytes on a busy
worker. Without a volume both are written inside the container, so they still
fill the host's disk but vanish when you recreate it, and every model has to
be downloaded again after an upgrade. The pendra-data volume
above is created for you on first run.
How much of the machine the worker uses
Docker doesn't limit a container unless you ask it to. By default the worker uses every GPU you pass in, as much of the machine's memory as its models need, and as much disk as the drive under its volume has. Here's what each one goes on, and how to rein it in:
| Resource | By default | To limit it |
|---|---|---|
| GPUs | Every GPU you pass in. Models too big for one card are spread across them. | Pass in only the cards you want to use: --gpus '"device=0"', or in compose replace count: all with device_ids: ["0"]. |
| Disk | Model files and the KV cache, both under /root/.pendra. There's no size cap on models, but the worker refuses to install one that won't fit in the free space. The KV cache caps itself at a fifth of the drive the volume is on, up to 250 GB. |
Docker can't cap the size of a named volume, so decide which drive it lives on instead: bind-mount a directory on a dedicated drive, e.g. -v /mnt/ssd/pendra:/root/.pendra. To keep the KV cache smaller, or turn off its disk tier, change the worker's KV cache setting in the console. To give it a drive of its own, see PENDRA_KV_CACHE_DIR in configuration. |
| System memory | No limit. Models pass through system memory on their way to the GPU, and any part of a model that doesn't fit in GPU memory runs from system memory instead. | Docker enforces --memory (mem_limit in compose), but the worker doesn't plan around it. It sizes itself for the whole machine's memory, and that's also the figure the console shows. If a model outgrows the limit, Docker stops the container mid-request. On a machine dedicated to Pendra, leave memory unlimited. If you do set a limit, keep it well above the part of your largest model that doesn't fit on the GPU, with generous headroom for the conversations the worker keeps in memory. |
| CPU | No limit. The GPU does the heavy lifting; the CPU matters on a worker with no GPU, or for the part of a model that runs off the GPU. | --cpus (cpus in compose) is safe to set. It only slows down work that runs on the CPU. On a machine with its own power sensor, the worker's power figure becomes an estimate. |
2. Connect the worker
- Sign in to the Pendra console.
- Open Workers → Worker Keys.
- Click Generate key — copy the base64 Ed25519 private key it shows you.
- Run
pendra setup(or paste it into the GUI setup wizard) and the daemon will start connecting.
Worker keys identify a specific machine to a Pendra organisation. They
are not the same as pdr_sk_ API keys —
those authenticate API clients, worker keys authenticate workers.
3. Install a model
A connected worker with no models can't serve requests. Pendra installs vetted catalogue models onto the worker with one click — no SSH, no shell.
- Open console.pendra.ai → Models.
- Browse the catalogue and click Install on a model — for example,
qwen3.6:27bornomic-embed-text. - Pick your worker as the destination.
- Install progress streams live in the console.
4. Verify
Check the daemon is healthy with pendra status:
$ pendra status
Status ✔ connected
Worker ID wrk-3f9b8a2d9e104c1a
Name gpu-01
Server wss://api.pendra.ai
Version 3.60.5
Variant cuda
GPU NVIDIA L4
Models (2)
· qwen3.6:27b
· nomic-embed-text
Open the console → Workers and your machine should appear within a few seconds. Head back to the Quickstart to make your first API request.
"GPU failed" warning in the console
If you installed a GPU build on a machine with an NVIDIA GPU but the GPU didn't start, the worker still comes online and keeps serving requests on the CPU, which is much slower. The console marks it with an amber GPU failed warning on the Workers list and explains the cause on the worker's page. While the warning is showing, Pendra sends requests to your other workers first. What to do depends on the cause the console shows:
-
GPU failed to start. The GPU was found but didn't
initialise. This is usually a stuck or mismatched NVIDIA driver, or a
Docker container started without GPU access. Restart the whole worker:
sudo systemctl restart pendraon Linux, quit and reopen the app on Windows, or restart the container. Restarting only the inference engine (pendra restart-backend) isn't enough. If the warning comes back, reload the NVIDIA driver or reboot the machine, check thatnvidia-smilists your GPU, and for Docker make sure the container runs with--gpus all. -
GPU not supported by this build. The CUDA build needs an
NVIDIA card with compute capability 7.5 or newer (GTX 16-series, RTX
20-series and later, or the A / L / H data-centre cards). Older cards such
as the V100, P100 or GTX 10-series can't run it, and restarting won't
help. Reinstall the worker with the Vulkan variant
(
pendra-vulkanon Linux, the Vulkan option in the Windows installer, or the:vulkanDocker image) to use the GPU.
The warning clears by itself once the worker reconnects with a working GPU.
Next steps
- Tune memory and GPU allocation: System requirements.
- Reference every env var: Configuration.
- Pick the right model variant: Choosing a model size.