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

  1. Stop and tear down running containers:
    sudo docker compose down
    
  2. Remove your service user from the docker group 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:

  1. Adjust ownership of HROOT files:
    sudo chown -R $USER:$USER ~/hroot
    
  2. Update .env configuration: 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

  1. Verify Unprivileged Execution: Check running processes on the host:
    ps aux | grep dockerd
    
    Notice that dockerd is now owned by your user (e.g. hroot), not root!
  2. 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!