Skip to main content

Installing nyxd on Linux

nyxd runs on any Linux host that meets the kernel and tooling requirements below (desktop, VM, VPS, edge box, ARM or x86). It was first written for a home Raspberry Pi so containers could run without Docker or a heavy daemon; that same footprint applies everywhere you want a minimal stack.

Typical setups: run nyxd on the host and nyx locally, or call the Unix-socket HTTP API from another machine you trust. For macOS/Windows machines and rootful vs rootless feature differences, see Platform matrix.

What you need on each Linux host​

RequirementNotes
Linux with overlayfs, namespaces, cgroupsDebian, Fedora, Ubuntu, Raspberry Pi OS 64-bit, cloud images, etc.
Root for nyxdOverlay, netns, and crun state require root today.
crunapt install crun, dnf install crun, or build from source.
Kernel modulesSee kernel requirements — overlay, bridge, veth, br_netfilter, nftables NAT, etc.
nft (optional but recommended)Used for port maps with the native network driver.
Go 1.27+ (build only)On the target host or cross-compile from a dev machine.

Networking defaults to -net-driver=native (no /opt/cni/bin). See networking.

Quick install​

One command per platform. On Linux it adds the nyxd package repository for your package manager and installs from it (so your system's upgrades keep nyxd current); on macOS and Windows it downloads the release and checks it against the signed checksums.txt. Either way nyxd is set up as a service that starts at boot. It takes well under a minute; Get started walks through it for your system, up to your first container.

# Linux and macOS
curl -fsSL https://pkgs.nyxd.io/install.sh | sh
# Windows (PowerShell, no admin rights needed once WSL is enabled)
irm https://pkgs.nyxd.io/install.ps1 | iex

What it does:

PlatformInstallsService
Debian, Ubuntu, Fedora, RHEL, Rocky, openSUSE, Arch, Alpinethe nyxd package repository (below) and the nyxd package from it, so upgrades and removal go through your package manager; crun comes as a dependencyenabled and started for the init system in use
Any other Linux (Void, Gentoo, Slackware, ...)nyxd, nyx in /usr/local/bin; installs crun when it cansame
Linux, --rootlessnyxd, nyx in ~/.local/bin, no rootsystemd user service
macOSnyx in /usr/local/bin, vfkit (Homebrew), the nyx VM that runs nyxdlaunchd agent runs nyx machine run at login (macos.md)
Windowsnyx.exe in %LOCALAPPDATA%\Programs\nyx (added to PATH), the nyx WSL2 distrologon task "nyx machine" runs nyx machine start

The service is set up for systemd, OpenRC, runit or SysV init, whichever the machine runs (no running init, as in a container: it says how to start nyxd by hand). Options:

curl -fsSL .../install.sh | sh -s -- --version v0.10.0 # a given release
curl -fsSL .../install.sh | sh -s -- --method package # the release package once, no repository
curl -fsSL .../install.sh | sh -s -- --method binary # skip the native package
curl -fsSL .../install.sh | sh -s -- --rootless # per user, no root daemon
curl -fsSL .../install.sh | sh -s -- --no-start # set up and enable, do not start
curl -fsSL .../install.sh | sh -s -- --uninstall [--purge] # --purge also deletes images and containers

Afterwards, let your user talk to the daemon without sudo (log in again afterwards):

sudo usermod -aG nyx "$USER" # Alpine: sudo addgroup "$USER" nyx
nyx ping

Package repositories​

The quick install adds these for you. To set one up by hand (or in configuration management), with the same signing key as the releases (fingerprint C910 E8A2 2680 CCCB BB7E 6ED2 F0DC FE8A 242B 1E99):

Debian, Ubuntu (amd64, arm64)

sudo curl -fsSLo /usr/share/keyrings/nyxd.gpg https://pkgs.nyxd.io/nyxd.gpg
echo "deb [signed-by=/usr/share/keyrings/nyxd.gpg] https://pkgs.nyxd.io/apt stable main" | sudo tee /etc/apt/sources.list.d/nyxd.list
sudo apt-get update && sudo apt-get install -y nyxd

Fedora, RHEL, Rocky, AlmaLinux, CentOS Stream (x86_64, aarch64)

sudo curl -fsSLo /etc/yum.repos.d/nyxd.repo https://pkgs.nyxd.io/rpm/nyxd.repo
sudo dnf install -y nyxd # dnf imports the key on first use

openSUSE, SLES

sudo zypper addrepo --refresh https://pkgs.nyxd.io/rpm/nyxd.repo
sudo zypper --gpg-auto-import-keys install -y nyxd

Alpine (x86_64, aarch64)

sudo wget -qO /etc/apk/keys/nyxd.rsa.pub https://pkgs.nyxd.io/alpine/nyxd.rsa.pub
echo https://pkgs.nyxd.io/alpine | sudo tee -a /etc/apk/repositories
sudo apk add nyxd

Arch Linux (x86_64; aarch64 for Arch Linux ARM)

curl -fsSL https://pkgs.nyxd.io/nyxd.asc | sudo pacman-key --add -
sudo pacman-key --lsign-key C910E8A22680CCCBBB7E6ED2F0DCFE8A242B1E99
printf '[nyxd]\nServer = https://pkgs.nyxd.io/arch/$arch\n' | sudo tee -a /etc/pacman.conf
sudo pacman -Sy nyxd

From then on apt upgrade, dnf upgrade, zypper update, apk upgrade or pacman -Syu installs new nyxd releases. The repositories keep the last five releases.

Install from a release package​

Each release has signed packages for amd64 and arm64. They install nyxd and nyx to /usr/bin, pull in crun, create the nyx group, and install, enable and start the service for your init system (an upgrade restarts it, removal stops and disables it). Check the signature first (verifying downloads).

sudo apt install ./nyxd_<version>_amd64.deb # Debian, Ubuntu
sudo dnf install ./nyxd-<version>-1.x86_64.rpm # Fedora, RHEL, Rocky, Alma
sudo pacman -U nyxd-<version>-1-x86_64.pkg.tar.zst # Arch Linux
sudo apk add --allow-untrusted ./nyxd_<version>_x86_64.apk # Alpine (after checking its .sig)

To install without starting it (images built for later, configuration first), put NYXD_NO_START=1 in /etc/default/nyxd before installing.

Managing the service​

Settings live in /etc/default/nyxd for every init system; restart after a change:

NYXD_OPTS="-log-level info -net-driver native" # any nyxd flags (nyxd -h)
NYXD_NO_START=0 # 1: package installs/upgrades do not (re)start it
Init systemStatus / restartLogs
systemdsystemctl status nyxd / systemctl restart nyxdjournalctl -u nyxd
OpenRCrc-service nyxd status / rc-service nyxd restart/var/log/nyxd.log
runitsv status nyxd / sv restart nyxdrunit's log (stderr)
SysV/etc/init.d/nyxd status / /etc/init.d/nyxd restart/var/log/nyxd.log

/usr/lib/nyxd/nyxd-service (/usr/local/lib/nyxd/ for install.sh binary installs) does the same on any of them: nyxd-service status|restart|setup|teardown|detect.

Install to /usr/bin​

From a repo build:

sudo make install-usr
# equivalent: sudo make install BINDIR=/usr/bin

Rootless (no root at all)​

Run nyxd as your normal user and it switches to rootless mode on its own: it creates a user namespace, keeps data in ~/.local/share/nyxd, and listens on $XDG_RUNTIME_DIR/nyxd/nyxd.sock, which nyx finds automatically. Requirements, limits and the systemd user unit are in Rootless.

Windows​

On Windows, nyx.exe runs nyxd in its own small WSL2 distro: nyx machine init then nyx machine start. See Windows.

Use nyx without sudo (rootful daemon)​

With a rootful nyxd, the nyx client can run as a normal user if it can open the control socket.

  1. Create a POSIX group (once), e.g. nyxd:

    sudo getent group nyxd >/dev/null || sudo groupadd --system nyxd
  2. Add your user to that group, then log out and back in (or newgrp nyxd) so id lists nyxd among your groups:

    sudo usermod -aG nyxd "$USER"
  3. Start nyxd with --socket-group=nyxd. The daemon keeps /run/nyxd/nyxd.sock at mode 0660 and chowns it to root:nyxd, so anyone in group nyxd can connect.

    sudo nyxd --base-dir=/var/lib/nyxd --socket-group=nyxd

    With systemd, append --socket-group=nyxd to ExecStart= in nyxd.service (the group must exist before the unit starts).

  4. Install nyx (and nyxd) to PATH, e.g. /usr/bin — the binary stays world-executable 755; access control is the socket, not the file mode on nyx:

    sudo make install-usr
  5. As your user: nyx ping, nyx ps, nyx run -d … without sudo.

Socket-group membership is root-equivalent for container operations: the API accepts privileged, capability changes, host bind mounts, and host networking. Treat the nyx / nyxd group like docker group access—only trusted operators. The daemon still runs those actions as root (or as the rootless userns owner).

Build on the target host​

git clone https://github.com/zrougamed/nyxd.git
cd nyxd
make build build-nyx
sudo make install # default: /usr/local/bin
# or system-wide:
sudo make install-usr # nyxd + nyx → /usr/bin
# or: sudo make install BINDIR=/usr/bin

Cross-compile (e.g. arm64 from x86_64)​

make build-arm64
# Example: copy to an arm64 host (replace user/hostname/path)
scp bin/nyxd-arm64 myarm64:/tmp/nyxd && ssh myarm64 'sudo install -m 755 /tmp/nyxd /usr/local/bin/nyxd'

Build the nyx client for GOOS=linux GOARCH=arm64 the same way (add a Makefile target if you want both binaries in one shot).

Optional: CNI plugins​

Only if you set nyxd -net-driver=cni:

sudo make install-cni

systemd​

sudo cp nyxd.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now nyxd

The unit in this repo uses Type=notify but the daemon does not call sd_notify yet — if systemd complains, switch the unit to Type=simple. See comments in nyxd.service.

Data directories​

Default --base-dir=/var/lib/nyxd. Ensure the filesystem is persistent (SD card or USB disk), not a tiny tmpfs-only root.

Only one nyxd may use a given base-dir at a time: the daemon takes an exclusive non-blocking flock on {base-dir}/run/nyxd-daemon.lock. A second start exits with an error instead of corrupting state.

Next steps​

  • Usage — nyx commands and curl examples
  • OpenAPI spec — HTTP API contract
  • Networking — native vs CNI, nyx run / stop behavior
  • QEMU Alpine — try nyxd inside QEMU with Alpine 3.23 before touching bare metal

Security scanning (dev machine)​

From the repo root (install Trivy and Grype first):

make scan-trivy
make scan-grype
# or both:
make scan