From 9b9b2054d35c3ac66daa6e23edb417cea92a745f Mon Sep 17 00:00:00 2001 From: librelad Date: Sat, 1 Aug 2026 11:08:32 +0100 Subject: [PATCH] fix(install): ensure ip_tables modules before rootless Docker setup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit get.docker.com/rootless aborts when ip_tables/ip6_tables aren't loaded. Ubuntu 24.04 and 26.04 ship both modules but don't autoload them on a fresh box, so rootless setup died there — and because the caller captures its output into $result, the reason never reached the console or the error report. The install continued, reported success, and printed credentials for a WebUI that was never running. initPrerequires now modprobes both modules and persists them to /etc/modules-load.d/libreportal-rootless.conf for subsequent boots, failing with an actionable message when the kernel genuinely lacks them (container/VM kernels without netfilter). installDockerRootless gets its own guard, since it also runs outside init.sh via start_docker / rootless_start_setup. It only attempts modprobe when it can — the de-sudoed manager has no modprobe in the LP_SYSTEM allowlist, matching how ubuntu.sh handles sudo-apt — and returns non-zero rather than proceeding into a failure whose message would be swallowed. Already-loaded modules are a clean no-op, so the normal post-install re-run path is unaffected. Uninstall removes the drop-in alongside the sysctl ones, and it's listed in the footprint summary. Co-Authored-By: Claude Opus 5 --- init.sh | 51 +++++++++++++++++++ .../install/rootless/rootless_docker.sh | 21 ++++++++ variables.sh | 4 ++ 3 files changed, 76 insertions(+) diff --git a/init.sh b/init.sh index c6a28eb..e4dc116 100755 --- a/init.sh +++ b/init.sh @@ -794,11 +794,57 @@ initOS() isSuccessful "OS Updated" } +# Rootless Docker needs ip_tables/ip6_tables present before its installer runs. +# Idempotent: safe to re-run, and a no-op once the modules are already live. +# Returns non-zero if the modules genuinely can't be loaded, so the caller can +# stop rather than let rootless setup fail later with a swallowed message. +initIptablesModules() +{ + local modules_conf="/etc/modules-load.d/libreportal-rootless.conf" + local mod missing=() + + for mod in ip_tables ip6_tables; do + # Already built in (or loaded) — nothing to do for this one. + if lsmod 2>/dev/null | grep -q "^${mod}\b"; then + continue + fi + if ! sudo modprobe "$mod" 2>/dev/null; then + missing+=("$mod") + fi + done + + if [[ ${#missing[@]} -gt 0 ]]; then + isError "Could not load required kernel module(s): ${missing[*]}" + isNotice "Rootless Docker cannot be installed without these. On a VPS this usually" + isNotice "means a container/VM kernel without netfilter — check with your provider." + return 1 + fi + + # Persist across reboots. Written unconditionally so an edited/truncated file + # gets repaired, but only when the content would actually change. + local desired="# LibrePortal: rootless Docker requires the legacy iptables modules +ip_tables +ip6_tables" + if [[ "$(cat "$modules_conf" 2>/dev/null)" != "$desired" ]]; then + echo "$desired" | sudo tee "$modules_conf" >/dev/null + isSuccessful "Persisted iptables modules to $modules_conf" + else + isSuccessful "iptables modules already loaded and persisted." + fi + return 0 +} + initPrerequires() { isHeader "Installing Prerequired Apps" # apache2-utils → htpasswd, used by hashPassword for fast local bcrypt. sudo apt-get install git zip curl sshpass dos2unix dnsutils apt-transport-https ca-certificates software-properties-common uidmap adduser apache2-utils restic -y + + # get.docker.com/rootless aborts when the legacy ip_tables modules aren't + # loaded. Ubuntu 24.04/26.04 ship them but don't autoload them on a fresh + # box, so rootless setup dies here with a message that never surfaces (the + # caller captures its output). Load them now and persist for later boots. + initIptablesModules TARGET_PATH="/usr/local/bin" CONFIG_FILE="$HOME/.bashrc" if ! echo "$PATH" | grep -q "$TARGET_PATH"; then @@ -1686,6 +1732,7 @@ runFullUninstall() printf " %-34s ${DIM}%s${NC}\n" "/etc/sudoers.d/$mgr" "scoped sudo grant" printf " %-34s ${DIM}%s${NC}\n" "libreportal.service" "systemd task processor" printf " %-34s ${DIM}%s${NC}\n" "/etc/sysctl.d/99-libreportal*" "rootless sysctl drop-ins" + printf " %-34s ${DIM}%s${NC}\n" "/etc/modules-load.d/libreportal*" "iptables module drop-in" echo "" printf " ${BOLD}Containers + binaries${NC}\n" printf " ${DIM}%s${NC}\n" "all containers + images + the rootless docker daemon" @@ -1748,6 +1795,10 @@ runFullUninstall() if [[ "$keep_docker" != "true" ]]; then rm -f /etc/sysctl.d/99-libreportal-hardening.conf /etc/sysctl.d/99-libreportal-rootless.conf sysctl --system >/dev/null 2>&1 + # Drop the modules-load drop-in too. The modules stay loaded until reboot, + # which is fine — we only stop *forcing* them on for a machine that no + # longer runs rootless docker. + rm -f /etc/modules-load.d/libreportal-rootless.conf fi rm -f /usr/local/bin/restic /usr/local/bin/kopia /usr/local/bin/ufw-docker rm -f /root/init.sh diff --git a/scripts/docker/install/rootless/rootless_docker.sh b/scripts/docker/install/rootless/rootless_docker.sh index 3565ab4..ae96d0c 100755 --- a/scripts/docker/install/rootless/rootless_docker.sh +++ b/scripts/docker/install/rootless/rootless_docker.sh @@ -93,6 +93,27 @@ installDockerRootless() local result; result=$(runSystem loginctl enable-linger $CFG_DOCKER_INSTALL_USER) checkSuccess "Adding automatic start (linger)" + # get.docker.com/rootless aborts outright when the legacy ip_tables + # modules aren't loaded — and its output is captured into $result below, + # so the real reason never reaches the console or the error report; the + # install just carries on and "succeeds" with no daemon. Ubuntu 24.04 and + # 26.04 ship these modules but don't autoload them on a fresh box. + # init.sh loads + persists them at install time; a later re-run by the + # de-sudoed manager can't modprobe (not in the LP_SYSTEM allowlist), so + # only attempt it when we actually can, and stop loudly when we can't. + local mod missing=() + for mod in ip_tables ip6_tables; do + lsmod 2>/dev/null | grep -q "^${mod}\b" && continue + sudo -n modprobe "$mod" 2>/dev/null || missing+=("$mod") + done + if [[ ${#missing[@]} -gt 0 ]]; then + isError "Rootless Docker needs kernel module(s) that aren't loaded: ${missing[*]}" + isNotice "Load now: sudo modprobe ${missing[*]}" + isNotice "Persist it: add one module per line to $modules_load" + isNotice "Stopping before rootless setup — it would fail with its error swallowed." + return 1 + fi + # Install rootless Docker and enable the user service, but do NOT # start it here. The rootless network override (override.conf, # written further down) and the daemon-reload that picks it up diff --git a/variables.sh b/variables.sh index 9b2f080..b3ac320 100755 --- a/variables.sh +++ b/variables.sh @@ -45,6 +45,10 @@ swap_file=/swapfile # the old non-standard /etc/sysctl/ path, so settings written elsewhere never # persist across reboot. sysctl="/etc/sysctl.d/99-libreportal-rootless.conf" +# Rootless Docker's installer aborts outright when the legacy ip_tables modules +# aren't loaded. Ubuntu 24.04/26.04 don't autoload them on a fresh box, so we +# both modprobe them now and persist them here for subsequent boots. +modules_load="/etc/modules-load.d/libreportal-rootless.conf" docker_log_file=libreportal.log backup_log_file=backup.log db_file=database.db