HAProxy That Refuses TLS 1.0
HAProxy terminating TLS 1.2 and 1.3 only with a modern cipher policy, HTTP redirected to HTTPS, HSTS on every response including HAProxy's own error pages (http-after-response, which the live test proved http-response does not cover), a self-signed certificate until yours arrives, stats kept local. Original role, live-tested on Rocky Linux 10.
Verification
Live-testedReally deployed to a container sandbox, proven idempotent (a second run changes nothing), verified against the role’s assertions, then torn down.
Conformance
- Static validation (yamllint · ansible-lint)
Provenance
- SHA-256 checksum
- Signature (pending)
Functional
- Live-tested - applied, verified, destroyed
Last verified 2026-09-19 · podman 4.9.3 · ansible 2.21.4 · how we verify
Documentation
haproxy-tls
HAProxy as a TLS-terminating reverse proxy: TLS 1.2 and 1.3 only with a modern cipher policy, HTTP redirected to HTTPS, HSTS and the usual response headers, and a self-signed certificate generated on first apply so the listener is encrypted before a real certificate arrives. Original role for EL 9 and 10, live-tested with podman on Rocky Linux 10.
bind :443 ssl on its own accepts TLS 1.0. HAProxy inherits whatever
OpenSSL allows unless ssl-default-bind-options and the cipher lists say
otherwise, and the package's sample configuration sets none of them. This role
writes ssl-min-ver TLSv1.2, the Mozilla intermediate cipher list and the TLS
1.3 suites into global, so every ssl bind line in the file - including ones
you add under conf.d/ - inherits the policy. The verify step offers a TLS 1.1
handshake and asserts it is refused, then negotiates TLS 1.3.
The headers are on every response, including HAProxy's own. The role sets
HSTS and the other response headers with http-after-response, not
http-response: the latter never runs on the 502 and 503 pages HAProxy
generates when a backend is down, which the live test showed by getting a 503
with no HSTS header at all. A browser that sees the error page without HSTS
has no reason to refuse plain HTTP next time.
No backend, no guessing. haproxy_tls_backend_servers is empty by default
and HAProxy answers 503 until you name one, which is also how the live test
proves TLS termination without an application behind it. Each entry is a plain
HAProxy server line minus the keyword (web1 10.0.1.10:8080 weight 2), and
check is appended unless you wrote it.
The certificate is yours. The role generates a self-signed PEM only where
haproxy_tls_pem_path does not exist. Put a real key-and-chain PEM there and it
is never touched again.
Stats stay local. The admin socket is root-only in /var/lib/haproxy, and
the stats page is off; on, it binds to loopback.
License
Commercial - IaC Bazaar EULA. (c) IaC Bazaar.
Usage code & full reference need an account
The complete copy-paste usage, the full input/output reference, and operational notes are free with an account - shown here and bundled in the download. Sign in and this section fills in.
- Variables
- Test