Introduction
In this lab, you will learn the fundamentals of load balancing using HAProxy.
Imagine a bank with only one teller. The line gets very long, and customers get angry. To fix this, the bank opens multiple teller windows. However, you now need a manager at the door to direct each customer to the next available window.
In this scenario:
- The Bank Manager is the Load Balancer (HAProxy).
- The Tellers are the Backend Servers (simulated web servers).
- The Customers are the Web Traffic.
You will build this setup on Linux. You will create two simulated web servers and configure HAProxy to split the traffic between them using round robin, one of the simplest balancing algorithms.
Round robin is useful as a starting mental model because it shows the basic purpose of a load balancer: distribute successive requests across multiple healthy backends instead of sending everything to one machine.
By the end of this lab, you will be able to:
- Run simple Python web servers.
- Configure HAProxy to accept traffic (Frontend) and send it to servers (Backend).
- See load balancing in action.
Prepare Terminals
To test a load balancer, we first need something to balance! We need to run two separate web servers at the same time. Since a running server occupies the terminal (it keeps running until you stop it), we cannot type new commands in the same window.
Therefore, we need to open extra terminal tabs. Think of this like opening multiple tabs in your web browser so you can look at different websites at once.
Operationally, this step helps separate roles in the system. The Python servers simulate your application tier, while the main terminal remains your control plane for the load balancer itself.
You currently have one terminal open (Terminal). Please open two more:
- Find the + (Plus) icon in the terminal interface.
- Click it twice to open Terminal 1 and Terminal 2.
We will use them like this:
- Terminal: Our Control Center (for configuring HAProxy).
- Terminal 1: Will run Server 1.
- Terminal 2: Will run Server 2.
Start Server 1
Now we will start our first "Teller" (Server 1). Instead of installing heavy web server software, we will use a handy tool built into Python that turns any folder into a website.
Please switch to Terminal 1.
First, go to the folder we prepared for Server 1.
cd ~/project/server1
Now, start the server. We will tell it to listen on port 8001. Think of a port like an apartment number. The computer is the building, and port 8001 is the specific door where Server 1 lives.
python3 -m http.server 8001
You will see a message saying Serving HTTP on 0.0.0.0 port 8001. This means the server is running and waiting for visitors. This terminal is now "busy", so don't type anything else here.
Start Server 2
Let's start the second "Teller" (Server 2) so we have someone to share the work.
Please switch to Terminal 2.
Go to the folder for Server 2.
cd ~/project/server2
Start this server on a different port, 8002. We cannot use 8001 because Server 1 is already using it (two families can't live in the same apartment 8001).
python3 -m http.server 8002
Now you have two independent web servers running. One says "Response from Server 1" (on port 8001) and the other says "Response from Server 2" (on port 8002).
Configure Frontend
Now that our servers are ready, let's configure the "Bank Manager" (HAProxy) to direct traffic to them.
This is where the frontend and backend split begins. A frontend describes how clients arrive at HAProxy, while a backend describes the server pool that will actually handle the work.
Switch back to Terminal.
We will start fresh by backing up the old configuration and creating a new one.
sudo mv /etc/haproxy/haproxy.cfg /etc/haproxy/haproxy.cfg.bak
sudo nano /etc/haproxy/haproxy.cfg
Copy and paste the following text into the editor. This defines the Frontend. The Frontend is the public face of the load balancer—it's where the customers (users) arrive.
global
log /dev/log local0
log /dev/log local1 notice
daemon
defaults
log global
mode http
option httplog
option dontlognull
timeout connect 5000
timeout client 50000
timeout server 50000
frontend http_front
bind *:80
default_backend http_back
Key parts to understand:
bind *:80: This tells HAProxy to listen on Port 80. Port 80 is the standard door for web traffic (HTTP). When you type a website name without a port, your browser goes to port 80.default_backend http_back: This tells HAProxy, "When people arrive here, send them to the group calledhttp_back."
That naming matters because HAProxy configuration is essentially a traffic map. Frontends receive connections, and backends represent the possible destinations for those connections.
Save the file (Ctrl+O, Enter) but you can keep it open if you want, or better yet, save and exit (Ctrl+X) to verify your progress step-by-step.
Configure Backend
Now we need to define that group of workers, the Backend.
Open the configuration file again if you closed it:
sudo nano /etc/haproxy/haproxy.cfg
Append the following lines to the end of the file:
backend http_back
server server1 127.0.0.1:8001 check
server server2 127.0.0.1:8002 check
What did we just do?
backend http_back: We created the group namedhttp_back.server server1 ...: We introduced our first worker (Server 1) at address127.0.0.1:8001(localhost port 8001).server server2 ...: We introduced our second worker (Server 2) at127.0.0.1:8002.check: This is crucial. It tells the Manager to periodically check if the worker is actually there (Healthy). If a server crashes, HAProxy will stop sending people to it.
Save the file (Ctrl+O, Enter) and exit (Ctrl+X).
Verify Balancing
How should the Manager decide who gets the next customer? The most common way is Round Robin. It's simply "taking turns".
- Customer 1 -> Server 1
- Customer 2 -> Server 2
- Customer 3 -> Server 1
- ...and so on.
Let's make this explicit in our configuration. Open the configuration file one last time:
sudo nano /etc/haproxy/haproxy.cfg
Find the backend http_back section you just added, and insert the balance directive so it looks like this:
backend http_back
balance roundrobin
server server1 127.0.0.1:8001 check
server server2 127.0.0.1:8002 check
Note: Indentation (spaces at the start of the line) matters for readability, although HAProxy is forgiving. Try to keep it tidy.
Save the file (Ctrl+O, Enter) and exit (Ctrl+X).
Reload HAProxy and Test
The configuration is ready, but HAProxy doesn't know about it yet. We need to reload the service to apply the changes.
sudo service haproxy restart
Now for the moment of truth! We will use a command called curl. Think of curl as a web browser without a graphical interface. It fetches a webpage and shows the text code on your screen.
We will connect to localhost (our machine) on the default port 80 (where HAProxy is listening).
Run this command multiple times:
curl localhost
You should see "Response from Server 1". Run it again.
curl localhost
Now you should see "Response from Server 2".
If you want to see it happen fast, you can run this loop command, which hits the server 4 times in a row:
for i in {1..4}; do
curl localhost
echo
done
You should see the output alternate perfectly: 1, 2, 1, 2.
This proves that your Load Balancer is working! It is receiving your requests on port 80 and fairly sharing the work between port 8001 and port 8002.
Summary
In this lab, you successfully built a Load Balanced Web Cluster!
Here is what you achieved:
- Simulated Backends: You used Python to create two working web servers on different ports (8001, 8002).
- Configured Frontend: You told HAProxy to listen on the standard web port (80).
- Configured Backend: You registered your two servers as the workforce.
- Round Robin: You set up a fair "taking turns" policy for distributing traffic.
This is the exact same architecture used by massive websites to handle millions of users, just on a smaller scale.



