I Built An Open-Source Replacement For Apc Smartslot Network Cards Opennmc
If you’ve ever managed a data center or home lab with APC UPS units, you know the pain of proprietary SmartSlot network cards. These cards are expensive, closed-source, and often become obsolete when APC moves on to newer models. I got tired of paying premium prices for outdated hardware, so I built OpenNMC—an open-source alternative that gives you full control over your UPS monitoring and management.
This comprehensive guide covers everything you need to know about OpenNMC, from understanding the technology to installing and configuring your own replacement for APC’s SmartSlot network cards. Whether you’re running a professional data center or a home lab, this project offers a cost-effective, customizable solution for UPS network management.
Understanding OpenNMC
What is OpenNMC?
OpenNMC (Open Network Management Card) is an open-source replacement for APC SmartSlot network cards. It’s built around a custom Linux System-on-Module (SoM) running Buildroot, with Network UPS Tools (NUT) as the underlying monitoring framework and a web interface for management. The project aims to provide the same functionality as APC’s proprietary cards while being open, affordable, and extensible.
History and Development
The project emerged from frustration with APC’s closed ecosystem. Commercial SmartSlot cards typically cost several hundred dollars and receive limited updates. As data centers and home labs increasingly adopt open-source solutions, the need for a transparent, modifiable UPS management system became clear. OpenNMC fills this gap by providing a hardware and software platform that anyone can modify, improve, and adapt to their specific needs.
Key Features and Capabilities
OpenNMC currently offers:
- SmartSlot Compatibility: Designed to fit directly into APC UPS SmartSlot interfaces
- NUT Integration: Full Network UPS Tools implementation for comprehensive UPS monitoring
- Web Interface: Browser-based management and monitoring dashboard
- SSH Access: Full system access for advanced configuration and troubleshooting
- Serial Communication: Direct communication with UPS units via the internal serial interface using apcsmart protocol
- Custom Hardware: Based on a custom Linux SoM for optimal performance and power efficiency
Pros and Cons
Advantages:
- Open-source and fully customizable
- Significantly lower cost than commercial alternatives
- No vendor lock-in
- Community-driven development and support
- Ability to add custom features and integrations
Limitations:
- Requires technical expertise to set up and maintain
- Hardware assembly required
- Limited to supported APC UPS models
- Ongoing development means some features may be experimental
Use Cases and Scenarios
OpenNMC is ideal for:
- Home Labs: Affordable UPS monitoring for personal infrastructure
- Small Data Centers: Cost-effective network management for multiple UPS units
- Educational Environments: Learning platform for UPS management and embedded Linux
- Research Facilities: Customizable monitoring solutions for specialized equipment
- Backup Power Systems: Integration with solar, generator, or other backup power setups
Current State and Future Trends
The project is actively developed with a growing community. Current priorities include expanding UPS model compatibility, improving the web interface, and adding advanced monitoring features. Future developments may include integration with popular monitoring systems like Prometheus, Grafana dashboards, and API endpoints for automation.
Comparison to Alternatives
| Feature | APC SmartSlot | OpenNMC | Third-party Cards |
|---|
| Cost | $300-800 | ~$100-150 | $200-400 |
| Open Source | No | Yes | Varies |
| Customization | Limited | Full | Limited |
| Community Support | Vendor only | Active community | Vendor-dependent |
| Hardware Control | None | Complete | Limited |
Prerequisites
Hardware Requirements
To build your own OpenNMC, you’ll need:
- APC UPS with SmartSlot: Compatible with various SmartUPS models
- Custom Linux SoM: ARM or x86-based system-on-module
- Serial Communication Hardware: RS-232 interface for UPS communication
- Power Supply: 5V or 12V depending on your SoM choice
- Enclosure: 3D-printed or custom case for the SmartSlot form factor
- MicroSD/EMMC Storage: For the operating system and configuration files
Software Requirements
- Buildroot: For creating the custom Linux distribution
- Network UPS Tools (NUT): Version 2.8 or later
- Web Server: Lighttpd or Nginx for the management interface
- SSH Server: Dropbear or OpenSSH for remote access
- Serial Communication Libraries: For apcsmart protocol support
Network and Security Considerations
- Network Access: The card needs network connectivity for remote monitoring
- Firewall Configuration: Restrict access to the management interface
- SSL/TLS: Implement HTTPS for secure web access
- Authentication: Set up user accounts and permissions
- Network Segmentation: Consider placing on a separate management network
User Permissions and Access Levels
- Administrator: Full system access, configuration changes
- Monitor: Read-only access to status and logs
- Backup: Limited access for backup operations only
Pre-installation Checklist
- Verify UPS model compatibility
- Ensure SmartSlot is functional
- Prepare development environment for Buildroot
- Test serial communication with the UPS
- Plan network configuration and IP addressing
- Set up backup procedures for existing configurations
Installation & Setup
Building the Custom Linux Distribution
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| # Clone the Buildroot repository
git clone https://github.com/buildroot/buildroot.git
cd buildroot
# Configure for your hardware platform
make menuconfig
# Enable required packages
# Target Packages → Networking Applications → nut
# Target Packages → Networking Applications → lighttpd
# Target Packages → Shells → dropbear
# Target Packages → System Tools → usbutils
# Build the system
make
# Flash to your storage medium
dd if=output/images/rootfs.ext4 of=/dev/sdX bs=4M status=progress
|
Initial System Configuration
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| # First boot configuration
ssh root@opennmc.local
# Set hostname
echo "opennmc" > /etc/hostname
hostname -F /etc/hostname
# Configure network interface
cat > /etc/network/interfaces << EOF
auto eth0
iface eth0 inet static
address 192.168.1.100
netmask 255.255.255.0
gateway 192.168.1.1
dns-nameservers 8.8.8.8 8.8.4.4
EOF
# Enable SSH at boot
systemctl enable dropbear
|
NUT Configuration
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
| # Configure NUT drivers
cat > /etc/nut/ups.conf << EOF
[ups]
driver = apcsmart
port = /dev/ttyS0
desc = "APC UPS via SmartSlot"
vendorid = 0x051d
EOF
# Configure UPS access
cat > /etc/nut/upsd.users << EOF
[admin]
password = your_secure_password
actions = SET
instcmds = ALL
[monuser]
password = monitor_password
upsmon master
EOF
# Configure monitoring
cat > /etc/nut/upsmon.conf << EOF
MONITOR ups@localhost 1 monuser monitor_password master
SHUTDOWNCMD "/sbin/shutdown -h +0"
EOF
|
Web Interface Setup
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
| # Configure lighttpd
cat > /etc/lighttpd/lighttpd.conf << EOF
server.modules = (
"mod_access",
"mod_alias",
"mod_compress",
"mod_redirect"
)
server.document-root = "/var/www"
server.upload-dirs = ( "/var/cache/lighttpd/uploads" )
server.errorlog = "/var/log/lighttpd/error.log"
server.pid-file = "/var/run/lighttpd.pid"
server.username = "www"
server.groupname = "www"
server.port = 80
compress.cache-dir = "/var/cache/lighttpd/compress/"
compress.filetype = ( "application/javascript", "text/css", "text/html", "text/plain" )
url.access-deny = ( "~", ".inc" )
static-file.exclude-extensions = ( ".php", ".pl", ".fcgi" )
index-file.names = ( "index.html" )
EOF
# Create web interface files
mkdir -p /var/www
cat > /var/www/index.html << EOF
<!DOCTYPE html>
<html>
<head>
<title>OpenNMC - UPS Monitoring</title>
</head>
<body>
<h1>OpenNMC Status</h1>
<div id="status">Loading...</div>
<script>
fetch('/status.json')
.then(response => response.json())
.then(data => {
document.getElementById('status').innerHTML = `
Model: ${data.model}<br>
Status: ${data.status}<br>
Battery: ${data.battery.charge}%
`;
});
</script>
</body>
</html>
EOF
|
Verification Steps
1
2
3
4
5
6
7
8
9
10
11
| # Test NUT communication
upsc ups@localhost
# Check web interface
curl http://localhost
# Verify SSH access
ssh monuser@localhost
# Test UPS shutdown command
upsdrvctl -u root shutdown
|
Configuration & Optimization
Advanced NUT Configuration
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| # Configure battery calibration
cat > /etc/nut/upsd.conf << EOF
MAXAGE 15
EOF
# Set up email notifications
cat > /etc/nut/notifycmd << EOF
#!/bin/bash
SUBJECT="UPS Alert: $4"
MESSAGE="UPS $2 on $1 has status: $4"
echo "$MESSAGE" | mail -s "$SUBJECT" admin@example.com
EOF
chmod +x /etc/nut/notifycmd
# Configure powerdown delay
upsrw -s onbattery.delay=30 ups@localhost
|
Security Hardening
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| # Configure firewall
iptables -F
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT
# Allow established connections
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
# Allow SSH (limited)
iptables -A INPUT -p tcp --dport 22 -s 192.168.1.0/24 -j ACCEPT
# Allow web interface (limited)
iptables -A INPUT -p tcp --dport 80 -s 192.168.1.0/24 -j ACCEPT
# Save rules
iptables-save > /etc/iptables/rules.v4
|
1
2
3
4
5
6
7
8
9
10
11
12
| # Optimize serial communication
stty -F /dev/ttyS0 2400 sane raw cs8 hupcl cread clocal -crtscts
# Configure NUT polling intervals
cat > /etc/nut/upsmon.conf << EOF
MONITOR ups@localhost 1 monuser monitor_password master
POLLFREQ 5
POLLFREQALERT 5
EOF
# Optimize memory usage
echo "vm.swappiness=10" >> /etc/sysctl.conf
|
Integration with Monitoring Systems
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| # Configure Prometheus metrics
cat > /usr/local/bin/ups_exporter << EOF
#!/bin/bash
upsc ups@localhost | grep -E '^(battery.charge|ups.status|input.voltage|output.voltage|ups.load)' | \
while read line; do
key=$(echo $line | cut -d' ' -f1 | sed 's/\./_/g')
value=$(echo $line | cut -d' ' -f2)
echo "ups_$key $value"
done
EOF
chmod +x /usr/local/bin/ups_exporter
# Add to crontab for regular collection
echo "* * * * * /usr/local/bin/ups_exporter > /var/lib/prometheus/metrics.txt" | crontab -
|
Customization Options
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| # Create custom scripts directory
mkdir -p /opt/opennmc/scripts
# Example custom alert script
cat > /opt/opennmc/scripts/low_battery_alert << EOF
#!/bin/bash
THRESHOLD=20
CURRENT=$(upsc ups@localhost battery.charge)
if [ "$CURRENT" -lt "$THRESHOLD" ]; then
MESSAGE="Battery at ${CURRENT}%, consider shutting down"
logger -t opennmc "$MESSAGE"
# Add your custom notification logic here
fi
EOF
chmod +x /opt/opennmc/scripts/low_battery_alert
# Add to crontab
echo "*/5 * * * * /opt/opennmc/scripts/low_battery_alert" | crontab -
|
Usage & Operations
Common Operations and Commands
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| # Check UPS status
upsc ups@localhost
# View detailed information
upsc ups@localhost ups.status
upsc ups@localhost battery.charge
upsc ups@localhost input.voltage
upsc ups@localhost output.voltage
# Test shutdown sequence
upsdrvctl -u root shutdown
# Manual battery test
upsdrvctl -u root battery.test.start
# View logs
tail -f /var/log/nut/ups.log
|
Monitoring and Maintenance
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
| # Set up log rotation
cat > /etc/logrotate.d/nut << EOF
/var/log/nut/*.log {
daily
missingok
rotate 30
compress
delaycompress
notifempty
create 644 nut nut
}
EOF
# Monitor system health
cat > /usr/local/bin/health_check << EOF
#!/bin/bash
echo "=== OpenNMC Health Check ==="
echo "Date: $(date)"
echo "Uptime: $(uptime)"
echo "Load: $(cat /proc/loadavg)"
echo "Memory: $(free -h | grep Mem)"
echo "Disk: $(df -h / | tail -1)"
echo "NUT Status: $(upsc ups@localhost ups.status 2>/dev/null || echo 'NUT not responding')"
EOF
chmod +x /usr/local/bin/health_check
# Schedule regular checks
echo "0 * * * * /usr/local/bin/health_check >> /var/log/opennmc_health.log" | crontab -
|
Backup and Recovery Procedures
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
| # Backup configuration files
cat > /usr/local/bin/backup_config << EOF
#!/bin/bash
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_DIR="/backup/opennmc/${DATE}"
mkdir -p "$BACKUP_DIR"
cp -r /etc/nut "$BACKUP_DIR/"
cp -r /etc/lighttpd "$BACKUP_DIR/"
cp /etc/network/interfaces "$BACKUP_DIR/"
cp /etc/ssh/sshd_config "$BACKUP_DIR/"
echo "Backup completed: $BACKUP_DIR"
EOF
chmod +x /usr/local/bin/backup_config
# Schedule daily backups
echo "0 2 * * * /usr/local/bin/backup_config" | crontab -
# Create recovery script
cat > /usr/local/bin/recover_config << EOF
#!/bin/bash
BACKUP_DIR="$1"
if [ -z "$BACKUP_DIR" ]; then
echo "Usage: $0 <backup_directory>"
exit 1
fi
cp -r "$BACKUP_DIR/nut/" /etc/
cp -r "$BACKUP_DIR/lighttpd/" /etc/
cp "$BACKUP_DIR/interfaces" /etc/network/
cp "$BACKUP_DIR/sshd_config" /etc/ssh/
systemctl restart nut
systemctl restart lighttpd
EOF
chmod +x /usr/local/bin/recover_config
|
Scaling Considerations
For multiple UPS units:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| # Configure multiple UPS devices
cat > /etc/nut/ups.conf << EOF
[ups1]
driver = apcsmart
port = /dev/ttyS0
desc = "UPS 1 in Rack A"
[ups2]
driver = apcsmart
port = /dev/ttyS1
desc = "UPS 2 in Rack B"
EOF
# Configure monitoring for multiple devices
cat > /etc/nut/upsmon.conf << EOF
MONITOR ups1@localhost 1 monuser monitor_password master
MONITOR ups2@localhost 1 monuser monitor_password master
EOF
|
Troubleshooting
Common Issues and Solutions
Issue: NUT cannot communicate with UPS
1
2
3
4
5
6
7
8
9
10
| # Check serial port permissions
ls -l /dev/ttyS0
chmod 666 /dev/ttyS0
# Test direct communication
echo -e "ID\r" > /dev/ttyS0
cat /dev/ttyS0
# Verify driver selection
upsdrvctl -u root start
|
Issue: Web interface not accessible
1
2
3
4
5
6
7
8
9
10
11
| # Check lighttpd status
systemctl status lighttpd
# Verify port binding
netstat -tlnp | grep 80
# Check firewall rules
iptables -L -n
# Test from localhost
curl http://localhost
|
Issue: SSH connection refused
1
2
3
4
5
6
7
8
| # Check SSH service
systemctl status dropbear
# Verify SSH port
netstat -tlnp | grep 22
# Check SSH configuration
cat /etc/ssh/sshd_config
|
Debug Commands and Log Analysis
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| # Enable debug logging for NUT
cat > /etc/nut/nut.conf << EOF
MODE=standalone
VERBOSE=3
EOF
# Monitor NUT communication
upsc -D ups@localhost
# Check system logs
journalctl -u nut-server
journalctl -u lighttpd
journalctl -u dropbear
# Monitor serial communication
cat /proc/tty/driver/serial
|
1
2
3
4
5
6
7
8
9
10
11
12
13
| # Optimize NUT polling frequency
cat > /etc/nut/upsmon.conf << EOF
MONITOR ups@localhost 1 monuser monitor_password master
POLLFREQ 3
POLLFREQALERT 1
AT ONBATT *EXECUTE /opt/opennmc/scripts/on_battery.sh
AT ONLINE *EXECUTE /opt/opennmc/scripts/online.sh
EOF
# Monitor system resources
top -b -n 1 | head -20
vmstat 1 5
iostat -x 1 3
|
Security Considerations
1
2
3
4
5
6
7
8
9
10
11
12
13
| # Regular security audit
cat > /usr/local/bin/security_audit << EOF
#!/bin/bash
echo "=== Security Audit ==="
echo "Last login: $(last -2 | head -1)"
echo "Listening ports: $(netstat -tlnp | wc -l)"
echo "Firewall rules: $(iptables -L | grep -c ACCEPT)"
echo "Password file: $(ls -lh /etc/shadow)"
EOF
chmod +x /usr/local/bin/security_audit
# Schedule weekly audits
echo "0 4 * * 0 /usr/local/bin/security_audit >> /var/log/security_audit.log" | crontab -
|
Where to Get Help and Resources
- Project Repository: https://github.com/yourusername/opennmc
- NUT Documentation: https://networkupstools.org/docs/user-manual.html
Buildroot Documentation: https://buildroot.org/docs.html