# HAProxy operations

### Install &amp; lifecycle

<div class="ui-scroll-area" data-direction="horizontal" data-scroll-padding="4" data-visibility="hover" id="bkmrk-action-command-id-no"><div class="ui-scroll-area__viewport"><div class="ui-scroll-area__content"><table><thead class="bg-muted/80" data-streamdown="table-header"><tr class="border-border border-b" data-streamdown="table-row"><th class="whitespace-nowrap px-4 py-2 text-left font-semibold text-sm" data-streamdown="table-header-cell">Action</th><th class="whitespace-nowrap px-4 py-2 text-left font-semibold text-sm" data-streamdown="table-header-cell">Command ID</th><th class="whitespace-nowrap px-4 py-2 text-left font-semibold text-sm" data-streamdown="table-header-cell">Notes</th></tr></thead><tbody class="divide-y divide-border bg-muted/40" data-streamdown="table-body"><tr class="border-border border-b" data-streamdown="table-row"><td><div class="md-table-cell-content">Install HAProxy</div></td><td><div class="md-table-cell-content">`<span class="md-inline-path-filename">haproxy.provision</span>`</div></td><td><div class="md-table-cell-content">Fresh VM</div></td></tr><tr class="border-border border-b" data-streamdown="table-row"><td><div class="md-table-cell-content">Re-install</div></td><td><div class="md-table-cell-content">`<span class="md-inline-path-filename">haproxy.provision</span>` + `force: true`</div></td><td><div class="md-table-cell-content">Overwrite install path</div></td></tr><tr class="border-border border-b" data-streamdown="table-row"><td><div class="md-table-cell-content">Reload</div></td><td><div class="md-table-cell-content">`<span class="md-inline-path-filename">haproxy.reload</span>`</div></td><td><div class="md-table-cell-content">After config edits</div></td></tr><tr class="border-border border-b" data-streamdown="table-row"><td><div class="md-table-cell-content">Provision standby from backup</div></td><td><div class="md-table-cell-content">`<span class="md-inline-path-filename">standby.provision_from_backup</span>`</div></td><td><div class="md-table-cell-content">Clone config from backup onto standby</div></td></tr></tbody></table>

</div></div></div>Jobs are enqueued to the API; the agent claims and runs them on the <span class="font-semibold" data-streamdown="strong">next heartbeat</span>.

### Admin stats socket (drain / ready)

Runtime backend control requires a <span class="font-semibold" data-streamdown="strong">Unix admin socket</span> in `<span class="md-inline-path-filename">haproxy.cfg</span>`:

```
stats socket /run/haproxy/admin.sock mode 600 level admin expose-fd listeners
stats timeout 2m
```

Enable via <span class="font-semibold" data-streamdown="strong">Recipe: Enable HAProxy admin stats socket</span> or <span class="font-semibold" data-streamdown="strong">Enable admin stats socket</span> action.

**Requires <span class="font-semibold" data-streamdown="strong">socot</span> + agent as <span class="font-semibold" data-streamdown="strong">root</span>. This is <span class="font-semibold" data-streamdown="strong">not</span> a public HTTP stats page.**

### Backend server states

From Management/topology table:

<div class="ui-scroll-area" data-direction="horizontal" data-scroll-padding="4" data-visibility="hover" id="bkmrk-action-command-id-ha"><div class="ui-scroll-area__viewport"><div class="ui-scroll-area__content"><table><thead class="bg-muted/80" data-streamdown="table-header"><tr class="border-border border-b" data-streamdown="table-row"><th class="whitespace-nowrap px-4 py-2 text-left font-semibold text-sm" data-streamdown="table-header-cell">Action</th><th class="whitespace-nowrap px-4 py-2 text-left font-semibold text-sm" data-streamdown="table-header-cell">Command ID</th><th class="whitespace-nowrap px-4 py-2 text-left font-semibold text-sm" data-streamdown="table-header-cell">HAProxy runtime</th></tr></thead><tbody class="divide-y divide-border bg-muted/40" data-streamdown="table-body"><tr class="border-border border-b" data-streamdown="table-row"><td><div class="md-table-cell-content">Drain</div></td><td><div class="md-table-cell-content">`<span class="md-inline-path-filename">haproxy.server_drain</span>`</div></td><td><div class="md-table-cell-content">`set server … state drain`</div></td></tr><tr class="border-border border-b" data-streamdown="table-row"><td><div class="md-table-cell-content">Ready</div></td><td><div class="md-table-cell-content">`<span class="md-inline-path-filename">haproxy.server_ready</span>`</div></td><td><div class="md-table-cell-content">`state ready`</div></td></tr><tr class="border-border border-b" data-streamdown="table-row"><td><div class="md-table-cell-content">Maintenance</div></td><td><div class="md-table-cell-content">`<span class="md-inline-path-filename">haproxy.server_maint</span>`</div></td><td><div class="md-table-cell-content">`state maint`</div></td></tr></tbody></table>

</div></div></div>### TLS (Let’s Encrypt on HAProxy)

<span class="font-semibold" data-streamdown="strong">Recipe: Let’s Encrypt (failover / HAProxy)</span>

- Uses <span class="font-semibold" data-streamdown="strong">DNS-01</span> via Cloudflare for the <span class="font-semibold" data-streamdown="strong">pool failover FQDN</span>
- Agent writes combined PEM: `<span class="md-inline-path-prefix">/etc/haproxy/certs/</span><span class="md-inline-path-filename"><hostname>.pem</span>`
- <span class="font-semibold" data-streamdown="strong">One-time operator step:</span> add `ssl crt /etc/haproxy/certs/<hostname>.pem` in config, validate, reload
- Renew from Management or cron preset `<span class="md-inline-path-filename">tls.acme_renew_force</span>`

The pool must have Cloudflare linked and a failover label set before the recipe applies.

### Status tab

Shows live traffic from agent heartbeat enrichment — <span class="font-semibold" data-streamdown="strong">not</span> a duplicate of the Overview topology diagram. Use for session rates, backend health columns, etc.