Rootless Docker Setup
By default, Docker requires root privileges. Rootless mode runs the Docker daemon and containers as a regular user, eliminating the need for sudo or adding users to the docker group. This is the most secure way to run Docker with the Reoclo Runner.
Why Rootless Docker
Section titled “Why Rootless Docker”With standard Docker, anyone in the docker group effectively has root access to the host. Rootless Docker eliminates this risk:
- The Docker daemon runs as your user, not root
- Containers cannot escalate to root on the host
- No
dockergroup membership needed - Better isolation between users on shared servers
Prerequisites
Section titled “Prerequisites”- Linux with a 64-bit kernel (Ubuntu 20.04+, Debian 11+, Fedora 36+, CentOS 9+, or similar)
- systemd with user session support (recommended). Systems without a user systemd (minimal container images, some VPS providers) are supported via the fallback documented in the Complete Setup Script —
dockerd-rootless.shis started manually and restarted on boot via a@rebootcrontab entry. - A non-root user that will run both Docker and the Reoclo Runner
Step 1: Install Required Packages
Section titled “Step 1: Install Required Packages”Install the uidmap package which provides newuidmap and newgidmap:
Ubuntu / Debian:
sudo apt updatesudo apt install -y uidmap dbus-user-sessionFedora / CentOS / RHEL:
sudo dnf install -y shadow-utils fuse-overlayfsStep 2: Configure Subordinate IDs
Section titled “Step 2: Configure Subordinate IDs”Your user needs at least 65,536 subordinate UIDs and GIDs. Check if they’re already configured:
grep ^$(whoami): /etc/subuidgrep ^$(whoami): /etc/subgidIf these return empty, add the mappings:
sudo usermod --add-subuids 100000-165535 --add-subgids 100000-165535 $(whoami)Verify the configuration:
grep ^$(whoami): /etc/subuid# Expected output: yourusername:100000:65536Step 3: Disable System Docker (If Installed)
Section titled “Step 3: Disable System Docker (If Installed)”If you have a system-wide Docker installation, disable it first to avoid conflicts:
sudo systemctl disable --now docker.service docker.socketsudo rm -f /var/run/docker.sockIf Docker is not installed at all, skip this step.
Step 4: Install Docker Engine
Section titled “Step 4: Install Docker Engine”If Docker is not installed yet, install it first:
Ubuntu / Debian:
# Add Docker's official GPG key and repositorysudo apt updatesudo apt install -y ca-certificates curlsudo install -m 0755 -d /etc/apt/keyringssudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.ascsudo chmod a+r /etc/apt/keyrings/docker.asc
echo \ "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \ $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \ sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt updatesudo apt install -y docker-ce docker-ce-cli containerd.io docker-ce-rootless-extrasFedora:
sudo dnf install -y dnf-plugins-coresudo dnf config-manager --add-repo https://download.docker.com/linux/fedora/docker-ce.reposudo dnf install -y docker-ce docker-ce-cli containerd.io docker-ce-rootless-extrasThe docker-ce-rootless-extras package is required for rootless mode.
Step 5: Install Rootless Docker
Section titled “Step 5: Install Rootless Docker”Run the rootless setup script as your non-root user (not with sudo):
dockerd-rootless-setuptool.sh installThe script will output environment variables to add to your shell. Add them to ~/.bashrc:
echo 'export PATH=/usr/bin:$PATH' >> ~/.bashrcecho 'export DOCKER_HOST=unix:///run/user/$(id -u)/docker.sock' >> ~/.bashrcsource ~/.bashrcStep 6: Enable the Service
Section titled “Step 6: Enable the Service”Start rootless Docker and enable it on boot:
systemctl --user start dockersystemctl --user enable dockerEnable lingering so the service runs even when you’re not logged in:
sudo loginctl enable-linger $(whoami)Step 7: Verify the Installation
Section titled “Step 7: Verify the Installation”docker info 2>&1 | grep -i "root"Expected output:
rootless: trueRun a quick test:
docker run --rm hello-worldIf you see “Hello from Docker!”, rootless Docker is working.
Also verify the socket path:
echo $DOCKER_HOST# Expected: unix:///run/user/<your-uid>/docker.sockStep 8: Install the Reoclo Runner
Section titled “Step 8: Install the Reoclo Runner”Now install the Reoclo Runner as the same user. The runner will automatically use rootless Docker since DOCKER_HOST is set in your environment.
- Go to Servers > Add Server in the Reoclo dashboard
- Click Generate Registration Token
- Run the install command on your server:
curl -fsSL https://get.reoclo.com/install.sh | bash -s -- <your-token>The runner’s systemd service runs as your user and inherits the DOCKER_HOST environment variable, so it talks to rootless Docker automatically.
Exposing Ports Below 1024
Section titled “Exposing Ports Below 1024”By default, rootless Docker cannot bind to ports below 1024 (like 80 and 443). To allow this:
Option A: Set the unprivileged port start (recommended):
sudo sh -c 'echo 0 > /proc/sys/net/ipv4/ip_unprivileged_port_start'Make it permanent:
sudo sh -c 'echo "net.ipv4.ip_unprivileged_port_start=0" >> /etc/sysctl.d/99-rootless-docker.conf'sudo sysctl --systemOption B: Use a reverse proxy on the host:
Run a host-level reverse proxy (like Caddy or nginx) that listens on ports 80/443 and forwards to Docker’s high ports. This is what Reoclo’s managed proxy does automatically.
Storage Considerations
Section titled “Storage Considerations”Rootless Docker stores images and containers in your home directory by default:
~/.local/share/docker/Ensure your home partition has sufficient disk space for Docker images and build caches. For production servers, consider mounting a dedicated volume at this path.
Check current usage:
docker system dfKnown Limitations
Section titled “Known Limitations”Most web application deployments work identically in rootless mode. The main limitations are:
| Limitation | Impact | Workaround |
|---|---|---|
| Ports below 1024 | Cannot bind by default | Set ip_unprivileged_port_start=0 or use a reverse proxy |
--net=host networking | Limited functionality | Use default bridge networking (recommended anyway) |
| AppArmor / SELinux | Some profiles may need adjustment | Usually works out of the box on Ubuntu/Fedora |
| cgroup v1 systems | Limited resource management | Upgrade to cgroup v2 (default on modern distros) |
None of these affect typical Reoclo deployments, which use bridge networking and high ports with a managed reverse proxy.
Troubleshooting
Section titled “Troubleshooting””docker: command not found”
Section titled “”docker: command not found””Ensure the Docker binaries are in your PATH:
echo 'export PATH=/usr/bin:$PATH' >> ~/.bashrcsource ~/.bashrc“Cannot connect to the Docker daemon”
Section titled ““Cannot connect to the Docker daemon””Verify the DOCKER_HOST variable and service status:
echo $DOCKER_HOSTsystemctl --user status dockerIf the service isn’t running, start it:
systemctl --user start docker“newuidmap: write to uid_map failed”
Section titled ““newuidmap: write to uid_map failed””Your user doesn’t have subordinate UID/GID mappings. Run Step 2 above to configure them.
Docker stops when you log out
Section titled “Docker stops when you log out”Enable lingering:
sudo loginctl enable-linger $(whoami)Runner can’t access Docker
Section titled “Runner can’t access Docker”Ensure the runner was installed as the same user that set up rootless Docker. Check that the runner’s systemd service has the correct DOCKER_HOST:
systemctl --user show reoclo-runner | grep EnvironmentIf DOCKER_HOST is not set, add it to the service override:
mkdir -p ~/.config/systemd/user/reoclo-runner.service.dcat > ~/.config/systemd/user/reoclo-runner.service.d/docker.conf << 'EOF'[Service]Environment="DOCKER_HOST=unix:///run/user/%U/docker.sock"EOFsystemctl --user daemon-reloadsystemctl --user restart reoclo-runnerComplete Setup Script
Section titled “Complete Setup Script”For convenience, here’s the full setup in one block (Ubuntu/Debian). Run as your non-root user. The script handles both the standard systemd case and the fallback for systems without a systemd user session (e.g., minimal Ubuntu/Debian images, LXC containers, some VPS providers): it detects whether systemctl --user works and, if not, starts dockerd-rootless.sh manually and installs a @reboot crontab entry for persistence.
#!/bin/bashset -e
# ─── 1. System packages ───────────────────────────────────────────────────────sudo apt updatesudo apt install -y uidmap dbus-user-session ca-certificates curl
# ─── 2. Sub-UID/GID mapping ───────────────────────────────────────────────────grep -q "^$(whoami):" /etc/subuid || sudo usermod --add-subuids 100000-165535 --add-subgids 100000-165535 $(whoami)
# ─── 3. Docker apt repo ───────────────────────────────────────────────────────sudo install -m 0755 -d /etc/apt/keyringssudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.ascsudo chmod a+r /etc/apt/keyrings/docker.ascecho "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" \ | sudo tee /etc/apt/sources.list.d/docker.list > /dev/nullsudo apt updatesudo apt install -y docker-ce docker-ce-cli containerd.io docker-ce-rootless-extras
# ─── 4. Disable system-wide Docker (rootless doesn't need it) ─────────────────sudo systemctl disable --now docker.service docker.socket 2>/dev/null || true
# ─── 5. Set up XDG_RUNTIME_DIR before running the installer ──────────────────# (required when systemd is not available — avoids /run/user/UID which# only exists when systemd-logind manages the user session)export XDG_RUNTIME_DIR=/home/$(whoami)/.docker/runmkdir -p "$XDG_RUNTIME_DIR"
# ─── 6. Install rootless Docker ───────────────────────────────────────────────dockerd-rootless-setuptool.sh install
# ─── 7. Persist env vars to .bashrc ──────────────────────────────────────────# Use a socket path under the user's home so it works with or without# systemd — /run/user/UID is only available when systemd-logind runs.grep -qxF 'export XDG_RUNTIME_DIR=/home/'"$(whoami)"'/.docker/run' ~/.bashrc || \ echo 'export XDG_RUNTIME_DIR=/home/'"$(whoami)"'/.docker/run' >> ~/.bashrc
grep -qxF 'export DOCKER_HOST=unix:///home/'"$(whoami)"'/.docker/run/docker.sock' ~/.bashrc || \ echo 'export DOCKER_HOST=unix:///home/'"$(whoami)"'/.docker/run/docker.sock' >> ~/.bashrc
grep -qxF 'export PATH=/usr/bin:$PATH' ~/.bashrc || \ echo 'export PATH=/usr/bin:$PATH' >> ~/.bashrc
export DOCKER_HOST=unix:///home/$(whoami)/.docker/run/docker.sockexport PATH=/usr/bin:$PATH
# ─── 8. Start dockerd (systemd-aware, falls back to manual) ──────────────────if systemctl --user start docker 2>/dev/null; then systemctl --user enable docker sudo loginctl enable-linger $(whoami) 2>/dev/null || true echo "[INFO] Started via systemd user session."else echo "[INFO] systemd not available — starting dockerd-rootless.sh manually." mkdir -p "$XDG_RUNTIME_DIR" dockerd-rootless.sh > /tmp/dockerd-rootless.log 2>&1 & disown
# Add crontab entry for reboot persistence (skip if already present) CRON_JOB="@reboot XDG_RUNTIME_DIR=/home/$(whoami)/.docker/run PATH=/usr/bin:/sbin:/usr/sbin:/bin dockerd-rootless.sh >> /tmp/dockerd-rootless.log 2>&1" ( crontab -l 2>/dev/null | grep -qxF "$CRON_JOB" ) || \ ( crontab -l 2>/dev/null; echo "$CRON_JOB" ) | crontab -
echo "[INFO] Crontab entry added for reboot persistence." sleep 3 # give the daemon a moment to startfi
# ─── 9. Kernel tuning (allow low ports) ──────────────────────────────────────sudo sh -c 'echo "net.ipv4.ip_unprivileged_port_start=0" >> /etc/sysctl.d/99-rootless-docker.conf'sudo sysctl --system > /dev/null
# ─── 10. Verify ───────────────────────────────────────────────────────────────echo ""docker info 2>&1 | grep -i rootless && echo "✓ Rootless confirmed" || echo "✗ Rootless flag not found — check /tmp/dockerd-rootless.log"docker run --rm hello-world
echo ""echo "✅ Rootless Docker is ready. Now install the Reoclo Runner."Next Steps
Section titled “Next Steps”- Runner Setup to install the Reoclo Runner agent
- Servers Overview to understand server management
- Encryption to learn how Reoclo protects your secrets