The Role of rc.local in Older Linux Systems
In older Linux distributions, the rc.local script served
as a simple, universally recognized mechanism for administrators to run
custom commands automatically at system boot. Acting as the final step
in the initialization sequence, it provided a hassle-free alternative to
writing complex initialization scripts for tasks that only required a
few shell commands. This article explores the purpose, functionality,
and common use cases of the rc.local script within
traditional Linux environments.
The Purpose of rc.local
Under traditional SysVinit and older BSD-style init systems, the system booted by transitioning through various "runlevels" (typically runlevels 2 through 5 for multi-user environments). Each runlevel executed a directory of structured service scripts designed to start core system daemons like networking, system logging, and storage management.
The rc.local file—usually located at
/etc/rc.local or /etc/rc.d/rc.local—was
intentionally placed at the very end of this execution chain. Because it
executed last, it ensured that all essential services, mounted
filesystems, and network interfaces were fully operational before any
user-defined commands ran.
Common Use Cases
The primary strength of rc.local was simplicity. Writing
a standard SysVinit script required boilerplate code to handle arguments
like start, stop, restart, and
status. For quick, one-off system adjustments,
rc.local bypassed this complexity. Common uses
included:
- Custom Network Configurations: Applying ad-hoc
iptablesfirewall rules, setting static routes, or altering network interface parameters via tools likeethtool. - Mounting Storage: Mounting non-critical network shares (such as NFS or SMB) that required the network to be active before mounting.
- Hardware and Kernel Tweaks: Writing values to the
/procor/sysvirtual filesystems to alter kernel settings or manage device power states. - Launching Ad-hoc Scripts: Starting custom background processes or monitoring scripts that did not ship with native service wrappers.
Execution Mechanics and Best Practices
The script operated under a specific set of rules that governed its execution:
- Root Privileges: The init system executed
rc.localdirectly withrootprivileges, allowing administrative changes without invokingsudo. - Execution Permission: The file required execution
rights (
chmod +x /etc/rc.local) and a valid shebang line (typically#!/bin/shor#!/bin/bash) at the top of the file. - Non-Blocking Commands: Because the boot sequence
waited for
rc.localto finish, any command that ran as an ongoing process had to be forked into the background using an ampersand (&). Failing to do so caused the boot sequence to hang indefinitely at that command. - Exit Status: The script typically concluded with
exit 0to signal to the init system that the execution completed successfully.
Transition to Modern Init Systems
Modern Linux distributions have largely replaced SysVinit with
systemd. In current environments, tasks previously
delegated to rc.local are typically managed using dedicated
.service unit files, which provide dependency management,
process isolation, and reliable restart capabilities. While many
distributions still offer a compatibility layer
(rc-local.service) to run /etc/rc.local if
present, native systemd units remain the standard approach
for modern service management.