{"id":14349,"date":"2025-12-17T12:30:27","date_gmt":"2025-12-17T07:00:27","guid":{"rendered":"https:\/\/www.youstable.com\/blog\/?p=14349"},"modified":"2025-12-24T16:13:40","modified_gmt":"2025-12-24T10:43:40","slug":"how-to-monitor-secure-haproxy-on-linux","status":"publish","type":"post","link":"https:\/\/www.youstable.com\/blog\/how-to-monitor-secure-haproxy-on-linux","title":{"rendered":"How to Monitor &#038; Secure HAProxy on Linux Server"},"content":{"rendered":"\n<p>To monitor &amp; secure HAProxy on Linux server, enable detailed logging and the stats\/admin socket, export metrics to Prometheus\/Grafana, and set actionable alerts. Then harden TLS, restrict access with firewall and ACLs, implement rate limiting and DDoS mitigations, keep HAProxy updated, and automate safe reloads and backups for continuous reliability.<\/p>\n\n\n\n<p>If you run critical applications behind HAProxy, knowing how to monitor and secure HAProxy on Linux is essential. This guide walks you through end\u2011to\u2011end HAProxy monitoring, alerting, and security hardening with clear steps, copy\u2011paste configs, and real\u2011world best practices we use on production-grade hosting at YouStable.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"who-this-guide-is-for\"><strong>Who This Guide Is For<\/strong><\/h2>\n\n\n\n<p>Beginners and sysadmins who want practical, <a href=\"https:\/\/www.youstable.com\/blog\/best-free-server-uptime-monitoring-tools\/\">reliable HAProxy monitoring and security<\/a> on Ubuntu, Debian, CentOS, AlmaLinux, or Rocky Linux. We\u2019ll cover HAProxy monitoring, HAProxy security best practices, and Linux server hardening without jargon or fluff.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"prerequisites\"><strong>Prerequisites<\/strong><\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/www.youstable.com\/blog\/install-mongodb-on-linux\/\">Linux server<\/a> with HAProxy 2.4+ (prefer LTS such as 2.6 or 2.8) and root\/sudo access<\/li>\n\n\n\n<li>rsyslog or systemd-journald enabled<\/li>\n\n\n\n<li>Firewall (UFW, nftables, or firewalld)<\/li>\n\n\n\n<li>Optional: Prometheus + Grafana for metrics and visual dashboards<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"step-1-enable-observability-logs-stats-metrics\"><strong>Step 1: Enable Observability (Logs, Stats, Metrics)<\/strong><\/h2>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"1-1-configure-haproxy-logging-with-rsyslog\"><strong>1.1 Configure HAProxy Logging with rsyslog<\/strong><\/h3>\n\n\n\n<p>Turn on structured, high-signal logs for request tracing and error analysis. Add or verify logging in haproxy.cfg:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># \/etc\/haproxy\/haproxy.cfg\nglobal\n  log \/dev\/log local0\n  log \/dev\/log local1 notice\n  user haproxy\n  group haproxy\n  chroot \/var\/lib\/haproxy\n  daemon\n  stats socket \/run\/haproxy\/admin.sock mode 660 level admin\n  maxconn 10000\n\ndefaults\n  log     global\n  mode    http\n  option  httplog\n  option  dontlognull\n  timeout connect 5s\n  timeout client  30s\n  timeout server  30s\n  http-reuse safe\n<\/code><\/pre>\n\n\n\n<p>Now map the log facilities in rsyslog:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># \/etc\/rsyslog.d\/49-haproxy.conf (Ubuntu\/Debian style)\nmodule(load=\"imudp\")\ninput(type=\"imudp\" port=\"514\")\n\n# Write HAProxy logs to dedicated files\nlocal0.*    -\/var\/log\/haproxy.log\nlocal1.notice  -\/var\/log\/haproxy-admin.log\n\n# Stop further processing\n&amp; stop\n<\/code><\/pre>\n\n\n\n<p>Restart services:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo systemctl restart rsyslog\nsudo systemctl restart haproxy\ntail -f \/var\/log\/haproxy.log<\/code><\/pre>\n\n\n\n<p>Tip: Use a custom log-format to include request IDs and timing when you need deeper insights.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"1-2-enable-haproxy-stats-page-and-admin-socket\"><strong>1.2 Enable HAProxy Stats Page and Admin Socket<\/strong><\/h3>\n\n\n\n<p>The stats page offers a quick operational view; the admin socket is for safe automation (draining, enabling, disabling servers).<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># Add to a frontend or a dedicated listen section\nlisten stats\n  bind :8404\n  mode http\n  stats enable\n  stats uri \/haproxy?stats\n  stats refresh 10s\n  stats realm HAProxy\\ Statistics\n  stats auth ops:StrongPasswordHere\n  acl allowed_net src 203.0.113.0\/24 198.51.100.10\n  http-request deny if !allowed_net\n<\/code><\/pre>\n\n\n\n<p>The admin socket was defined under \u201cglobal\u201d. Use it locally:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo socat stdio \/run\/haproxy\/admin.sock\n&gt; show info\n&gt; show servers state\n<\/code><\/pre>\n\n\n\n<p>Keep the admin socket on a Unix file (not a TCP port) and restrict permissions to trusted operators.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"1-3-export-metrics-to-prometheus-and-visualize-with-grafana\"><strong>1.3 Export Metrics to Prometheus and Visualize with Grafana<\/strong><\/h3>\n\n\n\n<p>Use the Prometheus HAProxy exporter to scrape stats via the socket or stats page. Example systemd unit using the official image\/container path (adjust as needed):<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># Install haproxy_exporter (binary or container). Example binary service:\n# \/etc\/systemd\/system\/haproxy-exporter.service\n&#91;Unit]\nDescription=Prometheus HAProxy Exporter\nAfter=network-online.target\n\n&#91;Service]\nUser=nobody\nGroup=nogroup\nExecStart=\/usr\/local\/bin\/haproxy_exporter \\\n  --haproxy.scrape-uri=unix:\/run\/haproxy\/admin.sock \\\n  --log.level=info\nRestart=always\n\n&#91;Install]\nWantedBy=multi-user.target\n\n# Then:\nsudo systemctl daemon-reload\nsudo systemctl enable --now haproxy-exporter\n<\/code><\/pre>\n\n\n\n<p>Prometheus scrape config:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># prometheus.yml\nscrape_configs:\n  - job_name: 'haproxy'\n    static_configs:\n      - targets: &#91;'127.0.0.1:9101']   # change to your exporter port\n<\/code><\/pre>\n\n\n\n<p>Import a community Grafana dashboard for HAProxy to visualize connections, response codes, queue depth, retries, and backend health.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"step-2-add-health-checks-and-alerts\"><strong>Step 2: Add Health Checks and Alerts<\/strong><\/h2>\n\n\n\n<p>Active health checks prevent routing to unhealthy backends and allow proactive alerts before users notice issues.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># In your backend\nbackend be_app\n  balance roundrobin\n  option httpchk GET \/health\n  http-check expect status 200\n  server app1 10.0.0.10:8080 check\n  server app2 10.0.0.11:8080 check<\/code><\/pre>\n\n\n\n<p>Example Prometheus alert rules (tune thresholds to your traffic):<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>groups:\n- name: haproxy-alerts\n  rules:\n  - alert: HAProxyHigh5xx\n    expr: sum(rate(haproxy_server_http_responses_total{code=\"5xx\"}&#91;5m])) &gt; 10\n    for: 10m\n    labels: { severity: \"warning\" }\n    annotations:\n      description: \"High 5xx rate across HAProxy backends\"\n  - alert: HAProxyBackendDown\n    expr: sum(haproxy_server_check_status{state=\"DOWN\"}) &gt;= 1\n    for: 2m\n    labels: { severity: \"critical\" }\n    annotations:\n      description: \"One or more HAProxy servers are DOWN\"<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"step-3-harden-tls-and-http-security\"><strong>Step 3: Harden TLS and HTTP Security<\/strong><\/h2>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"3-1-strong-tls-defaults-tls-1-2-1-3-only\"><strong>3.1 Strong TLS Defaults (TLS 1.2\/1.3 only)<\/strong><\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code># \/etc\/haproxy\/haproxy.cfg (global)\nssl-default-bind-options no-sslv3 no-tlsv10 no-tlsv11\nssl-default-bind-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:\\\nECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305\nssl-default-bind-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256\ntune.ssl.default-dh-param 2048\n<\/code><\/pre>\n\n\n\n<p>Bind certificates with HTTP\/2 and HSTS. Combine fullchain and key into a single PEM for HAProxy:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># Create PEM:\ncat \/etc\/letsencrypt\/live\/example.com\/fullchain.pem \/etc\/letsencrypt\/live\/example.com\/privkey.pem \\\n  | sudo tee \/etc\/haproxy\/certs\/example.com.pem &gt;\/dev\/null\nsudo chmod 600 \/etc\/haproxy\/certs\/example.com.pem\n<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code># Frontend with TLS and security headers\nfrontend fe_https\n  bind :443 ssl crt \/etc\/haproxy\/certs\/example.com.pem alpn h2,http\/1.1\n  http-response set-header Strict-Transport-Security \"max-age=31536000; includeSubDomains; preload\"\n  http-response set-header X-Content-Type-Options \"nosniff\"\n  http-response set-header X-Frame-Options \"SAMEORIGIN\"\n  http-response set-header Referrer-Policy \"strict-origin-when-cross-origin\"\n  # Proceed to your backend\n  default_backend be_app\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"3-2-mtls-to-backends-protect-east-west-traffic\"><strong>3.2 mTLS to Backends (Protect East-West traffic)<\/strong><\/h3>\n\n\n\n<p>When services are sensitive, enforce mutual TLS between HAProxy and backend servers:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>backend be_app\n  balance roundrobin\n  option httpchk GET \/health\n  http-check expect status 200\n  # Verify backend certs signed by your CA\n  server app1 10.0.0.10:8443 ssl verify required ca-file \/etc\/haproxy\/ca\/backend-ca.pem check\n  server app2 10.0.0.11:8443 ssl verify required ca-file \/etc\/haproxy\/ca\/backend-ca.pem check\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"step-4-restrict-access-and-throttle-abuse\"><strong>Step 4: Restrict Access and Throttle Abuse<\/strong><\/h2>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"4-1-firewall-and-private-admin-access\"><strong>4.1 Firewall and Private Admin Access<\/strong><\/h3>\n\n\n\n<p>Expose only public ports and lock down the stats page to trusted IPs.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># UFW example\nsudo ufw allow 80,443\/tcp\nsudo ufw allow from 203.0.113.0\/24 to any port 8404 proto tcp   # stats allowlist\nsudo ufw deny 8404\/tcp\nsudo ufw enable\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"4-2-rate-limiting-429-and-basic-ddos-mitigation\"><strong>4.2 Rate Limiting (429) and Basic DDoS Mitigation<\/strong><\/h3>\n\n\n\n<p>Use stick-tables to track per-IP request rates and deny abusive clients gracefully.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># In your TLS frontend\nfrontend fe_https\n  bind :443 ssl crt \/etc\/haproxy\/certs\/example.com.pem alpn h2,http\/1.1\n  # Track requests per client IP over 10s\n  stick-table type ip size 200k expire 10m store http_req_rate(10s)\n  http-request track-sc0 src\n  # Deny if &gt; 100 req\/s (tune per app)\n  http-request deny status 429 content-type \"text\/plain\" string \"Too many requests\" if { sc_http_req_rate(0) gt 100 }\n  default_backend be_app\n<\/code><\/pre>\n\n\n\n<p>You can add connection caps and queue-depth alerts. For volumetric DDoS, pair HAProxy with an upstream provider or dedicated network mitigation.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"4-3-blocklists-and-ip-reputation\"><strong>4.3 Blocklists and IP Reputation<\/strong><\/h3>\n\n\n\n<p>Maintain a simple denylist file and reload quickly when threats appear:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># \/etc\/haproxy\/blocked_ips.lst\n192.0.2.66\n198.51.100.99\n<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code># In frontend\nacl badip src -f \/etc\/haproxy\/blocked_ips.lst\nhttp-request deny if badip\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"step-5-host-hardening-and-operational-safety\"><strong>Step 5: Host Hardening and Operational Safety<\/strong><\/h2>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"5-1-least-privilege-chroot-and-permissions\"><strong>5.1 Least Privilege, Chroot, and Permissions<\/strong><\/h3>\n\n\n\n<p>Run HAProxy as a non-root user with chroot. We already set user\/group and chroot in the global section. Ensure strict permissions on certificates and the admin socket.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"5-2-selinux-apparmor-and-fail2ban\"><strong>5.2 SELinux\/AppArmor and Fail2ban<\/strong><\/h3>\n\n\n\n<p>Enable MAC controls and ban repeat offenders from logs.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># CentOS\/Alma\/Rocky SELinux: allow outbound backend connections\nsudo setsebool -P haproxy_connect_any 1\n\n# Ubuntu\/Debian AppArmor: adjust \/etc\/apparmor.d\/usr.sbin.haproxy as needed\n# then reload\nsudo systemctl reload apparmor\n<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code># Fail2ban simple jail example (tune for your log format)\n# \/etc\/fail2ban\/jail.d\/haproxy.conf\n&#91;haproxy-4xx]\nenabled = true\nport    = http,https\nfilter  = haproxy-4xx\nlogpath = \/var\/log\/haproxy.log\nmaxretry = 20\nfindtime = 300\nbantime  = 3600\n<\/code><\/pre>\n\n\n\n<p>Create a matching filter to catch suspicious repeated 401\/403 or malformed requests, then restart fail2ban.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"5-3-safe-testing-reloads-and-upgrades\"><strong>5.3 Safe Testing, Reloads, and Upgrades<\/strong><\/h3>\n\n\n\n<p>Validate config before reload and track LTS releases for stability.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># Validate and reload without dropping connections\nsudo haproxy -c -f \/etc\/haproxy\/haproxy.cfg\nsudo systemctl reload haproxy\n\n# Show current version and features\nhaproxy -vv\n<\/code><\/pre>\n\n\n\n<p>Use rolling or seamless reloads during traffic lulls. Subscribe to HAProxy LTS updates to receive security patches promptly.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"step-6-improve-http-intelligence-and-compatibility\"><strong>Step 6: Improve HTTP Intelligence and Compatibility<\/strong><\/h2>\n\n\n\n<p>Forward the real client IP to apps and standardize proxy headers. If you\u2019re behind another proxy or CDN (e.g., Cloudflare), honor its headers safely.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># Add X-Forwarded-* headers for apps\ndefaults\n  option forwardfor if-none\n  http-request set-header X-Forwarded-Proto https if { ssl_fc }\n\n# Cloudflare example: trust CF-Connecting-IP for logs\/ACLs (verify your IP allowlists)\nacl from_cf src -f \/etc\/haproxy\/cloudflare_ips.lst\nhttp-request set-var(txn.realip) req.hdr(CF-Connecting-IP) if from_cf\nhttp-request set-header X-Real-IP %&#91;var(txn.realip)] if from_cf\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"advanced-options-when-you-need-more\"><strong>Advanced Options (When You Need More)<\/strong><\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>WAF integration: Use HAProxy Enterprise WAF or <a href=\"https:\/\/www.youstable.com\/blog\/modsecurity-vs-waf\/\">SPOE with ModSecurity<\/a> v3 (spoa-modsecurity) for ruleset-driven protection.<\/li>\n\n\n\n<li>Canary and blue\/green: Route a small percentage of traffic with ACLs for safe experiments.<\/li>\n\n\n\n<li>Service discovery: Dynamically populate backends via DNS with health checks.<\/li>\n\n\n\n<li>mTLS at the edge: Client cert verification for admin apps or partner APIs.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"operational-checklist\"><strong>Operational Checklist<\/strong><\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Logging: Dedicated haproxy.log with httplog enabled and custom fields when needed<\/li>\n\n\n\n<li>Visibility: Stats page locked to admin IPs; admin socket local-only<\/li>\n\n\n\n<li>Metrics: Prometheus exporter + Grafana dashboards; alerts on 5xx, latency, backends DOWN<\/li>\n\n\n\n<li>TLS: TLS 1.2\/1.3 only, modern ciphers, HSTS, secure cert permissions<\/li>\n\n\n\n<li>Access: Firewall allow 80\/443, deny admin endpoints, maintain IP allowlists<\/li>\n\n\n\n<li>Abuse control: Stick-table rate limiting, blocklists, optional Fail2ban<\/li>\n\n\n\n<li>Hardening: Non-root user, chroot, SELinux\/AppArmor policies<\/li>\n\n\n\n<li>Ops: Validate config before reload; track LTS; regular backups of configs and certs<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"why-this-matters-real-world-insight\"><strong>Why This Matters (Real-World Insight)<\/strong><\/h2>\n\n\n\n<p>Most HAProxy outages stem from three issues: blind spots (no metrics\/alerts), weak TLS\/access controls, and unsafe changes during peak traffic. The steps above eliminate those risks by adding visibility, enforcing least privilege, and formalizing safe reloads and upgrades\u2014exactly how we run large-scale HAProxy clusters at YouStable.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"when-to-choose-managed-haproxy\"><strong>When to Choose Managed HAProxy<\/strong><\/h2>\n\n\n\n<p>If you prefer expert-run monitoring, patching, DDoS protection, and 24\u00d77 response, YouStable\u2019s <a href=\"https:\/\/www.youstable.com\/blog\/benefits-of-fully-managed-dedicated-server\/\">managed server plans<\/a> include HAProxy hardening, metrics, and incident-ready alerting. This lets your team focus on features while we handle uptime and security at the edge.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"faqs-how-to-monitor-and-secure-haproxy-on-linux-server\"><strong>FAQs: How to Monitor &amp; Secure HAProxy on Linux Server<\/strong><\/h2>\n\n\n\t\t<section\t\thelp class=\"sc_fs_faq sc_card    \"\n\t\t\t\t>\n\t\t\t\t<h3 id=\"how-do-i-enable-the-haproxy-stats-page-on-linux\">How do I enable the HAProxy stats page on Linux?<\/h3>\t\t\t\t<div>\n\t\t\t\t\t\t<div class=\"sc_fs_faq__content\">\n\t\t\t\t\n\n<p>Add a stats listener to haproxy.cfg, protect it with basic auth and an IP allowlist, then reload HAProxy. Example: a dedicated \u201clisten stats\u201d on port 8404 with stats uri \/haproxy?stats, stats auth user:pass, and an ACL to restrict by source IP.<\/p>\n\n\t\t\t<\/div>\n\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section\t\thelp class=\"sc_fs_faq sc_card    \"\n\t\t\t\t>\n\t\t\t\t<h3 id=\"what-are-the-top-haproxy-security-best-practices\">What are the top HAProxy security best practices?<\/h3>\t\t\t\t<div>\n\t\t\t\t\t\t<div class=\"sc_fs_faq__content\">\n\t\t\t\t\n\n<p>Use TLS 1.2\/1.3 only, strong ciphers, HSTS, and strict cert permissions. Restrict the stats page, keep the admin socket local with limited permissions, enforce firewall rules, add stick-table rate limiting, keep HAProxy on an LTS release, and validate config before reloads.<\/p>\n\n\t\t\t<\/div>\n\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section\t\thelp class=\"sc_fs_faq sc_card    \"\n\t\t\t\t>\n\t\t\t\t<h3 id=\"how-can-i-monitor-haproxy-with-prometheus-and-grafana\">How can I monitor HAProxy with Prometheus and Grafana?<\/h3>\t\t\t\t<div>\n\t\t\t\t\t\t<div class=\"sc_fs_faq__content\">\n\t\t\t\t\n\n<p>Run the haproxy_exporter using the Unix admin socket or the stats URL. Add a scrape job in Prometheus and import a HAProxy dashboard in Grafana. Then set alerts for 5xx spikes, backend DOWN, queue increases, and high response latency.<\/p>\n\n\t\t\t<\/div>\n\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section\t\thelp class=\"sc_fs_faq sc_card    \"\n\t\t\t\t>\n\t\t\t\t<h3 id=\"how-do-i-rate-limit-requests-in-haproxy\">How do I rate limit requests in HAProxy?<\/h3>\t\t\t\t<div>\n\t\t\t\t\t\t<div class=\"sc_fs_faq__content\">\n\t\t\t\t\n\n<p>Create a stick-table in your frontend, track source IPs, and deny when http_req_rate exceeds a threshold. Return 429 for excess traffic. Tune the threshold per endpoint and consider separate limits for login or API routes.<\/p>\n\n\t\t\t<\/div>\n\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section\t\thelp class=\"sc_fs_faq sc_card    \"\n\t\t\t\t>\n\t\t\t\t<h3 id=\"how-do-i-log-the-real-client-ip-behind-a-cdn-or-proxy\">How do I log the real client IP behind a CDN or proxy?<\/h3>\t\t\t\t<div>\n\t\t\t\t\t\t<div class=\"sc_fs_faq__content\">\n\t\t\t\t\n\n<p>Use option forwardfor to set X-Forwarded-For, and if behind Cloudflare or another CDN, trust their header (e.g., CF-Connecting-IP) only from CDN IP ranges via ACLs. For PROXY protocol setups, enable accept-proxy on the bind and configure the upstream to send PROXY protocol.<\/p>\n\n\n\n<p>With the above monitoring stack and layered security controls, you\u2019ll keep HAProxy observable, resilient, and safe\u2014ready for real-world traffic and threats.<\/p>\n\n\t\t\t<\/div>\n\t\t<\/div>\n\t\t<\/section>\n\t\t\n<script type=\"application\/ld+json\">\n\t{\n\t\t\"@context\": \"https:\/\/schema.org\",\n\t\t\"@type\": \"FAQPage\",\n\t\t\"mainEntity\": [\n\t\t\t\t\t{\n\t\t\t\t\"@type\": \"Question\",\n\t\t\t\t\"name\": \"How do I enable the HAProxy stats page on Linux?\",\n\t\t\t\t\"acceptedAnswer\": {\n\t\t\t\t\t\"@type\": \"Answer\",\n\t\t\t\t\t\"text\": \"<p>Add a stats listener to haproxy.cfg, protect it with basic auth and an IP allowlist, then reload HAProxy. Example: a dedicated \u201clisten stats\u201d on port 8404 with stats uri \/haproxy?stats, stats auth user:pass, and an ACL to restrict by source IP.<\/p>\"\n\t\t\t\t\t\t\t\t\t}\n\t\t\t}\n\t\t\t,\t\t\t\t{\n\t\t\t\t\"@type\": \"Question\",\n\t\t\t\t\"name\": \"What are the top HAProxy security best practices?\",\n\t\t\t\t\"acceptedAnswer\": {\n\t\t\t\t\t\"@type\": \"Answer\",\n\t\t\t\t\t\"text\": \"<p>Use TLS 1.2\/1.3 only, strong ciphers, HSTS, and strict cert permissions. Restrict the stats page, keep the admin socket local with limited permissions, enforce firewall rules, add stick-table rate limiting, keep HAProxy on an LTS release, and validate config before reloads.<\/p>\"\n\t\t\t\t\t\t\t\t\t}\n\t\t\t}\n\t\t\t,\t\t\t\t{\n\t\t\t\t\"@type\": \"Question\",\n\t\t\t\t\"name\": \"How can I monitor HAProxy with Prometheus and Grafana?\",\n\t\t\t\t\"acceptedAnswer\": {\n\t\t\t\t\t\"@type\": \"Answer\",\n\t\t\t\t\t\"text\": \"<p>Run the haproxy_exporter using the Unix admin socket or the stats URL. Add a scrape job in Prometheus and import a HAProxy dashboard in Grafana. Then set alerts for 5xx spikes, backend DOWN, queue increases, and high response latency.<\/p>\"\n\t\t\t\t\t\t\t\t\t}\n\t\t\t}\n\t\t\t,\t\t\t\t{\n\t\t\t\t\"@type\": \"Question\",\n\t\t\t\t\"name\": \"How do I rate limit requests in HAProxy?\",\n\t\t\t\t\"acceptedAnswer\": {\n\t\t\t\t\t\"@type\": \"Answer\",\n\t\t\t\t\t\"text\": \"<p>Create a stick-table in your frontend, track source IPs, and deny when http_req_rate exceeds a threshold. Return 429 for excess traffic. Tune the threshold per endpoint and consider separate limits for login or API routes.<\/p>\"\n\t\t\t\t\t\t\t\t\t}\n\t\t\t}\n\t\t\t,\t\t\t\t{\n\t\t\t\t\"@type\": \"Question\",\n\t\t\t\t\"name\": \"How do I log the real client IP behind a CDN or proxy?\",\n\t\t\t\t\"acceptedAnswer\": {\n\t\t\t\t\t\"@type\": \"Answer\",\n\t\t\t\t\t\"text\": \"<p>Use option forwardfor to set X-Forwarded-For, and if behind Cloudflare or another CDN, trust their header (e.g., CF-Connecting-IP) only from CDN IP ranges via ACLs. For PROXY protocol setups, enable accept-proxy on the bind and configure the upstream to send PROXY protocol.<\/p><p>With the above monitoring stack and layered security controls, you\u2019ll keep HAProxy observable, resilient, and safe\u2014ready for real-world traffic and threats.<\/p>\"\n\t\t\t\t\t\t\t\t\t}\n\t\t\t}\n\t\t\t\t\t\t]\n\t}\n<\/script>\n","protected":false},"excerpt":{"rendered":"<p>To monitor &amp; secure HAProxy on Linux server, enable detailed logging and the stats\/admin socket, export metrics to Prometheus\/Grafana, and [&hellip;]<\/p>\n","protected":false},"author":13,"featured_media":14502,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"site-sidebar-layout":"default","site-content-layout":"","ast-site-content-layout":"default","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","ast-disable-related-posts":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"footnotes":""},"categories":[350],"tags":[2181,2141],"class_list":["post-14349","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-knowledgebase","tag-how-to-monitor-secure-haproxy-on-linux-server","tag-linux-server"],"acf":[],"featured_image_src":"https:\/\/www.youstable.com\/blog\/wp-content\/uploads\/2025\/12\/How-to-Monitor-Secure-HAProxy-on-Linux-Server.jpg","author_info":{"display_name":"Prahlad Prajapati","author_link":"https:\/\/www.youstable.com\/blog\/author\/prahladblog"},"_links":{"self":[{"href":"https:\/\/www.youstable.com\/blog\/wp-json\/wp\/v2\/posts\/14349","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.youstable.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.youstable.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.youstable.com\/blog\/wp-json\/wp\/v2\/users\/13"}],"replies":[{"embeddable":true,"href":"https:\/\/www.youstable.com\/blog\/wp-json\/wp\/v2\/comments?post=14349"}],"version-history":[{"count":2,"href":"https:\/\/www.youstable.com\/blog\/wp-json\/wp\/v2\/posts\/14349\/revisions"}],"predecessor-version":[{"id":14480,"href":"https:\/\/www.youstable.com\/blog\/wp-json\/wp\/v2\/posts\/14349\/revisions\/14480"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.youstable.com\/blog\/wp-json\/wp\/v2\/media\/14502"}],"wp:attachment":[{"href":"https:\/\/www.youstable.com\/blog\/wp-json\/wp\/v2\/media?parent=14349"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.youstable.com\/blog\/wp-json\/wp\/v2\/categories?post=14349"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.youstable.com\/blog\/wp-json\/wp\/v2\/tags?post=14349"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}