Swapping systemd for OpenRC on Debian: A Hands-On Account
Ripping the init system out of a running Linux install is the kind of thing most of us know is possible but never actually do, because PID 1 is the one process you really don't want to get wrong. Daniel Cordova did it anyway — pulling systemd and dropping in OpenRC on a Debian Testing install running on a Snapdragon ThinkPad X13s — and wrote up the experience, footguns and all. It's a useful read both as a practical walkthrough and as an honest look at what breaks when you make this swap. His account is the basis for what follows, with some added context on the parts that bite.
Why Bother?
Cordova is upfront that this is curiosity and discomfort more than conviction. He's not anti-systemd — he's used it since its early days and acknowledges it works well for most use cases — but he's increasingly uneasy with how much it absorbs. The complaint isn't new: systemd keeps growing responsibilities that arguably belong to other projects, and a breaking change in one of those absorbed areas has taken down production deployments that a more modular design would have spared.
His specific tipping points were watching systemd integrate features he felt an init system had no business touching, including its own system installer. There's a real line, he argues, between "init system responsibilities" and the broader scope systemd keeps reaching for, and at some point the curiosity about how init systems actually work won out. The target: OpenRC, the dependency-based init system from the Gentoo world, on his home-hacking laptop.
Whatever you think of the systemd debate — and it's a genuine debate with reasonable people on both sides — the technical exercise of replacing PID 1 is instructive. If you've spent time with systemd's service model, it's worth understanding the alternative, the same way knowing systemd's own hardening and sandboxing controls deeply makes you a better judge of when that complexity earns its keep and when it doesn't.
The Installation, and the Big Footgun
Here's where it gets dangerous, and where Cordova's own system bit him. The core problem: systemd is marked as an essential package in Debian, and apt refuses to remove essential packages under normal circumstances. Plain apt-get just errors out; apt at least tells you why it won't.
The override is a flag that tells apt you really do mean it:
sudo apt purge --allow-remove-essential systemd
⚠️ Do not run that command on its own. It will leave your system unbootable. Removing systemd without an init system already in place to replace it means PID 1 is gone on next boot, and the machine drops into recovery — which is exactly what happened to Cordova. The only safe form chains the removal and the replacement into a single operation so you're never left with no init system at all:
sudo apt purge --allow-remove-essential systemd && sudo apt install openrc sysvinit-core
⚠️ Even chained, treat this as a high-risk operation: do it only on a machine you can physically access for recovery, never over SSH on a remote box with no console (you will lock yourself out), and have a live USB or recovery media ready before you start. This is not a "try it on the prod server" experiment. It's a "try it on the laptop you can plug a USB stick into" experiment. The && matters: if the purge succeeds and the install fails, you still have a broken boot, which is the next thing he hit.

What Broke
Even with the chained command, the swap wasn't clean. On reboot the system didn't come up properly, and Cordova landed in recovery mode (Ctrl-D to proceed and fix things). The cause: during the systemd purge, OpenRC got removed or never fully installed in the same transaction. The fix was to boot to recovery, get on WiFi, and reinstall directly:
sudo apt install openrc sysvinit-core
⚠️ This is the practical lesson hiding in the mishap: budget for a recovery cycle. Apt resolving a transaction that simultaneously removes an essential package and installs its replacement is fragile, and "it removed the thing I was installing" is a real outcome. Have console access and recovery media on hand, because you will likely need them.
After that, the system booted on OpenRC — but two things didn't work: battery status and audio.
Converting a systemd Service to OpenRC
Battery status turned out to be an unrelated kernel regression from his Debian Testing install on this ARM hardware, not an OpenRC problem. Audio he suspected needs a PipeWire/WirePlumber service launched on login, left for later.
The interesting part is the hardware-init service he did convert — starting the Qualcomm remoteprocs (SLPI/ADSP/CDSP coprocessors) that the Snapdragon platform needs. Under systemd it was a oneshot unit:
[Unit]
Description=Start Qualcomm remoteprocs (SLPI/ADSP/CDSP)
DefaultDependencies=no
After=initrd-root-fs.target local-fs.target
Before=sysinit.target
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/bin/sh -c 'echo start > /sys/class/remoteproc/remoteproc0/state; echo start > /sys/class/remoteproc/remoteproc1/state; echo start > /sys/class/remoteproc/remoteproc2/state'
[Install]
WantedBy=sysinit.target
His first-pass OpenRC equivalent was a plain shell script dropped in /etc/init.d/:
#!/bin/sh
echo start > /sys/class/remoteproc/remoteproc0/state
echo start > /sys/class/remoteproc/remoteproc1/state
echo start > /sys/class/remoteproc/remoteproc2/state
That worked, and it captures the philosophical difference cleanly: systemd's unit is declarative, with dependency ordering (After/Before) and lifecycle semantics (RemainAfterExit) expressed as configuration the init system interprets. OpenRC leans on shell scripts you write directly — closer to the metal, less magic, more your problem.
⚠️ One thing Cordova flags honestly: a bare script in /etc/init.d/ isn't really a proper OpenRC service yet. A real OpenRC init script uses the framework's structure — the #!/sbin/openrc-run shebang, a start() function, and depend() for ordering — rather than a raw shell script that happens to live in the init directory. His works for now, but it sidesteps OpenRC's actual dependency model. A production-grade version would look like:
#!/sbin/openrc-run
description="Start Qualcomm remoteprocs (SLPI/ADSP/CDSP)"
depend() {
after localmount
before sysinit
}
start() {
ebegin "Starting Qualcomm remoteprocs"
for n in 0 1 2; do
echo start > /sys/class/remoteproc/remoteproc${n}/state
done
eend $?
}
That gives you the dependency ordering and the start/stop semantics OpenRC expects, with proper status reporting, rather than a fire-and-forget script.
The Honest Verdict
Cordova's takeaway is refreshingly unhyped: OpenRC does the job, the experiment was a success, and he's not sure whether it'll be his permanent init system. He'll keep running it on the hacking laptop for a while and migrate his work laptop only if he stays comfortable. No evangelism, just "this works for me, and that's part of the Unix freedom to run whatever fits."
That's the right frame. Swapping init systems on a working install has real quirks and isn't necessarily a good idea for most people — but as a way to actually understand what PID 1 does, what systemd has absorbed, and what a leaner alternative looks like, it's a genuinely valuable exercise. Init systems are one of those layers that fluency with the surrounding tooling makes far less scary to poke at, the same way solid Linux process management fundamentals turn "PID 1 is terrifying" into "PID 1 is just a process with an important job."
If you try it, do it on hardware you can recover, keep the && in that purge command, and have a USB stick ready. And if OpenRC ends up fitting your workflow better than systemd, that's the whole point — run what works.