My Fanless OpenBSD Desktop

After the disappointment of my X1 Nano and learning that all future Intel "Evo"-branded laptops would lack S3 suspend, I started thinking about returning to my M1 MacBook full-time or building an OpenBSD desktop. I chose the latter, building my first desktop machine in many years.

desktop with screen and new desktop system


I briefly considered an arm64 CPU and motherboard, but the hardware support of OpenBSD/arm64 is not yet reliable enough for my daily use and the lead-time for ordering a HoneyComb LX2 was many weeks out.

I decided to go with an amd64 system since the OpenBSD/amd64 platform is very mature and I know it quite well. Beyond that, my only requirements for my new desktop were:

  • Excellent OpenBSD support
  • Fanless with no coil whine
  • A high-resolution, small monitor (more on that later)

Ever since reading Fabien Sanglard's writeup about building a system with a Streacom DB4 case, I knew I wanted that case in particular since it looks beautiful and could passively cool a 65W processor.


After the case, the next component I chose was the monitor. In retrospect, this would make everything else more complicated, but I am pretty picky about the screens in the laptops that I buy, so I wanted to make sure my desktop display was of high quality.

I've always chosen smaller (<= 14") laptop screens since I find too much horizontal space distracting. I prefer to separate tasks with virtual desktops rather than have everything on one giant screen. I wanted a smaller monitor that I could have closer to me, lower on my desk and angled slightly upward like a laptop screen.

In addition to good image reproduction, I needed a monitor with a high resolution that could display Firefox in 1.5x or 2x mode (layout.css.devPixelsPerPx). While not an absolute requirement, integrated speakers would be a nice option on the monitor so I wouldn't have to buy separate ones and find a place for them on my desk.

After some research, I chose the LG UltraFine 21.5" IPS LED monitor with a resolution of 4096x2304. This particular version of the LG UltraFine is no longer being produced, but the newer 24" version was larger but had a smaller resolution (3840x2160), and the newer 5K model (5120x2880) requires Thunderbolt. I found a 21.5" version on eBay that was in great condition in the original box.

Since the LG UltraFine had a VESA mount option, I purchased an Ergotron LX monitor arm to be able to position the monitor however I wanted on my desk.

LG UltraFine monitor attached to Ergotron LX monitor arm
Side profile of monitor positioning

After some testing with the monitor once I got it, I realized that using it with a desktop system might be difficult because it uses a single USB-C (non-Thunderbolt) cable for its display and audio, but it also has a 3-port USB-C hub on the back of it and its brightness controls and ambient light sensor also connect over that single USB-C cable.

This all works by using the USB-C cable for data as usual but it sends the screen data over DisplayPort using dedicated pins of the USB-C cable ("Alt Mode"). This requires that the computer it's connecting to have a USB-C port that can break out those pins and route them to the DisplayPort signal of the GPU while also handling the data devices of the USB-C connection. Using an external GPU ("video card" back in my day) would be difficult because even if it had a USB-C connector (most just have HDMI and/or DisplayPort), it would need to somehow route the data from that cable back to the computer as USB data since the GPU is only talking DisplayPort.

I didn't quite figure out how to do all of this until after I had already purchased the motherboard and CPU, but eventually I got it working using a Sunix upd2018 card (actually a Dell-branded version of it) which is a PCI USB-C card with a DisplayPort-out port. The monitor's USB-C cable is plugged into the PCI card, which then breaks out the DisplayPort out to an external connector and the USB-C data routes through the PCI connection as a normal USB-C card. Then a short DisplayPort cable is used to connect between the PCI card and the motherboard/GPU DisplayPort connector.

xhci0 at pci1 dev 0 function 0 "ASMedia ASM1042AE xHCI" rev 0x00: msi, xHCI 1.10
usb0 at xhci0: USB revision 3.0
uhub0 at usb0 configuration 1 interface 0 "ASMedia xHCI root hub" rev 3.00/1.00 addr 1

The monitor's brightness controls and ambient light sensor are available through USB HID devices, and its integrated speakers work through uaudio as expected:

uhub5 at uhub0 port 3 configuration 1 interface 0 "LG Electronics Inc. USB2.1 Hub" rev 2.10/52.26 addr 2
uhub6 at uhub5 port 4 configuration 1 interface 0 "LG USA product 0x9a48" rev 2.00/88.32 addr 3
uaudio0 at uhub6 port 1 configuration 1 interface 1 "LG Electronics Inc. USB Audio" rev 2.00/0.2f addr 4
uaudio0: class v1, high-speed, sync, channels: 2 play, 0 rec, 3 ctls
audio1 at uaudio0
uhub6: device problem, disabling port 2
uhidev0 at uhub6 port 4 configuration 1 interface 0 "LG Electronics Inc. USB Controls" rev 2.00/3.04 addr 5
uhidev0: iclass 3/0
uhid0 at uhidev0: input=64, output=64, feature=8
uhidev1 at uhub6 port 4 configuration 1 interface 1 "LG Electronics Inc. USB Controls" rev 2.00/3.04 addr 5
uhidev1: iclass 3/0
uhid1 at uhidev1: input=4, output=0, feature=6
uhidev2 at uhub6 port 4 configuration 1 interface 2 "LG Electronics Inc. USB Controls" rev 2.00/3.04 addr 5
uhidev2: iclass 3/0
uhid2 at uhidev2: input=6, output=0, feature=13

I'm still not sure why that port 2 gets disabled on the monitor's internal hub (not the 3-port hub on the back of it) but it doesn't seem to affect anything.


I already had my heart set on the Streacom DB4 fanless case, though I waffled a bit between the black and titanium colors before choosing black. The case as-is can dissipate enough heat for a 65W processor, though Streacom offers a separate heat-pipe add-on that can support up to 110W.

I purchased a Streacom ST-ZF240 ZeroFlex 240W PSU because it was also fanless. I've used a nanoPSU before but heard coil whine from it so I didn't want to go that route again.

I didn't quite appreciate how large and heavy the DB4 case is until it arrived. Fully assembled with everything in it, it weighs over 20 pounds and has a footprint of 10"x10"x11".

The main bulk of the case is held up 2" off the surface by two large feet, which only leaves 2" between the motherboard and my table. This makes it a bit difficult to plug in certain cables like a DisplayPort cable with a large connector, but my desk has a grommet in the corner where the case sits so the majority of the cables can pass straight down through the desk.

CPU and Motherboard

Since I've been pretty unhappy with Intel products lately, I decided to go with an AMD processor. I've never had one before so I wasn't very familiar with the lineup, but I wanted one with integrated graphics to avoid buying an external GPU since I wouldn't have room with the DisplayPort/USB-C card and because most external GPUs put out a ton of heat and/or have fans. I also needed a processor with a TDP of 65W or less to stay under the Streacom case's limits.

I decided on the AMD Ryzen 7 Pro 4750G 4 GHz 8-core processor with integrated Radeon Graphics. Technically this CPU is not supposed to be sold to end-users, but it's available on Amazon which was good enough for me.

cpu0: AMD Ryzen 7 PRO 4750G with Radeon Graphics, 4000.51 MHz, 17-60-01
cpu0: 32KB 64b/line 8-way I-cache, 32KB 64b/line 8-way D-cache, 512KB 64b/line 8-way L2 cache
cpu0: ITLB 64 4KB entries fully associative, 64 4MB entries fully associative
cpu0: DTLB 64 4KB entries fully associative, 64 4MB entries fully associative
cpu15 at mainbus0: apid 15 (application processor)
cpu15: AMD Ryzen 7 PRO 4750G with Radeon Graphics, 4000.01 MHz, 17-60-01

Once I had the CPU picked out, I looked for a motherboard. I've been out of the custom PC game for many years, but I was disappointed at how every non-server motherboard seems to be targeted towards gamers with all kinds of stupid flashing LEDs and aggressive branding. Beyond supporting the AM4-socketed Ryzen 4750G, my requirements for the motherboard were just that it have Intel gigabit ethernet (for optimum OpenBSD support), at least one M.2 socket for an NVMe drive, and have both HDMI (just in case) and DisplayPort ports.

Eventually I settled on the ASUS ROG Strix X570-I. The stupid RGB LEDs can be disabled in the BIOS/firmware menu by setting "AURA" to "Stealth Mode", and I unplugged the two 1" fans on the I/O board to keep everything silent. I also had to set the "CPU Fan Speed" in the "Monitor" section to "Ignore", or else it would indicate a fan error at every boot since I had none plugged in.

While I don't intend to use them, its onboard WiFi and sound work fine in OpenBSD:

iwx0 at pci4 dev 0 function 0 "Intel Wi-Fi 6 AX200" rev 0x1a, msix
azalia1 at pci10 dev 0 function 6 "AMD 17h/1xh HD Audio" rev 0x00: apic 18 int 12
azalia1: codecs: Realtek ALC1220
audio0 at azalia1

As does its ethernet port:

em0 at pci5 dev 0 function 0 "Intel I211" rev 0x03: msi, address 7c:10:c9:[...]


I purchased Crucial 16GB DDR4 3200 MHz RAM in a single DIMM in case I want to upgrade to 32GB later. Again, what's with all the RGB lighting and over-the-top heatsinks on the "gamer" RAM chips?

I installed a Samsung 980 Pro 1 TB NVMe SSD which I already had. The ASUS motherboard has two m.2 slots; one on the top which is underneath a large heatsink, and one on the bottom of the motherboard.

Keyboard and Mouse

I'm not big into mechanical keyboards (aside from the one on my Dolch PAC 64) but after seeing LGR's video about the Glorious GMMK Pro 75% keyboard, I decided to go with that one for my desktop. I like that it's very solid and small, but still includes arrow keys and a nice rotary knob. I also share LGR's opinion that the Glorious branding is stupid and over-the-top, but luckily it's just on the bottom of the keyboard so I only ever had to see it once taking it out of the box.

I opted for a black shell, aluminum switch plate, lubed (lol) Glorious Panda switches, and a "Dolch" DSA keycap set that I already had from years back.

The switches have a nice tactile feel without being too loud. Also as Clint noted in his video, the space bar occasionally sticks. I'm not sure if this will fix itself over time.

Configuration of the keys and lighting of the keyboard has to be done with a Windows-only piece of software, so I booted to my Windows-on-a-USB-stick and installed it. As with the motherboard, I disabled all RGB lighting on the keyboard. It would have been nice to have a subtle white backlighting on the keys like my laptops, but the GMMK Pro's white RGB lights look blue when at a low brightness. I reconfigured the keymap to put a permanent Control key where Caps Lock usually is (as I would do otherwise with xmodmap) and put Delete in the upper right corner, although I rarely need it.

Update (2022-01-26): I've been informed that the GMMK Pro is supported by the popular QMK Firmware which allows configuration under non-Windows operating systems.

I will probably need to get a wrist rest because my wrists hurt after just a couple days of typing on it due to the height of the keys. I'm used to typing on laptop keyboards which are only a few millimeters above the surface of my desk, so my wrists are usually at a much flatter angle. For this reason I've also been using a ThinkPad Compact USB Keyboard which feels just like a ThinkPad. My only complaint about this keyboard is that the plastic case can be creaky at times. If someone could reproduce the case in aluminum, I'd pay you many dollars.

As for my mouse, I'm not a gamer so I don't need something with 35 buttons on it. I had been using a Lenovo N50 wireless mouse for many years with my laptop and I like its design a lot, but its mouse click and especially its scroll wheel click are very loud. I recently switched to a Logitech M355 because it's nearly silent. It uses a wireless USB dongle which I have plugged into the back of the monitor.

uhidev2 at uhub5 port 2 configuration 1 interface 0 "Logitech USB Receiver" rev 2.00/30.00 addr 4
uhidev2: iclass 3/1
ums1 at uhidev2: 16 buttons, Z and W dir
wsmouse1 at ums1 mux 0
uhidev3 at uhub5 port 2 configuration 1 interface 1 "Logitech USB Receiver" rev 2.00/30.00 addr 4
uhidev3: iclass 3/0, 17 report ids
uhid5 at uhidev3 reportid 3: input=4, output=0, feature=0
uhidpp0 at uhidev3 reportid 16 device 1 mouse "M355" serial e6-4f-59-05

Its battery status is available via the uhidpp driver:

$ sysctl hw.sensors.uhidpp0
hw.sensors.uhidpp0.raw0=4 (battery levels)
hw.sensors.uhidpp0.percent0=90.00% (battery level), OK

My mousepad is some very thin piece of cloth/rubber that I don't remember where I got, but I like it because it's quiet and has no logos on it.


Of course my system wouldn't be usable to me if I couldn't run OpenBSD on it.

When I first booted OpenBSD on the system, once the amdgpu KMS driver took over from efifb, the system would hang (even with a lower-resolution HDMI monitor connected). After playing with random BIOS options, I discovered that the BIOS's CSM needs to be enabled for some reason. Even though the system still boots via EFI instead of legacy booting through the CSM, having the CSM enabled does something not-yet-understood that enables the video to work properly.

This would get the system to boot, but the LG UltraFine display would go blank (though the backlight was still on) once amdgpu took over. I SSH'd in and did an xinit, and then was able to change the resolution from 4096x2304@60Hz to 4096x2304@48Hz. I'm not sure if this is a bandwidth issue somewhere between the GPU, the DisplayPort, the cable, or some software issue. To work around this, I added a quirk to prefer the 4096x2304@48Hz rate in the monitor's EDID.

Since the LG UltraFine exposes a USB HID device to control its brightness, I wrote a driver to attach to it and expose the brightness adjustment through wsconsctl display.brightness.

$ dmesg | grep ulguf
ulguf0 at uhub6 port 4 configuration 1 interface 0 "LG Electronics Inc. USB Controls" rev 2.00/3.04 addr 7

$ wsconsctl display.brightness
$ wsconsctl display.brightness=20
display.brightness -> 20.00%

I still need to add support for reading the ambient light sensor and exposing it through sysctl hw.sensors, which I can then use with something like my xdimmer to automatically dim the screen at night.

To route sound through the monitor's speakers by default, I have made it use rsnd/1 by default, which maps to audio1, via uaudio0.

$ dmesg | grep uaudio
uaudio0 at uhub6 port 1 configuration 1 interface 1 "LG Electronics Inc. USB Audio" rev 2.00/0.2f addr 6
uaudio0: class v1, high-speed, sync, channels: 2 play, 0 rec, 3 ctls
audio1 at uaudio0

$ grep sndiod_flags /etc/rc.conf.local
sndiod_flags=-f rsnd/1

Since some people have asked, the window manager shown in my photos above is my sdorfehs which is a fork of ratpoison.

Other than the quirks with my monitor, OpenBSD works well on this motherboard and CPU.


CPU temperature can be monitored in OpenBSD with the ksmn driver:

$ sysctl hw.sensors.ksmn0
hw.sensors.ksmn0.temp0=54.25 degC

Through a make -j8 build of the system maxing out all cores, the CPU temperature tops out at about 90 °C with the case reaching about 45 °C (113 °F). The hottest point is, of course, where the heat pipes attach to the case wall:

Questions or comments?
Please feel free to contact me.