BTS#3: Removing Unwanted Services and Modules for a Headless Raspberry Pi Zero 2 W
Published at , last update 2025-07-09 21:44:46#bts #sysops
For my next small side project, I’m running a Raspberry Pi Zero 2 W as a proxy server for my website. In fact, right now, fabulous.system is served from this exact Pi!
For this task, the limited CPU capabilities are not that big of a deal, but the limited RAM is. Sometimes, 512 MB is really not enough memory. Clearly I can’t simply add more RAM to the Pi, so I decided to disable as many hardware features as possible.
I don’t need WiFi, sound or accelerated video; all I need is USB for my Ethernet adapters.
Modifying the startup configuration and kernel modules can lead to a non-bootable system or unwanted behavior. Be careful if you don’t have physical access to the device!
I started by removing all services I don’t need, since I have no use for WiFi, Bluetooth, sound handling, or local console setup. Since I am not going to use the GPIO pins and the Raspberry Pi Zero 2W has no built-in EEPROM, I can deactivate these services as well.
sudo systemctl disable --now avahi-daemon Bluetooth console-setup rpi-eeprom-update triggerhappy ModemManager wpa_supplicant alsa-restore rpc-statd-notify hciuart Bluetooth
Next, on to the hardware side of things!
In the startup configuration located at /boot/firmware/config.txt, remove the line
dtoverlay=vc4-kms-v3d
and add
dtparam=i2c_arm=off
dtparam=i2s=off
dtparam=spi=off
dtparam=audio=off
dtoverlay=disable-wifi
dtoverlay=disable-bt
display_auto_detect=0
camera_auto_detect=0
gpu_mem=16
Reboot the system to apply the changes. This modification disables (most) of the audio and higher-level video handling as well as some lower-end components like i²c and SPI. Setting gpu_mem to 16 restricts the GPU core to 16 MB of VRAM. Unfortunately, we can’t go any lower; 16 MB is the bare minimum. On this model of the Raspberry Pi series, the GPU (also known as VideoCore) does much more than just video output; it is also responsible for certain aspects of memory management and loading the initial firmware.
Finally, I blacklisted all kernel modules that are not essential for my use-case. To do this, modify the file /etc/modprobe.d/raspi-blacklist.conf and add the following entries:
blacklist bcm2835_codec
blacklist bcm2835_isp
blacklist Bluetooth
blacklist bnep
blacklist btbcm
blacklist drm
blacklist rfkill
blacklist snd
blacklist snd_bcm2835
blacklist snd_compress
blacklist snd_pcm
blacklist snd_pcm_dmaengine
blacklist snd_soc_core
blacklist snd_soc_hdmi_codec
This eliminates Bluetooth, DRM, and sound support. While it is tempting to disable the vc4 module as well: Don’t. I tried, and it somewhat worked, but led to issues with the USB Ethernet adapters causing hanging kernel threads when they were under heavy load. As far as I can tell, the remaining modules that are loaded at boot time are absolutely required.
With these modifications in place, the fully functional system now requires 83 Megabytes of RAM! This leaves me with plenty of space for further additions, such as an rsync server, a caching DNS proxy, and some caching for nginx.
Do you have any comments or suggestions regarding this article? Please drop an e-mail to feedback@felsqualle.com!