Learning Artix Linux - Systemd Service Migration
Episode 18 of 23

Learning Artix Linux - Systemd Service Migration

Moving from Arch/systemd to Artix requires understanding systemd's roles and their replacements. This episode covers the eudev, elogind, and D-Bus components, translating systemd units to Artix init scripts, and why systemd-dependent services can fail.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Introduction

For users coming from Arch or another systemd distro, the biggest challenge with Artix isn't the install — it's migration: moving services from systemd units to Artix init scripts. Episode 18 dissects systemd's roles one by one, its replacement components, and how to translate services correctly.

This understanding keeps you from getting lost when you encounter documentation that only mentions systemctl. You'll be able to map every systemd command to its equivalent on OpenRC, runit, s6, or dinit.

The Roles of systemd That Must Be Replaced

More Than an Init

systemd isn't just PID 1. It unifies many roles: init system, service manager, device manager (udev), login manager (logind), resolver (resolved), journal (journald), and more. On Artix, each role is handled by a dedicated component.

The replacement map:

systemd component replacements
systemd-init    -> OpenRC / runit / s6 / dinit
systemd-udevd   -> eudev
systemd-logind  -> elogind
systemd-journal -> per-application logs + rc-log
D-Bus           -> D-Bus (same, run via init)

systemd-udevd is replaced by eudev, systemd-logind by elogind, and the journal by ordinary application logs. There's no single daemon doing everything.

Practical Consequences

The journalctl command won't exist. Logs live in per-application files under /var/log/ or in service logs. The systemctl command also doesn't exist — it's replaced by rc-service, sv, s6-svc, or dinitctl depending on your init. Once you memorize this mapping, the rest of migration is just writing configuration files.

Translating Units to Init Scripts

The Anatomy of a systemd Unit

A systemd unit stores service metadata in key-value format. Example unit:

Example systemd unit
[Unit]
Description=Example service
After=network.target
 
[Service]
ExecStart=/usr/bin/example --daemon
Restart=on-failure
 
[Install]
WantedBy=multi-user.target

WantedBy=multi-user.target determines that the service is enabled at the multi-user runlevel. This must be mapped to the default runlevel on Artix.

Translating to OpenRC

On OpenRC, the unit above translates into a script in /etc/init.d/:

OpenRC script from the translation
#!/sbin/openrc-run
description="Example service"
 
depend() {
    need net
}
 
start() {
    ebegin "Starting example service"
    start-stop-daemon --start --background --make-pidfile \
        --pidfile /run/example.pid --exec /usr/bin/example
    eend $?
}
 
stop() {
    ebegin "Stopping example service"
    start-stop-daemon --stop --pidfile /run/example.pid
    eend $?
}

need net replaces After=network.target. start-stop-daemon handles start, backgrounding, and the PID file. After creating the script, register it with rc-update add.

Translating to Other Inits

For runit, create a service directory with a run script that executes the daemon; for s6, write a service database with a run script; for dinit, write a declarative .dinit file:

dinit file from the translation
type = process
command = /usr/bin/example --daemon
depends-on = network
restart = on-failure

depends-on = network on dinit is the equivalent of After=network.target on systemd. All inits carry the same information — only the format differs.

Why systemd-Dependent Services Fail

Hidden Dependencies

Some services implicitly depend on systemd: they call systemctl to communicate, write to the journal, or expect systemd sockets. Without systemd, these services fail in confusing ways.

A good first diagnosis: run the service manually in the foreground and read the error:

Run a daemon manually
sudo -u http /usr/bin/example --foreground

sudo -u http /usr/bin/example --foreground shows errors directly on the terminal. If the message mentions systemctl, journald, or DBUS_SESSION_BUS_ADDRESS, that's the source of the problem.

Common Solutions

For services that call systemctl, look for a --systemd-ignore option or replace it with an init command. For those needing D-Bus, make sure the dbus service is active in your init. For those writing to the journal, point them to a normal log file via the application's configuration:

Enable D-Bus on OpenRC
rc-update add dbus default
rc-service dbus start

The command rc-service dbus start ensures the bus is available for applications that need it. Most modern applications only need D-Bus and eudev to work normally.

Full Migration from Arch

Swapping the Repositories

Migrating from Arch to Artix is done by swapping the repos in /etc/pacman.conf from Arch's to Artix's, then reinstalling key packages. This procedure is fully documented on the Artix wiki. An essential preparation: a full backup first (episode 16), then:

Install the init after swapping repos
sudo pacman -S artix-base artix-base-openrc

artix-base-openrc installs the init foundation. Once the init is in place, packages ending in systemd must be replaced with their Artix variants.

After Migration

Verify that no packages drag in systemd:

Check for systemd dependencies
pacman -Q | grep systemd

The output of pacman -Q | grep systemd shows remaining systemd-related packages. Ideally it's empty or only helper tools that don't pull an active systemd daemon.

Conclusion

Episode 18 mapped systemd's roles and their replacements on Artix: init, eudev, elogind, and D-Bus. You also learned to translate systemd units into OpenRC, runit, s6, or dinit scripts, and to handle systemd-dependent services.

Key takeaways:

  • systemd unifies many roles; Artix replaces them one by one.
  • systemd-udevd is replaced by eudev, systemd-logind by elogind.
  • Unit translation: After= becomes need, WantedBy= becomes the default runlevel.
  • Each init has its own format: script, run directory, or .dinit file.
  • Services that call systemctl/journal fail without systemd.
  • Check for remaining systemd dependencies with pacman -Q | grep systemd.

In the next episode, episode 19, we'll cover virtualization and containers — QEMU/libvirt with virt-manager and KVM, and Docker/Podman in non-systemd and rootless modes.