← Back to Blog

OpenStack Load Balancer as a Service (LBaaS): How Octavia Works, With a CLI Walkthrough

Published · Updated · by RS Computers

OpenStack Octavia Load balancing

OpenStack's Load Balancer as a Service (LBaaS) is Octavia, a separate OpenStack service with its own API that lets every project create load balancers on demand: a virtual IP, listeners, pools of back-end servers and health checks. By default each load balancer runs on a small VM called an amphora with HAProxy inside; with the OVN provider it becomes rules in the virtual network and no VM boots at all. The old LBaaS plugin inside Neutron was deprecated in 2018 and left out of the Train release in 2019, so a guide that configures LBaaS in Neutron describes software that no longer ships.

The short version, in four lines:

Is Neutron LBaaS deprecated? Yes, and it is gone

Octavia grew out of the Neutron LBaaS project and has been the reference implementation of the LBaaS v2 API since the Liberty release in 2015. The neutron-lbaas deprecation notice marked the plugin and its dashboard deprecated in the Queens cycle (Queens came out on 28 February 2018), and neither was released as part of Train on 16 October 2019. The repository on OpenDev is retired. Octavia's v2 API is a fully backward compatible superset of LBaaS v2, so code written for LBaaS v2 has a direct path forward.

What older guides still get wrong

The Mitaka-era networking guide still turns up in search results, and an earlier version of this page made similar mistakes:

How does OpenStack Load Balancer as a Service work?

Octavia has a control plane that takes orders and a data plane that carries traffic. As Introducing Octavia describes it, the API controller validates each request and passes it over the message bus to the controller worker, which asks Nova for amphorae and Neutron for ports and pushes configuration. The health manager watches amphora heartbeats and starts failovers. The housekeeping manager cleans the database and rotates amphora certificates.

The data plane is the amphorae. The reference amphora is an Ubuntu image built with diskimage-create.sh that holds HAProxy, Keepalived and the amphora agent, whose TLS-protected REST API on TCP 9443 is how the worker writes HAProxy's configuration. HAProxy runs in its own network namespace, apart from the management interface. The image builder has defaulted to Ubuntu Minimal 24.04 (noble) since the 2025 releases, and since 19.0.0 it targets the build host's CPU architecture instead of always amd64.

Octavia leans on Keystone for authentication, Nova for amphorae, Neutron for ports and VIPs, Glance for the image and Barbican for TLS certificates. Keystone roles let developers create their own load balancers without filing a ticket, and each load balancer is a self-contained appliance, so one project's broken config cannot take down a neighbour's. That isolation is the best argument for the amphora design; the VM count is the trade-off.

The management network and its ports

Controllers reach amphorae over a separate network, usually called lb-mgmt-net, using mutual TLS signed by two certificate authorities (the install guide's create_dual_intermediate_CA.sh creates them). Amphora certificates last 30 days by default and housekeeping renews them. Getting this network right is most of an Octavia install.

PortTrafficSymptom when blocked
TCP 9876Clients to the Octavia APICLI calls time out
TCP 9443Controllers to each amphora agent, over lb-mgmt-netLoad balancers stuck in PENDING_CREATE, then ERROR
UDP 5555Amphora heartbeats to the health manager, every 10 secondsStale status; amphorae silent for 60 seconds get failed over
TCP 22Operators to amphorae, for debuggingNothing, until you need to look inside one

Amphora or OVN: which Octavia provider should you pick?

Amphora is the reference provider driver and the default. A10, F5 (provided by SAP SE), Radware and VMware NSX drivers also exist, maintained outside the Octavia team. The real choice is amphora against OVN, which programs load balancing into the OVN back end many Neutron deployments already run (our overview of SDN back ends in OpenStack shows where OVN sits). The Octavia feature matrix spells out the gap:

FeatureAmphoraOVN
Carries traffic withHAProxy in one VM, or two for active/standbyOVN on the existing hypervisors
Listener protocolsHTTP, HTTPS, TERMINATED_HTTPS, TCP, UDP, SCTP, PROMETHEUSTCP and UDP (the driver page adds SCTP)
AlgorithmsROUND_ROBIN, LEAST_CONNECTIONS, SOURCE_IPSOURCE_IP_PORT, plus SOURCE_IP since provider 11.0.0
Health monitorsHTTP, HTTPS, PING, TCP, TLS-HELLO, UDP-CONNECT, SCTPTCP and UDP-CONNECT
TLS termination, L7 rules, session persistence, ALPNYesNo
High availabilityACTIVE_STANDBY, if the operator enables itNot needed, no VM to lose

The OVN driver documentation adds that mixing IPv4 and IPv6 members is not supported. Vendors split on the default: Canonical's Sunbeam ships OVN as the default with amphora optional, while Red Hat's OpenStack Platform 16.2 guide calls OVN lightweight with a basic feature set suited to east-west traffic. Our rule of thumb: OVN for internal TCP and UDP services such as databases, brokers and DNS; amphora for anything a browser talks to. Once you need TLS termination, a redirect or a path rule, OVN is out anyway.

OVN is catching up slowly: ovn-octavia-provider 11.0.0, released for 2026.2, added SOURCE_IP and a plugin that syncs Octavia resources into the OVN database alongside Neutron's own sync.

What are listeners, pools, members and health monitors?

A load balancer owns one VIP, the stable address clients use. A listener is a protocol and port on that VIP, such as HTTP on 80, and forwards to a pool: a group of back ends sharing one algorithm. A member is one back-end address and port in exactly one pool, and a health monitor, at most one per pool, decides which members get traffic.

Listeners accept HTTP, HTTPS (TLS passed through), TERMINATED_HTTPS (TLS decrypted on the amphora), TCP, UDP, SCTP and PROMETHEUS, which exposes the load balancer's own metrics. If you already run Prometheus, as in our guide to monitoring from a second location, a PROMETHEUS listener limited with allowed_cidrs to the scraper's address is the cheapest way to get load balancer metrics into it. One default bites: timeout_client_data and timeout_member_data are 50,000 ms, so a WebSocket idle for 50 seconds gets cut unless you raise them.

Always use a health monitor in production, because without one a failed member stays in the pool. The cookbook says the URL path should need no login, answer in under a second and never be cached, and that the timeout should always be smaller than the delay, a rule its own example breaks with a delay of 5 and a timeout of 10. The walkthrough below uses 3.

How do you create a load balancer in OpenStack with the CLI?

These steps follow the upstream basic load balancing cookbook. You need python-openstackclient with the python-octaviaclient plugin (Hibiscus ships 10.3.0 and 3.15.0), credentials for an ordinary project user (demo in the install guides), a VIP subnet called public-subnet, and two web servers on private-subnet at 192.0.2.10 and 192.0.2.11 serving /healthcheck on port 80. Keep --wait on every command: it returns once the object leaves its PENDING state, and without it the next command fails with HTTP 409 Conflict.

  1. Create the load balancer. On an amphora cloud this boots a VM, so it takes as long as Nova does:

    # as the demo user, with demo-openrc sourced
    openstack loadbalancer create --name lb1 --vip-subnet-id public-subnet --wait

    Afterwards, openstack loadbalancer show lb1 should report provisioning_status ACTIVE and a vip_address.

  2. Add a listener, a round-robin pool, the health monitor and both servers:

    # as the demo user, with demo-openrc sourced
    openstack loadbalancer listener create --name listener1 --protocol HTTP --protocol-port 80 --wait lb1
    openstack loadbalancer pool create --name pool1 --lb-algorithm ROUND_ROBIN --listener listener1 --protocol HTTP --wait
    openstack loadbalancer healthmonitor create --delay 5 --max-retries 4 --timeout 3 --type HTTP --url-path /healthcheck --wait pool1
    openstack loadbalancer member create --subnet-id private-subnet --address 192.0.2.10 --protocol-port 80 --wait pool1
    openstack loadbalancer member create --subnet-id private-subnet --address 192.0.2.11 --protocol-port 80 --wait pool1
  3. Check the whole tree:

    # as the demo user, with demo-openrc sourced
    openstack loadbalancer status show lb1

    Every level should read "operating_status": "ONLINE". A member in ERROR means the monitor cannot fetch /healthcheck from it, so check that server's firewall first. Requests to the VIP should now alternate between the two servers.

Many clouds keep the VIP private and attach a floating IP: create the load balancer with --vip-subnet-id private-subnet, read vip_port_id from openstack loadbalancer show lb1, then:

# as the demo user, with demo-openrc sourced
openstack floating ip create public
openstack floating ip set --port <load_balancer_vip_port_id> <floating_ip_id>

Heat, Terraform and Ansible drive the same API once you outgrow typing.

How does Octavia TLS termination with Barbican work?

A TERMINATED_HTTPS listener decrypts on the amphora and passes HTTP, or re-encrypted HTTPS, to the members. Octavia's default certificate manager reads certificates from Barbican, OpenStack's secret store, so certificate, key and chain go in as one PKCS#12 bundle. Adapted from the cookbook, for the walkthrough's lb1:

# as the demo user, with demo-openrc sourced
openssl pkcs12 -export -inkey server.key -in server.crt -certfile ca-chain.crt -passout pass: -out server.p12
openstack secret store --name='tls_secret1' -t 'application/octet-stream' -e 'base64' --payload="$(base64 < server.p12)"
openstack loadbalancer listener create --protocol-port 443 --protocol TERMINATED_HTTPS --name listener2 --default-tls-container=$(openstack secret list | awk '/ tls_secret1 / {print $2}') --default-pool pool1 --wait lb1

The new listener reuses the walkthrough's pool1, so the members still get plain HTTP on port 80; the cookbook's scenario for HTTP and HTTPS on the same IP shares one pool the same way, with --default-pool. The bundle has an empty password, so delete server.p12 once Barbican holds it. Older vendor guides add an openstack acl user add step for Octavia's service user. With the default Barbican settings you can skip it: when you create the listener, the Octavia API uses your token to add its service user to the secret's read ACL, and if it still cannot read the certificate it refuses the request straight away instead of creating a listener.

The cookbook also covers SNI, client certificate authentication, HTTP/2 through ALPN and re-encryption to the back ends. Since 17.0.0 (2025.2) the default ciphers follow the OWASP and Mozilla intermediate profile, and 19.0.0 fixed how TLS 1.3 suites are written into HAProxy's config. What you lose against your own proxy is automatic Let's Encrypt renewal: a new certificate means a new secret and a listener update, so put the expiry date in your monitoring.

Can Octavia route by path or hostname?

Yes, on the amphora provider. An L7 policy is a set of rules joined with AND plus one action: send to a pool, redirect to a URL or prefix, or reject. Rules match the host name, path, a header, a cookie, the file type or client certificate fields. Policies run in order of position and the first full match wins, so the most specific goes first. The HTTP to HTTPS redirect from the L7 cookbook, for an HTTP listener named http_listener:

# as the demo user, with demo-openrc sourced
openstack loadbalancer l7policy create --action REDIRECT_PREFIX --redirect-prefix https://www.example.com/ --name policy1 --wait http_listener
openstack loadbalancer l7rule create --compare-type STARTS_WITH --type PATH --value / --wait policy1

Path routing uses --action REDIRECT_TO_POOL --redirect-pool static_pool with a rule like --type PATH --compare-type STARTS_WITH --value /js; host routing uses --type HOST_NAME --compare-type EQUAL_TO. If your automation builds redirect targets from user input, run at least 16.1.0, 17.0.1, 18.0.1 or 19.0.0: those reject the control characters and spaces that could previously inject lines into the HAProxy configuration.

How does Octavia high availability work?

Out of the box, it doesn't. The configuration reference sets loadbalancer_topology to SINGLE, one amphora. If its compute node dies, the health manager misses the heartbeats (every 10 seconds, declared dead after 60) and replaces the amphora elsewhere, capacity permitting. That is recovery, not high availability.

ACTIVE_STANDBY runs two amphorae sharing the VIP through VRRP, managed by Keepalived. By default the active one advertises every second, Keepalived checks HAProxy every 5 seconds and marks the node failed after 2 bad checks, and gratuitous ARPs refresh every 5 seconds so switches learn where the VIP went. Admins can make it the default for every load balancer with loadbalancer_topology, or offer it as a flavor that users pick; the flavors guide shows these commands with SINGLE, and ACTIVE_STANDBY is the other documented value:

# as the admin user, with admin-openrc sourced
openstack loadbalancer flavorprofile create --name amphora-ha-profile --provider amphora --flavor-data '{"loadbalancer_topology": "ACTIVE_STANDBY"}'
openstack loadbalancer flavor create --name ha-lb --flavorprofile amphora-ha-profile --description "High availability load balancer" --enable

Users add --flavor ha-lb when creating a load balancer. Two things matter more than the flavor itself. enable_anti_affinity in [nova] defaults to False, so both amphorae of a pair may land on one hypervisor and die together; turn it on. And promise nobody zero downtime: clients with connections through the failed amphora should expect to reconnect. Octavia 19.0.0 also fixed a VRRP split-brain during amphora failover.

What each load balancer costs the cloud

The install guide's example amphora flavor is 1 vCPU, 1,024 MB of RAM and a 2 GB disk. Octavia publishes no throughput figures, so size from your own load tests; TLS termination is what eats CPU. Count VMs, not load balancers: 40 projects with one HA load balancer each means 80 amphorae in the Octavia service project, whose Nova quota must cover them. To roll out a new image, upload it to Glance with the amphora tag and run openstack loadbalancer failover on each load balancer, a few at a time.

Why is my Octavia load balancer stuck in PENDING_CREATE?

First, the two status fields, as the load balancer API reference defines them. provisioning_status tracks Octavia's own work (ACTIVE, PENDING_CREATE, PENDING_UPDATE, PENDING_DELETE, DELETED, ERROR); operating_status tracks traffic (ONLINE, OFFLINE, DRAINING, DEGRADED, ERROR, NO_MONITOR). ACTIVE and DEGRADED together just means a member failed its check.

Stuck in PENDING_CREATE

The worker almost always cannot reach the new amphora. Check that controllers route into lb-mgmt-net, that its security group lets them reach the amphora on TCP 9443, and that Glance has an image with the amphora tag. A blocked UDP 5555 does not hold up creation; it shows up afterwards, as in the port table above. Pending objects are immutable, so a delete fails with 409 until the worker gives up and sets ERROR. With the default settings it tries the amphora connection 120 times, 5 seconds apart, so that takes at least 10 minutes, and longer when every attempt has to time out first. After a database outage, the operator maintenance guide says pending objects reach ERROR after about 2 hours 45 minutes with default settings.

Failovers nobody asked for

Change the heartbeat encryption key and Octavia can read no heartbeats, so it fails every amphora over at once. And when a dead compute node returns and its hypervisor restarts the old amphora VMs, Octavia assumes they were deleted during failover and will not touch them again, so they are yours to delete by hand. Check first: list the amphorae through the amphora API and match each VM's Nova instance ID against compute_id. A match in any status other than DELETED means that amphora is still in use.

What changed in Octavia in 2025 and 2026?

Hibiscus, the 34th OpenStack release, arrived on 30 September 2026 and its announcement never mentions Octavia, which for a load balancer is a decent sign. The Octavia release notes hold what operators need:

2024.2 Dalmatian reached end of life on 29 April 2026 and gets no further releases, as the OpenStack releases page shows.

Octavia, or HAProxy or Caddy on a plain VPS?

Octavia earns its keep when many teams need load balancers without waiting for an admin. For one team with three web servers it is a lot of machinery. Don't build OpenStack for the load balancer; if the platform question is still open, our Proxmox or OpenStack comparison is the better start.

QuestionOctavia (amphora)HAProxy or Caddy on a VPS
Who creates oneAny project member, through the APIWhoever has root
CertificatesStored in Barbican, renewed by youCaddy renews Let's Encrypt certificates itself
Balancing choicesThree algorithmsTwelve policies in Caddy, about as many in HAProxy
High availabilityTwo amphorae with VRRPYour design, such as two proxies behind health-checked DNS
UpkeepControl plane, image, lb-mgmt-net, CAsOne package, one config file
VersionWhatever the amphora image carriesYour pick, such as HAProxy 3.4 LTS or Caddy 2.11.7

Here is the walkthrough's pool in Caddy. According to its reverse_proxy documentation, the default policy is random and its active checks run every 30 seconds with a 5-second timeout, so this tightens them to match the Octavia monitor. Passive checks stay off until you set fail_duration.

# as root: the whole of /etc/caddy/Caddyfile
example.com {
	reverse_proxy 192.0.2.10:80 192.0.2.11:80 {
		lb_policy round_robin
		health_uri /healthcheck
		health_interval 5s
		health_timeout 3s
	}
}

Installing Caddy itself is covered in our reverse proxy and free HTTPS guide.

Where RS Computers fits

We don't sell OpenStack projects, so there is no Octavia endpoint on our side. We run KVM virtual servers: VPS plans on a 1 Gb/s port and VDS plans on a 10 Gb/s port, all on NVMe, each with its own IPv4 and IPv6 address and free weekly backups, in Amsterdam (Netherlands), Prishtina (Kosovo) and Dublin (Ireland). The vCPUs are shared. Around an OpenStack cloud they suit three jobs:

For a lab or proof of concept, start with the OVN provider, which boots no VMs; amphorae are Nova instances and would run nested inside a virtual server. The VPS and VDS plans page lists every plan, with the same plans and prices in all three cities. Planning something larger? Message us on Telegram or email info@rscomputers-ks.com with what you want to build, and we will suggest a plan and quote the setup.

Frequently asked questions

What is Octavia in OpenStack?

Octavia is OpenStack's Load Balancer as a Service, an open source, operator-scale load balancing service with its own API on port 9876. Projects use it to create load balancers carried by HAProxy amphora VMs or, with the OVN provider, by OVN itself.

When was neutron-lbaas removed?

neutron-lbaas was deprecated in the Queens cycle (Queens shipped on 28 February 2018) and was not released as part of Train on 16 October 2019. Octavia replaced it, and its v2 API is a backward compatible superset of LBaaS v2.

What is an amphora in Octavia?

An amphora is the VM, container or bare metal host that carries a load balancer's traffic. The reference amphora is an Ubuntu 24.04 image with HAProxy, Keepalived and an agent that receives its configuration over TLS on port 9443. A SINGLE load balancer uses one amphora, an ACTIVE_STANDBY one uses two.

Does Octavia use HAProxy?

The default amphora provider does: each amphora runs HAProxy in its own network namespace with a configuration Octavia generates. The OVN provider uses no HAProxy, which is why it handles only layer 4 traffic such as TCP and UDP and has no TLS termination or L7 rules.

What ports does Octavia use?

The API listens on TCP 9876. Controllers reach each amphora agent on TCP 9443 over lb-mgmt-net, and amphorae send heartbeats to the health manager on UDP 5555 every 10 seconds by default.

What is the difference between provisioning_status and operating_status?

provisioning_status tracks Octavia's own work on an object, and anything in a PENDING state rejects changes with HTTP 409. operating_status tracks traffic health, so an ACTIVE load balancer can still be DEGRADED when one member fails its health checks.

← All articles

Chat on Telegram