🐧 How to enable rc.local shell script in systemd at Linux boot

We can easily enable rc.local shell scripting support in systemd when the Linux system boots. Traditionally, the /etc/rc.local shell script is used by Linux developers and sysadmin to invoke other scripts or commands after all services have loaded. Typically /etc/rc.local is called at the end when Linux init switches to multi-user runlevel. However, by default, /etc/rc.local support is disabled in systemd. In this article, we will show you how to enable and execute rc.local shell script at boot time using systemd on Linux.

Enabling rc.local shell script in systemd at boot of Linux system

Compatibility with /etc/rc.local is achieved through systemd using a special service called rc-local.service.

This module is automatically called in multi-user.target by systemd-rc-local-generator if /etc/rc.local is executable.

Executing rc.local shell script at boot time using systemd

Naturally, create or update / edit a file called /etc/rc.local using your favorite text editor.

I’m going to use the vim command:

$ sudo vim /etc/rc.local## RHEL/CentOS/Fedora Linux отредактируйте файл /etc/rc.d/rc.local ##
$ sudo vim /etc/rc.d/rc.local

Add the required commands or call the script. Here is my file:

#!/bin/sh
# 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.

🐧 How to save file in Vi / Vim and exit

Make sure you set the executable permissions for the file with the chmod command:

$ sudo chmod -v +x /etc/rc.local

Setting up rc-local.service on Linux when systemd starts

All we need to do is enter the following systemctl command:

$ sudo systemctl enable rc-local.service

Reboot Linux:

$ sudo reboot

Check the status after reboot:

$ sudo systemctl status rc-local.service

Here’s what we see on the 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
             └─debian.conf
     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 itsecforu systemd[1]: Starting /etc/rc.local Compatibility
Nov 04 13:29:54 itsecforu systemd[1]: Started /etc/rc.local Compatibility.

How to view service configuration

Open the terminal app and type:

$ sudo systemctl cat rc-local.service

We will see the 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 multi-user.target by
# systemd-rc-local-generator if /etc/rc.local is executable.
[Unit]
Description=/etc/rc.local Compatibility
Documentation=man:systemd-rc-local-generator(8)
ConditionFileIsExecutable=/etc/rc.local
After=network.target
 
[Service]
Type=forking
ExecStart=/etc/rc.local start
TimeoutSec=0
RemainAfterExit=yes
GuessMainPID=no
 
# /usr/lib/systemd/system/rc-local.service.d/debian.conf
[Unit]
# not specified by LSB, but has been behaving that way in Debian under SysV
# init and upstart
After=network-online.target
 
# Often contains status messages which users expect to see on the console
# during boot
[Service]
StandardOutput=journal+console
StandardError=journal+console

Note. Run sudo SYSTEMD_LOG_LEVEL = debug / usr / lib / systemd / system-generators / systemd-rc-local-generator to debug problems with /etc/rc.local when the script fails to load.

Linux runlevel information

When init was used by default, we had the following runlevels:

  • S – boot Linux system
  • 0 – turn off Linux
  • 6 – Restart Linux
  • 1 – Linux single user mode, used for Linux system emergency recovery
  • 2-5 – Common multi-user system supporting both CLI and GUI and full network connectivity

Often times, Linux distributions and the Unix system have changed these runlevel values ​​to suit their needs.

However, /etc/rc.local is called when the system enters multiuser mode through runlevels 2 through 5.

However, this default was removed when most Linux distributions switched to systemd.

Therefore, I wrote this quick guide for Linux developers and system administrators.

Creating your own service is easy with systemd on Linux

Instead of a shell script in /etc/rc.d/ or a call to /etc/rc.local, we’ll do it differently.

It only works on Linux, not other Unix flavors. Then 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
#
[Unit]
Before=network.target
[Service]
Type=oneshot
ExecStart=/path/to/command
ExecStart=/path/to/script arg1 arg2
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target

For example, here’s how we can set Wireguard or openvpn iptables rules:

# /etc/systemd/system/wireguard-iptables.service
[Unit]
Before=network.target
[Service]
Type=oneshot
ExecStart=/usr/sbin/iptables -t nat -A POSTROUTING -s 10.8.1.0/24 ! -d 10.8.1.0/24 -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 10.8.1.0/24 -j ACCEPT
ExecStart=/usr/sbin/iptables -I FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT
ExecStop=/usr/sbin/iptables -t nat -D POSTROUTING -s 10.8.1.0/24 ! -d 10.8.1.0/24 -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 10.8.1.0/24 -j ACCEPT
ExecStop=/usr/sbin/iptables -D FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target

And then:

$ sudo systemctl enable wireguard-iptables.service
$ sudo systemctl start wireguard-iptables.service
$ sudo systemctl stop wireguard-iptables.service

Conclusion

I hope you find this quick guide to enabling /etc/rc.local support useful for backward compatibility and ease of use with systemd.

Sidebar