Supermicro Fan Speed Script

2U Supermicro servers are my go-to. These are much quieter than 1U servers, but the fans spin at 8800RPM. The IPMI fan modes available are Full (9000RPM), Heavy IO (6000RPM), and Optimal (supposed to auto-adjust). Unfortunately, setting the Fan Mode to Optimal seems to have a floor speed of 4500RPM, which is too loud. Even though my servers are in the garage, I sometimes work on projects there and can’t have it that noisy!

In the past, I’ve replaced Supermicro fans with low RPM Antec or Noctua fans, but since I moved my homelab to the garage I don’t need it to be that quiet.

Here’s my script, which tries to control the fan speed such that the noise is below that of a jet engine and the CPU temperature is below 50C. To avoid hunting, I set a minimum and maximum CPU range between 40-50C. The logic is simple:

  1. Set FAN speed mode to Full (this allows manual control of the fans).
  2. If the CPU is above 50C, bump the speed up by 10%
  3. If the CPU is below 40C, drop fan speed by 1%
  4. Repeat steps 2 and 3 every minute

    ⚠️ WARNING 1: Using this script could overheat and damage your CPU and other components; your server may release the magic smoke, burn through crystals like you’re traveling at Warp 10, or catch fire due to using this script. I just wrote it yesterday, so there may be bugs. I advise you not to use this script. If you go against my advice, keep a close eye on your temperatures.

    ⚠️ WARNING 2: This script was designed for a Supermicro X10 Motherboard. Yours may have a different fan configuration, in which case you will want to add or change the ipmitool commands.
Supermicro 2U Server with Four Fans

# apt install python3
# apt install ipmitools

# vim /usr/local/bin/

#!/usr/bin/env python3
import os
import subprocess
import time
import syslog
import re

# Set your desired temperature range and minimum fan speed
MIN_FAN_SPEED = 5  # Sets an initial fan speed of 5% 
current_fan_speed = MIN_FAN_SPEED

# IPMI tool command to set the fan control mode to manual (Full)
os.system("ipmitool raw 0x30 0x45 0x01 0x01")

# Get the current CPU temperature
def get_cpu_temperature():
    temp_output = subprocess.check_output("ipmitool sdr type temperature", shell=True).decode()
    cpu_temp_lines = [line for line in temp_output.split("\n") if "CPU" in line and "degrees" in line]

    if cpu_temp_lines:
        cpu_temps = [int('\d+(?= degrees)', line).group()) for line in cpu_temp_lines if'\d+(?= degrees)', line)]
        avg_cpu_temp = sum(cpu_temps) // len(cpu_temps)
        return avg_cpu_temp
        print("Failed to retrieve CPU temperature.")
        return None

# Set the fan speed
def set_fan_speed(speed):
    global current_fan_speed
    current_fan_speed = speed

    # Convert the speed percentage to a hex value
    hex_speed = format(speed * 255 // 100, "02x")

    # Set the fan speed for all 4 zones
    os.system(f"ipmitool raw 0x30 0x70 0x66 0x01 0x00 0x{hex_speed}")
    os.system(f"ipmitool raw 0x30 0x70 0x66 0x01 0x01 0x{hex_speed}")

    # Log the fan speed change to syslog
    syslog.syslog(syslog.LOG_INFO, f"Fan speed adjusted to {speed}%")

    # Print the fan speed change to console
    print(f"Fan speed adjusted to {speed}% - {hex_speed}")

# Set initial minimum fan speed

while True:

    cpu_temp = get_cpu_temperature()

    # Print the current CPU temperature to console
    print(f"Current CPU temperature: {cpu_temp}°C")

    if cpu_temp > MAX_TEMP and current_fan_speed < 100:
        # Increase the fan speed by 10% to cool down the CPU
        new_fan_speed = min(current_fan_speed + 10, 100)
    elif cpu_temp < MIN_TEMP and current_fan_speed > MIN_FAN_SPEED:
        # Decrease the fan speed by 1% if the temperature is below the minimum threshold
        new_fan_speed = max(current_fan_speed - 1, MIN_FAN_SPEED)

    # Wait for 60 seconds before checking the temperature again

# vim /etc/systemd/system/fan_control.service :

Description=Fan Controller Service

ExecStart=/usr/bin/python3 /usr/local/bin/


Set file permissions:
# chmod 755 /usr/local/bin/
# systemctl daemon-reload
# systemctl enable fan_control.service
# systemctl start fan_control.service
# systemctl status fan_control.service

Bugs: so, I’ve come across one bug where the script won’t spin down both fan zones, but killing the script and running it a second or third time seems to work. I suspect this is from sending ipmi commands too fast, so I’ve added sleep delays, but because it’s an intermittent issue who knows if that fixed it.

Improvement ideas: It would be great to add temperature monitoring for the other components (HDD, etc.). But in my observation, if I can keep the CPU cool the rest of the components are okay.

To watch the status, check IPMI or tail syslog:

Temperature readings all green
Fan Speed readings around 3000RPM

# tail -F /var/log/syslog |grep -E ‘speed|temp’

Fan speed adjusted to 4% - 0a
Current CPU temperature: 38°C
Fan speed adjusted to 3% - 07
Current CPU temperature: 39°C
Fan speed adjusted to 2% - 05
Current CPU temperature: 39°C
Fan speed adjusted to 1% - 02
Current CPU temperature: 48°C
Current CPU temperature: 50°C
Current CPU temperature: 52°C
Fan speed adjusted to 11%
Current CPU temperature: 51°C
Current CPU temperature: 48°C
Current CPU temperature: 46°C

That was set up last night.

When I woke up this morning, the fans were running at a pleasant hum of 1800 RPM.

He who blesses his friend with a loud voice early in the morning, It will be counted as a curse to him. – Proverbs 27:14 LSB

Join Ben's Newsletter

Subscribe and get my Homelab Security Tips 🛡️

(I won't share your email with anyone; unsubscribe any time)

Leave a Comment