Skip to content

Replace nginx with HAProxy and introduce new rule syntax#1

Merged
dash14 merged 21 commits intomainfrom
migrate-haproxy
Mar 1, 2026
Merged

Replace nginx with HAProxy and introduce new rule syntax#1
dash14 merged 21 commits intomainfrom
migrate-haproxy

Conversation

@dash14
Copy link
Copy Markdown
Owner

@dash14 dash14 commented Mar 1, 2026

Summary

  • Replace nginx with HAProxy as the egress proxy, enabling L4/L7 filtering with detailed block reasons (not-allowed, dns-failed, missing-sni, missing-host-header, ip-not-allowed)
  • Migrate process management from entrypoint.sh to s6-overlay for proper service supervision (dnsmasq, HAProxy, init scripts)
  • Introduce new rule syntax with allowed_https_rules, allowed_http_rules, and allowed_ip_rules inputs, supporting wildcard patterns (*, **, ?), wildcard port (example.com:*), and regex (~-prefixed) — replacing the deprecated
    allowed_*_domains / *_ports inputs
  • Refactor setup/main.mjs into structured functions with dependency injection for better testability
  • Show blocked hosts with reasons in audit mode report and scope fail_on_blocked to restrict mode only
  • Add test cases for dns-failed, missing-sni, missing-host-header, nested subdomain blocking, and direct IP access

Test plan

  • Run make test to execute restrict mode and audit mode integration tests
  • Verify HAProxy starts correctly with s6-overlay process supervision
  • Confirm rule parsing: wildcard patterns, wildcard port *, regex rules, and legacy input compatibility
  • Validate report output shows block reasons in both audit and restrict modes
  • Check that deprecated allowed_*_domains / *_ports inputs still work with deprecation warnings

Migrate the proxy layer from nginx (stream + http modules) to HAProxy, enabling unified TCP/HTTP filtering in a single process with iptables REDIRECT. Domain allowlists are replaced with regex-based rules (ALLOWED_HTTPS_RULES, ALLOWED_HTTP_RULES, ALLOWED_IP_RULES) that match against host:port pairs for more flexible control.
…locking

Add edge-case test coverage for infrastructure-level blocking behaviors:
- DNS resolution failure (NXDOMAIN) for both HTTP and HTTPS
- TLS ClientHello without SNI extension
- HTTP request without Host header
- Direct IP access blocking (restrict mode assertion)

These cases are blocked even in audit mode since they represent protocol/infrastructure errors rather than policy decisions.
hdr(host) -m found returns true even when the Host header is present but empty (e.g., "Host: "). Add hdr_len(host) gt 0 check to also block requests with empty Host header values.
Docker log driver may not have captured all HAProxy output when docker compose logs runs immediately. Add a 500ms delay to ensure logs are fully available.
Change EXTERNAL_RESOLVER from space-delimited with inline "valid=301s" parameter to simple comma-separated IP format (e.g. "1.1.1.1,8.8.8.8").
Move "hold valid 300s" and "accepted_payload_size 8192" into the HAProxy config template as static values, eliminating the need for parsing mixed tokens in entrypoint.sh.
Replace the monolithic entrypoint.sh with s6-overlay process supervisor to manage dnsmasq, haproxy, and initialization tasks as discrete services with proper dependency ordering via s6-rc.
Introduce setup/rules.mjs providing a rule parser that converts
user-facing allow rules (wildcard patterns, ~regex, IP addresses)
into HAProxy-compatible regex strings. Add unit tests with regex
behavior verification, and a make test_unit target to run them.
…ted rules

Replace legacy domain-based parameters (allowed_https_domains,
allowed_http_domains, https_ports, http_ports) with new unified
rule parameters (allowed_https_rules, allowed_http_rules) that
support per-rule port specification. Legacy parameters are kept
as deprecated with automatic conversion. Switch the internal
delimiter from comma to whitespace. Add E2E test cases for
nested subdomain blocking and HTTP wildcard matching.
…restrict mode

In audit mode, display blocked connections (e.g., protocol errors)
in the report and emit a notice instead of failing the step.
The fail_on_blocked parameter now only applies to restrict mode.
Remove the now-unnecessary || true from test_audit_mode target.
Add docs/rules.md as a rule syntax reference covering wildcards,
regex, IP addresses, and migration from deprecated parameters.
Update README.md, development guide, and example workflow to
reflect the new allowed_https_rules / allowed_http_rules parameters.
Separate IP address rules into a dedicated `allowed_ip_rules` input
instead of auto-detecting them from HTTPS/HTTP rule inputs. Add
wildcard port `*` syntax to match any port (e.g., `example.com:*`).

Refactor main.mjs into structured functions with dependency injection
and simplify rule parsing by removing `{…}` block preservation.
Remove stale comment referencing removed {…} block syntax and replace
empty HAPROXY_AUDIT_ACCEPT value with a descriptive HAProxy comment for
restrict mode.
Reject blocked domains before do-resolve to avoid unnecessary DNS
queries for connections that will be denied.
Add setup/convert-rules.mjs so Makefile can accept wildcard syntax
instead of requiring hand-written regex. Move rules.mjs and its tests
into setup/lib/ for better organization.
@dash14 dash14 force-pushed the migrate-haproxy branch from 8b581e9 to aad7fb0 Compare March 1, 2026 06:09
dash14 added 4 commits March 1, 2026 17:06
Keep stdin open with sleep after printf to prevent BusyBox nc from
closing the connection before HAProxy processes the HTTP request in
the backend. Also remove unnecessary 500ms delay from report script.
- Fix test mock targeting console.warn instead of console.log in
  buildLegacyRules empty portsInput test
- Guard against whitespace-only portsInput by trimming before fallback
- Validate regex syntax in ~-prefixed rules to fail early instead of
  crashing HAProxy at startup
Comment thread setup/lib/rules.mjs Dismissed
dash14 added 2 commits March 1, 2026 18:21
- Reorder sections logically: Network Isolation → DNS → Proxy → Direct IP
- Clarify DNS redirect, HTTP proxy, and iptables descriptions
- Add missing Host header rejection to proxy control section
- Split Direct IP section into traffic redirection and IP allowlist check
- Fix variable names and add audit mode link
@dash14 dash14 merged commit a4a9cf1 into main Mar 1, 2026
6 checks passed
@dash14 dash14 deleted the migrate-haproxy branch March 1, 2026 10:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants