One machine behind a domain name is simple until the day it needs a restart for an update, or the load outgrows it. A load balancer takes traffic on its own address and spreads it across several machines: you take one out for maintenance, the others keep serving.
The FFxF load balancer is a managed service. You describe where traffic goes; FFxF runs the load balancer, obtains its Let's Encrypt certificates and keeps it up to date. This guide sets one up end to end, with the actual output of a load balancer in service.
1. How it fits together
- A pool groups the machines serving the same thing, each with a
port:
webfor the site,apifor the API. - A listener is an entry port on the load balancer's address, HTTP, HTTPS or TCP, with a default pool.
- Rules send a hostname or a path prefix to another pool:
/api/toapi, the rest toweb.
The target machines share a private network with the load balancer. They need no public address, and their firewalls can close 80 and 443 to the Internet: the private network is never filtered.
2. Create the load balancer
In the console, under Load balancers, give it a name and pick your machines' private network. The same through the API:
curl -s -X POST https://api.ffxf.net/v1/load-balancers \
-H "Authorization: Bearer $FFXF_TOKEN" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"name": "pilote", "vpc": 15}'
{"data":{"id":1,"name":"pilote","status":"pending","billing":{"mode":"hourly","rate":"0.010","currency":"CAD"}}}
A load balancer is billed by the hour, 0.010 CAD, about 7.30 CAD for a full month. It
is ready within minutes: its status goes from pending to
active, and it gets an IPv4 and an IPv6 address. Pools and listeners can
be set up meanwhile.
3. A pool and its targets
For this demo, a single machine of the private network, at 10.50.0.2,
runs three small HTTP servers on ports 8081, 8082 and 8083. In production these would
be separate machines; the load balancer treats them the same way.
curl -s -X POST https://api.ffxf.net/v1/load-balancers/1/pools \
-H "Authorization: Bearer $FFXF_TOKEN" -H "Content-Type: application/json" \
-d '{"name": "web", "protocol": "http", "health_type": "http", "health_path": "/"}'
curl -s -X PUT https://api.ffxf.net/v1/load-balancers/1/pools/1/targets \
-H "Authorization: Bearer $FFXF_TOKEN" -H "Content-Type: application/json" \
-d '{"targets": [{"vm": 150, "port": 8081}, {"vm": 150, "port": 8082}]}'
A machine is named by its number, the one shown in the console and the API. The load
balancer checks each target every 5 seconds, here with an HTTP request on
/: three failures take it out of the pool, two successes bring it back.
A second pool, api, points at port 8083.
4. An HTTPS listener and DNS
curl -s -X POST https://api.ffxf.net/v1/load-balancers/1/listeners \
-H "Authorization: Bearer $FFXF_TOKEN" -H "Content-Type: application/json" \
-d '{"port": 443, "protocol": "https", "default_pool": 1, "redirect_https": true}'
With redirect_https, port 80 redirects to HTTPS. For the certificate,
point your name at the load balancer: an A record to its IPv4, an
AAAA to its IPv6. As soon as the name points the right way, the load
balancer requests its certificate from Let's Encrypt; in our demo it was active about
thirty seconds after the listener was created.
5. Routing by path
curl -s -X PUT https://api.ffxf.net/v1/load-balancers/1/listeners/1/rules \
-H "Authorization: Bearer $FFXF_TOKEN" -H "Content-Type: application/json" \
-d '{"rules": [
{"hostname": "app.example.com", "pool": 1},
{"hostname": "app.example.com", "path_prefix": "/api/", "pool": 2}
]}'
The order you send does not matter: the load balancer evaluates rules most specific first (hostname and path, then hostname alone, then path alone), and the first match wins. The console's Routing tab shows them in that order, followed by the "Otherwise" line that leads to the default pool.
6. Check it
$ for i in 1 2 3 4; do curl -s https://app.example.com/; done
pilote 8081
pilote 8082
pilote 8081
pilote 8082
$ curl -s https://app.example.com/api/
pilote 8083
$ curl -s -o /dev/null -w "%{http_code} %{redirect_url}\n" http://app.example.com/
301 https://app.example.com/
Requests alternate between the two targets of the web pool,
/api/ goes to the other pool, and HTTP is redirected. On the application
side, the visitor's address arrives in the X-Forwarded-For header, with
X-Forwarded-Proto and X-Forwarded-Port.
7. Maintenance without downtime
Before updating a machine, click Drain next to it in the Pools tab
(or send {"drain": true} through the API). It gets no new connections,
current ones finish, and the change is live within about ten seconds. Once the update
is done, Restore brings it back.
A target that fails without warning is taken out by the health checks, and the Pools tab shows it as down. If every target of a pool fails, the load balancer answers 503 instead of leaving visitors waiting.
8. Who can connect
Only 80, 443 and your listeners' ports are open on the load balancer's address. Each listener accepts allowed sources: a TCP 5432 listener in front of a database pool can accept your office address only. While an HTTPS listener exists, port 80 stays open to everyone, because Let's Encrypt validates certificates there.
9. Statistics and usage
The Statistics tab charts requests by response class, traffic and concurrent sessions over 1 hour, 24 hours or 7 days. The overview gives the cost for the current month and the activity of the last minute.
Traffic through the load balancer is counted on the target machines, as if they had served it themselves: it uses their included bandwidth. In the demo, two 10 MB downloads through the load balancer added 20,972,166 bytes to the target machine's counter.
10. From an AI agent
The FFxF MCP server exposes the same steps:
create_load_balancer, upsert_pool,
set_targets, upsert_listener and set_rules. An
agent can build the whole load balancer from one sentence; its instructions ask it to
state the price before ordering, then to tell you which DNS records to create.
Checklist
- Machines in one private network, each service on a known port.
- One pool per service, with a health check that really tests the application.
- An HTTPS listener with redirection from port 80.
- DNS pointed, then the certificate active in the Certificates tab.
- Ports 80 and 443 of the targets closed to the Internet by their firewall.
- Drain before every maintenance.
Every call is detailed in the load balancer documentation, and the targets' firewall in protecting a VM with the cloud firewall.