Dynamic IPMI fan control daemon for Supermicro servers.
Replaces the BMC's aggressive default fan curve with a smooth thermal ramp, keeping the system quiet at idle while still responding to real load.
Supermicro 1U servers ship with BMC fan control tuned for worst-case datacenter
environments. At idle or light load in a home lab or office, the result is
ear-splitting fan noise. This daemon wraps ipmitool to assert a custom thermal
curve, detect and correct BMC overrides, and stay out of the way when things
actually get hot.
Developed and tested on:
- Board: Supermicro X10DRU (dual socket Xeon E5 v4), 1U, 2 fan zones
- OS: Ubuntu 24.04
- GPU: Intel Arc Pro B50
- Board: Supermicro X11DPG-OT (SYS-4029GP-TRT, dual socket, GPU chassis), 4U, 4 fan zones
- OS: Ubuntu 26.04
- GPU: none yet (Intel, planned)
May work on other X10/X11-series boards. Zone count and idle floors vary by
chassis — see FAN_ZONES in Configuration below. X9 boards use a different
IPMI raw command scale (0x00–0xff) and will need adjustments.
< 50°C → fans at minimum speed (floor)
50–70°C → linear interpolation, min → max speed
>= 70°C → panic mode: step up aggressively every interval
The BMC is not disabled — it remains the thermal safety net. This daemon runs on top of it and corrects overrides every check interval. If the BMC slams fans to full due to a genuine thermal event, the daemon will detect it and only correct back down once temps are under control.
Important: Fan mode is set to Full (0x01) once at startup only. Issuing
the mode command in a loop causes a momentary 100% fan spike every time — do
not change this behavior.
ipmitoolpython3- IPMI kernel modules:
ipmi_devintf,ipmi_si - Root / sudo access
sudo apt install ipmitool python3# Copy script
sudo cp ipmi-fan-control.py /usr/local/bin/
sudo chmod +x /usr/local/bin/ipmi-fan-control.py
# Load IPMI modules at boot
echo -e "ipmi_devintf\nipmi_si" | sudo tee /etc/modules-load.d/ipmi.conf
# Install and enable service
sudo cp ipmi-fan-control.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now ipmi-fan-control.serviceAll tunable values are at the top of ipmi-fan-control.py:
| Variable | Default | Description |
|---|---|---|
FAN_ZONES |
[(0x00, 0x10), (0x01, 0x10)] |
List of (zone_index, idle_floor) tuples. One entry per fan zone the BMC exposes — probe with ipmitool raw 0x30 0x70 0x66 0x00 <zone> per index before assuming only 2 zones exist (some 4U/GPU chassis expose 4). Each zone can have its own floor. MIN_SPEED is derived as the lowest floor across all zones. |
MAX_SPEED |
0x64 |
Fan ceiling, shared across all zones |
RAMP_START_TEMP |
50 |
°C where ramp begins |
RAMP_END_TEMP |
70 |
°C where ramp ends / panic begins |
PANIC_TEMP |
70 |
°C threshold for panic mode |
STEP_UP |
0x10 |
Speed increase per interval in panic mode |
MAX_STEP_UP |
0x08 |
Max speed increase per interval in ramp zone |
DEADBAND |
0x04 |
Minimum delta before issuing a new fan command |
CHECK_INTERVAL |
10 |
Seconds between checks |
| % | Hex |
|---|---|
| 10 | 0x0a |
| 16 | 0x10 |
| 20 | 0x14 |
| 25 | 0x19 |
| 30 | 0x1e |
| 40 | 0x28 |
| 50 | 0x32 |
| 60 | 0x3c |
| 75 | 0x4b |
| 100 | 0x64 |
# Live logs
journalctl -fu ipmi-fan-control.service
# Current fan mode (should be 0x01 after startup)
sudo ipmitool raw 0x30 0x45 0x00
# Current fan duty cycle (zone 0)
sudo ipmitool raw 0x30 0x70 0x66 0x00 0x00
# CPU temps
sensorsFans spike to 100% on service restart
Should not happen — ExecStartPre asserts Full mode and idle fan speeds
directly (matching FAN_ZONES) before the daemon even starts, so the BMC
never gets a window to apply its own loud default curve. If you change
FAN_ZONES in the script, update the matching ipmitool lines in
ipmi-fan-control.service too — they're not read from the script.
BMC override detected warnings in logs Expected occasionally. The BMC runs its own fan polling on a fixed schedule. The daemon detects and corrects these within one check interval.
ipmitool: Could not open device at /dev/ipmi0 IPMI kernel modules not loaded. Run:
sudo modprobe ipmi_devintf ipmi_siAnd make sure /etc/modules-load.d/ipmi.conf exists (see Installation).
Script not executable
sudo chmod +x /usr/local/bin/ipmi-fan-control.pyShebang must be line 1
If you edit the script, ensure #!/usr/bin/env python3 is the very first line.
A comment before the shebang breaks execution (exit code 203).
MIT