2025-08-21 18:32:47 -07:00
# IP Blocking API Documentation
This document describes the IP blocking functionality added to HAProxy Manager, which allows WHP (Web Hosting Platform) to manage blocked IP addresses through the API.
## Overview
The IP blocking feature allows administrators to:
2025-11-17 12:07:32 -08:00
- Block specific IP addresses or CIDR ranges from accessing any sites managed by HAProxy
- Unblock previously blocked IP addresses or CIDR ranges
- View all currently blocked IP addresses and CIDR ranges
- Track who blocked an IP/CIDR and when
2025-08-21 18:32:47 -07:00
2025-11-17 12:07:32 -08:00
When an IP is blocked (or falls within a blocked CIDR range), visitors from that IP address will receive a 403 Forbidden response.
### CIDR Range Support
The IP blocking system supports CIDR notation for blocking entire network ranges:
- **Single IP**: `192.168.1.100` (blocks only this IP)
- **CIDR Range**: `192.168.1.0/24` (blocks 256 IPs from 192.168.1.0 to 192.168.1.255)
- **Common CIDR Masks**:
- `/32` - Single IP (1 address)
- `/24` - Standard subnet (256 addresses)
- `/16` - Large network (65,536 addresses)
- `/8` - Very large network (16,777,216 addresses)
2025-08-22 08:31:17 -07:00
## Features
- **Runtime IP blocking**: Changes take effect immediately without HAProxy restarts
- **Map file based**: No ACL word limits, supports unlimited blocked IPs
- **Safe configuration management**: Automatic validation and rollback on failures
- **Runtime map synchronization**: Keep database and HAProxy runtime in sync
- **Audit logging**: All operations are logged for monitoring and compliance
2025-08-21 18:32:47 -07:00
## API Endpoints
### Authentication
All IP blocking endpoints require API key authentication when `HAPROXY_API_KEY` is set:
``` bash
Authorization: Bearer your-api-key
```
### 1. Get All Blocked IPs
Retrieve a list of all currently blocked IP addresses.
**Endpoint: ** `GET /api/blocked-ips`
**Response: **
``` json
[
{
"id" : 1 ,
"ip_address" : "192.168.1.100" ,
"reason" : "Suspicious activity detected" ,
"blocked_at" : "2024-01-15 10:30:00" ,
"blocked_by" : "WHP Admin Panel"
} ,
{
"id" : 2 ,
"ip_address" : "10.0.0.50" ,
"reason" : "Brute force attempts" ,
"blocked_at" : "2024-01-15 11:45:00" ,
"blocked_by" : "Security System"
}
]
```
**Example Request: **
``` bash
curl -X GET http://localhost:8000/api/blocked-ips \
-H "Authorization: Bearer your-api-key"
```
### 2. Block an IP Address
Add an IP address to the blocked list.
**Endpoint: ** `POST /api/blocked-ips`
**Request Body: **
``` json
{
"ip_address" : "192.168.1.100" ,
"reason" : "Suspicious activity detected" ,
"blocked_by" : "WHP Admin Panel"
}
```
**Parameters: **
2025-11-17 12:07:32 -08:00
- `ip_address` (required): The IP address or CIDR range to block (e.g., "192.168.1.100" or "192.168.1.0/24")
2025-08-21 18:32:47 -07:00
- `reason` (optional): Reason for blocking (default: "No reason provided")
- `blocked_by` (optional): Who/what initiated the block (default: "API")
**Response: **
``` json
{
"status" : "success" ,
"blocked_ip_id" : 1 ,
"message" : "IP 192.168.1.100 has been blocked"
}
```
**Error Responses: **
- `400 Bad Request` : IP address is missing
- `409 Conflict` : IP address is already blocked
- `500 Internal Server Error` : Configuration generation failed
2025-11-17 12:07:32 -08:00
**Example Request (Single IP): **
2025-08-21 18:32:47 -07:00
``` bash
curl -X POST http://localhost:8000/api/blocked-ips \
-H "Authorization: Bearer your-api-key" \
-H "Content-Type: application/json" \
-d '{
"ip_address": "192.168.1.100",
"reason": "Multiple failed login attempts",
"blocked_by": "WHP Security Module"
}'
```
2025-11-17 12:07:32 -08:00
**Example Request (CIDR Range): **
``` bash
curl -X POST http://localhost:8000/api/blocked-ips \
-H "Authorization: Bearer your-api-key" \
-H "Content-Type: application/json" \
-d '{
"ip_address": "192.168.1.0/24",
"reason": "DDoS attack from compromised ISP",
"blocked_by": "WHP Security Module"
}'
```
### 3. Unblock an IP Address or CIDR Range
2025-08-21 18:32:47 -07:00
2025-11-17 12:07:32 -08:00
Remove an IP address or CIDR range from the blocked list.
2025-08-21 18:32:47 -07:00
**Endpoint: ** `DELETE /api/blocked-ips`
**Request Body: **
``` json
{
"ip_address" : "192.168.1.100"
}
```
**Parameters: **
2025-11-17 12:07:32 -08:00
- `ip_address` (required): The IP address or CIDR range to unblock (must match exactly as it was blocked)
2025-08-21 18:32:47 -07:00
**Response: **
``` json
{
"status" : "success" ,
"message" : "IP 192.168.1.100 has been unblocked"
}
```
**Error Responses: **
- `400 Bad Request` : IP address is missing
- `404 Not Found` : IP address not found in blocked list
- `500 Internal Server Error` : Configuration generation failed
**Example Request: **
``` bash
curl -X DELETE http://localhost:8000/api/blocked-ips \
-H "Authorization: Bearer your-api-key" \
-H "Content-Type: application/json" \
-d '{"ip_address": "192.168.1.100"}'
```
## Integration with WHP
### PHP Integration Example
Here's how to integrate the IP blocking API into WHP using PHP:
``` php
< ? php
class HAProxyIPBlocker {
private $apiUrl ;
private $apiKey ;
public function __construct ( $apiUrl , $apiKey ) {
$this -> apiUrl = rtrim ( $apiUrl , '/' );
$this -> apiKey = $apiKey ;
}
/**
* Get all blocked IPs
*/
public function getBlockedIPs () {
return $this -> makeRequest ( 'GET' , '/api/blocked-ips' );
}
/**
* Block an IP address
*/
public function blockIP ( $ipAddress , $reason = null , $blockedBy = 'WHP Control Panel' ) {
$data = [
'ip_address' => $ipAddress ,
'reason' => $reason ? : 'Blocked via WHP Control Panel' ,
'blocked_by' => $blockedBy
];
return $this -> makeRequest ( 'POST' , '/api/blocked-ips' , $data );
}
/**
* Unblock an IP address
*/
public function unblockIP ( $ipAddress ) {
$data = [ 'ip_address' => $ipAddress ];
return $this -> makeRequest ( 'DELETE' , '/api/blocked-ips' , $data );
}
/**
* Make API request
*/
private function makeRequest ( $method , $endpoint , $data = null ) {
$url = $this -> apiUrl . $endpoint ;
$headers = [
'Authorization: Bearer ' . $this -> apiKey ,
'Content-Type: application/json'
];
$ch = curl_init ();
curl_setopt ( $ch , CURLOPT_URL , $url );
curl_setopt ( $ch , CURLOPT_RETURNTRANSFER , true );
curl_setopt ( $ch , CURLOPT_HTTPHEADER , $headers );
curl_setopt ( $ch , CURLOPT_CUSTOMREQUEST , $method );
if ( $data ) {
curl_setopt ( $ch , CURLOPT_POSTFIELDS , json_encode ( $data ));
}
$response = curl_exec ( $ch );
$httpCode = curl_getinfo ( $ch , CURLINFO_HTTP_CODE );
curl_close ( $ch );
$result = json_decode ( $response , true );
if ( $httpCode >= 200 && $httpCode < 300 ) {
return [ 'success' => true , 'data' => $result ];
} else {
return [ 'success' => false , 'error' => $result [ 'message' ] ? ? 'Unknown error' , 'code' => $httpCode ];
}
}
}
// Usage example:
$haproxyBlocker = new HAProxyIPBlocker ( 'http://haproxy-manager:8000' , 'your-api-key-here' );
// Block an IP
$result = $haproxyBlocker -> blockIP ( '192.168.1.100' , 'Spam detection' , 'WHP Anti-Spam Module' );
if ( $result [ 'success' ]) {
echo " IP blocked successfully: " . $result [ 'data' ][ 'message' ];
} else {
echo " Error: " . $result [ 'error' ];
}
// Get all blocked IPs
$blockedIPs = $haproxyBlocker -> getBlockedIPs ();
if ( $blockedIPs [ 'success' ]) {
foreach ( $blockedIPs [ 'data' ] as $ip ) {
echo " Blocked IP: { $ip [ 'ip_address' ] } - Reason: { $ip [ 'reason' ] } \n " ;
}
}
// Unblock an IP
$result = $haproxyBlocker -> unblockIP ( '192.168.1.100' );
if ( $result [ 'success' ]) {
echo " IP unblocked successfully " ;
}
?>
```
### WHP Control Panel Integration
To add IP blocking management to the WHP control panel:
1. **Create a management interface page ** (`/admin/ip-blocking.php` ):
``` php
< ? php
// Initialize the HAProxy IP Blocker
$haproxyBlocker = new HAProxyIPBlocker (
getenv ( 'HAPROXY_MANAGER_URL' ) ? : 'http://haproxy-manager:8000' ,
getenv ( 'HAPROXY_API_KEY' )
);
// Handle form submissions
if ( $_SERVER [ 'REQUEST_METHOD' ] === 'POST' ) {
if ( isset ( $_POST [ 'action' ])) {
switch ( $_POST [ 'action' ]) {
case 'block' :
$ip = filter_var ( $_POST [ 'ip_address' ], FILTER_VALIDATE_IP );
if ( $ip ) {
$result = $haproxyBlocker -> blockIP (
$ip ,
$_POST [ 'reason' ] ? ? '' ,
$_SESSION [ 'admin_username' ] ? ? 'WHP Admin'
);
$message = $result [ 'success' ]
? " IP { $ip } has been blocked "
: " Error: " . $result [ 'error' ];
}
break ;
case 'unblock' :
$ip = filter_var ( $_POST [ 'ip_address' ], FILTER_VALIDATE_IP );
if ( $ip ) {
$result = $haproxyBlocker -> unblockIP ( $ip );
$message = $result [ 'success' ]
? " IP { $ip } has been unblocked "
: " Error: " . $result [ 'error' ];
}
break ;
}
}
}
// Get current blocked IPs
$blockedIPs = $haproxyBlocker -> getBlockedIPs ();
?>
<!DOCTYPE html>
<html>
<head>
<title>IP Blocking Management - WHP</title>
</head>
<body>
<h1>IP Blocking Management</h1>
<?php if (isset($message)): ?>
<div class="alert"><?= htmlspecialchars($message) ?></div>
<?php endif; ?>
<!-- Block IP Form -->
<h2>Block an IP Address</h2>
<form method="POST">
<input type="hidden" name="action" value="block">
<label>IP Address: <input type="text" name="ip_address" required pattern="\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}"></label><br>
<label>Reason: <input type="text" name="reason" size="50"></label><br>
<button type="submit">Block IP</button>
</form>
<!-- Currently Blocked IPs -->
<h2>Currently Blocked IPs</h2>
<table border="1">
<thead>
<tr>
<th>IP Address</th>
<th>Reason</th>
<th>Blocked By</th>
<th>Blocked At</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<?php if ($blockedIPs['success']): ?>
<?php foreach ($blockedIPs['data'] as $ip): ?>
<tr>
<td><?= htmlspecialchars($ip['ip_address']) ?></td>
<td><?= htmlspecialchars($ip['reason']) ?></td>
<td><?= htmlspecialchars($ip['blocked_by']) ?></td>
<td><?= htmlspecialchars($ip['blocked_at']) ?></td>
<td>
<form method="POST" style="display:inline">
<input type="hidden" name="action" value="unblock">
<input type="hidden" name="ip_address" value="<?= htmlspecialchars($ip['ip_address']) ?>">
<button type="submit">Unblock</button>
</form>
</td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
</table>
</body>
</html>
```
2. **Environment Configuration **
Add these environment variables to your WHP configuration:
``` bash
# HAProxy Manager API Configuration
HAPROXY_MANAGER_URL = http://haproxy-manager:8000
HAPROXY_API_KEY = your-secure-api-key-here
```
3. **Automatic Blocking Integration **
You can automatically block IPs based on certain criteria:
``` php
// Example: Auto-block after multiple failed login attempts
function handleFailedLogin ( $username , $ipAddress ) {
global $haproxyBlocker ;
// Track failed attempts (implement your own logic)
$failedAttempts = getFailedAttempts ( $ipAddress );
if ( $failedAttempts >= 5 ) {
$haproxyBlocker -> blockIP (
$ipAddress ,
" 5+ failed login attempts for user: { $username } " ,
" WHP Security System "
);
// Log the blocking action
error_log ( " Auto-blocked IP { $ipAddress } due to multiple failed login attempts " );
}
}
```
## How It Works
1. **Database Storage ** : Blocked IPs are stored in the SQLite database table `blocked_ips`
2. **HAProxy Configuration ** : When an IP is blocked/unblocked, the HAProxy configuration is regenerated
3. **ACL Rules ** : HAProxy uses ACL rules to check if a source IP is in the blocked list
4. **Blocked Page ** : Blocked IPs are served a custom "Access Denied" page via the default backend
## Testing
To test the IP blocking functionality:
``` bash
# Block your test IP
curl -X POST http://localhost:8000/api/blocked-ips \
-H "Authorization: Bearer your-api-key" \
-H "Content-Type: application/json" \
-d '{"ip_address": "YOUR_TEST_IP", "reason": "Testing"}'
# Try to access a site (you should see the blocked page)
curl -H "X-Forwarded-For: YOUR_TEST_IP" http://localhost
# Unblock the IP
curl -X DELETE http://localhost:8000/api/blocked-ips \
-H "Authorization: Bearer your-api-key" \
-H "Content-Type: application/json" \
-d '{"ip_address": "YOUR_TEST_IP"}'
```
## Notes
- IP blocks are applied globally to all domains managed by HAProxy
2025-08-22 08:31:17 -07:00
- Changes take effect immediately without HAProxy restarts (runtime updates)
- Blocked IPs are persistent across HAProxy restarts (stored in database and map file)
- Map files support unlimited IPs (no ACL word limit restrictions)
- Consider implementing rate limiting on the API endpoints to prevent abuse
## New API Endpoints (Map File Era)
### 4. Safe Configuration Reload
Safely reload the HAProxy configuration with validation and automatic rollback.
**Endpoint: ** `POST /api/config/reload`
**Response: **
``` json
{
"status" : "success" ,
"message" : "HAProxy configuration reloaded safely"
}
```
**Error Response: **
``` json
{
"status" : "error" ,
"message" : "Safe reload failed: Config validation failed: ..."
}
```
**Example Request: **
``` bash
curl -X POST http://localhost:8000/api/config/reload \
-H "Authorization: Bearer your-api-key"
```
### 5. Sync Runtime Map
Synchronize blocked IPs from database to HAProxy runtime map.
**Endpoint: ** `POST /api/blocked-ips/sync`
**Response: **
``` json
{
"status" : "success" ,
"message" : "Synced 150/150 IPs to runtime map" ,
"total_ips" : 150 ,
"synced_ips" : 150
}
```
**Example Request: **
``` bash
curl -X POST http://localhost:8000/api/blocked-ips/sync \
-H "Authorization: Bearer your-api-key"
```
## Runtime Map Commands
For advanced users, you can interact directly with HAProxy's runtime API:
``` bash
# Add IP to runtime (immediate effect)
echo "add map #0 192.168.1.100" | socat stdio /var/run/haproxy.sock
# Remove IP from runtime
echo "del map #0 192.168.1.100" | socat stdio /var/run/haproxy.sock
# Clear all blocked IPs from runtime
echo "clear map #0" | socat stdio /var/run/haproxy.sock
# Show all runtime map entries
echo "show map #0" | socat stdio /var/run/haproxy.sock
```
## Migration from ACL Method
If you're upgrading from the old ACL-based method:
1. **Automatic ** : Just update the HAProxy Manager code - it will automatically migrate
2. **Validation ** : The new system includes automatic config validation and rollback
3. **No Downtime ** : Runtime updates mean no service interruptions
4. **Scalable ** : No more 64 IP limit - handle thousands of blocked IPs