1. Overview

In this tutorial, we’ll learn how to run a bash script as a daemon in the background.

2. Daemonizing Script as a Regular User

We can make use of bash processes to run our script in the background. We launch background tasks or processes with the & operator.

For example, let’s daemonize this simple script which we’ve placed at /home/baeldung/script.sh:

# Print a message every 60 seconds.
while :; do
    sleep 60
    echo "Slept for 60 seconds!"
done

Running the script with the nohup command ensures that it’s not killed when we exit the terminal:

$ nohup ./script.sh &
nohup: appending output to nohup.out

nohup logs any output from the script into the nohup.out file:

$ cat nohup.out 
Slept for 60 seconds!
Slept for 60 seconds!
...

We can close the terminal after starting the script.

For killing the process, we can log the launched process’s PID into a file and use it with kill:

$ nohup ./script.sh &
nohup: appending output to nohup.out
$ echo $! > ./script.pid
$ cat script.pid
4946

The $! variable stores the PID of the newly launched process. Therefore, we can just kill the script:

$ kill $(cat ./script.pid)

While the method we’ve seen here is straightforward, it does require extra user intervention for the startup and shutdown of the script.

3. Daemonizing Script System-Wide

We just learned how to run scripts in the background as regular users. Now, we’ll cover more sophisticated methods which allow us to control the script via the system’s service manager.

3.1. Using systemd

We can use systemd unit files to launch our script at boot. Unit files describe how the system should execute the given program.

Let’s create a unit file at /etc/systemd/system/script_daemon.service:

[Unit]
Description=Script Daemon

[Service]
Type=simple
User=baeldung
ExecStart=/home/baeldung/script.sh
Restart=on-failure

[Install]
WantedBy=default.target

We set the user that the script will run with the User= option and the path to the script with the ExecStart= option. The various options are documented in the systemd.exec man page.

Now, let’s enable the service:

$ sudo systemctl daemon-reload
$ sudo systemctl enable script_daemon.service
Created symlink /etc/systemd/system/shutdown.target.wants/script_daemon.service → /etc/systemd/system/script_daemon.service

Here, we reload the systemd config and enable our service using the systemctl tool, which helps manage systemd services.

We can also add dependencies to various other services.

For example, we might want to ensure that the network is available before starting our script. We do this with the After= option:

[Unit]
Description=Script Daemon
After=network.target

[Service]
...

We can restart the service with sudo systemctl restart script_daemon.service. It will be auto-started at boot.

3.2. Using /etc/rc.local

The /etc/rc.local file consists of commands that we want to run. Hence, we can just append the path to our script into this file:

$ echo "/home/baeldung/script.sh" >> /etc/rc.local

The script is executed as the root user by default. For dropping privileges, we can execute the command as a different user with su:

$ echo "su - baeldung /home/baeldung/script.sh" >> /etc/rc.local

**We should note that this command should be the last one run from /etc/rc.local since it blocks execution.
**

To make it non-blocking, we can use the nohup command with the & operator that we learned about earlier.

Further, we should avoid this approach using the /etc/rc.local file if systemd is available as it is a legacy file.

4. Conclusion

In this article, we learned various methods we can use to run scripts as daemons. We used bash processes, systemd services, and the /etc/rc.local file. We also learned about dropping privileges when running scripts through the system’s service manager.