From 2ce600bb6d174ea41c7d510ac79e412926d7ef48 Mon Sep 17 00:00:00 2001 From: cclohmar Date: Fri, 10 Jul 2026 13:54:33 +0100 Subject: [PATCH] fix: podman network with fixed IPs, remove host networking --- compose/authelia.yaml | 13 ++- compose/caddy.yaml | 14 ++- compose/launcher.yaml | 23 +++++ config/authelia/configuration.yml | 2 +- config/caddy/Caddyfile | 11 +-- deploy.sh | 139 ++++++++---------------------- main.go | 12 +-- 7 files changed, 90 insertions(+), 124 deletions(-) create mode 100644 compose/launcher.yaml diff --git a/compose/authelia.yaml b/compose/authelia.yaml index 12726e5..90823fc 100644 --- a/compose/authelia.yaml +++ b/compose/authelia.yaml @@ -3,9 +3,16 @@ services: image: git24hcom/authelia:latest container_name: authelia restart: unless-stopped - network_mode: host + expose: + - "9091" + - "8080" volumes: - /opt/nextworkspace/config/authelia/:/config/ - /opt/nextworkspace/data/authelia/:/data/ - environment: - - TZ=UTC + networks: + nextwks-net: + ipv4_address: 172.16.0.11 + +networks: + nextwks-net: + external: true diff --git a/compose/caddy.yaml b/compose/caddy.yaml index 224b442..f6f4d2e 100644 --- a/compose/caddy.yaml +++ b/compose/caddy.yaml @@ -3,10 +3,18 @@ services: image: caddy:latest container_name: caddy restart: unless-stopped - network_mode: host + ports: + - "80:80" + - "443:443" volumes: - /opt/nextworkspace/config/caddy/:/etc/caddy/ - /opt/nextworkspace/data/caddy/:/data/ - /opt/nextworkspace/logs/caddy/:/var/log/caddy/ - environment: - - TZ=UTC + - /opt/nextworkspace/www/:/opt/nextworkspace/www/ + networks: + nextwks-net: + ipv4_address: 172.16.0.10 + +networks: + nextwks-net: + external: true diff --git a/compose/launcher.yaml b/compose/launcher.yaml new file mode 100644 index 0000000..03cc083 --- /dev/null +++ b/compose/launcher.yaml @@ -0,0 +1,23 @@ +services: + launcher: + image: alpine:latest + container_name: launcher + restart: unless-stopped + expose: + - "9000" + volumes: + - /opt/nextworkspace/:/opt/nextworkspace/ + - /opt/nextworkspace/data/:/opt/nextworkspace/data/ + - /opt/nextworkspace/lng/:/opt/nextworkspace/lng/ + - /opt/nextworkspace/.env:/opt/nextworkspace/.env + working_dir: /opt/nextworkspace + command: /opt/nextworkspace/nextworkspace + environment: + - CONFIG_DIR=/opt/nextworkspace/config/nextworkspace + networks: + nextwks-net: + ipv4_address: 172.16.0.12 + +networks: + nextwks-net: + external: true diff --git a/config/authelia/configuration.yml b/config/authelia/configuration.yml index 1d2d32f..19fdf28 100644 --- a/config/authelia/configuration.yml +++ b/config/authelia/configuration.yml @@ -1,7 +1,7 @@ ############################################################### # Authelia configuration # ############################################################### -host: 127.0.0.1 +host: 0.0.0.0 port: 9091 log: diff --git a/config/caddy/Caddyfile b/config/caddy/Caddyfile index be61477..1b09e20 100644 --- a/config/caddy/Caddyfile +++ b/config/caddy/Caddyfile @@ -6,21 +6,16 @@ # Authelia OIDC provider auth.{DOMAIN} { - reverse_proxy 127.0.0.1:9091 + reverse_proxy authelia:9091 } # Main workspace (forward auth with Authelia) app.{DOMAIN} { - # Forward auth to Authelia verify endpoint - forward_auth 127.0.0.1:9091 { + forward_auth authelia:9091 { uri /api/verify?rd=https://auth.{DOMAIN}/ - - # Copy auth headers to upstream copy_headers Remote-User Remote-Name Remote-Email Remote-Groups } - - # Serve launcher + proxy upstream apps - reverse_proxy 127.0.0.1:9000 + reverse_proxy launcher:9000 } # Public landing page diff --git a/deploy.sh b/deploy.sh index 0b1a7b7..c90f318 100755 --- a/deploy.sh +++ b/deploy.sh @@ -5,8 +5,7 @@ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" REPO_DIR="/opt/NextWks" TARGET_DIR="/opt/nextworkspace" BACKUP_DIR="/opt/backup" -SERVICE_NAME="nextworkspace" -BINARY_NAME="nextworkspace" +NETWORK_NAME="nextwks-net" HEALTH_CHECK_RETRIES=10 HEALTH_CHECK_INTERVAL=2 @@ -17,7 +16,6 @@ elif [ -f "$TARGET_DIR/.env" ]; then set -a; source "$TARGET_DIR/.env"; set +a fi DOMAIN="${DOMAIN:-nextwks.eu}" -APP_SUB="${APP_SUB:-app}" # --- Mode --- GREENFIELD=false @@ -27,46 +25,32 @@ else echo "[MODE] Smart update (target exists)"; fi # --- Pull + build --- cd "$REPO_DIR" -echo "[1/5] Pulling latest code..." +echo "[1/6] Pulling latest code..." git pull 2>/dev/null || true -echo "[2/5] Building binary..." +echo "[2/6] Building binary..." export PATH=$PATH:/usr/local/go/bin -go build -o "$BINARY_NAME" . +go build -o nextworkspace . # --- Greenfield --- if [ "$GREENFIELD" = true ]; then - echo "[3/5] Full teardown..." - systemctl stop $SERVICE_NAME 2>/dev/null || true - systemctl disable $SERVICE_NAME 2>/dev/null || true - rm -f /etc/systemd/system/$SERVICE_NAME.service - systemctl daemon-reload - - # Backup Caddy certs before destroying - CADDY_CERTS="$TARGET_DIR/data/caddy/caddy/certificates" - if [ -d "$CADDY_CERTS" ]; then - mkdir -p "$BACKUP_DIR/certificates" - cp -r "$CADDY_CERTS"/* "$BACKUP_DIR/certificates/" 2>/dev/null || true - echo "[INFO] Caddy certificates backed up" - fi - - sudo -u master podman rm -f caddy authelia 2>/dev/null || true - sudo -u master podman pod rm -f caddy authelia 2>/dev/null || true + echo "[3/6] Full teardown..." + podman rm -f caddy authelia launcher 2>/dev/null || true if [ -d "$TARGET_DIR" ]; then chattr -R -i "$TARGET_DIR" 2>/dev/null || true rm -rf "$TARGET_DIR" fi - echo "[4/5] Building production directories..." + echo "[4/6] Building directories..." mkdir -p "$TARGET_DIR/config/caddy" mkdir -p "$TARGET_DIR/config/authelia" mkdir -p "$TARGET_DIR/data/caddy" mkdir -p "$TARGET_DIR/data/authelia" + mkdir -p "$TARGET_DIR/compose" mkdir -p "$TARGET_DIR/www" mkdir -p "$TARGET_DIR/config/nextworkspace" mkdir -p "$TARGET_DIR/logs/caddy" - # Ensure data dirs are owned by the runtime user chown -R master:master "$TARGET_DIR/data/caddy" 2>/dev/null || true chown -R master:master "$TARGET_DIR/logs/caddy" 2>/dev/null || true @@ -76,75 +60,60 @@ if [ "$GREENFIELD" = true ]; then chmod 600 "$TARGET_DIR/.env" fi - # Generate secrets if missing - JWT_SECRET="${JWT_SECRET:-$(openssl rand -hex 32)}" - SESSION_SECRET="${SESSION_SECRET:-$(openssl rand -hex 32)}" - ADMIN_PASSWORD_HASH="${ADMIN_PASSWORD_HASH:-}" - - # Generate bcrypt password hash for Authelia - HASH_TOOL="$(dirname "$0")/tools/hash-password/main.go" - if [ -z "$ADMIN_PASSWORD_HASH" ] && [ -n "${ADMIN_PASSWORD:-}" ] && [ -f "$HASH_TOOL" ]; then - ADMIN_PASSWORD_HASH=$(cd "$(dirname "$0")" && go run ./tools/hash-password/ "$ADMIN_PASSWORD" 2>/dev/null || echo "") - if [ -n "$ADMIN_PASSWORD_HASH" ] && [ -f "$BACKUP_DIR/.env" ]; then - echo "ADMIN_PASSWORD_HASH='$ADMIN_PASSWORD_HASH'" >> "$BACKUP_DIR/.env" - fi - fi - - # Generate Caddyfile (using | delimiter to avoid conflicts with / and @) + # Generate Caddyfile sed -e "s|{DOMAIN}|$DOMAIN|g" -e "s|{TLS_EMAIL}|${TLS_EMAIL:-admin@$DOMAIN}|g" \ "$SCRIPT_DIR/config/caddy/Caddyfile" > "$TARGET_DIR/config/caddy/Caddyfile" - # Generate Authelia config + # Generate Authelia config (minimal — deploy.sh fills secrets) + JWT_SECRET="${JWT_SECRET:-$(openssl rand -hex 32)}" + SESSION_SECRET="${SESSION_SECRET:-$(openssl rand -hex 32)}" sed -e "s|{DOMAIN}|$DOMAIN|g" \ -e "s|{JWT_SECRET}|$JWT_SECRET|g" \ -e "s|{SESSION_SECRET}|$SESSION_SECRET|g" \ -e "s|{SMTP_HOST}|${SMTP_HOST:-smtp.openxchange.eu}|g" \ -e "s|{SMTP_PORT}|${SMTP_PORT:-587}|g" \ -e "s|{SMTP_USER}|${SMTP_USER:-post@nextwks.eu}|g" \ - -e "s|{SMTP_PASS}|${SMTP_PASS}|g" \ + -e "s|{SMTP_PASS}|$SMTP_PASS|g" \ "$SCRIPT_DIR/config/authelia/configuration.yml" > "$TARGET_DIR/config/authelia/configuration.yml" # Generate users database + ADMIN_PASSWORD_HASH="${ADMIN_PASSWORD_HASH:-}" + if [ -z "$ADMIN_PASSWORD_HASH" ] && [ -n "${ADMIN_PASSWORD:-}" ] && [ -f "$SCRIPT_DIR/tools/hash-password/main.go" ]; then + ADMIN_PASSWORD_HASH=$(cd "$SCRIPT_DIR" && go run ./tools/hash-password/ "$ADMIN_PASSWORD" 2>/dev/null || echo "") + fi sed -e "s|{ADMIN_PASSWORD_HASH}|$ADMIN_PASSWORD_HASH|g" \ -e "s|{TLS_EMAIL}|${TLS_EMAIL:-admin@$DOMAIN}|g" \ "$SCRIPT_DIR/config/authelia/users_database.yml" > "$TARGET_DIR/config/authelia/users_database.yml" - # Copy compose files + # Copy compose files + binary cp "$SCRIPT_DIR/compose/caddy.yaml" "$TARGET_DIR/compose/caddy.yaml" cp "$SCRIPT_DIR/compose/authelia.yaml" "$TARGET_DIR/compose/authelia.yaml" - - # Copy binary + cp "$SCRIPT_DIR/compose/launcher.yaml" "$TARGET_DIR/compose/launcher.yaml" cp "$BINARY_NAME" "$TARGET_DIR/$BINARY_NAME" if [ -f "$REPO_DIR/VERSION" ]; then cp "$REPO_DIR/VERSION" "$TARGET_DIR/VERSION" fi - # Copy www landing page + # Copy landing page if [ -d "$SCRIPT_DIR/config/www" ]; then cp -r "$SCRIPT_DIR/config/www"/* "$TARGET_DIR/www/" fi - # Deploy Caddy + Authelia - echo "[5/5] Deploying Caddy and Authelia..." - mkdir -p "$TARGET_DIR/data/caddy" - - # Restore Caddy certs from backup if available - if [ -d "$BACKUP_DIR/certificates/acme-v02" ]; then - mkdir -p "$CADDY_CERTS" - cp -r "$BACKUP_DIR/certificates"/* "$CADDY_CERTS/" 2>/dev/null || true - echo "[INFO] Restored Caddy certificates from backup" - fi - - sudo -u master podman-compose -f "$TARGET_DIR/compose/caddy.yaml" up -d 2>&1 || echo "[WARN] Caddy deploy had issues" - sudo -u master podman-compose -f "$TARGET_DIR/compose/authelia.yaml" up -d 2>&1 || echo "[WARN] Authelia deploy had issues" - - # Basic launcher config + # Copy launcher config cp -r "$SCRIPT_DIR/config/nextworkspace"/* "$TARGET_DIR/config/nextworkspace/" 2>/dev/null || true - # Copy apps.yaml template - cp "$SCRIPT_DIR/config/nextworkspace/apps.yaml" "$TARGET_DIR/config/nextworkspace/apps.yaml" 2>/dev/null || true + # Create podman network + echo "[5/6] Creating podman network..." + podman network create --subnet 172.16.0.0/24 "$NETWORK_NAME" 2>/dev/null || true - # Extract Authelia secret for binary + # Deploy all containers + echo "[6/6] Deploying containers..." + podman-compose -f "$TARGET_DIR/compose/launcher.yaml" up -d 2>&1 || echo "[WARN] Launcher deploy had issues" + podman-compose -f "$TARGET_DIR/compose/authelia.yaml" up -d 2>&1 || echo "[WARN] Authelia deploy had issues" + podman-compose -f "$TARGET_DIR/compose/caddy.yaml" up -d 2>&1 || echo "[WARN] Caddy deploy had issues" + + # Extract Authelia secret + sleep 3 AUTHELIA_SECRET=$(grep -oP 'session_secret: \K.*' "$TARGET_DIR/config/authelia/configuration.yml" 2>/dev/null || echo "") if [ -n "$AUTHELIA_SECRET" ]; then if ! grep -q "AUTHELIA_SECRET" "$BACKUP_DIR/.env" 2>/dev/null; then @@ -152,48 +121,12 @@ if [ "$GREENFIELD" = true ]; then fi fi - # Write systemd service - cat > /etc/systemd/system/$SERVICE_NAME.service </dev/null || true - echo "[4/5] Swapping binary..." - cp "$BINARY_NAME" "$TARGET_DIR/$BINARY_NAME" - - # Ensure AUTHELIA_SECRET is in .env - AUTHELIA_SECRET=$(grep -oP 'session_secret: \K.*' "$TARGET_DIR/config/authelia/configuration.yml" 2>/dev/null || echo "") - if [ -n "$AUTHELIA_SECRET" ]; then - if ! grep -q "AUTHELIA_SECRET" "$BACKUP_DIR/.env" 2>/dev/null; then - echo "AUTHELIA_SECRET=$AUTHELIA_SECRET" >> "$BACKUP_DIR/.env" - echo "[INFO] AUTHELIA_SECRET added to .env" - fi - fi - - echo "[5/5] Restarting services..." - sudo -u master podman restart caddy authelia 2>/dev/null || true - systemctl restart $SERVICE_NAME + echo "[3/6] Redeploying containers..." + podman-compose -f "$TARGET_DIR/compose/launcher.yaml" up -d 2>&1 || true + podman-compose -f "$TARGET_DIR/compose/authelia.yaml" up -d 2>&1 || true + podman-compose -f "$TARGET_DIR/compose/caddy.yaml" restart 2>&1 || true fi # --- Health check --- diff --git a/main.go b/main.go index 5267d63..ff308e2 100644 --- a/main.go +++ b/main.go @@ -303,7 +303,7 @@ func proxyToUpstream(upstream string) http.HandlerFunc { } func adminHandler(w http.ResponseWriter, r *http.Request) { - apiBase := "http://127.0.0.1:8080" + apiBase := "http://172.16.0.11:8080" apiToken := os.Getenv("AUTHELIA_SECRET") configDir := os.Getenv("CONFIG_DIR") if configDir == "" { @@ -348,13 +348,13 @@ func adminHandler(w http.ResponseWriter, r *http.Request) { // Check service statuses autheliaUp := false - if resp, err := http.Get("http://127.0.0.1:9091/api/health"); err == nil { + if resp, err := http.Get("http://172.16.0.11:9091/api/health"); err == nil { autheliaUp = resp.StatusCode == 200 resp.Body.Close() } caddyUp := false // Check port 80 responds (don't follow HTTPS redirect) - if conn, err := net.DialTimeout("tcp", "127.0.0.1:80", 3*time.Second); err == nil { + if conn, err := net.DialTimeout("tcp", "172.16.0.10:80", 3*time.Second); err == nil { caddyUp = true conn.Close() } @@ -511,7 +511,7 @@ type apiUser struct { func fetchAllUsers() ([]apiUser, error) { apiToken := os.Getenv("AUTHELIA_SECRET") - req, _ := http.NewRequest("GET", "http://127.0.0.1:8080/api/users", nil) + req, _ := http.NewRequest("GET", "http://172.16.0.11:8080/api/users", nil) req.Header.Set("Authorization", "Bearer "+apiToken) resp, err := http.DefaultClient.Do(req) if err != nil { @@ -608,7 +608,7 @@ func initials(s string) string { // --- API proxy for authelia-api --- func apiProxyHandler(w http.ResponseWriter, r *http.Request) { - target, _ := url.Parse("http://127.0.0.1:8080") + target, _ := url.Parse("http://172.16.0.11:8080") proxy := httputil.NewSingleHostReverseProxy(target) // Inject Bearer token for authelia-api auth token := os.Getenv("AUTHELIA_SECRET") @@ -638,7 +638,7 @@ func globalSettingsHandler(w http.ResponseWriter, r *http.Request) { // Check Authelia health autheliaUp := false - if resp, err := http.Get("http://127.0.0.1:9091/api/health"); err == nil { + if resp, err := http.Get("http://172.16.0.11:9091/api/health"); err == nil { autheliaUp = resp.StatusCode == 200 resp.Body.Close() }