diff --git a/deploy/systemd/haproxy-edgeguard.conf b/deploy/systemd/haproxy-edgeguard.conf new file mode 100644 index 0000000..6d27a00 --- /dev/null +++ b/deploy/systemd/haproxy-edgeguard.conf @@ -0,0 +1,14 @@ +# systemd drop-in: point distro HAProxy at the EdgeGuard-generated +# config without touching /etc/haproxy/haproxy.cfg (which is a +# conffile of the haproxy package). Installed by edgeguard-api's +# postinst into /etc/systemd/system/haproxy.service.d/edgeguard.conf. +[Unit] +# api_backend points at edgeguard-api on 127.0.0.1:9443 — wait for +# it to be up before starting, otherwise HAProxy 503s for ~5s while +# its L4 health-check polls. +After=edgeguard-api.service +Wants=edgeguard-api.service + +[Service] +ExecStart= +ExecStart=/usr/sbin/haproxy -Ws -f /etc/edgeguard/haproxy/haproxy.cfg -p /run/haproxy.pid -S /run/haproxy-master.sock diff --git a/internal/haproxy/haproxy.cfg.tpl b/internal/haproxy/haproxy.cfg.tpl index b0c712d..23e6ea9 100644 --- a/internal/haproxy/haproxy.cfg.tpl +++ b/internal/haproxy/haproxy.cfg.tpl @@ -29,9 +29,12 @@ frontend public_http bind :80 acl is_acme path_beg /.well-known/acme-challenge/ - use_backend api_backend if is_acme - http-request redirect scheme https code 301 unless { ssl_fc } is_acme + # Redirect to HTTPS first (skipped for ACME paths) — must come + # before use_backend so HAProxy doesn't warn about ordering. + http-request redirect scheme https code 301 unless is_acme + + use_backend api_backend if is_acme # ── Public :443 ──────────────────────────────────────────────────────── # TLS termination. Reads certs from /etc/edgeguard/tls/ — postinst diff --git a/packaging/debian/edgeguard-api/DEBIAN/control b/packaging/debian/edgeguard-api/DEBIAN/control index 6bd801e..a82d45d 100644 --- a/packaging/debian/edgeguard-api/DEBIAN/control +++ b/packaging/debian/edgeguard-api/DEBIAN/control @@ -12,8 +12,8 @@ Description: EdgeGuard — native Reverse-Proxy / LB / Forward-Proxy / VPN / Fir PG Streaming Replication + provider Floating-IP for HTTP ingress). . This package ships the management API, scheduler and CLI. -Depends: postgresql-16 | postgresql-17, edgeguard-keydb (>= 6.3.4-edgeguard1), haproxy (>= 2.8), squid, wireguard-tools, unbound, nftables, certbot, openssl, sudo, adduser, systemd, ca-certificates -Recommends: apparmor, fail2ban +Depends: postgresql-16 | postgresql-17, haproxy (>= 2.8), squid, wireguard-tools, unbound, nftables, certbot, openssl, sudo, adduser, systemd, ca-certificates +Recommends: edgeguard-keydb (>= 6.3.4-edgeguard1), apparmor, fail2ban Section: admin Priority: optional Installed-Size: 0 diff --git a/packaging/debian/edgeguard-api/DEBIAN/postinst b/packaging/debian/edgeguard-api/DEBIAN/postinst index 23b2668..c250f73 100755 --- a/packaging/debian/edgeguard-api/DEBIAN/postinst +++ b/packaging/debian/edgeguard-api/DEBIAN/postinst @@ -73,8 +73,29 @@ case "$1" in exit 1 fi - # ── systemd ────────────────────────────────────────────────── + # ── Render initial service configs ─────────────────────────── + # Writes /etc/edgeguard/haproxy/haproxy.cfg + nftables.d/ + # ruleset.nft from the (just-migrated, empty) PG state. + # --no-reload because haproxy isn't pointed at our config yet + # — the drop-in below does that, then we restart. + if ! sudo -n -u "$EG_USER" /usr/bin/edgeguard-ctl render-config --no-reload; then + echo "postinst: edgeguard-ctl render-config failed — aborting" >&2 + exit 1 + fi + + # ── HAProxy systemd drop-in: read EdgeGuard config ─────────── + # Keeps the distro /etc/haproxy/haproxy.cfg untouched (it's a + # conffile of the haproxy package). Drop-in is reversible by + # removing the file + daemon-reload. + install -d /etc/systemd/system/haproxy.service.d + if [ -f /etc/edgeguard/systemd/haproxy-edgeguard.conf ]; then + install -m 0644 /etc/edgeguard/systemd/haproxy-edgeguard.conf \ + /etc/systemd/system/haproxy.service.d/edgeguard.conf + fi + + # ── systemd: pick up new units + restart haproxy with our cfg systemctl daemon-reload + systemctl restart haproxy.service || true systemctl enable --now edgeguard-api.service edgeguard-scheduler.service || true ;; diff --git a/packaging/debian/edgeguard-api/DEBIAN/postrm b/packaging/debian/edgeguard-api/DEBIAN/postrm index 2cfe19c..dd2bbb3 100755 --- a/packaging/debian/edgeguard-api/DEBIAN/postrm +++ b/packaging/debian/edgeguard-api/DEBIAN/postrm @@ -3,14 +3,28 @@ set -e case "$1" in purge) - # Only on purge: remove user, configs, state. + # Only on purge: remove user, configs, state, HAProxy + # drop-in (so the distro haproxy.cfg path takes over again). if getent passwd edgeguard >/dev/null; then deluser --quiet edgeguard >/dev/null 2>&1 || true fi + rm -f /etc/systemd/system/haproxy.service.d/edgeguard.conf + rmdir /etc/systemd/system/haproxy.service.d 2>/dev/null || true + systemctl daemon-reload || true rm -rf /etc/edgeguard /var/lib/edgeguard /var/log/edgeguard ;; - remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear) + remove) + # Plain remove (not purge) — pull our HAProxy override so + # the haproxy daemon goes back to its distro config and + # keeps running. + rm -f /etc/systemd/system/haproxy.service.d/edgeguard.conf + rmdir /etc/systemd/system/haproxy.service.d 2>/dev/null || true + systemctl daemon-reload || true + systemctl reload haproxy.service 2>/dev/null || true + ;; + + upgrade|failed-upgrade|abort-install|abort-upgrade|disappear) ;; *) diff --git a/scripts/apt-repo/build-package.sh b/scripts/apt-repo/build-package.sh index 761bab3..2e5345d 100755 --- a/scripts/apt-repo/build-package.sh +++ b/scripts/apt-repo/build-package.sh @@ -71,6 +71,13 @@ build_api() { install -m 0644 "$REPO_ROOT/deploy/systemd/edgeguard-scheduler.service" \ "$build_dir/etc/systemd/system/" + # systemd drop-in for HAProxy — postinst copies it into + # /etc/systemd/system/haproxy.service.d/. Shipped under + # /etc/edgeguard/systemd/ so dpkg owns the source file. + mkdir -p "$build_dir/etc/edgeguard/systemd" + install -m 0644 "$REPO_ROOT/deploy/systemd/haproxy-edgeguard.conf" \ + "$build_dir/etc/edgeguard/systemd/" + # Installed-Size in KB (rounded up) local size size="$(du -sk "$build_dir" | awk '{print $1}')"