Set up Lighttpd with mod_proxy to distribute traffic across multiple backend servers, implement health checks for automatic failover, and configure SSL termination for a robust high availability web infrastructure.
Prerequisites
- Multiple backend servers running web applications
- Root or sudo access
- Basic understanding of HTTP and load balancing concepts
What this solves
Lighttpd load balancing distributes incoming web traffic across multiple backend servers to prevent single points of failure and handle increased traffic loads. This configuration ensures your web application stays available even if individual backend servers fail, while improving response times through intelligent traffic distribution.
Step-by-step configuration
Install Lighttpd and required modules
Install Lighttpd with the proxy module needed for load balancing functionality.
sudo apt update
sudo apt install -y lighttpd lighttpd-mod-deflate
Enable proxy module
Enable the mod_proxy module which handles load balancing and backend server communication.
sudo lighty-enable-mod proxy
Configure main Lighttpd settings
Set up the primary configuration with optimized settings for load balancing workloads.
server.modules = (
"mod_indexfile",
"mod_access",
"mod_alias",
"mod_redirect",
"mod_proxy",
"mod_compress",
"mod_accesslog"
)
server.document-root = "/var/www/html"
server.upload-dirs = ( "/var/cache/lighttpd/uploads" )
server.errorlog = "/var/log/lighttpd/error.log"
server.pid-file = "/run/lighttpd.pid"
server.username = "www-data"
server.groupname = "www-data"
server.port = 80
Performance optimizations for load balancing
server.max-connections = 2048
server.max-fds = 2048
server.event-handler = "linux-sysepoll"
server.network-backend = "linux-sendfile"
Index files
index-file.names = ( "index.php", "index.html", "index.htm" )
URL rewriting for compatibility
url.access-deny = ( "~", ".inc" )
MIME type configuration
include "/etc/lighttpd/conf-available/mime.conf"
Set up backend server definitions
Configure multiple backend servers that will handle the actual application requests.
# Backend server pool configuration
proxy.balance = "round-robin"
proxy.server = (
"" => (
"backend1" => (
"host" => "203.0.113.10",
"port" => 8080,
"check-local" => "disable"
),
"backend2" => (
"host" => "203.0.113.11",
"port" => 8080,
"check-local" => "disable"
),
"backend3" => (
"host" => "203.0.113.12",
"port" => 8080,
"check-local" => "disable"
)
)
)
Health check configuration
proxy.header = (
"upgrade" => "enable",
"connect" => "enable"
)
Connection timeout settings
proxy.server-timeout = 30
proxy.connect-timeout = 10
Load balancing method options:
"round-robin" - distributes requests evenly
"least-connection" - sends to server with fewest active connections
"hash" - uses client IP for consistent server assignment
"fair" - weighted distribution based on response times
Enable the proxy configuration
Activate the proxy configuration to make load balancing active.
sudo ln -sf /etc/lighttpd/conf-available/10-proxy.conf /etc/lighttpd/conf-enabled/
sudo lighttpd -t -f /etc/lighttpd/lighttpd.conf
Configure SSL termination (optional but recommended)
Set up SSL/TLS termination at the load balancer for secure connections.
sudo mkdir -p /etc/lighttpd/ssl
sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout /etc/lighttpd/ssl/server.key \
-out /etc/lighttpd/ssl/server.crt \
-subj "/C=US/ST=State/L=City/O=Organization/CN=example.com"
# SSL configuration
$HTTP["scheme"] == "http" {
url.redirect = (".*" => "https://%0$0")
}
$SERVER["socket"] == ":443" {
ssl.engine = "enable"
ssl.pemfile = "/etc/lighttpd/ssl/server.crt"
ssl.privkey = "/etc/lighttpd/ssl/server.key"
ssl.cipher-list = "ECDHE+AESGCM:ECDHE+CHACHA20:DHE+AESGCM:DHE+CHACHA20:!aNULL:!SHA1:!AESCCM"
ssl.honor-cipher-order = "enable"
ssl.disable-client-renegotiation = "enable"
ssl.use-sslv2 = "disable"
ssl.use-sslv3 = "disable"
}
sudo ln -sf /etc/lighttpd/conf-available/10-ssl.conf /etc/lighttpd/conf-enabled/
Configure health checking and failover
Set up advanced health monitoring to automatically remove failed backends from the pool.
# Advanced health checking
proxy.balance = "round-robin"
proxy.server = (
"" => (
"backend1" => (
"host" => "203.0.113.10",
"port" => 8080,
"check-local" => "disable",
"disable-time" => 60,
"allow-x-sendfile" => "enable"
),
"backend2" => (
"host" => "203.0.113.11",
"port" => 8080,
"check-local" => "disable",
"disable-time" => 60,
"allow-x-sendfile" => "enable"
),
"backend3" => (
"host" => "203.0.113.12",
"port" => 8080,
"check-local" => "disable",
"disable-time" => 60,
"allow-x-sendfile" => "enable"
)
)
)
Health check endpoint (optional)
$HTTP["url"] =~ "^/health/?$" {
proxy.server = ()
setenv.add-response-header = ( "Content-Type" => "application/json" )
server.document-root = "/var/www/health"
}
Create health check endpoint
Set up a simple health check endpoint for monitoring system status.
sudo mkdir -p /var/www/health
{"status":"healthy","timestamp":"$(date -Iseconds)","load_balancer":"lighttpd"}
sudo chown -R www-data:www-data /var/www/health
sudo chmod -R 644 /var/www/health/*
Configure logging for monitoring
Set up comprehensive logging to track backend server performance and failures.
# Enhanced logging for load balancer monitoring
accesslog.filename = "/var/log/lighttpd/access.log"
accesslog.format = "%h %V %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %D %{X-Forwarded-For}i"
Separate log for backend errors
$HTTP["status"] =~ "^[45]" {
accesslog.filename = "/var/log/lighttpd/backend-errors.log"
}
Debug logging (enable only for troubleshooting)
debug.log-request-header = "enable"
debug.log-response-header = "enable"
sudo ln -sf /etc/lighttpd/conf-available/20-logging.conf /etc/lighttpd/conf-enabled/
Set up log rotation
Configure log rotation to prevent disk space issues from large access logs.
/var/log/lighttpd/*.log {
daily
rotate 30
compress
delaycompress
missingok
notifempty
create 640 www-data adm
postrotate
if [ -f /run/lighttpd.pid ]; then
/bin/kill -USR1 $(cat /run/lighttpd.pid)
fi
endscript
}
Start and enable Lighttpd
Start the load balancer and enable it to start automatically on boot.
sudo systemctl enable lighttpd
sudo systemctl start lighttpd
sudo systemctl status lighttpd
Verify your setup
Test the load balancer configuration and confirm traffic distribution.
# Check Lighttpd status
sudo systemctl status lighttpd
Test configuration syntax
sudo lighttpd -t -f /etc/lighttpd/lighttpd.conf
Check if load balancer is responding
curl -I http://localhost/
curl -I https://localhost/
Test health check endpoint
curl http://localhost/health
Monitor backend distribution in logs
sudo tail -f /var/log/lighttpd/access.log
Check for backend connection errors
sudo tail -f /var/log/lighttpd/error.log
Test specific backend responses
for i in {1..6}; do curl -s http://localhost/ | grep -o "Server: .*" || echo "Request $i"; done
Advanced load balancing configuration
Configure weighted load balancing
Assign different weights to backends based on their capacity or performance.
# Weighted round-robin load balancing
proxy.balance = "round-robin"
proxy.server = (
"" => (
"backend1" => (
"host" => "203.0.113.10",
"port" => 8080,
"check-local" => "disable",
"disable-time" => 60,
"weight" => 3 # This server gets 3x more requests
),
"backend2" => (
"host" => "203.0.113.11",
"port" => 8080,
"check-local" => "disable",
"disable-time" => 60,
"weight" => 2 # This server gets 2x more requests
),
"backend3" => (
"host" => "203.0.113.12",
"port" => 8080,
"check-local" => "disable",
"disable-time" => 60,
"weight" => 1 # Base weight
)
)
)
Set up session affinity (sticky sessions)
Configure session persistence to ensure user sessions stay on the same backend server.
# Session affinity based on client IP
proxy.balance = "hash"
proxy.server = (
"" => (
"backend1" => (
"host" => "203.0.113.10",
"port" => 8080,
"check-local" => "disable"
),
"backend2" => (
"host" => "203.0.113.11",
"port" => 8080,
"check-local" => "disable"
),
"backend3" => (
"host" => "203.0.113.12",
"port" => 8080,
"check-local" => "disable"
)
)
)
Alternative: Cookie-based session affinity
Requires application support for session cookies
Common issues
| Symptom | Cause | Fix |
|---|---|---|
| 502 Bad Gateway errors | Backend servers unreachable | Check backend server status and network connectivity with telnet 203.0.113.10 8080 |
| All traffic goes to one backend | Load balancing not configured properly | Verify proxy.balance = "round-robin" and restart lighttpd |
| SSL certificate errors | Certificate path or permissions wrong | Check certificate files exist and are readable: sudo ls -la /etc/lighttpd/ssl/ |
| Configuration test fails | Syntax errors in config files | Run sudo lighttpd -t -f /etc/lighttpd/lighttpd.conf for detailed error messages |
| High memory usage | Too many concurrent connections | Adjust server.max-connections and monitor with sudo netstat -an | grep :80 | wc -l |
| Backend health checks failing | Backend servers responding slowly | Increase proxy.server-timeout and disable-time values |
Performance optimization tips
For high-traffic scenarios, consider these additional optimizations that complement the NGINX performance optimization techniques:
- Connection pooling: Enable keep-alive connections to backends to reduce connection overhead
- Caching: Implement response caching for static content using mod_cache
- Compression: Enable gzip compression to reduce bandwidth usage
- Monitoring: Set up comprehensive monitoring similar to Prometheus and Grafana monitoring approaches
- Resource limits: Tune file descriptor limits and connection pools based on traffic patterns
Next steps
- Configure NGINX reverse proxy with SSL termination for comparison
- Set up uptime monitoring for your load balancer
- Compare with HAProxy load balancing configuration
- Configure Lighttpd clustering for load balancer redundancy
- Implement automatic backend server discovery and scaling
Running this in production?
Automated install script
Run this to automate the entire setup
#!/usr/bin/env bash
set -euo pipefail
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
# Default values
BACKEND1_IP=""
BACKEND2_IP=""
BACKEND3_IP=""
DOMAIN="localhost"
ENABLE_SSL=false
# Usage message
usage() {
echo "Usage: $0 -b1 BACKEND1_IP -b2 BACKEND2_IP -b3 BACKEND3_IP [-d DOMAIN] [-s]"
echo " -b1: Backend server 1 IP address"
echo " -b2: Backend server 2 IP address"
echo " -b3: Backend server 3 IP address"
echo " -d: Domain name (optional, default: localhost)"
echo " -s: Enable SSL termination (optional)"
exit 1
}
# Parse arguments
while getopts "b1:b2:b3:d:sh" opt; do
case $opt in
1) BACKEND1_IP="$OPTARG" ;;
2) BACKEND2_IP="$OPTARG" ;;
3) BACKEND3_IP="$OPTARG" ;;
d) DOMAIN="$OPTARG" ;;
s) ENABLE_SSL=true ;;
h) usage ;;
*) usage ;;
esac
done
# Validate required arguments
if [[ -z "$BACKEND1_IP" || -z "$BACKEND2_IP" || -z "$BACKEND3_IP" ]]; then
echo -e "${RED}Error: All three backend IPs are required${NC}"
usage
fi
# Check if running as root
if [[ $EUID -ne 0 ]]; then
echo -e "${RED}Error: This script must be run as root${NC}"
exit 1
fi
# Cleanup function for rollback
cleanup() {
echo -e "${YELLOW}Cleaning up on failure...${NC}"
systemctl stop lighttpd 2>/dev/null || true
}
trap cleanup ERR
# Detect distro and set package manager
echo -e "${YELLOW}[1/8] Detecting distribution...${NC}"
if [ -f /etc/os-release ]; then
. /etc/os-release
case "$ID" in
ubuntu|debian)
PKG_MGR="apt"
PKG_INSTALL="apt install -y"
LIGHTTPD_USER="www-data"
LIGHTTPD_GROUP="www-data"
ENABLE_MOD_CMD="lighty-enable-mod"
;;
almalinux|rocky|centos|rhel|ol|fedora)
PKG_MGR="dnf"
PKG_INSTALL="dnf install -y"
LIGHTTPD_USER="lighttpd"
LIGHTTPD_GROUP="lighttpd"
ENABLE_MOD_CMD=""
;;
amzn)
PKG_MGR="yum"
PKG_INSTALL="yum install -y"
LIGHTTPD_USER="lighttpd"
LIGHTTPD_GROUP="lighttpd"
ENABLE_MOD_CMD=""
;;
*)
echo -e "${RED}Unsupported distro: $ID${NC}"
exit 1
;;
esac
echo -e "${GREEN}Detected: $PRETTY_NAME${NC}"
else
echo -e "${RED}Error: Cannot detect distribution${NC}"
exit 1
fi
# Update package manager
echo -e "${YELLOW}[2/8] Updating package manager...${NC}"
if [[ "$PKG_MGR" == "apt" ]]; then
apt update
else
$PKG_MGR update -y
fi
# Install Lighttpd
echo -e "${YELLOW}[3/8] Installing Lighttpd...${NC}"
if [[ "$PKG_MGR" == "apt" ]]; then
$PKG_INSTALL lighttpd lighttpd-mod-deflate
else
$PKG_INSTALL lighttpd
fi
# Create necessary directories
mkdir -p /var/www/html
mkdir -p /var/cache/lighttpd/uploads
mkdir -p /var/log/lighttpd
# Set proper ownership
chown -R $LIGHTTPD_USER:$LIGHTTPD_GROUP /var/www/html
chown -R $LIGHTTPD_USER:$LIGHTTPD_GROUP /var/cache/lighttpd
chown -R $LIGHTTPD_USER:$LIGHTTPD_GROUP /var/log/lighttpd
# Configure main Lighttpd settings
echo -e "${YELLOW}[4/8] Configuring main Lighttpd settings...${NC}"
cat > /etc/lighttpd/lighttpd.conf << EOF
server.modules = (
"mod_indexfile",
"mod_access",
"mod_alias",
"mod_redirect",
"mod_proxy",
"mod_compress",
"mod_accesslog"
)
server.document-root = "/var/www/html"
server.upload-dirs = ( "/var/cache/lighttpd/uploads" )
server.errorlog = "/var/log/lighttpd/error.log"
server.pid-file = "/run/lighttpd.pid"
server.username = "$LIGHTTPD_USER"
server.groupname = "$LIGHTTPD_GROUP"
server.port = 80
# Performance optimizations for load balancing
server.max-connections = 2048
server.max-fds = 2048
server.event-handler = "linux-sysepoll"
server.network-backend = "linux-sendfile"
# Index files
index-file.names = ( "index.php", "index.html", "index.htm" )
# URL access controls
url.access-deny = ( "~", ".inc" )
# Include MIME types
include_shell "/usr/share/lighttpd/include-conf-enabled.pl"
EOF
# Configure proxy settings
echo -e "${YELLOW}[5/8] Configuring load balancer settings...${NC}"
if [[ "$PKG_MGR" == "apt" ]]; then
PROXY_CONF="/etc/lighttpd/conf-available/10-proxy.conf"
mkdir -p /etc/lighttpd/conf-available
mkdir -p /etc/lighttpd/conf-enabled
else
PROXY_CONF="/etc/lighttpd/conf.d/10-proxy.conf"
mkdir -p /etc/lighttpd/conf.d
fi
cat > "$PROXY_CONF" << EOF
# Backend server pool configuration
proxy.balance = "round-robin"
proxy.server = (
"" => (
"backend1" => (
"host" => "$BACKEND1_IP",
"port" => 8080,
"check-local" => "disable"
),
"backend2" => (
"host" => "$BACKEND2_IP",
"port" => 8080,
"check-local" => "disable"
),
"backend3" => (
"host" => "$BACKEND3_IP",
"port" => 8080,
"check-local" => "disable"
)
)
)
# Health check configuration
proxy.header = (
"upgrade" => "enable",
"connect" => "enable"
)
# Connection timeout settings
proxy.server-timeout = 30
proxy.connect-timeout = 10
EOF
# Enable proxy module
if [[ "$PKG_MGR" == "apt" ]]; then
ln -sf /etc/lighttpd/conf-available/10-proxy.conf /etc/lighttpd/conf-enabled/
fi
# Configure SSL if requested
if [[ "$ENABLE_SSL" == true ]]; then
echo -e "${YELLOW}[6/8] Configuring SSL termination...${NC}"
mkdir -p /etc/lighttpd/ssl
chmod 755 /etc/lighttpd/ssl
# Generate self-signed certificate
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout /etc/lighttpd/ssl/server.key \
-out /etc/lighttpd/ssl/server.crt \
-subj "/C=US/ST=State/L=City/O=Organization/CN=$DOMAIN" 2>/dev/null
chmod 644 /etc/lighttpd/ssl/server.crt
chmod 600 /etc/lighttpd/ssl/server.key
chown $LIGHTTPD_USER:$LIGHTTPD_GROUP /etc/lighttpd/ssl/server.*
# SSL configuration
if [[ "$PKG_MGR" == "apt" ]]; then
SSL_CONF="/etc/lighttpd/conf-available/10-ssl.conf"
else
SSL_CONF="/etc/lighttpd/conf.d/10-ssl.conf"
fi
cat > "$SSL_CONF" << EOF
\$HTTP["scheme"] == "http" {
url.redirect = (".*" => "https://%0\$0")
}
\$SERVER["socket"] == ":443" {
ssl.engine = "enable"
ssl.pemfile = "/etc/lighttpd/ssl/server.crt"
ssl.privkey = "/etc/lighttpd/ssl/server.key"
ssl.cipher-list = "ECDHE+AESGCM:ECDHE+CHACHA20:DHE+AESGCM:DHE+CHACHA20:!aNULL:!SHA1:!AESCCM"
ssl.honor-cipher-order = "enable"
ssl.disable-client-renegotiation = "enable"
ssl.use-sslv2 = "disable"
ssl.use-sslv3 = "disable"
}
EOF
if [[ "$PKG_MGR" == "apt" ]]; then
ln -sf /etc/lighttpd/conf-available/10-ssl.conf /etc/lighttpd/conf-enabled/
fi
else
echo -e "${YELLOW}[6/8] Skipping SSL configuration...${NC}"
fi
# Test configuration
echo -e "${YELLOW}[7/8] Testing configuration...${NC}"
lighttpd -t -f /etc/lighttpd/lighttpd.conf
# Start and enable Lighttpd
echo -e "${YELLOW}[8/8] Starting Lighttpd service...${NC}"
systemctl enable lighttpd
systemctl restart lighttpd
# Verification checks
echo -e "${GREEN}Installation completed successfully!${NC}"
echo -e "${GREEN}Backend servers configured:${NC}"
echo -e " Backend 1: $BACKEND1_IP:8080"
echo -e " Backend 2: $BACKEND2_IP:8080"
echo -e " Backend 3: $BACKEND3_IP:8080"
echo -e "${GREEN}Load balancing method: round-robin${NC}"
if [[ "$ENABLE_SSL" == true ]]; then
echo -e "${GREEN}SSL termination enabled for domain: $DOMAIN${NC}"
echo -e "${YELLOW}Note: Using self-signed certificate. Replace with valid certificate for production.${NC}"
fi
# Show service status
systemctl status lighttpd --no-pager
Review the script before running. Execute with: bash install.sh