refactor: consolidate all roles into ansible/roles/ and update ansible.cfg
- Move all roles from playbooks/roles/ to roles/ - Update roles_path in ansible.cfg - Add cast user to common role - Create standalone podman role - Add semaphore role with Podman + Quadlet support
This commit is contained in:
0
ansible/roles/haproxy/README.md
Normal file
0
ansible/roles/haproxy/README.md
Normal file
147
ansible/roles/haproxy/defaults/main.yml
Normal file
147
ansible/roles/haproxy/defaults/main.yml
Normal file
@@ -0,0 +1,147 @@
|
||||
---
|
||||
# ansible/roles/haproxy/defaults/main.yml
|
||||
|
||||
# HAProxy version and installation
|
||||
haproxy_version: "3.2"
|
||||
haproxy_install_method: "package" # package or source
|
||||
|
||||
# System configuration
|
||||
haproxy_user: haproxy
|
||||
haproxy_group: haproxy
|
||||
haproxy_chroot_dir: /var/lib/haproxy
|
||||
haproxy_config_dir: /etc/haproxy
|
||||
haproxy_log_dir: /var/log/haproxy
|
||||
|
||||
# Global settings
|
||||
haproxy_global_maxconn: 4096
|
||||
haproxy_global_log_facility: local0
|
||||
haproxy_global_log_level: info
|
||||
haproxy_global_nbthread: "{{ ansible_processor_vcpus }}"
|
||||
|
||||
# Default timeouts (milliseconds)
|
||||
haproxy_timeout_connect: 5000
|
||||
haproxy_timeout_client: 50000
|
||||
haproxy_timeout_server: 50000
|
||||
|
||||
# Stats interface
|
||||
haproxy_stats_enable: true
|
||||
haproxy_stats_port: 8404
|
||||
haproxy_stats_uri: /stats
|
||||
haproxy_stats_refresh: 30s
|
||||
haproxy_stats_username: admin
|
||||
haproxy_stats_password: "{{ vault_haproxy_stats_password | default('changeme') }}"
|
||||
|
||||
# SSL/TLS configuration
|
||||
haproxy_ssl_cert_dir: "{{ haproxy_config_dir }}/certs"
|
||||
haproxy_ssl_default_crt: "{{ haproxy_ssl_cert_dir }}/default.pem"
|
||||
haproxy_ssl_ciphers: "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384"
|
||||
haproxy_ssl_options: "ssl-min-ver TLSv1.2 no-tls-tickets"
|
||||
|
||||
# Health check defaults
|
||||
haproxy_health_check_interval: 2000
|
||||
haproxy_health_check_timeout: 1000
|
||||
haproxy_health_check_rise: 2
|
||||
haproxy_health_check_fall: 3
|
||||
|
||||
# Service discovery integration
|
||||
haproxy_netbox_integration: false # true
|
||||
haproxy_netbox_url: "http://fire-station.local.mk-labs.cloud:8000"
|
||||
haproxy_netbox_token: "{{ vault_netbox_token | default('') }}"
|
||||
|
||||
# Frontends configuration
|
||||
haproxy_frontends: []
|
||||
# - name: http_front
|
||||
# bind: "*:80"
|
||||
# mode: http
|
||||
# redirect: "scheme https code 301"
|
||||
#
|
||||
# - name: https_front
|
||||
# bind: "*:443 ssl crt {{ haproxy_ssl_cert_dir }}"
|
||||
# mode: http
|
||||
# options:
|
||||
# - "http-server-close"
|
||||
# - "forwardfor"
|
||||
# acls:
|
||||
# - "netbox hdr(host) -i fire-station.local.mk-labs.cloud"
|
||||
# - "wordpress hdr(host) -i be-our-guest.local.mk-labs.cloud"
|
||||
# use_backends:
|
||||
# - "netbox_back if netbox"
|
||||
# - "wordpress_back if wordpress"
|
||||
|
||||
# Backends configuration
|
||||
haproxy_backends: []
|
||||
# - name: netbox_back
|
||||
# mode: http
|
||||
# balance: roundrobin
|
||||
# options:
|
||||
# - "httpchk GET /"
|
||||
# servers:
|
||||
# - name: fire-station
|
||||
# address: 10.1.71.102:8000
|
||||
# check: true
|
||||
|
||||
# TCP services configuration
|
||||
haproxy_tcp_services: []
|
||||
# - name: postgres
|
||||
# frontend_port: 5432
|
||||
# backend_port: 5432
|
||||
# balance: leastconn
|
||||
# servers:
|
||||
# - name: netbox-db
|
||||
# address: 10.1.71.102
|
||||
|
||||
# Firewall configuration
|
||||
haproxy_configure_firewall: true
|
||||
haproxy_firewall_allowed_ports:
|
||||
- 80/tcp
|
||||
- 443/tcp
|
||||
- 8404/tcp
|
||||
|
||||
# Monitoring and observability
|
||||
haproxy_prometheus_exporter: false
|
||||
haproxy_prometheus_port: 9101
|
||||
|
||||
# Logging
|
||||
haproxy_rsyslog_config: true
|
||||
haproxy_log_rotation: true
|
||||
|
||||
# Certificate management - Certbot with Cloudflare DNS
|
||||
haproxy_certbot_enable: true
|
||||
haproxy_certbot_challenge_method: "dns-cloudflare" # or "webroot" for HTTP-01
|
||||
haproxy_certbot_email: "ryan.blundon@protonmail.com"
|
||||
haproxy_certbot_staging: false # Set to true for testing with Let's Encrypt staging
|
||||
|
||||
# Cloudflare DNS configuration
|
||||
haproxy_certbot_cloudflare_api_token: "{{ vault_cloudflare_api_token }}"
|
||||
haproxy_certbot_cloudflare_credentials_file: "/etc/letsencrypt/cloudflare.ini"
|
||||
|
||||
# Certificate domains - DNS-01 supports wildcards
|
||||
haproxy_certbot_domains:
|
||||
- domain: "*.mk-labs.cloud"
|
||||
include_base: true
|
||||
- domain: "*.local.mk-labs.cloud"
|
||||
include_base: true # Also include local.mk-labs.cloud
|
||||
- domain: "lightning-lane.local.mk-labs.cloud"
|
||||
include_base: false
|
||||
|
||||
# Alternative: specific domains without wildcard
|
||||
# haproxy_certbot_domains:
|
||||
# - domain: "lightning-lane.local.mk-labs.cloud"
|
||||
# - domain: "fire-station.local.mk-labs.cloud"
|
||||
# - domain: "be-our-guest.local.mk-labs.cloud"
|
||||
|
||||
# Certbot renewal settings
|
||||
haproxy_certbot_renewal_cron_minute: "0"
|
||||
haproxy_certbot_renewal_cron_hour: "3" # 3 AM daily
|
||||
haproxy_certbot_renewal_cron_day: "*"
|
||||
haproxy_certbot_post_hook: "{{ haproxy_config_dir }}/certbot-post-hook.sh"
|
||||
|
||||
# Certificate storage
|
||||
haproxy_certbot_cert_dir: "/etc/letsencrypt/live"
|
||||
haproxy_certbot_archive_dir: "/etc/letsencrypt/archive"
|
||||
|
||||
# DNS propagation wait time (seconds)
|
||||
haproxy_certbot_dns_propagation_seconds: 60
|
||||
|
||||
# Fallback to self-signed if Certbot fails
|
||||
haproxy_certbot_fallback_selfsigned: true
|
||||
26
ansible/roles/haproxy/handlers/main.yml
Normal file
26
ansible/roles/haproxy/handlers/main.yml
Normal file
@@ -0,0 +1,26 @@
|
||||
---
|
||||
# ansible/roles/haproxy/handlers/main.yml
|
||||
|
||||
- name: Reload haproxy
|
||||
ansible.builtin.systemd:
|
||||
name: haproxy
|
||||
state: reloaded
|
||||
listen: reload haproxy
|
||||
|
||||
- name: Restart haproxy
|
||||
ansible.builtin.systemd:
|
||||
name: haproxy
|
||||
state: restarted
|
||||
daemon_reload: true
|
||||
listen: restart haproxy
|
||||
|
||||
- name: Reload systemd
|
||||
ansible.builtin.systemd:
|
||||
daemon_reload: true
|
||||
listen: reload systemd
|
||||
|
||||
- name: Restart rsyslog
|
||||
ansible.builtin.systemd:
|
||||
name: rsyslog
|
||||
state: restarted
|
||||
listen: restart rsyslog
|
||||
202
ansible/roles/haproxy/tasks/certbot-cloudflare.yml
Normal file
202
ansible/roles/haproxy/tasks/certbot-cloudflare.yml
Normal file
@@ -0,0 +1,202 @@
|
||||
---
|
||||
# ansible/roles/haproxy/tasks/certbot-cloudflare.yml
|
||||
|
||||
- name: Install Certbot and Cloudflare DNS plugin
|
||||
ansible.builtin.package:
|
||||
name:
|
||||
- certbot
|
||||
- python3-certbot-dns-cloudflare
|
||||
state: present
|
||||
|
||||
- name: Create Let's Encrypt configuration directory
|
||||
ansible.builtin.file:
|
||||
path: /etc/letsencrypt
|
||||
state: directory
|
||||
owner: root
|
||||
group: root
|
||||
mode: '0755'
|
||||
|
||||
- name: Create Cloudflare credentials file
|
||||
ansible.builtin.template:
|
||||
src: cloudflare-credentials.ini.j2
|
||||
dest: "{{ haproxy_certbot_cloudflare_credentials_file }}"
|
||||
owner: root
|
||||
group: root
|
||||
mode: '0600'
|
||||
no_log: true
|
||||
|
||||
- name: Create Certbot post-renewal hook script
|
||||
ansible.builtin.template:
|
||||
src: certbot-post-hook.sh.j2
|
||||
dest: "{{ haproxy_certbot_post_hook }}"
|
||||
owner: root
|
||||
group: root
|
||||
mode: '0755'
|
||||
|
||||
- name: Create Certbot renewal hooks directory
|
||||
ansible.builtin.file:
|
||||
path: /etc/letsencrypt/renewal-hooks/deploy
|
||||
state: directory
|
||||
mode: '0755'
|
||||
|
||||
- name: Link post-hook to renewal hooks directory
|
||||
ansible.builtin.file:
|
||||
src: "{{ haproxy_certbot_post_hook }}"
|
||||
dest: /etc/letsencrypt/renewal-hooks/deploy/haproxy-reload.sh
|
||||
state: link
|
||||
force: true
|
||||
|
||||
- name: Check for existing certificates
|
||||
ansible.builtin.stat:
|
||||
path: "{{ haproxy_certbot_cert_dir }}/{{ item.domain | regex_replace('\\*\\.', '') }}"
|
||||
register: existing_certs
|
||||
loop: "{{ haproxy_certbot_domains }}"
|
||||
loop_control:
|
||||
label: "{{ item.domain }}"
|
||||
|
||||
- name: Build certificate request commands
|
||||
ansible.builtin.set_fact:
|
||||
certbot_commands: "{{ certbot_commands | default([]) + [command_item] }}"
|
||||
vars:
|
||||
cert_name: "{{ item.item.domain | regex_replace('\\*\\.', '') }}"
|
||||
domain_list: >-
|
||||
{{ [item.item.domain] +
|
||||
(item.item.include_base | default(false) | ternary(
|
||||
[item.item.domain | regex_replace('\\*\\.', '')],
|
||||
[]
|
||||
))
|
||||
}}
|
||||
command_item:
|
||||
domain: "{{ item.item.domain }}"
|
||||
cert_name: "{{ cert_name }}"
|
||||
domains: "{{ domain_list }}"
|
||||
exists: "{{ item.stat.exists }}"
|
||||
loop: "{{ existing_certs.results }}"
|
||||
loop_control:
|
||||
label: "{{ item.item.domain }}"
|
||||
|
||||
- name: Display certificate request plan
|
||||
ansible.builtin.debug:
|
||||
msg: |
|
||||
Will request certificates for:
|
||||
{% for cmd in certbot_commands %}
|
||||
- {{ cmd.cert_name }} ({{ cmd.domains | join(', ') }}) - {{ 'EXISTS' if cmd.exists else 'NEW' }}
|
||||
{% endfor %}
|
||||
|
||||
- name: Request certificates from Let's Encrypt via Cloudflare DNS
|
||||
ansible.builtin.command: >
|
||||
certbot certonly
|
||||
--non-interactive
|
||||
--agree-tos
|
||||
--email {{ haproxy_certbot_email }}
|
||||
--dns-cloudflare
|
||||
--dns-cloudflare-credentials {{ haproxy_certbot_cloudflare_credentials_file }}
|
||||
--dns-cloudflare-propagation-seconds {{ haproxy_certbot_dns_propagation_seconds }}
|
||||
--cert-name {{ item.cert_name }}
|
||||
{% for domain in item.domains %}
|
||||
--domain {{ domain }}
|
||||
{% endfor %}
|
||||
{% if haproxy_certbot_staging %}
|
||||
--staging
|
||||
{% endif %}
|
||||
--deploy-hook {{ haproxy_certbot_post_hook }}
|
||||
loop: "{{ certbot_commands }}"
|
||||
loop_control:
|
||||
label: "{{ item.cert_name }}"
|
||||
when: not item.exists
|
||||
register: certbot_result
|
||||
failed_when:
|
||||
- certbot_result.rc != 0
|
||||
- "'Certificate not yet due for renewal' not in certbot_result.stdout"
|
||||
- "'too many certificates already issued' not in certbot_result.stderr"
|
||||
|
||||
- name: Display certificate request results
|
||||
ansible.builtin.debug:
|
||||
msg: "Certificate for {{ item.item.cert_name }}: {{ 'SUCCESS' if item.rc == 0 else 'SKIPPED/FAILED' }}"
|
||||
loop: "{{ certbot_result.results }}"
|
||||
loop_control:
|
||||
label: "{{ item.item.cert_name }}"
|
||||
when: certbot_result.results is defined
|
||||
|
||||
- name: Run post-hook to combine certificates for HAProxy
|
||||
ansible.builtin.command: "{{ haproxy_certbot_post_hook }}"
|
||||
changed_when: true
|
||||
when: certbot_result.changed
|
||||
|
||||
- name: Setup automatic certificate renewal via cron
|
||||
ansible.builtin.cron:
|
||||
name: "Certbot certificate renewal"
|
||||
minute: "{{ haproxy_certbot_renewal_cron_minute }}"
|
||||
hour: "{{ haproxy_certbot_renewal_cron_hour }}"
|
||||
day: "{{ haproxy_certbot_renewal_cron_day }}"
|
||||
job: "/usr/bin/certbot renew --quiet --deploy-hook {{ haproxy_certbot_post_hook }} 2>&1 | logger -t certbot"
|
||||
user: root
|
||||
state: present
|
||||
|
||||
- name: Create systemd timer for certificate renewal (alternative to cron)
|
||||
when: ansible_service_mgr == "systemd"
|
||||
block:
|
||||
- name: Create certbot renewal service
|
||||
ansible.builtin.copy:
|
||||
content: |
|
||||
[Unit]
|
||||
Description=Certbot Renewal
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/usr/bin/certbot renew --quiet --deploy-hook {{ haproxy_certbot_post_hook }}
|
||||
StandardOutput=journal
|
||||
StandardError=journal
|
||||
dest: /etc/systemd/system/certbot-renewal.service
|
||||
mode: '0644'
|
||||
|
||||
- name: Create certbot renewal timer
|
||||
ansible.builtin.copy:
|
||||
content: |
|
||||
[Unit]
|
||||
Description=Certbot Renewal Timer
|
||||
|
||||
[Timer]
|
||||
OnCalendar=daily
|
||||
RandomizedDelaySec=1h
|
||||
Persistent=true
|
||||
|
||||
[Install]
|
||||
WantedBy=timers.target
|
||||
dest: /etc/systemd/system/certbot-renewal.timer
|
||||
mode: '0644'
|
||||
|
||||
- name: Enable and start certbot renewal timer
|
||||
ansible.builtin.systemd:
|
||||
name: certbot-renewal.timer
|
||||
enabled: true
|
||||
state: started
|
||||
daemon_reload: true
|
||||
|
||||
- name: Test certificate renewal (dry-run)
|
||||
ansible.builtin.command: certbot renew --dry-run --dns-cloudflare --dns-cloudflare-credentials {{ haproxy_certbot_cloudflare_credentials_file }}
|
||||
register: renewal_test
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
|
||||
- name: Display renewal test results
|
||||
ansible.builtin.debug:
|
||||
msg: |
|
||||
Certificate renewal dry-run: {{ 'SUCCESS ✓' if renewal_test.rc == 0 else 'FAILED ✗' }}
|
||||
|
||||
{% if renewal_test.rc == 0 %}
|
||||
Your certificates will renew automatically.
|
||||
{% else %}
|
||||
Please check the output above for errors.
|
||||
{% endif %}
|
||||
|
||||
- name: List all certificates
|
||||
ansible.builtin.command: certbot certificates
|
||||
register: cert_list
|
||||
changed_when: false
|
||||
|
||||
- name: Display certificate information
|
||||
ansible.builtin.debug:
|
||||
msg: "{{ cert_list.stdout_lines }}"
|
||||
78
ansible/roles/haproxy/tasks/certificates.yml
Normal file
78
ansible/roles/haproxy/tasks/certificates.yml
Normal file
@@ -0,0 +1,78 @@
|
||||
---
|
||||
# ansible/roles/haproxy/tasks/certificates.yml
|
||||
|
||||
- name: Check if default certificate exists
|
||||
ansible.builtin.stat:
|
||||
path: "{{ haproxy_ssl_default_crt }}"
|
||||
register: default_cert
|
||||
|
||||
- name: Generate self-signed certificate for development
|
||||
when: not default_cert.stat.exists
|
||||
block:
|
||||
- name: Generate private key
|
||||
openssl_privatekey:
|
||||
path: "{{ haproxy_ssl_cert_dir }}/default.key"
|
||||
size: 2048
|
||||
mode: '0600'
|
||||
owner: "{{ haproxy_user }}"
|
||||
group: "{{ haproxy_group }}"
|
||||
|
||||
- name: Generate certificate signing request
|
||||
openssl_csr:
|
||||
path: "{{ haproxy_ssl_cert_dir }}/default.csr"
|
||||
privatekey_path: "{{ haproxy_ssl_cert_dir }}/default.key"
|
||||
common_name: "lightning-lane.local.mk-labs.cloud"
|
||||
subject_alt_name:
|
||||
- "DNS:lightning-lane.local.mk-labs.cloud"
|
||||
- "DNS:*.local.mk-labs.cloud"
|
||||
owner: "{{ haproxy_user }}"
|
||||
group: "{{ haproxy_group }}"
|
||||
|
||||
- name: Generate self-signed certificate
|
||||
openssl_certificate:
|
||||
path: "{{ haproxy_ssl_cert_dir }}/default.crt"
|
||||
privatekey_path: "{{ haproxy_ssl_cert_dir }}/default.key"
|
||||
csr_path: "{{ haproxy_ssl_cert_dir }}/default.csr"
|
||||
provider: selfsigned
|
||||
selfsigned_not_after: "+3650d"
|
||||
owner: "{{ haproxy_user }}"
|
||||
group: "{{ haproxy_group }}"
|
||||
|
||||
- name: Combine certificate and key for HAProxy
|
||||
ansible.builtin.shell: |
|
||||
cat {{ haproxy_ssl_cert_dir }}/default.crt \
|
||||
{{ haproxy_ssl_cert_dir }}/default.key \
|
||||
> {{ haproxy_ssl_default_crt }}
|
||||
args:
|
||||
creates: "{{ haproxy_ssl_default_crt }}"
|
||||
|
||||
- name: Set permissions on combined certificate
|
||||
ansible.builtin.file:
|
||||
path: "{{ haproxy_ssl_default_crt }}"
|
||||
owner: "{{ haproxy_user }}"
|
||||
group: "{{ haproxy_group }}"
|
||||
mode: '0600'
|
||||
|
||||
- name: Create certificate directory structure
|
||||
ansible.builtin.file:
|
||||
path: "{{ haproxy_ssl_cert_dir }}/{{ item }}"
|
||||
state: directory
|
||||
owner: "{{ haproxy_user }}"
|
||||
group: "{{ haproxy_group }}"
|
||||
mode: '0755'
|
||||
loop:
|
||||
- live
|
||||
- archive
|
||||
|
||||
- name: Deploy additional certificates
|
||||
when: haproxy_ssl_certificates is defined
|
||||
block:
|
||||
- name: Copy certificate files
|
||||
ansible.builtin.copy:
|
||||
src: "{{ item.src }}"
|
||||
dest: "{{ haproxy_ssl_cert_dir }}/live/{{ item.name }}.pem"
|
||||
owner: "{{ haproxy_user }}"
|
||||
group: "{{ haproxy_group }}"
|
||||
mode: '0600'
|
||||
loop: "{{ haproxy_ssl_certificates }}"
|
||||
notify: Reload haproxy
|
||||
94
ansible/roles/haproxy/tasks/configure.yml
Normal file
94
ansible/roles/haproxy/tasks/configure.yml
Normal file
@@ -0,0 +1,94 @@
|
||||
---
|
||||
# ansible/roles/haproxy/tasks/configure.yml
|
||||
|
||||
- name: Fetch services from NetBox
|
||||
when: haproxy_netbox_integration
|
||||
block:
|
||||
- name: Query NetBox for service configurations
|
||||
ansible.builtin.uri:
|
||||
url: "{{ haproxy_netbox_url }}/api/ipam/services/"
|
||||
method: GET
|
||||
headers:
|
||||
Authorization: "Token {{ haproxy_netbox_token }}"
|
||||
Accept: "application/json"
|
||||
return_content: true
|
||||
register: netbox_services
|
||||
changed_when: false
|
||||
|
||||
- name: Parse NetBox services
|
||||
ansible.builtin.set_fact:
|
||||
haproxy_frontends: "{{ haproxy_frontends | default([]) + netbox_parsed_frontends }}"
|
||||
haproxy_backends: "{{ haproxy_backends | default([]) + netbox_parsed_backends }}"
|
||||
vars:
|
||||
netbox_parsed_frontends: "{{ netbox_services.json.results | map(attribute='custom_fields') | list }}"
|
||||
netbox_parsed_backends: "{{ netbox_services.json.results | map(attribute='custom_fields') | list }}"
|
||||
when: netbox_services.json.results is defined
|
||||
|
||||
- name: Generate HAProxy main configuration
|
||||
ansible.builtin.template:
|
||||
src: haproxy.cfg.j2
|
||||
dest: "{{ haproxy_config_dir }}/haproxy.cfg"
|
||||
owner: root
|
||||
group: root
|
||||
mode: '0644'
|
||||
backup: true
|
||||
validate: 'haproxy -c -f %s'
|
||||
notify: reload haproxy
|
||||
|
||||
- name: Configure rsyslog for HAProxy
|
||||
when: haproxy_rsyslog_config
|
||||
block:
|
||||
- name: Create rsyslog configuration for HAProxy
|
||||
ansible.builtin.copy:
|
||||
content: |
|
||||
# HAProxy logging configuration
|
||||
$ModLoad imudp
|
||||
$UDPServerRun 514
|
||||
|
||||
# Create separate log files for HAProxy
|
||||
local0.* {{ haproxy_log_dir }}/haproxy.log
|
||||
local0.info {{ haproxy_log_dir }}/haproxy-info.log
|
||||
local0.notice {{ haproxy_log_dir }}/haproxy-notice.log
|
||||
local0.err {{ haproxy_log_dir }}/haproxy-error.log
|
||||
|
||||
# Stop processing HAProxy logs
|
||||
& stop
|
||||
dest: /etc/rsyslog.d/49-haproxy.conf
|
||||
mode: '0644'
|
||||
notify: restart rsyslog
|
||||
|
||||
- name: Configure logrotate for HAProxy
|
||||
when: haproxy_log_rotation
|
||||
ansible.builtin.template:
|
||||
src: logrotate.j2
|
||||
dest: /etc/logrotate.d/haproxy
|
||||
mode: '0644'
|
||||
|
||||
- name: Create HAProxy systemd override directory
|
||||
ansible.builtin.file:
|
||||
path: /etc/systemd/system/haproxy.service.d
|
||||
state: directory
|
||||
mode: '0755'
|
||||
|
||||
- name: Configure HAProxy systemd service overrides
|
||||
ansible.builtin.copy:
|
||||
content: |
|
||||
[Service]
|
||||
# Increase file descriptor limits
|
||||
LimitNOFILE=65536
|
||||
|
||||
# Runtime directory
|
||||
RuntimeDirectory=haproxy
|
||||
RuntimeDirectoryMode=0755
|
||||
|
||||
# Security hardening
|
||||
NoNewPrivileges=true
|
||||
ProtectSystem=strict
|
||||
ProtectHome=true
|
||||
PrivateTmp=true
|
||||
ReadWritePaths={{ haproxy_log_dir }}
|
||||
dest: /etc/systemd/system/haproxy.service.d/override.conf
|
||||
mode: '0644'
|
||||
notify:
|
||||
- Reload systemd
|
||||
- Restart haproxy
|
||||
128
ansible/roles/haproxy/tasks/install.yml
Normal file
128
ansible/roles/haproxy/tasks/install.yml
Normal file
@@ -0,0 +1,128 @@
|
||||
---
|
||||
# ansible/roles/haproxy/tasks/install.yml
|
||||
|
||||
- name: Install HAProxy repository (Ubuntu)
|
||||
when: ansible_os_family == "Debian"
|
||||
block:
|
||||
- name: Add HAProxy PPA
|
||||
ansible.builtin.apt_repository:
|
||||
repo: "ppa:vbernat/haproxy-{{ haproxy_version }}"
|
||||
state: present
|
||||
update_cache: true
|
||||
|
||||
- name: Install HAProxy
|
||||
ansible.builtin.apt:
|
||||
name: haproxy
|
||||
state: present
|
||||
update_cache: true
|
||||
|
||||
- name: Install HAProxy (Fedora/RHEL)
|
||||
when: ansible_os_family == "RedHat"
|
||||
block:
|
||||
- name: Install HAProxy
|
||||
ansible.builtin.dnf:
|
||||
name: haproxy
|
||||
state: present
|
||||
|
||||
- name: Install additional packages
|
||||
ansible.builtin.package:
|
||||
name:
|
||||
- rsyslog
|
||||
- logrotate
|
||||
- socat # For HAProxy socket communication
|
||||
state: present
|
||||
|
||||
- name: Create HAProxy system user
|
||||
ansible.builtin.user:
|
||||
name: "{{ haproxy_user }}"
|
||||
group: "{{ haproxy_group }}"
|
||||
system: true
|
||||
shell: /usr/sbin/nologin
|
||||
home: "{{ haproxy_chroot_dir }}"
|
||||
create_home: true
|
||||
|
||||
- name: Create required directories
|
||||
ansible.builtin.file:
|
||||
path: "{{ item }}"
|
||||
state: directory
|
||||
owner: "{{ haproxy_user }}"
|
||||
group: "{{ haproxy_group }}"
|
||||
mode: '0755'
|
||||
loop:
|
||||
- "{{ haproxy_config_dir }}"
|
||||
- "{{ haproxy_ssl_cert_dir }}"
|
||||
- "{{ haproxy_log_dir }}"
|
||||
- "{{ haproxy_chroot_dir }}"
|
||||
- /var/lib/haproxy/dev
|
||||
|
||||
- name: Create HAProxy socket directory
|
||||
ansible.builtin.file:
|
||||
path: /run/haproxy
|
||||
state: directory
|
||||
owner: "{{ haproxy_user }}"
|
||||
group: "{{ haproxy_group }}"
|
||||
mode: '0755'
|
||||
|
||||
- name: Configure firewall rules
|
||||
when: haproxy_configure_firewall
|
||||
block:
|
||||
- name: Open HAProxy ports (UFW)
|
||||
when: ansible_os_family == "Debian"
|
||||
community.general.ufw:
|
||||
rule: allow
|
||||
port: "{{ item.split('/')[0] }}"
|
||||
proto: "{{ item.split('/')[1] }}"
|
||||
loop: "{{ haproxy_firewall_allowed_ports }}"
|
||||
|
||||
- name: Open HAProxy ports (firewalld)
|
||||
when: ansible_os_family == "RedHat"
|
||||
ansible.posix.firewalld:
|
||||
port: "{{ item }}"
|
||||
permanent: true
|
||||
state: enabled
|
||||
immediate: true
|
||||
loop: "{{ haproxy_firewall_allowed_ports }}"
|
||||
|
||||
- name: Install Prometheus HAProxy exporter
|
||||
when: haproxy_prometheus_exporter
|
||||
block:
|
||||
- name: Download HAProxy exporter
|
||||
ansible.builtin.get_url:
|
||||
url: "https://github.com/prometheus/haproxy_exporter/releases/download/v0.15.0/haproxy_exporter-0.15.0.linux-amd64.tar.gz"
|
||||
dest: /tmp/haproxy_exporter.tar.gz
|
||||
mode: '0644'
|
||||
|
||||
- name: Extract HAProxy exporter
|
||||
ansible.builtin.unarchive:
|
||||
src: /tmp/haproxy_exporter.tar.gz
|
||||
dest: /usr/local/bin/
|
||||
remote_src: true
|
||||
extra_opts:
|
||||
- --strip-components=1
|
||||
- --wildcards
|
||||
- '*/haproxy_exporter'
|
||||
|
||||
- name: Create HAProxy exporter systemd service
|
||||
ansible.builtin.copy:
|
||||
content: |
|
||||
[Unit]
|
||||
Description=HAProxy Exporter
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User={{ haproxy_user }}
|
||||
ExecStart=/usr/local/bin/haproxy_exporter --haproxy.scrape-uri=unix:/run/haproxy/admin.sock
|
||||
Restart=on-failure
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
dest: /etc/systemd/system/haproxy-exporter.service
|
||||
mode: '0644'
|
||||
|
||||
- name: Enable and start HAProxy exporter
|
||||
ansible.builtin.systemd:
|
||||
name: haproxy-exporter
|
||||
state: started
|
||||
enabled: true
|
||||
daemon_reload: true
|
||||
40
ansible/roles/haproxy/tasks/main.yml
Normal file
40
ansible/roles/haproxy/tasks/main.yml
Normal file
@@ -0,0 +1,40 @@
|
||||
---
|
||||
# ansible/roles/haproxy/tasks/main.yml
|
||||
|
||||
# - name: Include OS-specific variables
|
||||
# include_vars: "{{ ansible_os_family }}.yml"
|
||||
# tags: [haproxy, always]
|
||||
|
||||
- name: Include installation tasks
|
||||
ansible.builtin.include_tasks: install.yml
|
||||
tags: [haproxy, install]
|
||||
|
||||
- name: Include Certbot with Cloudflare DNS tasks
|
||||
ansible.builtin.include_tasks: certbot-cloudflare.yml
|
||||
when:
|
||||
- haproxy_certbot_enable
|
||||
- haproxy_certbot_challenge_method == "dns-cloudflare"
|
||||
tags: [haproxy, certificates, certbot, cloudflare]
|
||||
|
||||
- name: Include fallback self-signed certificate tasks
|
||||
ansible.builtin.include_tasks: certificates.yml
|
||||
when:
|
||||
- not haproxy_certbot_enable
|
||||
- haproxy_certbot_fallback_selfsigned | default(false)
|
||||
tags: [haproxy, certificates, selfsigned]
|
||||
|
||||
- name: Include configuration tasks
|
||||
ansible.builtin.include_tasks: configure.yml
|
||||
tags: [haproxy, configure]
|
||||
|
||||
- name: Include validation tasks
|
||||
ansible.builtin.include_tasks: validate.yml
|
||||
tags: [haproxy, validate]
|
||||
|
||||
- name: Ensure HAProxy is started and enabled
|
||||
ansible.builtin.systemd:
|
||||
name: haproxy
|
||||
state: started
|
||||
enabled: true
|
||||
daemon_reload: true
|
||||
tags: [haproxy, service]
|
||||
47
ansible/roles/haproxy/tasks/validate.yml
Normal file
47
ansible/roles/haproxy/tasks/validate.yml
Normal file
@@ -0,0 +1,47 @@
|
||||
---
|
||||
# ansible/roles/haproxy/tasks/validate.yml
|
||||
|
||||
- name: Validate HAProxy configuration syntax
|
||||
command: haproxy -c -f {{ haproxy_config_dir }}/haproxy.cfg
|
||||
register: haproxy_validation
|
||||
changed_when: false
|
||||
failed_when: haproxy_validation.rc != 0
|
||||
|
||||
- name: Display validation results
|
||||
debug:
|
||||
msg: "{{ haproxy_validation.stdout_lines }}"
|
||||
when: haproxy_validation.stdout_lines is defined
|
||||
|
||||
- name: Check HAProxy service status
|
||||
systemd:
|
||||
name: haproxy
|
||||
state: started
|
||||
register: haproxy_status
|
||||
changed_when: false
|
||||
|
||||
- name: Verify HAProxy is listening on configured ports
|
||||
wait_for:
|
||||
host: "{{ ansible_default_ipv4.address }}"
|
||||
port: "{{ item }}"
|
||||
timeout: 10
|
||||
loop:
|
||||
- 80
|
||||
- 443
|
||||
- "{{ haproxy_stats_port }}"
|
||||
when: haproxy_status.status.ActiveState == "active"
|
||||
|
||||
- name: Test stats interface accessibility
|
||||
uri:
|
||||
url: "http://localhost:{{ haproxy_stats_port }}{{ haproxy_stats_uri }}"
|
||||
user: "{{ haproxy_stats_username }}"
|
||||
password: "{{ haproxy_stats_password }}"
|
||||
force_basic_auth: true
|
||||
status_code: 200
|
||||
register: stats_test
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
|
||||
- name: Display stats interface status
|
||||
debug:
|
||||
msg: "Stats interface is {{ 'accessible' if stats_test.status == 200 else 'not accessible' }}"
|
||||
|
||||
107
ansible/roles/haproxy/templates/certbot-post-hook.sh.j2
Normal file
107
ansible/roles/haproxy/templates/certbot-post-hook.sh.j2
Normal file
@@ -0,0 +1,107 @@
|
||||
#!/bin/bash
|
||||
# {{ ansible_managed }}
|
||||
# Certbot post-renewal hook for HAProxy
|
||||
# Combines certificate and private key for HAProxy consumption
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Configuration
|
||||
LETSENCRYPT_LIVE="/etc/letsencrypt/live"
|
||||
HAPROXY_CERT_DIR="{{ haproxy_ssl_cert_dir }}/live"
|
||||
HAPROXY_USER="{{ haproxy_user }}"
|
||||
HAPROXY_GROUP="{{ haproxy_group }}"
|
||||
LOG_FILE="{{ haproxy_log_dir }}/certbot-hook.log"
|
||||
|
||||
# Ensure HAProxy cert directory exists
|
||||
mkdir -p "$HAPROXY_CERT_DIR"
|
||||
|
||||
# Logging function
|
||||
log() {
|
||||
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$LOG_FILE"
|
||||
}
|
||||
|
||||
log "Starting certificate deployment for HAProxy"
|
||||
|
||||
# Track if any certificates were updated
|
||||
CERTS_UPDATED=false
|
||||
|
||||
# Process each certificate in Let's Encrypt live directory
|
||||
for cert_dir in "$LETSENCRYPT_LIVE"/*; do
|
||||
if [ ! -d "$cert_dir" ] || [ "$(basename "$cert_dir")" = "README" ]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
CERT_NAME=$(basename "$cert_dir")
|
||||
|
||||
# Check if certificate files exist
|
||||
if [ ! -f "$cert_dir/fullchain.pem" ] || [ ! -f "$cert_dir/privkey.pem" ]; then
|
||||
log "WARNING: Missing certificate files for $CERT_NAME, skipping"
|
||||
continue
|
||||
fi
|
||||
|
||||
log "Processing certificate: $CERT_NAME"
|
||||
|
||||
# Create combined PEM file (fullchain + privkey)
|
||||
# HAProxy requires the certificate chain and private key in a single file
|
||||
COMBINED_PEM="$HAPROXY_CERT_DIR/${CERT_NAME}.pem"
|
||||
|
||||
# Combine certificates
|
||||
cat "$cert_dir/fullchain.pem" "$cert_dir/privkey.pem" > "$COMBINED_PEM.tmp"
|
||||
|
||||
# Check if certificate actually changed
|
||||
if [ -f "$COMBINED_PEM" ] && cmp -s "$COMBINED_PEM" "$COMBINED_PEM.tmp"; then
|
||||
log "Certificate $CERT_NAME unchanged, skipping"
|
||||
rm "$COMBINED_PEM.tmp"
|
||||
continue
|
||||
fi
|
||||
|
||||
# Move new certificate into place
|
||||
mv "$COMBINED_PEM.tmp" "$COMBINED_PEM"
|
||||
|
||||
# Set proper permissions
|
||||
chown "$HAPROXY_USER:$HAPROXY_GROUP" "$COMBINED_PEM"
|
||||
chmod 600 "$COMBINED_PEM"
|
||||
|
||||
log "Created/Updated: $COMBINED_PEM"
|
||||
CERTS_UPDATED=true
|
||||
done
|
||||
|
||||
# Create/update default certificate symlink
|
||||
# Use the first wildcard cert or the first available cert as default
|
||||
DEFAULT_CERT="{{ haproxy_ssl_default_crt }}"
|
||||
WILDCARD_CERT="$HAPROXY_CERT_DIR/local.mk-labs.cloud.pem"
|
||||
|
||||
if [ -f "$WILDCARD_CERT" ]; then
|
||||
ln -sf "$WILDCARD_CERT" "$DEFAULT_CERT"
|
||||
log "Updated default certificate symlink to wildcard cert"
|
||||
elif [ -n "$(ls -A "$HAPROXY_CERT_DIR" 2>/dev/null)" ]; then
|
||||
FIRST_CERT=$(ls "$HAPROXY_CERT_DIR"/*.pem 2>/dev/null | head -n1)
|
||||
ln -sf "$FIRST_CERT" "$DEFAULT_CERT"
|
||||
log "Updated default certificate symlink to $FIRST_CERT"
|
||||
fi
|
||||
|
||||
# Only reload HAProxy if certificates were actually updated
|
||||
if [ "$CERTS_UPDATED" = true ]; then
|
||||
log "Certificates updated, validating HAProxy configuration"
|
||||
|
||||
# Validate HAProxy configuration
|
||||
if haproxy -c -f {{ haproxy_config_dir }}/haproxy.cfg >/dev/null 2>&1; then
|
||||
log "HAProxy configuration valid, reloading service"
|
||||
|
||||
if systemctl reload haproxy; then
|
||||
log "HAProxy reloaded successfully"
|
||||
else
|
||||
log "ERROR: Failed to reload HAProxy"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
log "ERROR: HAProxy configuration validation failed"
|
||||
haproxy -c -f {{ haproxy_config_dir }}/haproxy.cfg 2>&1 | tee -a "$LOG_FILE"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
log "No certificates were updated, skipping HAProxy reload"
|
||||
fi
|
||||
|
||||
log "Certificate deployment complete"
|
||||
exit 0
|
||||
@@ -0,0 +1,12 @@
|
||||
# {{ ansible_managed }}
|
||||
# Cloudflare API credentials for Certbot DNS-01 challenge
|
||||
# This file contains sensitive information and should be protected
|
||||
|
||||
# Cloudflare API Token (RECOMMENDED)
|
||||
# Create at: https://dash.cloudflare.com/profile/api-tokens
|
||||
# Required permissions: Zone:DNS:Edit for specific zone
|
||||
dns_cloudflare_api_token = {{ haproxy_certbot_cloudflare_api_token }}
|
||||
|
||||
# Alternative: Global API Key (NOT RECOMMENDED - too permissive)
|
||||
# dns_cloudflare_email = your-email@example.com
|
||||
# dns_cloudflare_api_key = your-global-api-key
|
||||
188
ansible/roles/haproxy/templates/haproxy.cfg.j2
Normal file
188
ansible/roles/haproxy/templates/haproxy.cfg.j2
Normal file
@@ -0,0 +1,188 @@
|
||||
{# ansible/roles/haproxy/templates/haproxy.cfg.j2 #}
|
||||
#---------------------------------------------------------------------
|
||||
# HAProxy Configuration for {{ inventory_hostname }}
|
||||
# Generated by Ansible - DO NOT EDIT MANUALLY
|
||||
# Magic Kingdom Labs - lightning-lane load balancer
|
||||
#---------------------------------------------------------------------
|
||||
|
||||
#---------------------------------------------------------------------
|
||||
# Global settings
|
||||
#---------------------------------------------------------------------
|
||||
global
|
||||
log 127.0.0.1 {{ haproxy_global_log_facility }} {{ haproxy_global_log_level }}
|
||||
chroot {{ haproxy_chroot_dir }}
|
||||
pidfile /var/run/haproxy.pid
|
||||
maxconn {{ haproxy_global_maxconn }}
|
||||
user {{ haproxy_user }}
|
||||
group {{ haproxy_group }}
|
||||
daemon
|
||||
nbthread {{ haproxy_global_nbthread }}
|
||||
|
||||
# Runtime socket for management
|
||||
stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners
|
||||
stats timeout 30s
|
||||
|
||||
# SSL/TLS configuration
|
||||
ssl-default-bind-ciphers {{ haproxy_ssl_ciphers }}
|
||||
ssl-default-bind-options {{ haproxy_ssl_options }}
|
||||
ssl-default-server-ciphers {{ haproxy_ssl_ciphers }}
|
||||
ssl-default-server-options {{ haproxy_ssl_options }}
|
||||
|
||||
# Performance tuning
|
||||
tune.ssl.default-dh-param 2048
|
||||
tune.ssl.cachesize 100000
|
||||
tune.ssl.lifetime 600
|
||||
|
||||
#---------------------------------------------------------------------
|
||||
# Common defaults
|
||||
#---------------------------------------------------------------------
|
||||
defaults
|
||||
mode http
|
||||
log global
|
||||
option httplog
|
||||
option dontlognull
|
||||
option http-server-close
|
||||
option redispatch
|
||||
retries 3
|
||||
timeout connect {{ haproxy_timeout_connect }}
|
||||
timeout client {{ haproxy_timeout_client }}
|
||||
timeout server {{ haproxy_timeout_server }}
|
||||
timeout http-request 10s
|
||||
timeout http-keep-alive 10s
|
||||
timeout check 10s
|
||||
maxconn 3000
|
||||
|
||||
# Error pages
|
||||
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
|
||||
|
||||
#---------------------------------------------------------------------
|
||||
# Stats interface
|
||||
#---------------------------------------------------------------------
|
||||
{% if haproxy_stats_enable %}
|
||||
listen stats
|
||||
bind *:{{ haproxy_stats_port }}
|
||||
mode http
|
||||
stats enable
|
||||
stats uri {{ haproxy_stats_uri }}
|
||||
stats refresh {{ haproxy_stats_refresh }}
|
||||
stats realm Magic\ Kingdom\ Labs\ -\ HAProxy\ Statistics
|
||||
stats auth {{ haproxy_stats_username }}:{{ haproxy_stats_password }}
|
||||
stats admin if TRUE
|
||||
{% endif %}
|
||||
|
||||
#---------------------------------------------------------------------
|
||||
# HTTP Redirect Frontend (HTTP -> HTTPS)
|
||||
#---------------------------------------------------------------------
|
||||
frontend http_front
|
||||
bind *:80
|
||||
mode http
|
||||
|
||||
# Redirect all HTTP traffic to HTTPS
|
||||
redirect scheme https code 301
|
||||
|
||||
#---------------------------------------------------------------------
|
||||
# HTTPS Frontend with SNI
|
||||
#---------------------------------------------------------------------
|
||||
frontend https_front
|
||||
bind *:443 ssl crt {{ haproxy_ssl_cert_dir }}/live crt {{ haproxy_ssl_default_crt }} alpn h2,http/1.1
|
||||
mode http
|
||||
|
||||
# Security headers
|
||||
http-response set-header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
|
||||
http-response set-header X-Frame-Options "SAMEORIGIN"
|
||||
http-response set-header X-Content-Type-Options "nosniff"
|
||||
http-response set-header X-XSS-Protection "1; mode=block"
|
||||
|
||||
# Logging
|
||||
option httplog
|
||||
option forwardfor
|
||||
|
||||
{% if haproxy_frontends is defined and haproxy_frontends | length > 0 %}
|
||||
{% for frontend in haproxy_frontends %}
|
||||
{% if frontend.acls is defined %}
|
||||
# ACLs for {{ frontend.name }}
|
||||
{% for acl in frontend.acls %}
|
||||
acl {{ acl }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
{% for frontend in haproxy_frontends %}
|
||||
{% if frontend.use_backends is defined %}
|
||||
# Backend routing for {{ frontend.name }}
|
||||
{% for use_backend in frontend.use_backends %}
|
||||
use_backend {{ use_backend }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
# Default backend
|
||||
default_backend no_match_back
|
||||
|
||||
#---------------------------------------------------------------------
|
||||
# Backends
|
||||
#---------------------------------------------------------------------
|
||||
{% for backend in haproxy_backends %}
|
||||
backend {{ backend.name }}
|
||||
mode {{ backend.mode | default('http') }}
|
||||
balance {{ backend.balance | default('roundrobin') }}
|
||||
{% if backend.options is defined %}
|
||||
{% for option in backend.options %}
|
||||
option {{ option }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if backend.http_check is defined %}
|
||||
option httpchk {{ backend.http_check }}
|
||||
{% endif %}
|
||||
{% if backend.servers is defined %}
|
||||
{% for server in backend.servers %}
|
||||
server {{ server.name }} {{ server.address }}{% if server.check | default(false) %} check{% endif %}{% if server.backup | default(false) %} backup{% endif %}{% if server.weight is defined %} weight {{ server.weight }}{% endif %}
|
||||
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
{% endfor %}
|
||||
|
||||
# Default backend for unmatched requests
|
||||
backend no_match_back
|
||||
mode http
|
||||
http-request deny deny_status 404
|
||||
|
||||
#---------------------------------------------------------------------
|
||||
# TCP Services
|
||||
#---------------------------------------------------------------------
|
||||
{% for tcp_service in haproxy_tcp_services %}
|
||||
# {{ tcp_service.name | upper }} Service (TCP)
|
||||
frontend {{ tcp_service.name }}_front
|
||||
bind *:{{ tcp_service.frontend_port }}
|
||||
mode tcp
|
||||
option tcplog
|
||||
{% if tcp_service.timeout_client is defined %}
|
||||
timeout client {{ tcp_service.timeout_client }}
|
||||
{% endif %}
|
||||
default_backend {{ tcp_service.name }}_back
|
||||
|
||||
backend {{ tcp_service.name }}_back
|
||||
mode tcp
|
||||
balance {{ tcp_service.balance | default('roundrobin') }}
|
||||
{% if tcp_service.timeout_server is defined %}
|
||||
timeout server {{ tcp_service.timeout_server }}
|
||||
{% endif %}
|
||||
{% if tcp_service.timeout_connect is defined %}
|
||||
timeout connect {{ tcp_service.timeout_connect }}
|
||||
{% endif %}
|
||||
{% if tcp_service.servers is defined %}
|
||||
{% for server in tcp_service.servers %}
|
||||
server {{ server.name }} {{ server.address }}:{{ tcp_service.backend_port }}{% if server.check | default(true) %} check{% endif %}
|
||||
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
{% endfor %}
|
||||
14
ansible/roles/haproxy/templates/logrotate.j2
Normal file
14
ansible/roles/haproxy/templates/logrotate.j2
Normal file
@@ -0,0 +1,14 @@
|
||||
{# ansible/roles/haproxy/templates/logrotate.j2 #}
|
||||
{{ haproxy_log_dir }}/*.log {
|
||||
daily
|
||||
rotate 14
|
||||
missingok
|
||||
notifempty
|
||||
compress
|
||||
delaycompress
|
||||
sharedscripts
|
||||
postrotate
|
||||
/bin/kill -HUP `cat /var/run/rsyslog.pid 2> /dev/null` 2> /dev/null || true
|
||||
/bin/kill -HUP `cat /var/run/haproxy.pid 2> /dev/null` 2> /dev/null || true
|
||||
endscript
|
||||
}
|
||||
Reference in New Issue
Block a user