How to enable rc.local shell script on systemd while booting Linux system

We can easily enable rc.local shell script support on systemd while booting the Linux system. Traditionally, the shell script /etc/rc.local used by developers and Linux sysadmin to call other scripts or commands after all services are loaded. Typically /etc/rc.local get called at the end when Linux init switched to a multiuser runlevel. However, by default. /etc/rc.local support is disabled under systemd. This page shows how to enable and execute rc.local shell script during boot using systemd on Linux.

Tutorial details
Difficulty level Easy
Root privileges Yes
Requirements Linux with systemd as init
Est. reading time 5m

Enabling rc.local shell script on systemd while booting Linux system

/etc/rc.local compatibility achieved on systemd using special service called rc-local.service. This unit gets called automatically into by systemd-rc-local-generator if /etc/rc.local is executable.

Executing rc.local shell script during boot using systemd

Naturally, create or update/edit the file named /etc/rc.local using your favorite text editor. I am going to use vim command:
$ sudo vim /etc/rc.local
## RHEL/CentOS/Fedora Linux edit the /etc/rc.d/rc.local ##
$ sudo vim /etc/rc.d/rc.local

Append required commands or call script. Here is my file:

# add your commands 
# call your scripts here
# let us set stuff for my wifi
/sbin/iw phy0 wowlan enable magic-packet disconnect
# last line must be exit 0 
exit 0

Save and close the file when using vim. Make sure you set executable permission using the chmod command:
$ sudo chmod -v +x /etc/rc.local

Turing on rc-local.service on Linux when systemd is init

All we need to do is type the following systemctl command:
$ sudo systemctl enable rc-local.service
Reboot the Linux box:
$ sudo reboot
Verify status after reboot:
$ sudo systemctl status rc-local.service
Here is what we see on screen:

● rc-local.service - /etc/rc.local Compatibility
     Loaded: loaded (/etc/systemd/system/rc-local.service; enabled-runtime; ven>
    Drop-In: /usr/lib/systemd/system/rc-local.service.d
     Active: active (exited) since Wed 2020-11-04 13:29:54 IST; 1h 59min ago
       Docs: man:systemd-rc-local-generator(8)
      Tasks: 0 (limit: 37939)
     Memory: 0B
     CGroup: /system.slice/rc-local.service

Nov 04 13:29:54 nixcraft-wks01 systemd[1]: Starting /etc/rc.local Compatibility
Nov 04 13:29:54 nixcraft-wks01 systemd[1]: Started /etc/rc.local Compatibility.

See how to view status of a service on Linux using systemctl command for more info.

How to see service configuration

Open the terminal app and then type:
$ sudo systemctl cat rc-local.service
We see systemd configuration as follows:

# /etc/systemd/system/rc-local.service
#  SPDX-License-Identifier: LGPL-2.1+
#  This file is part of systemd.
#  systemd is free software; you can redistribute it and/or modify it
#  under the terms of the GNU Lesser General Public License as published by
#  the Free Software Foundation; either version 2.1 of the License, or
#  (at your option) any later version.
# This unit gets pulled automatically into by
# systemd-rc-local-generator if /etc/rc.local is executable.
Description=/etc/rc.local Compatibility
ExecStart=/etc/rc.local start
# /usr/lib/systemd/system/rc-local.service.d/debian.conf
# not specified by LSB, but has been behaving that way in Debian under SysV
# init and upstart
# Often contains status messages which users expect to see on the console
# during boot

Note: Run sudo SYSTEMD_LOG_LEVEL=debug /usr/lib/systemd/system-generators/systemd-rc-local-generator to debug /etc/rc.local issues when script is not loading.

A note about runlevels

Back in the days when init was the default, we had different runlevels as follows:

  • S – Boot the Linux system
  • 0 – Shutdown the Linux box
  • 6 – Reboot the Linux
  • 1 – Linux Single-user mode used for recovering Linux system in an emergency mode
  • 2 to 5 – Normal operation multiuser system that supported both CLI and GUI and full networking

Often Linux distros and Unix system modified these runlevel values as per their needs. However, /etc/rc.local got called when the system entered multiuser mode via runlevel 2 to 5. However, this default was removed when the majority of Linux distro switched to systemd. Hence, I wrote this quick guide for Linux developers and system administrators.

Creating your own service is easy with systemd on Linux

Instead of shell script in /etc/rc.d/ or call /etc/rc.local we do this now. It only works on Linux and not other Unix variants. Then you just do:

# /etc/systemd/system/my-service-name-goes-here.service
# Sample template to call your script or command when systemd boots into multi user mode
ExecStart=/path/to/script arg1 arg2

For instance here is how we can install wireguard or openvpn iptables rules:

# /etc/systemd/system/wireguard-iptables.service
ExecStart=/usr/sbin/iptables -t nat -A POSTROUTING -s ! -d -j SNAT --to 123.x.x.x
ExecStart=/usr/sbin/iptables -I INPUT -p udp --dport 1194 -j ACCEPT
ExecStart=/usr/sbin/iptables -I FORWARD -s -j ACCEPT
ExecStart=/usr/sbin/iptables -I FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT
ExecStop=/usr/sbin/iptables -t nat -D POSTROUTING -s ! -d -j SNAT --to 123.x.x.x
ExecStop=/usr/sbin/iptables -D INPUT -p udp --dport 1194 -j ACCEPT
ExecStop=/usr/sbin/iptables -D FORWARD -s -j ACCEPT
ExecStop=/usr/sbin/iptables -D FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT

And then:
$ sudo systemctl enable wireguard-iptables.service
$ sudo systemctl start wireguard-iptables.service
$ sudo systemctl stop wireguard-iptables.service


I hope you find this quick tutorial about enabling /etc/rc.local support useful for backward compatibility and ease of use purposes when using systemd. Make sure you read systemd documentation.

🐧 Get the latest tutorials on Linux, Open Source & DevOps via RSS feed or Weekly email newsletter.

🐧 5 comments so far... add one

CategoryList of Unix and Linux commands
Disk space analyzersdf ncdu pydf
File Managementcat tree
FirewallAlpine Awall CentOS 8 OpenSUSE RHEL 8 Ubuntu 16.04 Ubuntu 18.04 Ubuntu 20.04
Network UtilitiesNetHogs dig host ip nmap
OpenVPNCentOS 7 CentOS 8 Debian 10 Debian 8/9 Ubuntu 18.04 Ubuntu 20.04
Package Managerapk apt
Processes Managementbg chroot cron disown fg jobs killall kill pidof pstree pwdx time
Searchinggrep whereis which
User Informationgroups id lastcomm last lid/libuser-lid logname members users whoami who w
WireGuard VPNAlpine CentOS 8 Debian 10 Firewall Ubuntu 20.04
5 comments… add one
  • exalib Nov 5, 2020 @ 2:53

    I hate systemd. Old good Debian 8.x was nice. Debian 10 and systemd. I may switch to FreeBSD.

  • rob07 Nov 5, 2020 @ 8:42

    At least on my RHEL/CentOS 8 and Fedora Linux file is /etc/rc.d/rc.local but it is symlinked too:
    ls -l /etc/{,rc.d}/rc.local
    I saw:

    lrwxrwxrwx 1 root root  13 Jul 21 14:57 /etc//rc.local -> rc.d/rc.local
    -rw-r--r-- 1 root root 474 Jul 21 14:57 /etc/rc.d/rc.local

    May be update page?

  • Darius Dec 14, 2020 @ 0:44

    Perhaps this only exists in Debian/Ubuntu based distros, couldn’t find it anywhere in Arch/Manjaro system.

    • Vrasno Dec 15, 2020 @ 7:09

      Here is how you enable rc.local on Arch Linux:
      sudo vim /etc/systemd/system/rc-local.service

      Description=/etc/rc.local support
      # disable timeout logic

      Enable it:
      sudo systemctl enable rc-local.service
      Create /etc/rc.local
      sudo touch /etc/rc.local
      sudo chmod +x /etc/rc.local
      sudo vim /etc/rc.local

      Start it:
      sudo systemctl start rc-local.service
      sudo systemctl status rc-local.service

Leave a Reply

Your email address will not be published.

Use HTML <pre>...</pre> for code samples. Still have questions? Post it on our forum