If you manage multiple VPS nodes and offer SMTP services selectively to clients, automating the management of IP sets can save significant effort. In this guide, we’ll walk through how we automated the synchronization of SMTP-enabled IPs across over 100 VPS nodes.
This tutorial has been tested and is fully operational on Virtualizor-based KVM VPS nodes. The script is configured to run at 1-hour intervals by default, but you can adjust the interval depending on your requirements and available resources. It can be set up on a separate server, on the same server as WHMCS, or another VPS. If using the WHMCS server, ensure it is properly secured, as this script has access to all your servers.
Prerequisites
- Python 3.x installed on your system.
- Required Python libraries:
pip install paramiko pandas
- WHMCS with VPS product configurations.
- SSH access to all VPS nodes and the WHMCS server.
ipset
installed and configured on each VPS node.- Proper iptables rules set up on all VPS nodes (detailed below).
Required iptables and ipset Configuration on VPS Nodes
To manage SMTP access effectively, you need the following iptables
and ipset
rules configured on all VPS nodes. These rules must also persist across reboots:
modprobe br_netfilter
ipset create allowed_ips hash:ip
iptables -F
iptables -P FORWARD DROP
iptables -I FORWARD -m set --match-set allowed_ips src -o viifbr0 -p tcp --dport 25 -j ACCEPT
iptables -I FORWARD -m set --match-set allowed_ips dst -o viifbr0 -p tcp --dport 25 -j ACCEPT
iptables -A FORWARD -o viifbr0 -p tcp --dport 25 -j REJECT
iptables -A FORWARD -o viifbr0 -j ACCEPT
service iptables save
These rules ensure that SMTP traffic is blocked by default unless explicitly allowed via ipset
. Ensure the rules are applied on every reboot of the VPS nodes.
Overview of the Solution
- Fetch VPS Configuration from WHMCS: Retrieve a JSON file listing VPS configurations, including SMTP-enabled status and associated IPs.
- Process Data: Parse the JSON file to extract primary and additional IPs for SMTP-enabled VPSs.
- Sync IP Sets Across Nodes: Use
ipset
to update allowed IPs for SMTP on each node. This includes adding or removing IPs as needed. - Parallel Execution: Speed up the process by handling multiple nodes concurrently with Python threading.
Implementation
1. Create the Excel File for Node Information
The Python script uses an Excel file to identify the SSH IPs and ports of all VPS nodes. Create an Excel file in the following format:
IP Address | SSH Port |
---|---|
192.168.1.100 | 22 |
192.168.1.101 | 2222 |
Save this file as securecrt_servers.xlsx
and ensure it is accessible to the script.
2. Fetch VPS Data from WHMCS
Add a hook in WHMCS to export VPS data:
File: /path/to/whmcs/includes/hooks/export_vps_data.php
<?php
use Illuminate\Database\Capsule\Manager as Capsule;
add_hook('AfterCronJob', 100, function($vars) {
$logFile = __DIR__ . '/export_hook_debug.log';
$filePath = __DIR__ . '/vps_data.json';
try {
$vpsData = Capsule::table('tblhosting')
->join('tblproducts', 'tblhosting.packageid', '=', 'tblproducts.id')
->join('tblclients', 'tblhosting.userid', '=', 'tblclients.id')
->leftJoin('tblhostingconfigoptions', 'tblhosting.id', '=', 'tblhostingconfigoptions.relid')
->leftJoin('tblproductconfigoptions', 'tblhostingconfigoptions.configid', '=', 'tblproductconfigoptions.id')
->select(
'tblclients.firstname',
'tblclients.lastname',
'tblhosting.dedicatedip',
'tblhosting.assignedips',
'tblhosting.domain',
'tblproducts.name as productname',
'tblproductconfigoptions.optionname',
'tblhostingconfigoptions.optionid'
)
->where('tblproducts.type', 'server')
->where('tblhosting.domainstatus', 'Active')
->get();
$formattedData = [];
foreach ($vpsData as $vps) {
$smtp_enabled = false;
if (stripos($vps->optionname ?? '', 'SMTP Access') !== false && $vps->optionid > 0) {
$smtp_enabled = true;
}
$formattedData[] = [
'client_name' => $vps->firstname . ' ' . $vps->lastname,
'primary_ip' => $vps->dedicatedip,
'additional_ips' => $vps->assignedips,
'domain' => $vps->domain,
'product_name' => $vps->productname,
'smtp_enabled' => $smtp_enabled,
];
}
file_put_contents($filePath, json_encode($formattedData, JSON_PRETTY_PRINT));
} catch (Exception $e) {
file_put_contents($logFile, "Error: " . $e->getMessage() . PHP_EOL, FILE_APPEND);
}
});
3. Configure SMTP Access Using WHMCS Configurable Options
To enable or disable SMTP for a VPS:
- Set Up a Configurable Option:
- Go to WHMCS Admin > Products/Services > Configurable Options.
- Create an option named
SMTP Access
with values such asEnabled
andDisabled
.
- Client Self-Management (Optional):
- If you want clients to manage this option while ordering or upgrading, associate the configurable option with the product.
- Manual Control:
- To keep SMTP access manual, hide the configurable option from clients and enable or disable it directly in the admin panel.
Note: Changes to SMTP access will take effect within the interval configured for the sync script (default: 1 hour).
4. Automate Syncing with Python
File: /path/to/script/smtp_sync.py
import requests
import subprocess
import paramiko
import ipaddress
import os
import pandas as pd
import re
import json
from concurrent.futures import ThreadPoolExecutor
DEBUG = True
NODES_FILE_PATH = '/path/to/securecrt_servers.xlsx'
nodes_df = pd.read_excel(NODES_FILE_PATH)
NODES = [
{"host": row["IP Address"], "port": row["SSH Port"]}
for _, row in nodes_df.iterrows()
]
IPSET_NAME = "allowed_ips"
ERROR_LOG_FILE = "node_errors.log"
WHMCS_SERVER = {
"host": "whmcs-server-ip",
"user": "your-whmcs-user",
"port": 22,
"key_path": os.path.expanduser("~/.ssh/id_rsa")
}
REMOTE_VPS_FILE = "/path/to/whmcs/hooks/vps_data.json"
LOCAL_VPS_FILE = "/tmp/vps_data.json"
# Define functions for fetching, processing, and syncing IPs
# See the complete script in the provided implementation.
Cron Job Setup
Run the Python script every hour by adding it to your crontab:
crontab -e
Add the following line:
0 * * * * /usr/bin/python3 /path/to/script/smtp_sync.py >> /var/log/smtp_sync.log 2>&1
Benefits of the Solution
- Automated Management: No manual updates to IP sets are required.
- Scalability: Handles hundreds of nodes efficiently using multithreading.
- Reliability: Synchronization ensures consistent SMTP access control across all nodes.