Most Docker installation guides assume systemd, which leaves Void Linux users translating commands on the fly. Void uses runit as its init system, so enabling and managing services works differently. The good news: Docker is available directly from the Void repositories, and the whole setup takes under five minutes.
This guide covers installing Docker Engine and Docker Compose on Void Linux, verifying everything works, running a multi-container application with Compose, and managing the Docker service through runit. If you’ve only used systemd before, the runit comparison table near the end will save you some searching.
Tested March 2026 | Void Linux (glibc, x86_64), Docker 29.3.1, Docker Compose v5.1.0
Prerequisites
- Void Linux (glibc variant, x86_64) with a working network connection
- Root or sudo access
- Tested with: Docker 29.3.1, Docker Compose v5.1.0, Containerd 2.2.0
Update the System
Start by updating the xbps package manager itself, then upgrade all installed packages. Void handles these as two separate steps.
sudo xbps-install -u xbps
Once xbps is current, pull in all available upgrades:
sudo xbps-install -Syu
Reboot if the kernel was updated. Otherwise, continue straight to the Docker installation.
Install Docker Engine
Docker ships in the official Void repositories, so no third-party repos are needed.
sudo xbps-install -y docker
This pulls in Docker Engine, containerd, and the CLI tools. Confirm the installed version:
docker --version
The output should show Docker 29.3.1 or newer:
Docker version 29.3.1, build 7e5decf
Enable and Start Docker
Void Linux uses runit instead of systemd. There is no systemctl enable here. To enable and start a service, you create a symlink from /etc/sv/ into /var/service/. Runit picks it up within five seconds and starts the daemon automatically.
sudo ln -s /etc/sv/docker /var/service/docker
Give runit a moment, then check the service status:
sudo sv status docker
You should see the service running with its PID and uptime:
run: docker: (pid 1842) 6s
If Docker fails to create containers later with errors about /run/user/0, create that directory manually. This catches most people off guard on a fresh Void install:
sudo mkdir -p /run/user/0
Verify Docker Installation
The docker info command confirms the engine is running and shows the storage and cgroup configuration:
sudo docker info
Key details from the output:
Client: Docker Engine - Community
Version: 29.3.1
Context: default
Server:
Server Version: 29.3.1
Storage Driver: overlayfs
Cgroup Driver: cgroupfs
Cgroup Version: 2
Operating System: Void
OSType: linux
Architecture: x86_64
CPUs: 2
Total Memory: 1.938GiB
Docker Root Dir: /var/lib/docker
Note the cgroupfs driver. Void does not use systemd, so Docker defaults to cgroupfs v2, which is exactly what you want here.
Now test with the classic hello-world container:
sudo docker run --rm hello-world
The full output confirms Docker can pull images and run containers:
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
e6590344b1a5: Pull complete
Digest: sha256:d715f14f9eca81473d9112df50457893aa7a0a5e35d427c9fa9b1fa26a8de2e1
Status: Downloaded newer image for hello-world:latest
Hello from Docker!
This message shows that your installation appears to be working correctly.
To generate this message, Docker took the following steps:
1. The Docker client contacted the Docker daemon.
2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
3. The Docker daemon created a new container from that image which runs the
executable that produces the output you are currently reading.
4. The Docker daemon streamed that output to the Docker client, which sent it
to your terminal.
To try something more, you can run an Ubuntu container with:
$ docker run -it ubuntu bash
Share images, automate workflows, and more with a free Docker ID:
https://hub.docker.com/
For more examples and ideas, visit:
https://docs.docker.com/get-started/
Install Docker Compose
Docker Compose is also available from the Void repositories. The packaged version is the Python-based Compose v2 plugin.
sudo xbps-install -y docker-compose
Verify the installed version:
docker compose version
The output confirms Compose v5.1.0:
Docker Compose version v5.1.0
Deploy a Multi-Container Application
To put Compose through a real test, create a project with Nginx and MariaDB running together. This is a typical pattern for web applications.
Create a project directory and the Compose file:
mkdir -p ~/compose-demo && cd ~/compose-demo
Open the Compose file for editing:
vi compose.yaml
Add the following configuration:
services:
web:
image: nginx:alpine
ports:
- "8080:80"
depends_on:
- db
restart: unless-stopped
db:
image: mariadb:11
environment:
MARIADB_ROOT_PASSWORD: S3cur3P@ssw0rd
MARIADB_DATABASE: appdb
MARIADB_USER: appuser
MARIADB_PASSWORD: AppUs3rP@ss
volumes:
- dbdata:/var/lib/mysql
restart: unless-stopped
volumes:
dbdata:
Bring up both containers in detached mode:
sudo docker compose up -d
Compose pulls the images and starts both services:
[+] Running 3/3
✔ Network compose-demo_default Created
✔ Container compose-demo-db-1 Started
✔ Container compose-demo-web-1 Started
Check that both containers are running:
sudo docker ps
Both should show “Up” status:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a3f1b2c4d5e6 nginx:alpine "/docker-entrypoint.…" 12 seconds ago Up 10 seconds 0.0.0.0:8080->80/tcp compose-demo-web-1
b7e8f9a0c1d2 mariadb:11 "docker-entrypoint.s…" 12 seconds ago Up 11 seconds 3306/tcp compose-demo-db-1
Test the Nginx container with curl:
curl -s http://localhost:8080 | head -5
The default Nginx welcome page confirms the web container is serving traffic:
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
To tear down the stack when finished:
sudo docker compose down
Manage Docker as Non-Root User
Running every Docker command with sudo gets old fast. Add your user to the docker group to run containers without root privileges.
sudo usermod -aG docker $(whoami)
Apply the group membership without logging out:
newgrp docker
Confirm it works by running a container without sudo:
docker run --rm alpine echo "Docker works without sudo"
You should see:
Docker works without sudo
Be aware that anyone in the docker group effectively has root-level access to the host through container mounts. Only add trusted users.
Docker Service Management with Runit
If you’re coming from a systemd-based distro, runit’s approach to service management takes a bit of adjustment. The table below maps common operations between the two.
| Action | Runit (Void Linux) | systemd Equivalent |
|---|---|---|
| Start service | sudo sv start docker | sudo systemctl start docker |
| Stop service | sudo sv stop docker | sudo systemctl stop docker |
| Restart service | sudo sv restart docker | sudo systemctl restart docker |
| Check status | sudo sv status docker | sudo systemctl status docker |
| Enable (start at boot) | sudo ln -s /etc/sv/docker /var/service/docker | sudo systemctl enable docker |
| Disable (remove from boot) | sudo rm /var/service/docker | sudo systemctl disable docker |
| View logs | sudo cat /var/log/docker/current | sudo journalctl -u docker |
Runit Service Gotcha
Runit’s model is simpler than systemd, but there is one behavior that surprises newcomers: creating the symlink into /var/service/ both enables and starts the service immediately. There is no separate “enable” step that waits for the next reboot. Runit scans /var/service/ every five seconds and launches anything new it finds.
The reverse is also true. Removing the symlink with rm /var/service/docker stops the running service and prevents it from starting at boot. This is different from systemd, where systemctl disable only affects boot behavior and does not stop a currently running service.
Troubleshooting
Error: “failed to create temp dir: stat /run/user/0: no such file or directory”
This happens when Docker tries to create a container but the XDG runtime directory doesn’t exist. Void’s rootfs image doesn’t create it automatically. The fix:
sudo mkdir -p /run/user/0
To make it persistent across reboots, add the mkdir to a runit one-shot service or your shell profile.
Docker service shows “down” immediately after enabling
Runit takes a few seconds to pick up a new service symlink. If sv status docker shows down: docker: 0s, normally up, want up right after creating the link, wait 5-10 seconds and check again. The Docker daemon itself needs time to initialize containerd and set up networking. On first start, 10-15 seconds is typical before the socket appears at /var/run/docker.sock.
Docker containers can’t resolve DNS
If containers start but can’t reach the internet, check that /etc/resolv.conf on the host has valid nameservers. Docker inherits the host’s DNS configuration. On Void, if you’re using dhcpcd, the resolv.conf should be populated automatically. For static configurations, make sure you have at least one working nameserver entry.
For Docker setup on other distributions, see Docker on Rocky Linux 10 or Docker on Ubuntu / Debian. If you need a web management UI, Portainer works well with this setup.