From e92382266fa5338e0e01e8cbe377653b7f0ba476 Mon Sep 17 00:00:00 2001 From: cclohmar Date: Sat, 11 Jul 2026 00:38:24 +0100 Subject: [PATCH] =?UTF-8?q?rootless=20podman:=20ports=208080/8443,=20iptab?= =?UTF-8?q?les=20redirect=2080=E2=86=928080=20443=E2=86=928443,=20no=20sud?= =?UTF-8?q?o=20for=20podman?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- compose/stack.yaml | 4 +-- tools/nextwks.sh | 89 +++++++++++++++++++++++----------------------- 2 files changed, 46 insertions(+), 47 deletions(-) diff --git a/compose/stack.yaml b/compose/stack.yaml index 7adae8b..0c4d4ba 100644 --- a/compose/stack.yaml +++ b/compose/stack.yaml @@ -4,8 +4,8 @@ services: container_name: caddy restart: unless-stopped ports: - - "80:80" - - "443:443" + - "8080:80" + - "8443:443" volumes: - /opt/nextworkspace/config/caddy/:/etc/caddy/ - /opt/nextworkspace/data/caddy/:/data/:Z diff --git a/tools/nextwks.sh b/tools/nextwks.sh index e5cba05..7559249 100755 --- a/tools/nextwks.sh +++ b/tools/nextwks.sh @@ -21,7 +21,7 @@ usage() { MODE="${1#--}" case "$MODE" in install|update|destroy) ;; *) usage ;; esac -# Helper: run with sudo if not already root +# Helper: run with sudo only for commands that need it maybe_sudo() { if [ "$(id -u)" -eq 0 ]; then "$@"; else sudo "$@"; fi } @@ -42,7 +42,7 @@ echo "=== NextWorkspace ${MODE} ===" if [ "$MODE" = "install" ]; then echo "[*] Installing system dependencies..." maybe_sudo apt-get update -qq - maybe_sudo apt-get install -y -qq git build-essential curl podman podman-compose + maybe_sudo apt-get install -y -qq git build-essential curl podman podman-compose iptables-persistent if ! command -v go &>/dev/null; then echo "[*] Installing Go..." @@ -57,6 +57,33 @@ if [ "$MODE" = "install" ]; then export PATH=$PATH:/usr/local/go/bin fi + # Enable user lingering — containers stay alive after logout + maybe_sudo loginctl enable-linger "$USER" 2>/dev/null || true + + # Clean up any old rootful containers from a previous deploy + echo "[*] Cleaning up old rootful containers (if any)..." + maybe_sudo podman stop caddy authelia launcher 2>/dev/null || true + maybe_sudo podman rm caddy authelia launcher 2>/dev/null || true + maybe_sudo podman network rm "$NETWORK_NAME" 2>/dev/null || true + + # Set up iptables: redirect 80→8080, 443→8443 for rootless Caddy + echo "[*] Setting up iptables port redirects (80→8080, 443→8443)..." + maybe_sudo iptables -t nat -C PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080 2>/dev/null || \ + maybe_sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080 + maybe_sudo iptables -t nat -C PREROUTING -p tcp --dport 443 -j REDIRECT --to-port 8443 2>/dev/null || \ + maybe_sudo iptables -t nat -A PREROUTING -p tcp --dport 443 -j REDIRECT --to-port 8443 + maybe_sudo iptables -t nat -C OUTPUT -p tcp --dport 80 -j REDIRECT --to-port 8080 2>/dev/null || \ + maybe_sudo iptables -t nat -A OUTPUT -p tcp --dport 80 -j REDIRECT --to-port 8080 + maybe_sudo iptables -t nat -C OUTPUT -p tcp --dport 443 -j REDIRECT --to-port 8443 2>/dev/null || \ + maybe_sudo iptables -t nat -A OUTPUT -p tcp --dport 443 -j REDIRECT --to-port 8443 + # Persist across reboots + if command -v netfilter-persistent &>/dev/null; then + maybe_sudo netfilter-persistent save 2>/dev/null || true + else + maybe_sudo mkdir -p /etc/iptables + maybe_sudo sh -c 'iptables-save > /etc/iptables/rules.v4' + fi + echo "" echo "--- NextWorkspace Configuration ---" read -p "Domain [nextwks.eu]: " input; DOMAIN="${input:-$DOMAIN}" @@ -140,6 +167,11 @@ maybe_sudo mkdir -p "$TARGET_DIR/config/caddy" "$TARGET_DIR/config/authelia" \ # ============================================================ if [ "$MODE" = "destroy" ]; then echo "[*] Full teardown..." + # Stop rootless containers + podman stop caddy authelia launcher 2>/dev/null || true + podman rm caddy authelia launcher 2>/dev/null || true + podman network rm "$NETWORK_NAME" 2>/dev/null || true + # Wipe target maybe_sudo rm -rf "$TARGET_DIR" maybe_sudo mkdir -p "$TARGET_DIR/config/caddy" "$TARGET_DIR/config/authelia" \ "$TARGET_DIR/data/caddy" "$TARGET_DIR/data/authelia" \ @@ -227,67 +259,34 @@ maybe_sudo chown -R "$RUN_USER:" "$TARGET_DIR" 2>/dev/null || true maybe_sudo chown -R "$RUN_USER:" "$BACKUP_DIR" 2>/dev/null || true # ============================================================ -# 9. STOP old containers (all modes, as root) -# ============================================================ -echo "[*] Stopping any previous containers..." -for c in caddy authelia launcher; do - maybe_sudo podman stop "$c" 2>/dev/null && echo " stopped $c" || true - maybe_sudo podman rm "$c" 2>/dev/null && echo " removed $c" || true -done -sleep 1 - -# ============================================================ -# 10. PORT CHECK — before deploy -# ============================================================ -if maybe_sudo ss -tlnp 2>/dev/null | grep -q ':80 '; then - echo "==============================================" - echo "[WARN] Port 80 is already in use." - maybe_sudo ss -tlnp 2>/dev/null | grep ':80 ' - echo "" - echo " This is usually Caddy from a previous run." - echo "==============================================" - echo "" - read -p "Stop the container on port 80 now? [y/N]: " KILL - if [ "$KILL" = "y" ] || [ "$KILL" = "Y" ]; then - maybe_sudo podman stop caddy 2>/dev/null || true - maybe_sudo podman rm caddy 2>/dev/null || true - sleep 2 - echo "[OK] Port 80 freed." - else - echo "[ABORT] Free port 80 first, then re-run." - exit 1 - fi -fi - -# ============================================================ -# 11. DEPLOY stack (as root — needs port 80/443) +# 9. DEPLOY stack (rootless podman — no sudo!) # ============================================================ echo "[*] Deploying containers on $NETWORK_NAME..." -maybe_sudo podman network create "$NETWORK_NAME" 2>/dev/null || true +podman network create "$NETWORK_NAME" 2>/dev/null || true # AUTHELIA_SECRET is SESSION_SECRET (Authelia session.secret) AUTHELIA_SECRET="${SESSION_SECRET:-}" if [ -z "$AUTHELIA_SECRET" ]; then - AUTHELIA_SECRET=$(maybe_sudo sed -n '/^session:/,/^[a-z]/p' "$TARGET_DIR/config/authelia/configuration.yml" \ + AUTHELIA_SECRET=$(sed -n '/^session:/,/^[a-z]/p' "$TARGET_DIR/config/authelia/configuration.yml" \ | grep 'secret:' | awk '{print $2}' 2>/dev/null || echo "") fi # Generate compose file with substituted secret sed -e "s|{AUTHELIA_SECRET}|$AUTHELIA_SECRET|g" \ "$BUILD_DIR/compose/stack.yaml" > "$GEN_DIR/stack.yaml" -maybe_sudo cp "$GEN_DIR/stack.yaml" "$TARGET_DIR/compose/stack.yaml" +cp "$GEN_DIR/stack.yaml" "$TARGET_DIR/compose/stack.yaml" -maybe_sudo podman-compose -f "$TARGET_DIR/compose/stack.yaml" down 2>/dev/null || true +podman-compose -f "$TARGET_DIR/compose/stack.yaml" down 2>/dev/null || true sleep 1 -maybe_sudo podman-compose -f "$TARGET_DIR/compose/stack.yaml" up -d 2>&1 || echo "[WARN] Stack deploy had issues" +podman-compose -f "$TARGET_DIR/compose/stack.yaml" up -d 2>&1 || echo "[WARN] Stack deploy had issues" # ============================================================ -# 12. HEALTH CHECK +# 10. HEALTH CHECK # ============================================================ echo "[*] Running health check..." for i in $(seq 1 $HEALTH_CHECK_RETRIES); do - HEALTH=$(maybe_sudo podman exec launcher curl -sf http://127.0.0.1:9000/health 2>/dev/null || echo "") + HEALTH=$(podman exec launcher curl -sf http://127.0.0.1:9000/health 2>/dev/null || echo "") if [ "$HEALTH" = "OK" ]; then echo "[OK] NextWorkspace launcher is healthy" echo "[OK] https://$DOMAIN/" @@ -299,8 +298,8 @@ done echo "[FAIL] Health check failed — launcher did not respond" echo "" echo "--- Container status ---" -maybe_sudo podman ps -a --filter "name=caddy|authelia|launcher" 2>/dev/null || true +podman ps -a --filter "name=caddy|authelia|launcher" 2>/dev/null || true echo "" echo "--- Launcher logs (last 20 lines) ---" -maybe_sudo podman logs launcher --tail 20 2>/dev/null || echo " (no logs)" +podman logs launcher --tail 20 2>/dev/null || echo " (no logs)" exit 1