Migrating an Existing Docker Installation to Rootless Docker - wiso-forschungslabor/hroot-documentation GitHub Wiki
This guide details how to migrate an existing HROOT v4.0.x Docker deployment running on a standard system-wide (rootful) Docker daemon to Rootless Docker.
1. Why Migrate to Rootless Docker?
In initial HROOT v4.0.x setups, administrators often added the host user to the system docker group (usermod -aG docker). While convenient, granting access to /var/run/docker.sock on a rootful Docker daemon is equivalent to granting passwordless host root access.
Key Benefits of Rootless Docker:
- True Root-Free Isolation: The Docker daemon (
dockerd) and all containers run inside an unprivileged user namespace. If an application container or the Docker socket were compromised, the attacker cannot escalate to root on the server. - Safe In-App 1-Click Updates: Restores full compatibility with HROOT's built-in 1-Click Update button in the Admin UI (
/admin/options/check), communicating securely with the user-space socket without granting host root privileges. - Zero Downtime Risk / Zero Data Loss: Since HROOT stores all persistent data (database, uploads, configuration) in directory volume mounts on the host, migrating takes less than 3 minutes and preserves all laboratory data.
2. Step-by-Step Migration Procedure
Step 1: Create a Database Backup
Before making any changes, navigate to your HROOT directory (e.g. ~/hroot or /srv/hroot) and create a fresh database dump:
cd ~/hroot
sudo docker compose exec db mysqldump -u hroot -p${DATABASE_PASSWORD} ${DATABASE_NAME:-hroot_production} > backup_pre_rootless_$(date +%F_%H%M).sql
Step 2: Stop Existing Containers & Remove Docker Group Membership
- Stop and tear down running containers:
sudo docker compose down - Remove your service user from the
dockergroup to eliminate the host security backdoor:sudo gpasswd -d $USER docker
Step 3: One-Time System Preparation (Requires sudo)
Run these one-time commands as administrator to install rootless helper utilities, allow unprivileged binding to ports 80/443, and enable background process persistence:
# 1. Install user-namespace tools and session bus (Ubuntu/Debian)
sudo apt update && sudo apt install -y uidmap slirp4netns dbus-user-session docker.io docker-compose-v2
# 2. Allow unprivileged ports for standard HTTP/HTTPS (< 1024)
sudo sysctl -w net.ipv4.ip_unprivileged_port_start=80
echo "net.ipv4.ip_unprivileged_port_start=80" | sudo tee /etc/sysctl.d/50-rootless-docker.conf
# 3. Enable linger so user services continue running after logout and on boot
sudo loginctl enable-linger $USER
Step 4: Initialize and Start Rootless Docker (NO sudo)
Switch to (or remain logged in as) your unprivileged service user and start the rootless daemon:
# Initialize Docker in user space (~/.local/share/docker)
dockerd-rootless-setuptool.sh install
# Enable and start user systemd service
systemctl --user enable --now docker
Verify that Rootless Docker is active:
docker info --format '{{.SecurityOptions}}'
# Output should include: rootless
Step 5: Fix Volume Permissions & Update .env
Because the previous installation was managed via rootful Docker, ensure your unprivileged user owns the data directories and configure the user-space socket:
- Adjust ownership of HROOT files:
sudo chown -R $USER:$USER ~/hroot - Update
.envconfiguration: Open.env(e.g.nano .env) or append the user socket configuration:# Set the Docker socket to your user runtime directory: echo "DOCKER_SOCKET=/run/user/$(id -u)/docker.sock" >> .env # Ensure updater webhook URL is configured: echo "UPDATE_WEBHOOK_URL=http://updater:8080/v1/update" >> .env
Step 6: Start HROOT Unprivileged
From this point forward, never run sudo docker again. Simply launch HROOT with your regular user account:
# Pull the latest image layers
docker compose pull
# Start all services
docker compose up -d
# Verify startup logs
docker compose logs -f web
3. Post-Migration Verification
- Verify Unprivileged Execution:
Check running processes on the host:
Notice thatps aux | grep dockerddockerdis now owned by your user (e.g.hroot), notroot! - Verify In-App 1-Click Update:
Log into your HROOT instance as an Administrator $\rightarrow$ Navigate to Options $\rightarrow$ Check for Updates (
/admin/options/check).
The update button will now safely connect to the updater service via your user-space Docker socket!