--- - name: Configure HAProxy Load Balancer hosts: proxy become: true vars: vip_address: "172.16.1.253" backend_servers: "{{ groups['server'] }}" backend_port: 443 stats_port: 9000 stats_uri: "/haproxy_stats" stats_realm: "HAProxy Statistics" stats_user: "admin" stats_password: "haproxy_secure_pass" ssl_cert_path: "/etc/haproxy/ssl/www.au.team.pem" server_name: "www.au.team" tasks: - name: Install HAProxy package ansible.builtin.apt: name: haproxy state: present update_cache: true tags: haproxy - name: Create SSL directory for HAProxy ansible.builtin.file: path: /etc/haproxy/ssl state: directory mode: '0755' owner: root group: root tags: ssl - name: Generate combined PEM certificate for HAProxy ansible.builtin.shell: | cat /etc/angie/ssl/www.au.team.crt /etc/angie/ssl/www.au.team.key > {{ ssl_cert_path }} chmod 600 {{ ssl_cert_path }} args: creates: "{{ ssl_cert_path }}" tags: ssl - name: Configure HAProxy with SSL termination and roundrobin ansible.builtin.template: content: | global log /dev/log local0 log /dev/log local1 notice chroot /var/lib/haproxy stats socket /run/haproxy/admin.sock mode 660 level admin stats timeout 30s user haproxy group haproxy daemon ssl-default-bind-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384 ssl-default-bind-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256 ssl-default-bind-options ssl-min-ver TLSv1.2 no-tls-tickets defaults log global mode http option httplog option dontlognull timeout connect 5000 timeout client 50000 timeout server 50000 errorfile 400 /etc/haproxy/errors/400.http errorfile 403 /etc/haproxy/errors/403.http errorfile 408 /etc/haproxy/errors/408.http errorfile 500 /etc/haproxy/errors/500.http errorfile 502 /etc/haproxy/errors/502.http errorfile 503 /etc/haproxy/errors/503.http errorfile 504 /etc/haproxy/errors/504.http # Frontend: HTTPS with SNI support frontend https_front bind {{ vip_address }}:443 ssl crt {{ ssl_cert_path }} alpn h2,http/1.1 bind {{ vip_address }}:80 server_name {{ server_name }} # HTTP to HTTPS redirect http-request redirect scheme https unless { ssl_fc } # HSTS header http-response set-header Strict-Transport-Security "max-age=31536000; includeSubDomains" # ACL for stats acl is_stats path_beg {{ stats_uri }} use_backend stats_backend if is_stats default_backend web_backend # Backend: Web servers with roundrobin backend web_backend balance roundrobin option httpchk GET / HTTP/1.1\r\nHost:\ {{ server_name }} http-check expect status 200 {% for server in backend_servers %} server {{ server }} {{ hostvars[server]['ansible_host'] | default(server) }}:{{ backend_port }} check ssl verify none {% endfor %} # Stats backend backend stats_backend stats enable stats uri {{ stats_uri }} stats realm {{ stats_realm }} stats auth {{ stats_user }}:{{ stats_password }} stats admin if TRUE dest: /etc/haproxy/haproxy.cfg mode: '0644' backup: true validate: "haproxy -c -f %s" notify: Reload haproxy tags: haproxy - name: Add www.au.team to /etc/hosts for local resolution ansible.builtin.lineinfile: path: /etc/hosts regexp: '^127\.0\.1\.1\s+www\.au\.team' line: "127.0.1.1 {{ server_name }}" state: present tags: dns - name: Enable and start HAProxy service ansible.builtin.systemd: name: haproxy enabled: true state: started daemon_reload: true tags: haproxy handlers: - name: Reload haproxy ansible.builtin.systemd: name: haproxy state: reloaded daemon_reload: true