SPFBL is one of the most powerful tools available today for email flow control, reputation validation, and relentless spam fighting. However, since it is a Java-based application and often runs isolated, diagnosing failures can seem complex to administrators who are only used to native Linux services (such as Postfix or Nginx).
Recently, I restructured a production infrastructure with a high email processing load that suffered from silent crashes and unregulated memory consumption. During the stabilization process, I documented all debugging, optimization, and automation steps. This guide is designed to be a comprehensive administration reference for running SPFBL 24x7 on Linux.
1. SPFBL architecture and installation#
SPFBL requires a modern Java Runtime Environment (JRE). Using Java 11 or higher is recommended to ensure security improvements and optimized Garbage Collector performance.
Installing dependencies#
On Debian/Ubuntu:
sudo apt update
sudo apt install default-jre -y
On RHEL/CentOS/Rocky Linux:
sudo dnf install java-11-openjdk-headless -y
Directory layout and manual installation#
To keep the system organized and secure, we create a dedicated directory in /opt/spfbl and isolate the database in /var/lib/spfbl:
# Download SPFBL (replace with the official stable version URL)
wget https://spfbl.org/download/spfbl-latest.tar.gz
# Extract files
tar -xzf spfbl-latest.tar.gz
sudo mkdir -p /opt/spfbl
sudo cp -r spfbl-*/* /opt/spfbl/
# Create data and log directories
sudo mkdir -p /var/lib/spfbl
sudo mkdir -p /var/log/spfbl
# Adjust permissions for a dedicated system user (recommended for security)
sudo useradd -r -s /bin/false spfbl || true
sudo chown -R spfbl:spfbl /opt/spfbl /var/lib/spfbl /var/log/spfbl
systemd service configuration#
Create the /etc/systemd/system/spfbl.service file:
[Unit]
Description=SPFBL Anti-Spam Service
After=network.target
[Service]
Type=simple
User=spfbl
WorkingDirectory=/opt/spfbl
EnvironmentFile=-/etc/default/spfbl
ExecStart=/usr/bin/java $JAVA_OPTS -jar /opt/spfbl/spfbl.jar
Restart=on-failure
RestartSec=10
LimitNOFILE=65536
TimeoutStopSec=30
[Install]
WantedBy=multi-user.target
2. Main configurations and port mapping#
All of SPFBL's logic is governed by the /opt/spfbl/conf/spfbl.conf file. If this file does not exist, the service will create a default one on the first run, which you should adjust for the required network ports.
To check the active port configuration:
cat /opt/spfbl/conf/spfbl.conf | grep -i "port\|server"
Default ports and their functions:#
- Port 80 (HTTP): Web Interface / Dashboard (often changed to avoid conflict with Nginx or Apache).
- Port 8001 (TCP): REST API used by mail servers and integrated systems to query reputation and status.
- Port 8002 (UDP): Integrated DNS server, used to answer RBL and SPF queries.
- Port 9877 (UDP): Internal/alternative DNS query port specific to some SPFBL clients.
3. JVM optimization: tuning memory and garbage collection#
SPFBL consumes resources according to the volume of queries received. Default JVM settings can suffer from high latency or crash due to OutOfMemoryError if the Heap limits are not adjusted properly.
Create or edit the /etc/default/spfbl file to pass the correct JVM arguments:
# Define Heap parameters and the G1 GC garbage collector
JAVA_OPTS="-Xms512m -Xmx2048m -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -Xlog:gc*:file=/var/log/spfbl/gc.log:time,uptime:filecount=5,filesize=10M"
Analysis of the recommended flags:#
-Xms512m: Initial allocation of 512MB RAM at boot to prevent constant heap resizing.-Xmx2048m: Maximum ceiling of 2GB RAM for the Heap. Prevents VPS memory exhaustion.-XX:+UseG1GC: Ensures the G1 collector is used. Critical for low-latency request handling.-XX:MaxGCPauseMillis=200: Attempts to keep garbage collection pauses below 200 milliseconds to avoid choking Postfix.-Xlog:gc*: Directs Garbage Collection logs to/var/log/spfbl/gc.logwith automatic rotation across 5 files of 10MB each.
If you are running on an older JVM (Java 8), use:
JAVA_OPTS="-Xms512m -Xmx2048m -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -Xloggc:/var/log/spfbl/gc.log -XX:+PrintGCDetails"
After modifying the flags, run:
sudo systemctl daemon-reload
sudo systemctl restart spfbl
4. Initial diagnosis and graceful restart flow#
If SPFBL crashes, an untidy restart can lock up system resources if there are "orphan" Java processes holding onto network ports.
How to verify java version and path#
To ensure the active JVM is compatible and up to date:
# Check installed version
java -version
# Locate the absolute path of the active executable
readlink -f $(which java)
# If multiple versions exist and you need to switch
sudo update-alternatives --config java
Graceful restart procedure#
- Stop the service via systemd:
sudo systemctl stop spfbl
- Verify if any orphan Java process associated with SPFBL remains:
ps aux | grep spfbl | grep -v grep
- If the process persists (stuck on I/O or timing out), force terminate it safely:
# Send SIGTERM first
sudo kill -15 [PID]
sleep 3
# If it is still running, force it with SIGKILL
sudo kill -9 [PID]
- Confirm the release of TCP/UDP ports:
ss -tlnp | grep -E "80|8001|8002|9877"
- Start the service cleanly:
sudo systemctl start spfbl
# Validate active status
sleep 5
sudo systemctl status spfbl
5. Deciphering failures with specific logs#
General system logs (syslog) often omit internal Java exceptions. You need to inspect the service-specific logs:
- Application Log:
/var/log/spfbl/spfbl.log - Error Log (Stderr):
/var/log/spfbl/error.log - Garbage Collection Log:
/var/log/spfbl/gc.log
Inspection commands and systemd filters:#
# Monitor application logs in real-time
tail -f /var/log/spfbl/spfbl.log
# Filter grave systemd errors in the last hour
sudo journalctl -u spfbl --since "1 hour ago" -p err
# Temporarily enable debug log output to trace protocol issues
sudo journalctl -u spfbl -p debug -f
6. Network ports, connectivity, and firewall rules#
Many administrators suffer from Connection Refused errors when trying to integrate Postfix or Exim with SPFBL. This usually happens due to blocked network ports or incorrect bind settings.
Test local and remote connectivity#
# Check if ports are listening
ss -tlnup | grep -E "80|8001|8002|9877"
# Test HTTP response of the REST API (Port 8001)
curl -I http://localhost:8001/
# Perform a local DNS RBL query on port 8002
dig @localhost -p 8002 example.com
# Perform a DNS query on port 9877
dig @localhost -p 9877 example.com
Configuring the firewall (UFW & iptables)#
In UFW (Debian/Ubuntu), allow only what is strictly necessary for your infrastructure:
# Allow web access only on internal/local network (Port 80)
sudo ufw allow from 127.0.0.1 to any port 80 proto tcp
# Allow queries to REST API (Port 8001) and DNS (Port 8002 / 9877)
sudo ufw allow 8001/tcp
sudo ufw allow 8002/udp
sudo ufw allow 9877/udp
sudo ufw reload
In pure IPTables, with rule saving and persistence:
sudo iptables -A INPUT -p tcp --dport 8001 -j ACCEPT
sudo iptables -A INPUT -p udp --dport 8002 -j ACCEPT
sudo iptables -A INPUT -p udp --dport 9877 -j ACCEPT
# Save and persist rules
sudo apt install iptables-persistent -y
sudo netfilter-persistent save
7. Maintenance procedures: backup and upgrades#
Never modify SPFBL binary files without creating reliable backups first.
Backup routine#
The SPFBL database stores accumulated local reputation data. Back it up with the service stopped, or use atomic copy tools to avoid corrupting the /var/lib/spfbl/spfbl.db database.
# Stop the service
sudo systemctl stop spfbl
# Create a complete backup archive
sudo tar -czf /root/spfbl-backup-$(date +%Y%m%d).tar.gz \
/opt/spfbl/conf/ \
/var/lib/spfbl/ \
/etc/systemd/system/spfbl.service \
/etc/default/spfbl
# Copy the database file only
sudo cp /var/lib/spfbl/spfbl.db /root/spfbl-db-backup-$(date +%Y%m%d).db
# Restart the service
sudo systemctl start spfbl
Secure upgrade procedure#
To upgrade SPFBL without losing your database history or custom configurations:
# 1. Stop the service
sudo systemctl stop spfbl
# 2. Run a full preventive backup
sudo tar -czf /root/spfbl-pre-update-$(date +%Y%m%d).tar.gz /opt/spfbl/ /var/lib/spfbl/
# 3. Download the new version from the official website
wget https://spfbl.org/download/spfbl-latest.tar.gz
tar -xzf spfbl-latest.tar.gz
# 4. Replace essential binaries without overwriting conf/ directory and the database
sudo cp spfbl-*/spfbl.jar /opt/spfbl/
# Update script utilities if needed
sudo cp spfbl-*/*.sh /opt/spfbl/ 2>/dev/null || true
# 5. Adjust permissions
sudo chown -R spfbl:spfbl /opt/spfbl/
# 6. Start the service and validate logs
sudo systemctl start spfbl
sleep 5
sudo systemctl status spfbl
8. Monitoring, health check, and auto-recovery script#
Monitoring only if the SPFBL process is running is not enough. We must check if the REST API answers successfully within a tolerable timeout.
Creating a health check script (/usr/local/bin/check_spfbl.sh)#
This script validates HTTP status on port 8001. If the response is invalid or slow, it restarts the service and logs the event.
#!/bin/bash
# SPFBL health validation script
TARGET_URL="http://localhost:8001/"
LOG_FILE="/var/log/spfbl/healthcheck.log"
# Run HTTP request with a 5-second timeout
HTTP_STATUS=$(curl -o /dev/null -s -w "%{http_code}" --connect-timeout 5 $TARGET_URL)
if [ "$HTTP_STATUS" -eq 200 ] || [ "$HTTP_STATUS" -eq 302 ]; then
echo "$(date '+%Y-%m-%d %H:%M:%S') - SPFBL Healthy (HTTP $HTTP_STATUS)" >> $LOG_FILE
else
echo "$(date '+%Y-%m-%d %H:%M:%S') - CRITICAL: SPFBL down or slow (HTTP $HTTP_STATUS). Restarting..." >> $LOG_FILE
sudo systemctl restart spfbl
fi
Make the script executable:
sudo chmod +x /usr/local/bin/check_spfbl.sh
Cron schedule for 24x7 monitoring#
To run this health check every 5 minutes, append to root's /etc/crontab or set up via crontab:
*/5 * * * * root /usr/local/bin/check_spfbl.sh >/dev/null 2>&1
9. Memory troubleshooting and JVM resource monitoring#
If your VPS memory usage is hitting the threshold and causing Out of Memory (OOM) killer occurrences, use Java-specific commands to identify memory leaks and check resource consumption:
# 1. Check physical memory (RSS) vs virtual memory (VSZ) usage
ps -p $(pgrep -f spfbl.jar) -o pid,rss,vsz,%mem,%cpu,cmd
# 2. Monitor Garbage Collector execution in real-time (1s interval, 5 times)
jstat -gc $(pgrep -f spfbl.jar) 1000 5
# 3. Output a JVM Heap summary to inspect memory distribution
jmap -heap $(pgrep -f spfbl.jar)
# 4. Check the process tree and active secondary threads
pstree -p $(pgrep -f spfbl.jar)
Troubleshooting checklist: SPFBL service#
Use this structured list to diagnose service incidents quickly and efficiently.
Initial diagnostics#
- [ ] Service Status: Run
systemctl status spfbland verify if it is active. - [ ] Orphan Processes: Run
ps aux | grep javato check for concurrent/lingering instances. - [ ] Port Binding: Execute
ss -tlnp | grep javato validate listening status on ports. - [ ] Error Logs: Inspect
/var/log/spfbl/error.logfor runtime exceptions. - [ ] JVM Memory Limits: Ensure a proper
-Xmxlimit is configured in the environment file.
Network and connectivity checks#
- [ ] Local Firewall: Run
ufw statusoriptables -Lto ensure SMTP servers can reach the ports. - [ ] Bind Settings: Verify that bind is set to
0.0.0.0if remote access is required, or127.0.0.1for local integration. - [ ] DNS Resolution Test: Run
dig @localhost -p 8002 example.comfrom inside the server. - [ ] REST API Test: Test HTTP connectivity using
curl -I http://localhost:8001/.
With these diagnostics and automations implemented, running SPFBL shifts from a troubleshooting guessing game to a reliable, managed infrastructure operation.
Was this article helpful?
Leave a quick reaction to help prioritize future technical guides:
This post is licensed under CC BY-NC.



Comments
Join the discussion below.
0 comments