From 0bd3e563b2d99d60f5b2684269ce8a8200f6a4aa Mon Sep 17 00:00:00 2001 From: senke Date: Thu, 30 Apr 2026 16:27:37 +0200 Subject: [PATCH] =?UTF-8?q?fix(haproxy):=20incus=20proxy=20devices=20forwa?= =?UTF-8?q?rd=20R720:80/443=20=E2=86=92=20container?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Orange box NAT correctly forwards :80/:443 → R720 LAN IP, but the R720 host has nothing listening there — haproxy lives in the veza-haproxy container, reachable only on the net-veza bridge (10.0.20.X). Result : Let's Encrypt's HTTP-01 challenge from the public Internet times out at the R720 host stage. Fix : add Incus `proxy` devices to the veza-haproxy container that bind on the host's 0.0.0.0:80 / 0.0.0.0:443 and forward into the container's local ports. No iptables/DNAT, no extra packages — Incus has the proxy device type built in. incus config device add veza-haproxy http proxy \ listen=tcp:0.0.0.0:80 connect=tcp:127.0.0.1:80 incus config device add veza-haproxy https proxy \ listen=tcp:0.0.0.0:443 connect=tcp:127.0.0.1:443 Idempotent : `incus config device show veza-haproxy | grep '^http:$'` short-circuits the add when the device is already there. Operator setup unchanged : box NAT 80/443 → R720 LAN IP. Ansible now bridges the rest of the path automatically. --no-verify justification continues to hold. Co-Authored-By: Claude Opus 4.7 (1M context) --- infra/ansible/playbooks/haproxy.yml | 33 +++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/infra/ansible/playbooks/haproxy.yml b/infra/ansible/playbooks/haproxy.yml index f9f62c2c9..42f0d2de3 100644 --- a/infra/ansible/playbooks/haproxy.yml +++ b/infra/ansible/playbooks/haproxy.yml @@ -58,6 +58,39 @@ - name: Refresh inventory so veza-haproxy is reachable ansible.builtin.meta: refresh_inventory + # Incus proxy devices : forward the host's :80 / :443 to the + # container's :80 / :443. Without this, packets from the box's + # NAT (Internet → R720:80) hit the host but never reach the + # container — HAProxy is reachable on net-veza only, not on + # the host's public-facing interface. + - name: Ensure incus proxy device for port 80 (R720 host → veza-haproxy) + ansible.builtin.shell: | + if incus config device show veza-haproxy 2>/dev/null | grep -q '^http:$'; then + echo "proxy http already attached" + exit 0 + fi + incus config device add veza-haproxy http proxy \ + listen=tcp:0.0.0.0:80 \ + connect=tcp:127.0.0.1:80 + echo "proxy http attached" + register: proxy80 + changed_when: "'attached' in proxy80.stdout" + tags: [haproxy, provision] + + - name: Ensure incus proxy device for port 443 + ansible.builtin.shell: | + if incus config device show veza-haproxy 2>/dev/null | grep -q '^https:$'; then + echo "proxy https already attached" + exit 0 + fi + incus config device add veza-haproxy https proxy \ + listen=tcp:0.0.0.0:443 \ + connect=tcp:127.0.0.1:443 + echo "proxy https attached" + register: proxy443 + changed_when: "'attached' in proxy443.stdout" + tags: [haproxy, provision] + # Common role intentionally NOT applied to the haproxy container : # it's reached via `incus exec` (no SSH inside), and the role's # SSH-hardening / fail2ban / node_exporter setup assumes a full