diff --git a/configs/network/network_docker b/configs/network/network_docker index 9eaf31f..802504e 100755 --- a/configs/network/network_docker +++ b/configs/network/network_docker @@ -5,3 +5,4 @@ CFG_NETWORK_NAME=vpn # Network Name - Docker network name for container communication CFG_NETWORK_SUBNET=10.100.0.0/16 # Network Subnet - Subnet range for Docker network CFG_NETWORK_MTU=1500 # Network MTU - Maximum transmission unit for network packets +CFG_ROOTLESS_NET=pasta # Rootless Network Driver - Network stack for rootless Docker; pasta (default): faster and preserves the real client source IP; slirp4netns: legacy fallback if pasta misbehaves. The matching rootlesskit port driver is selected automatically. [pasta:Pasta (recommended)|slirp4netns:slirp4netns (fallback)] diff --git a/containers/libreportal/frontend/js/components/config/config-options.js b/containers/libreportal/frontend/js/components/config/config-options.js index e781967..30111d5 100755 --- a/containers/libreportal/frontend/js/components/config/config-options.js +++ b/containers/libreportal/frontend/js/components/config/config-options.js @@ -190,6 +190,10 @@ class ConfigOptions { { value: 'rooted', label: 'Rooted' }, { value: 'rootless', label: 'Rootless' } ], + 'CFG_ROOTLESS_NET': [ + { value: 'pasta', label: 'Pasta (recommended)' }, + { value: 'slirp4netns', label: 'slirp4netns (fallback)' } + ], 'CFG_UFW_LOGGING': [ { value: 'off', label: 'Off' }, { value: 'low', label: 'Low' }, diff --git a/scripts/docker/install/rootless/rootless_docker.sh b/scripts/docker/install/rootless/rootless_docker.sh index ce0aa8f..0f1c3de 100755 --- a/scripts/docker/install/rootless/rootless_docker.sh +++ b/scripts/docker/install/rootless/rootless_docker.sh @@ -110,15 +110,30 @@ EOF checkSuccess "Setting up Rootless for $CFG_DOCKER_INSTALL_USER" ((menu_number++)) + + # The net namespace driver and the rootlesskit port driver are a matched + # pair — mixing them makes rootlesskit reject the config and the daemon + # silently never starts (this is why an earlier pasta+builtin attempt + # bricked the install). The user picks one network stack via + # CFG_ROOTLESS_NET; we derive its only valid port driver here: + # pasta -> implicit (fastest; propagates the real client IP) + # slirp4netns -> builtin (legacy fallback) + local rootless_net="${CFG_ROOTLESS_NET:-pasta}" + local rootless_port_driver + case "$rootless_net" in + pasta) rootless_port_driver="implicit" ;; + slirp4netns) rootless_port_driver="builtin" ;; + *) + isNotice "Unknown CFG_ROOTLESS_NET='$rootless_net'; falling back to pasta." + rootless_net="pasta" + rootless_port_driver="implicit" + ;; + esac + echo "" - echo "---- $menu_number. Configuring rootless networking (slirp4netns + builtin port driver)." + echo "---- $menu_number. Configuring rootless networking ($rootless_net + $rootless_port_driver port driver)." echo "" - # slirp4netns is the net namespace driver; the builtin rootlesskit port - # driver skips slirp4netns's userspace port-handler and shaves - # per-connection overhead. (pasta is faster but requires a recent passt - # AND port driver none/implicit — the pasta+builtin combo is rejected by - # rootlesskit, which silently kept the rootless daemon from starting.) systemd_user_dir="/home/$CFG_DOCKER_INSTALL_USER/.config/systemd/user" local result=$(dockerCommandRunInstallUser "mkdir -p $systemd_user_dir") checkSuccess "Create the systemd user directory if it doesn't exist" @@ -132,14 +147,35 @@ EOF sudo bash -c "cat < '$override_conf_file' [Service] -Environment='DOCKERD_ROOTLESS_ROOTLESSKIT_NET=slirp4netns' -Environment='DOCKERD_ROOTLESS_ROOTLESSKIT_PORT_DRIVER=builtin' +Environment='DOCKERD_ROOTLESS_ROOTLESSKIT_NET=$rootless_net' +Environment='DOCKERD_ROOTLESS_ROOTLESSKIT_PORT_DRIVER=$rootless_port_driver' Environment='DOCKERD_ROOTLESS_ROOTLESSKIT_MTU=$CFG_NETWORK_MTU' EOL" local result=$(sudo chown $CFG_DOCKER_INSTALL_USER:$CFG_DOCKER_INSTALL_USER $override_conf_file) checkSuccess "Updating ownership for override.conf" + # Disable userland-proxy so the kernel/net driver forwards ports directly + # and the container sees the real client source IP instead of the + # rootlesskit gateway. Merge into any existing daemon.json rather than + # clobbering it. + docker_cfg_dir="/home/$CFG_DOCKER_INSTALL_USER/.config/docker" + daemon_json="$docker_cfg_dir/daemon.json" + + local result=$(sudo -u "$CFG_DOCKER_INSTALL_USER" mkdir -p "$docker_cfg_dir") + checkSuccess "Create the rootless docker config directory if it doesn't exist" + + if sudo test -f "$daemon_json"; then + local result=$(sudo bash -c "tmp=\$(mktemp) && jq '. + {\"userland-proxy\": false}' '$daemon_json' > \"\$tmp\" && mv \"\$tmp\" '$daemon_json'") + checkSuccess "Setting userland-proxy=false in existing daemon.json" + else + local result=$(sudo bash -c "printf '%s\n' '{\"userland-proxy\": false}' > '$daemon_json'") + checkSuccess "Writing rootless daemon.json with userland-proxy=false" + fi + + local result=$(sudo chown $CFG_DOCKER_INSTALL_USER:$CFG_DOCKER_INSTALL_USER "$daemon_json") + checkSuccess "Updating ownership for daemon.json" + local result=$(dockerCommandRunInstallUser "systemctl --user daemon-reload") checkSuccess "Reload the systemd user manager configuration"