Set Up an Octavia Load Balancer in OpenStack
Make apps highly available with Octavia: create a load balancer, add a listener and a member pool, attach health monitors, and expose it with a floating IP.
A single web server is a single point of failure. Octavia, OpenStack's load-balancing service, solves this by distributing traffic across a pool of backend instances and steering it away from any that fail a health check. It is the cloud-scale successor to the single-host Nginx reverse proxy โ same idea, but elastic, API-driven, and highly available.
This tutorial builds a working HTTP load balancer end to end: a load balancer on a subnet, a listener on port 80, a member pool of two instances, and a health monitor that removes unhealthy members automatically. It assumes you already have tenant networking and at least two running instances serving a web app.
Prerequisites
- A running OpenStack 2025.2 cloud with the Octavia (load-balancer) service enabled.
- The
openstackclient with thepython-octaviaclientplugin installed. - Two instances on
acme-subnetrunning a web server on port 80, plus their private IPs.
source ~/acme-openrc
openstack loadbalancer provider list
openstack server list -c Name -c NetworksThe Octavia object model
Four objects stack together. A load balancer owns a VIP on a subnet. A listener binds a protocol and port (for example HTTP:80) on that VIP. A pool defines how traffic is balanced and groups the backends. Members are the backend instances in the pool, and a health monitor probes them so only healthy members receive traffic.
Step 1: Create the load balancer
Create the load balancer on your tenant subnet. Octavia provisions an Amphora VM (or driver-specific resource) to host the VIP, so this step takes a minute or two:
openstack loadbalancer create --name acme-lb --vip-subnet-id acme-subnet
openstack loadbalancer show acme-lb -c provisioning_status -c vip_addressWait until provisioning_status reads ACTIVE before continuing. You can poll it, or watch the operating status:
openstack loadbalancer list -c name -c provisioning_status -c operating_statusStep 2: Add a listener
The listener accepts client connections. Create an HTTP listener on port 80 attached to the load balancer:
openstack loadbalancer listener create --name acme-listener \
--protocol HTTP --protocol-port 80 acme-lbStep 3: Create a pool
The pool decides the balancing algorithm and holds the members. ROUND_ROBIN is a sensible default; LEAST_CONNECTIONS suits long-lived connections:
openstack loadbalancer pool create --name acme-pool \
--lb-algorithm ROUND_ROBIN --listener acme-listener --protocol HTTPStep 4: Add members
Add each backend instance to the pool by its private IP and the subnet it lives on. Repeat for every backend:
openstack loadbalancer member create --name web-01 \
--address 10.0.0.42 --protocol-port 80 --subnet-id acme-subnet acme-pool
openstack loadbalancer member create --name web-02 \
--address 10.0.0.43 --protocol-port 80 --subnet-id acme-subnet acme-poolStep 5: Attach a health monitor
The health monitor periodically probes each member and pulls failing ones out of rotation. An HTTP monitor that expects a 200 on / is a good start:
openstack loadbalancer healthmonitor create --name acme-hm \
--delay 5 --timeout 3 --max-retries 3 --type HTTP --url-path / acme-poolStep 6: Expose the VIP and test
The VIP is on the private subnet. Attach a floating IP to it so clients on the outside can reach the load balancer, then test that requests are distributed:
openstack floating ip create ext-net openstack loadbalancer show acme-lb -c vip_port_id openstack floating ip set --port <vip_port_id> 203.0.113.80from outside, repeat requests โ responses should alternate between backends
for i in $(seq 1 6); do curl -s http://203.0.113.80/ | grep -o 'web-0[12]'; done
Verification
Confirm everything is healthy. Both the load balancer and the pool members should report a healthy operating status:
openstack loadbalancer status show acme-lb openstack loadbalancer member list acme-pool -c name -c operating_status
operating_status should be ONLINE for healthy members
To prove failover works, stop the web server on one backend and watch its member flip to ERROR while traffic continues uninterrupted to the other.
Common errors and troubleshooting
Load balancer stuck in PENDING_CREATE
Octavia is still building the Amphora, or the service cannot schedule one. Give it a few minutes; if it never goes ACTIVE, an admin should check the Octavia worker logs and that the management network and image for Amphorae exist.
Members show as ERROR / offline
The health monitor cannot reach the backend. Confirm the web server is actually listening on port 80, and that a security group on the members allows traffic from the load balancer subnet on that port.
Curl times out on the VIP
Usually the floating IP is not associated with the VIP port, or no security group permits port 80 inbound. Re-check the floating IP association and the listener protocol/port.
All traffic hits one backend
Persistent connections or session stickiness can mask round-robin. Use separate requests (as in the loop above) and confirm the pool algorithm is ROUND_ROBIN.
Cleaning up
openstack loadbalancer delete acme-lb --cascade
openstack floating ip delete 203.0.113.80
Conclusion
You have built a highly available HTTP service: a load balancer with a listener, a balanced pool, health-checked members, and a public VIP โ all provisioned through the API and resilient to a backend failure. This is the cloud-scale version of fronting an app with a reverse proxy, and it is how production workloads stay online during deploys and outages. Combine it with persistent volumes and multiple instances for a complete, resilient stack.
Running Octavia in production โ with redundant Amphorae, TLS termination, and capacity to spare โ is part of the managed platform clouditiv operates on a sovereign on-premise cloud, so your apps get cloud-grade high availability without you maintaining the load-balancing fleet.