Terraform can manage HAProxy configurations, but it doesn’t actually run HAProxy for you; it generates HAProxy configuration files and can then tell an existing HAProxy process to reload them.
Let’s see this in action with a basic HAProxy setup. Imagine we have a cluster of web servers and want HAProxy to load balance traffic to them.
Here’s a Terraform configuration to define a frontend that listens on port 80 and a backend pool of three web servers:
provider "haproxy" {
# Path to the HAProxy binary if not in PATH
# haproxy_binary = "/usr/local/sbin/haproxy"
}
resource "haproxy_frontend" "web_frontend" {
name = "http_frontend"
bind = "0.0.0.0:80"
mode = "http"
default_backend = haproxy_backend.web_backend.name
}
resource "haproxy_backend" "web_backend" {
name = "web_servers"
mode = "http"
balance = "roundrobin"
servers = [
"web1 192.168.1.10:80 check",
"web2 192.168.1.11:80 check",
"web3 192.168.1.12:80 check",
]
}
resource "haproxy_config" "reload" {
config_file = "/etc/haproxy/haproxy.cfg"
reload_command = "sudo /usr/local/sbin/haproxy -f /etc/haproxy/haproxy.cfg -reload"
depends_on = [
haproxy_frontend.web_frontend,
haproxy_backend.web_backend,
]
}
When you run terraform apply, the haproxy provider will generate a haproxy.cfg file based on these resources. It doesn’t directly modify the running HAProxy process itself. Instead, it writes the configuration to a file (defined by config_file in the haproxy_config resource). The reload_command is then executed, which tells the existing HAProxy process to read the newly generated configuration file.
The problem this solves is managing HAProxy’s complex, often manually edited configuration files in a declarative, version-controlled way. Instead of SSHing in and sudo vi /etc/haproxy/haproxy.cfg, you define your desired state in Terraform.
Internally, the haproxy provider translates your Terraform resource definitions into the specific frontend, backend, listen, acl, use_backend, and other HAProxy configuration stanzas. The haproxy_config resource is crucial here; it acts as a trigger. When the frontend or backend resources change, haproxy_config detects this dependency and executes the specified reload_command. This command is what actually instructs the HAProxy daemon to re-read its configuration.
You control the HAProxy setup through the attributes of the haproxy_frontend and haproxy_backend resources. For instance, changing balance from "roundrobin" to "leastconn" in the web_backend resource will update the generated haproxy.cfg and trigger a reload. You can define complex ACLs, health checks, SSL termination, and more, all within Terraform.
The haproxy_config resource’s reload_command is where the magic of applying the configuration happens. It’s not the Terraform provider that’s running HAProxy; it’s a command that tells the already running HAProxy process to pick up the new config. This means you need HAProxy installed and running on the target machine where you execute terraform apply, or on a machine that HAProxy can be controlled from. The provider simply orchestrates the generation and the reload signal.
Many users overlook that the haproxy_config resource’s reload_command typically requires elevated privileges (like sudo) to interact with the HAProxy daemon. If this command fails, Terraform will report success, but HAProxy won’t pick up the changes. You’ll need to verify the command’s execution manually or use Terraform’s provisioner blocks for more complex deployment scenarios if reload_command isn’t sufficient.
The next challenge is often managing HAProxy’s static file configurations, such as SSL certificates, which Terraform’s native HAProxy provider doesn’t directly manage.