OpenRC
OpenRC is a dependency-based init system designed for Unix-like operating systems, which manages the initialization and control of services while maintaining compatibility with traditional system-provided init programs such as SysVinit or BSD init.[1] It was developed primarily for Gentoo Linux but has been ported to various other distributions including Alpine Linux, where it serves as the default init system, and can be installed on systems like Arch Linux via community packages.[2][3][4] Key features of OpenRC include support for parallel service startup to accelerate boot times, dependency resolution to ensure services start in the correct order, and integration with modern components like cgroups for resource management and udev for device handling.[2] The system is lightweight with minimal dependencies, allowing it to run on resource-constrained environments, and it supports runlevels—named states such as "default" or "boot"—along with stacked runlevels for flexible service inheritance across contexts.[1][3] Service management is handled through commands likerc-service for starting/stopping individual services and rc-update for adding them to runlevels, with additional capabilities for user-level services and hotplugging hardware events.[3][4]
OpenRC emphasizes modularity and portability, working atop existing init frameworks without replacing them entirely, and it includes optional tools like openrc-init for enhanced process supervision and elogind for compatibility with systemd-like session management features.[2] Its design prioritizes simplicity and customization, making it suitable for embedded systems, servers, and desktops where administrators seek alternatives to more monolithic init systems.[1] Installation typically involves emerging the package in Gentoo or using package managers in other distros, followed by configuring kernel parameters and service files in directories like /etc/init.d/ and /etc/conf.d/.[2][4]
History
Origins and Development
OpenRC was created in 2007 by Roy Marples, a developer contributing to both NetBSD and Gentoo Linux, as a lightweight init system designed to serve as an alternative to SysVinit while introducing built-in support for service dependencies.[5][6] This development addressed key shortcomings in Gentoo's existing Baselayout, which used pure shell scripts for init handling, leading to challenges in maintenance, debugging, and overall performance.[6] Marples' goal was to create a more modular framework that could enhance boot processes and extend portability to a broader range of Unix-like operating systems beyond Gentoo.[6][7] The project originated within the Gentoo ecosystem, where Marples announced the development of baselayout-2 early in 2007 as a complete rewrite of Gentoo's init script design, originally conceived by Daniel Robbins.[6] By mid-2007, alpha versions of this reimplementation were integrated into Gentoo, marking the transition from a basic service manager to a comprehensive init system capable of handling system startup and shutdown.[6][8] Towards the end of the year, following Marples' retirement from active Gentoo involvement, the project was renamed OpenRC and released independently, allowing it to evolve outside Gentoo's direct control while retaining strong ties to the distribution.[6][8] OpenRC was licensed from the outset under the 2-clause BSD license, a choice that emphasized its open-source nature and facilitated easy adoption and modification across different platforms.[6][7] The initial codebase was implemented in C99 for its core libraries and utilities, complemented by POSIX-compliant shell scripts for service definitions and runtime logic, ensuring broad compatibility with standards-based Unix environments.[6] This approach resulted in a highly compact implementation, totaling around 10,000 lines of C code and 4,000 lines of shell script, underscoring its design focus on efficiency and minimal footprint.[6]Major Releases and Updates
OpenRC's development began as an extension of Gentoo's modular init scripts, with its first independent public release occurring in 2007 under Roy Marples, who introduced core dependency-based service management to enable ordered and parallel startup of system processes.[6] A significant enhancement came in version 0.21, released in June 2016, which added the supervise-daemon utility for process supervision, allowing OpenRC to monitor and automatically restart daemons that terminate unexpectedly. Version 0.25, issued in April 2017, marked a key evolution by incorporating openrc-init, OpenRC's own PID 1 implementation, which serves as a drop-in replacement for traditional SysVinit systems and eliminates the need for external init dependencies while supporting full boot and shutdown orchestration.[9] Since Roy Marples handed over maintenance around 2010, OpenRC has been stewarded by the Gentoo OpenRC Project and broader OpenRC Developers group, evolving into a distro-neutral solution with contributions from communities including Alpine Linux and Artix Linux to enhance portability across Linux and BSD environments.[6][4] As of November 2025, the latest stable release is version 0.63, incorporating ongoing maintenance such as bug fixes for BSD compatibility, default enablement of cgroup v2 support since version 0.51 in 2023, and refinements to parallel service execution for faster boot times.[10][2][11]Design
Core Components
OpenRC's architecture is built around a set of modular components that enable dependency-based service management while maintaining compatibility with existing Unix-like init systems. The primary module is rc, which serves as the main framework responsible for orchestrating system initialization, service startup, and shutdown processes. Written primarily in C for efficiency and portability, rc parses shell scripts located in the/etc/init.d directory to construct a dependency graph, allowing services to start in the correct order based on declared needs and uses.[2][12][13]
Since version 0.25, OpenRC includes openrc-init, an optional init program that can fully replace the traditional /sbin/init (such as SysVinit) for standalone operation on Linux systems. By default, OpenRC integrates with the system's provided init, invoking rc during boot via mechanisms like inittab entries, but openrc-init enables a more self-contained setup by handling process ID 1 responsibilities directly. This component enhances flexibility for distributions seeking to minimize external dependencies while preserving OpenRC's core functionality.[9][4][14]
Another key optional module is supervise-daemon, introduced as part of OpenRC since version 0.21, which acts as a lightweight process supervisor for managing daemons. It monitors child processes, restarts them if they terminate unexpectedly, and handles logging of stdout and stderr, providing a consistent method for starting, stopping, and restarting services without requiring external tools like start-stop-daemon in all cases. Supervise-daemon keeps daemons in the foreground as direct children, using PID files to track supervision status.[15][16]
OpenRC's design emphasizes portability through its C-based core and use of POSIX-compliant shell scripts, supporting deployment on Linux and FreeBSD without major modifications. The dependency graph engine relies on standardized shell scripting conventions, where service interdependencies are declared via keywords in script headers, enabling cross-platform consistency. Additionally, OpenRC offers optional compatibility with external supervisors such as runit or s6, configurable via parameters in init scripts (e.g., supervisor=s6), allowing users to leverage specialized process monitoring tools alongside OpenRC's service management.[13][17][18]
Service Management and Dependencies
OpenRC service scripts are stored in the/etc/init.d directory and are implemented as POSIX-compliant shell scripts, typically starting with #!/sbin/openrc-run. These scripts must include core functions such as start(), stop(), restart(), and status(), along with a depend() function to declare inter-service relationships. The depend() function uses keywords to specify prerequisites, enabling OpenRC to resolve startup order automatically while maintaining compatibility with traditional SysVinit practices. Since version 0.60, OpenRC supports user services, with the feature stabilized as of September 2025.[19][1][20]
Dependency declarations in OpenRC support both hard and soft requirements, as well as sequencing controls. The need keyword enforces a hard, one-time dependency, ensuring the specified service starts (if not already running) before the current script proceeds; for instance, need net requires network services to be active for services like SSH. In contrast, use indicates a soft, ongoing dependency, assuming the service is available without attempting to start it, such as use dns for name resolution that persists during the service's runtime. The after keyword handles ordering without dependency enforcement, like after logger to sequence logging initialization, while before reverses this for reverse ordering. Additional keywords include want for optional startups and provide to allow one script to fulfill multiple service types. These mechanisms support conditional dependencies via environment variables in /etc/conf.d/ configuration files, allowing dynamic behavior based on system state. OpenRC also permits parallel execution of independent services to optimize boot times.[19][2][1]
Service management in OpenRC relies on dedicated tools for configuration and control. The rc-update utility manages runlevel associations by adding or removing symlinks in /etc/runlevels/, for example, rc-update add sshd default to enable the SSH service in the default runlevel, or rc-update del sshd boot to remove it from the boot runlevel. Manual operations use rc-service, which invokes script functions directly, such as rc-service net.eth0 start to activate a network interface or rc-service sshd status to check runtime state. Monitoring is facilitated by rc-status, which displays overall system status or filters by service, like rc-status -a for all services or rc-status --servicelist for a concise list. Runlevels follow SysV-style conventions with defaults like sysinit, boot, and default, but OpenRC extends this by supporting custom runlevels through directory creation in /etc/runlevels/ and stacked configurations via rc-update -s.[2][21]
Error handling and logging are integrated into OpenRC's service framework for reliability. Scripts use helper functions like ebegin and eend to output status messages and handle return codes, ensuring failures are reported clearly during execution. Logging is enabled by setting rc_logger="YES" in /etc/rc.conf, directing output to /var/log/rc.log for post-boot analysis of startup issues or service errors. Conditional dependencies can incorporate environment checks, such as testing variables in start_pre() or stop_pre() hooks to validate configurations before proceeding, preventing cascading failures. For crashed services, rc-service <service> zap resets the service state without full reinitialization.[19][2][22]
Features
Boot and Shutdown Processes
The boot process in OpenRC begins with the kernel invoking the init program, typically SysV init or the optional openrc-init (available since OpenRC 0.25),[9] which consults /etc/inittab to execute the sysinit runlevel via /sbin/openrc sysinit.[23] This runlevel processes scripts in /etc/runlevels/sysinit, handling essential hardware initialization, filesystem mounting as defined in /etc/fstab, and basic system setup such as loading kernel modules and configuring consoles.[23] Following sysinit, init triggers the boot runlevel with /sbin/openrc boot, executing scripts in /etc/runlevels/boot for additional low-level tasks like setting up networking basics and local filesystems.[23] The sequence then advances to the default runlevel via /sbin/openrc default (or another specified runlevel from the kernel command line using the softlevel parameter), where user-oriented services in /etc/runlevels/default are started.[2] Service startup order is determined by a dependency graph derived from keywords like need, use, want, before, and after in the service scripts located in /etc/init.d/, ensuring prerequisites are met before dependent services launch.[23] Optional parallelism in the boot process allows non-dependent services to start concurrently, potentially reducing overall boot time, and is enabled by setting rc_parallel="YES" in the global configuration file /etc/rc.conf.[3] This feature processes independent scripts simultaneously while respecting dependency constraints, though it is considered experimental in some implementations and may require careful testing to avoid issues with service ordering.[3] System-wide settings like boot delays can also be tuned in /etc/rc.conf to accommodate hardware-specific needs, such as adding a pause before proceeding to the next runlevel.[24] The shutdown process reverses the boot sequence by traversing the dependency graph in opposite order, stopping services cleanly to allow proper resource release and cleanup.[24] Initiated via commands like openrc shutdown or through init signals, it first halts the default runlevel services, then boot, and finally sysinit-related components, with configurable timeouts per service to wait for graceful stops before resorting to force-kill options if necessary.[24] During both boot and shutdown, OpenRC provides colorized console output for real-time feedback, using green for successful actions, red for failures, and yellow for warnings, enhancing readability on the terminal.[1] Verbose modes can be activated for debugging by adjusting settings in /etc/rc.conf or using command-line flags, displaying detailed execution traces.[2] Persistent logging is available by enabling rc_logger="YES" in /etc/rc.conf, directing output to /var/log/rc.log for post-boot analysis.[2] Environment setup integrates global parameters from /etc/rc.conf with per-service overrides in /etc/conf.d/, allowing customized variables like network interfaces or daemon options to influence the processes without altering core scripts.[24]Advanced Functionalities
OpenRC provides daemon supervision through thesupervise-daemon tool, which starts daemons as child processes and automatically restarts them upon unexpected termination to ensure service reliability.[15] This tool captures the daemon's stdout and stderr for logging, using a PID file for the supervisor itself rather than the daemon, allowing seamless restarts without external intervention.[25] Administrators can configure respawn behavior in init scripts by setting supervisor="supervise-daemon", along with options like command_args_foreground to prevent daemonization and pidfile for supervisor tracking; for instance, in the acpid service, killing the process triggers an immediate restart, demonstrating the tool's effectiveness in maintaining uptime.[15]
For resource management, OpenRC integrates with control groups (cgroups) to impose per-service limits on CPU and memory usage, creating a hierarchical structure under an openrc controller for organized process isolation.[26] Activation occurs via rc_controller_cgroups="YES" in /etc/rc.conf, supporting both hybrid cgroups v1/v2 modes or unified v2 by default since OpenRC 0.51, with controllers like cpu and memory enabled for fine-grained control.[26] Per-service configurations in /etc/conf.d/<service> allow settings such as rc_cgroup_settings="cpu.max 1500000 1000000\nmemory.high 4G" for v2, enforcing limits like 1.5 seconds of CPU time per second and a 4 GB memory soft cap, while rc_cgroup_cleanup="yes" ensures complete process tree termination on service stop.[26] This integration extends to user namespaces for enhanced isolation, enabling container-like environments by grouping related processes without requiring full container runtimes.[2]
OpenRC handles complex multi-process services through customizable init scripts that manage multiple daemons via dependency chains and conditional logic, ensuring coordinated starts and stops.[2] For example, the Samba service script conditionally launches smbd for file sharing, nmbd for name resolution, and winbindd for authentication based on configuration flags like samba_nmbd or samba_winbindd, using start-stop-daemon to handle each process independently while respecting overall service dependencies. This approach allows services like Samba to operate as a cohesive unit, starting only necessary components to optimize resource use and reliability.[27]
User services in OpenRC enable non-root management, allowing individual users to control personal daemons without system-wide privileges, introduced in version 0.60 (experimental).[2] Scripts reside in /etc/user/init.d/ with configurations in /etc/user/conf.d/, managed via rc-service --user <service> start and user-specific runlevels in ${XDG_CONFIG_HOME}/rc/runlevels/, requiring XDG_RUNTIME_DIR for state (often set by elogind or shell profiles).[2] Services are added with rc-update --user add <service>, and PAM integration via pam_openrc.so automates session initialization, permitting users to run tools like MPD as themselves for isolated, secure operation.[28]
As of November 2025, the latest version of OpenRC is 0.63.[29]
OpenRC's extensibility supports hooks for third-party supervision tools, enhancing its core functionality with specialized process management.[2] The s6 USE flag installs s6-linux-init for integration with the s6 suite, allowing s6 to handle daemon supervision in place of supervise-daemon, while runit can serve as a backend for process restarting through custom init script adaptations.[30] Additionally, networking dependencies are IPv6-aware, with netifrc permitting service reliance on IPv6-enabled interfaces like net.eth0 via /etc/conf.d/net configurations, ensuring services wait for full IPv6 connectivity before starting.[31]