A few weeks ago we talked about the relax switch. An implementation of a funny idea a friend of mine had to run a very particular type of music when people enter your bathroom and turn on a switch.
I always wanted to try gokrazy and this project was perfect for this. In this post I want to talk about gokrazy and how I migrated the project to run as an appliance.
The relax switch. Short demo.
Gokrazy allows you to run your software in an “appliance” mode. Meaning your device only runs the specific software components you want to run, nothing else. This has huge implications. Gokrazy only runs the linux kernel and the processes for your services. Nothing else. This means the attacking surface reduces significantly, making the device more secure.
I am sure you have worked in project using a single board computer like raspberry pi. Typically you install the OS and then run your applications there. Maybe you update the OS periodically, maybe not. But if you do, those updates do not happen as often as you’d like. The gokrazy project updates the linux kernel pretty much within hours after they are released upstream in the official linux kernel sources.
But there is more. The way you work with gokrazy is by first, building all the necessary bits in your local machine using the gokrazy cli tools and then you flash the sd card (or disk). After that, you can perform updates with a single command using the gokrazy tooling. The updates happen over the network. Gokrazy sends the new data (kernel, packages, etc…) and reboots the machine. Pair that with tailscale (supported in gokrazy) and you can perform remote, automatic updates periodically. The reboot times are super fast because we don’t have that many services to run. This project takes 5 seconds to load in my pi 4.
One of the challenges I had when migrating this project to gokrazy was making the audio hardware work under Gokrazy. Gokrazy has sound support (the gokrazy linux kernel has sound support) but I couldn’t make it work with the raspberry pi 4 hardware. But I knew there was support built in. What I end up doing is to use a usb audio dongle. That was recognized by linux just fine:
> breakglass gktest
2025/06/26 10:07:21 checking breakglass status on gokrazy instance "gktest"
2025/06/26 10:07:21 restarting breakglass
2025/06/26 10:07:22 polling SSH port to become available
2025/06/26 10:07:22 [ssh gktest]
__
.-----.-----| |--.----.---.-.-----.--.--.
| _ | _ | <| _| _ |-- __| | |
|___ |_____|__|__|__| |___._|_____|___ |
|_____| host: "gktest" |_____|
model: Raspberry Pi 4 Model B Rev 1.2
build: 2025-06-25T18:15:13-04:00
/tmp/breakglass3145481158 # cat /proc/asound/cards
0 [Device ]: USB-Audio - USB Audio Device
C-Media Electronics Inc. USB Audio Device at usb-0000:01:00.0-1.3, full speed
I have to check with the gokrazy maintainers because it is strange that the kernel in gokrazy is not configured for the pi sound card. I maybe have done something wrong.
The next issue was playing talking to my output audio card via
alsa from my go code. All the
projects out there seem to end up using
oto which uses cgo. But gokrazy disables
cgo (CGO_ENABLED=0
) because it does not ship with a C runtime (glibc or any
standard library). So there is no runtime for cgo to hook into. This forces
you to ship fully static go binaries.
Luckly I ended up finding a go project that implements the alsa interactions fully in go. And that worked like a charm.
The relax switch. Early stages.
I am planning on adding a mqtt server in the appliance soon, probably a mosquitto server. I will report back.
The source code for the project is here. Check it out and let me know what you think.