The init system is the first process started by the Linux kernel (PID 1) and is responsible for booting the system, starting services, and handling shutdown. While systemd dominates the Linux server landscape, many administrators prefer alternative init systems for their simplicity, transparency, and smaller attack surface.
This guide compares three mature init systems for self-hosted servers: OpenRC (the Gentoo and Alpine Linux default), s6 (the modern supervision suite from skarnet), and runit (the minimal init used by Void Linux and Docker base images). Each offers a fundamentally different philosophy for service management.
Why Choose an Alternative Init System?
Systemd is feature-rich but controversial. Its monolithic design bundles service management, logging, networking, device management, and more into a single codebase exceeding 1.4 million lines of code. For administrators who value simplicity and auditability, alternative init systems offer focused, smaller implementations that do one thing well.
Attack surface reduction is the primary security argument. OpenRC (~30,000 lines), s6 (~25,000 lines for the supervision suite), and runit (~8,000 lines) are each dramatically smaller than systemd. Fewer lines of code running as PID 1 means fewer potential vulnerabilities in the most privileged process on your system.
Boot speed is another factor. Minimal init systems can boot a server in under 2 seconds because they start only essential services in parallel without the complex dependency resolution that systemd performs. For container environments and embedded systems, this translates to faster time-to-service.
Transparency and debugging improve with simpler init systems. When a service fails to start, runit and s6 provide clear, text-based supervision logs. OpenRC uses straightforward shell scripts that any administrator can read and modify. Understanding and fixing service issues is easier when the init system’s behavior is predictable and documented.
For container-specific process management, see our supervisord vs s6-overlay vs runit guide and container init processes comparison. For broader system monitoring, our Linux OOM prevention guide covers memory management across init systems.
OpenRC: Dependency-Based Init for Gentoo and Alpine
OpenRC (1,837+ stars) is a dependency-based init system that serves as the default for Gentoo Linux and Alpine Linux. It uses a runlevel system with explicit service dependencies defined in shell scripts.
Features
- Runlevel management — boot, default, nonetwork, and custom runlevels
- Dependency resolution — services declare
need,use,want, andbefore/afterrelationships - Shell-based service scripts — all service definitions are readable POSIX shell scripts
- cgroup support — optional process tracking and resource isolation via cgroups
- No daemon required — OpenRC scripts run directly without a persistent supervisor daemon
- Cross-platform — works on Linux, FreeBSD, NetBSD, and macOS
Service Script Example
Service scripts live in /etc/init.d/ and follow a standard structure:
| |
Managing Services
| |
Installation on Debian/Ubuntu
| |
Docker Deployment
OpenRC is commonly used as the init system in Alpine-based containers:
| |
s6: Modern Process Supervision Suite
s6 (931+ stars) is a small suite of Unix programs designed for process supervision, service management, and logging. Created by Laurent Bercot, s6 follows the Unix philosophy of small, composable tools.
Features
- Process supervision — automatic restart, lifecycle management, and notification
- Service dependencies — declarative dependency graphs with parallel startup
- s6-rc — service manager that handles dependency ordering and startup sequencing
- s6-log — high-performance structured logging with automatic rotation
- s6-svscan — the supervisor daemon that monitors service directories
- Minimal footprint — each tool is independently small and auditable
- No shell required — service definitions are configuration files, not scripts
Service Definition
Services are defined by creating a directory in /etc/s6-rc/sourced/ with a type file and a run script:
| |
run script:
| |
Managing Services
| |
Docker Deployment with s6-overlay
| |
runit: Minimal Service Supervisor
runit (282+ stars on void-linux fork) is an init scheme with process supervision for Unix-like systems. Used by Void Linux as its default init and by many Docker images as a lightweight PID 1, runit is the simplest of the three systems compared here.
Features
- Three-stage boot — stage 1 (system initialization), stage 2 (service supervision), stage 3 (shutdown)
- Service directories — each service is a directory with a
runscript - Automatic restart — supervised processes are restarted immediately if they exit
- Log supervision — each service can have an associated log service
- Minimal codebase — approximately 8,000 lines of C code
- Cross-platform — Linux, macOS, FreeBSD, NetBSD support
Service Definition
Services live in /etc/sv/ with a single run script:
| |
Create a log service in /etc/sv/nginx/log/run:
| |
Managing Services
| |
Docker Deployment
runit is the most common init system in minimal Docker images:
| |
Feature Comparison
| Feature | OpenRC | s6 | runit |
|---|---|---|---|
| Primary role | System init + service manager | Process supervision suite | Minimal init + supervisor |
| Lines of code | ~30,000 | ~25,000 (suite) | ~8,000 |
| Service definitions | Shell scripts in /etc/init.d/ | Config files + execline scripts | run scripts in /etc/sv/ |
| Dependency management | Yes (need/use/want/before/after) | Yes (s6-rc dependency database) | No (manual ordering) |
| Runlevels | Yes (boot, default, custom) | Yes (service bundles) | No (single run state) |
| Logging | Via external logger | Built-in (s6-log) | Via svlogd per service |
| Automatic restart | No (needs external monitor) | Yes (s6-svscan) | Yes (runsvdir) |
| Container friendly | Moderate (needs init wrapper) | Yes (s6-overlay) | Yes (native) |
| Learning curve | Low (familiar shell scripts) | Medium (execline syntax) | Low (simple run scripts) |
| Used by | Gentoo, Alpine, Devuan | skarnet projects, containers | Void Linux, Docker images |
| GitHub stars | 1,837+ | 931+ | 282+ |
| Best for | Full Linux distributions | Advanced process supervision | Minimal containers and servers |
Choosing the Right Init System
Use OpenRC when you want a full-featured init system with familiar shell-based service scripts. It’s the most systemd-like alternative, offering runlevels, dependency management, and a comprehensive service ecosystem. Ideal for servers where you need traditional init system capabilities without systemd’s complexity.
Use s6 when you need advanced process supervision with reliable dependency management. Its s6-rc service manager provides the most sophisticated dependency resolution of the three, and s6-log offers structured logging without external dependencies. Best for infrastructure where service reliability and proper lifecycle management are critical.
Use runit when simplicity is paramount. Its minimal design means less to understand, less to configure, and less that can go wrong. The straightforward run script model makes service definitions trivially simple. Ideal for containers, embedded systems, and administrators who value minimalism.
FAQ
Can I replace systemd with OpenRC on an existing system?
Yes, but it requires careful migration. On Debian, install the openrc package and select it as the default init during installation. On Gentoo, OpenRC is the default. The migration involves replacing systemd unit files with OpenRC service scripts and ensuring all dependencies are properly declared. Always test on a non-production system first.
Does s6 work without execline?
Yes, but execline is recommended. Service run scripts can be written in any shell (bash, sh, dash), but execline (also from skarnet) provides a cleaner, non-Turing-complete syntax that avoids common shell scripting pitfalls. The s6 documentation strongly recommends using execline for all service definitions.
Can runit handle service dependencies?
Not natively. runit starts all services in parallel and does not resolve dependencies. If service B depends on service A, you must either: (1) add a sleep or retry loop in service B’s run script, (2) use s6-rc on top of runit (which is possible), or (3) manage dependency ordering externally. This is runit’s primary limitation compared to OpenRC and s6.
Which init system is best for Docker containers?
runit is the most common choice for container PID 1 due to its minimal footprint and simplicity. s6-overlay (s6’s Docker adaptation) is also popular when you need service dependencies inside containers. OpenRC is less common in containers because it expects a full system environment.
Do these init systems support cgroups?
OpenRC has optional cgroup support for process tracking and resource isolation. s6 can work with cgroups but does not manage them directly. runit has no cgroup integration. If you need cgroup-based resource management, OpenRC is the most capable of the three, though systemd remains the most comprehensive.
How do I migrate from systemd to an alternative init?
- Install the alternative init system alongside systemd
- Create equivalent service definitions (unit files → init scripts/run scripts)
- Test all services in the new init system
- Reboot with the alternative init as PID 1 (via kernel boot parameter
init=/sbin/openrc-initor equivalent) - Remove systemd packages after verifying all services work
Always maintain a rescue boot option (GRUB entry with
init=/bin/sh) in case the migration fails.