How to run script on startup on Ubuntu 22.04
Jammy Jellyfish Server/Desktop
10 June 2022 by Korbin Brown
The purpose of this article is to configure a script such as a Bash script
or Python script to run upon system startup in Ubuntu 22.04 Jammy Jellyfish
Server/Desktop.
In this tutorial you will learn:
- How to create Systemd service unit
- How to create a simple disk space check script
- How to set permissions to Systemd service unit file
- How to set script permissions
- How to enable Systemd service unit to run at the system startup
How to run script on startup on Ubuntu 22.04 Jammy Jellyfish Server/Desktop
Software Requirements and Linux Command Line Conventions
Category | Requirements, Conventions or Software Version Used
|
System | Ubuntu 22.04 Jammy Jellyfish
|
Software | N/A
|
Other | Privileged access to your Linux system as root or via the sudo
command.
|
Conventions | # – requires given linux commands to be executed with root
privileges either
directly as a root user or by use of sudo command
$ – requires given linux commands to be executed as a regular non
-privileged user
|
How to run script on startup
on Ubuntu 22.04 step by step instructions
The Ubuntu 22.04 is based on Systemd hence the simplest and recommended way
to run a script on startup is to create a Systemd service file and execute
any script such as bash, python etc, via this service during the system
boot.
The below steps will show you to run an example bash script which reports
disk space usage of the /home directory and saves the report in the /root
directory every time the Ubuntu 22.04 system boots.
Step 1 First, create a Systemd service file as in an example below. We
will
store this file as /etc/systemd/system/disk-space-check.service.
- [Unit]
- After=network.target
-
- [Service]
- ExecStart=/usr/local/bin/disk-space-check.sh
-
- [Install]
- WantedBy=default.target
After:
Instructs systemd on when the script should be run. In our case
the
script will run after network connection. Other example could be
mysql.target etc.
ExecStart:
This field provides a full path to the actual script to be
executed on startup
WantedBy:
Into what boot target the systemd unit should be installed
Note
For more information on how to create Systemd service unit execute the man
systemd.unit command.
Step 2 Create a script to be executed on Ubuntu system startup. As
specified
in the above Step 1, the path and the name of the new script in our example
will be /usr/local/bin/disk-space-check.sh
.
The below is an example of such script:
- #!/bin/bash
- ### BEGIN INIT INFO
- # Provides: haltusbpower
- # Required-Start: $all
- # Required-Stop:
- # Default-Start: 2 3 4 5
- # Default-Stop:
- # Short-Description: Halts USB power...
- ### END INIT INFO
-
- date > /root/disk_space_report.txt
- du -sh /home/ >> /root/disk_space_report.txt
Step 3 Set appropriate permissions for both, the Systemd service unit and
script:
$ sudo chmod 744 /usr/local/bin/disk-space-check.sh
$ sudo chmod 664 /etc/systemd/system/disk-space-check.service
Step 4 Next, enable the service unit:
- $ sudo systemctl daemon-reload
- $ sudo systemctl enable disk-space-check.service
Step 5 Now you are ready to reboot your system. Once the system boots
you
should see the following file containing disk space usage within your /root
directory:
$ sudo ls /root/
disk_space_report.txt
Closing Thoughts
In this tutorial, we saw how to configure Ubuntu 22.04 to run a script upon
each system startup. This is a handy feature for system administrators to
implement in order to make sure a Bash or Python script is executed every
time Ubuntu loads in from a system reboot.
Related Linux Tutorials:
=======================================================
multi-user.target
1.) multi-user.target is basically the closest equivalent of classic
SysVinit runlevel 3 that systemd has. When a systemd system boots up,
systemd is trying to make the system state match the state specified by
default.target - which is usually an alias for either graphical.target or
multi-user.target.
multi-user.target normally defines a system state where all network services
are started up and the system will accept logins, but a local GUI is not
started. This is the typical default system state for server systems, which
might be rack-mounted headless systems in a remote server room.
graphical.target is another possible alias for default.target. Normally it's
defined as a superset of the multi-user.target: it includes everything the
multi-user.target does, plus the activation of a local GUI login. So kind of
like runlevel 5 in classic SysVinit.
The line WantedBy=multi-user.target in a service is essentially the same as
specifying "this service should start in runlevels 3, 4 and 5" in SysVinit
systems: it tells systemd that this service should be started as part of
normal system start-up, whether or not a local GUI is active.
However, WantedBy is separate from the enabled/disabled state: so in another
sense, it's sort of a "preset": it determines under what conditions the
automatic start may happen, but only when the service is enabled in the
first place.
2.) if you omit the WantedBy=multi-user.target line and no other enabled
service includes a Requires=your.service or Wants=your.service in its
service definition, your service will not be started automatically.
systemd works on dependencies, and at boot time, if nothing Requires or
Wants your service, it won't be started even if the service is enabled.
Sure, you could edit your default.target to add or delete Requires or Wants
lines for any services you want started at boot time - but so that you can
just drop a new service file into the system and have it work by default
(which makes things very easy for software package managers), systemd has
the WantedBy and RequiredBy keywords which can be used to insert Wants and
Requires-type dependencies (respectively) from "the other end".
3.) You should omit the line if you don't want the service to be ever
started automatically at boot time, or this service is a part of a chain of
dependencies you've defined explicitly.
For example, you might be refactoring server application A and for some
reason or another decide to split some optional functionality off it into a
separate service B, to allow the user the choice of not installing it if it
isn't needed. You could then make service B a separate service-B.rpm, and
define B.service with WantedBy=A.service to make systemd start up service B
automatically whenever service A is started - but only when service-B.rpm is
actually installed.
Note that a Wants or WantedBy only says that the system should startup one
service whenever another service or target is also started, but it specifies
nothing at all about the startup/shutdown order. If you need service B to be
already running when service A starts up, you'd need to add Before=A.service
in the B.service file to explicitly specify the start-up order dependency.
4.) Anytime you do want the service to have the capability of being started
automatically at boot time, and there are no other dependencies already
edited Mar 15, 2019 at 6:57 answered Mar 14, 2019 at 22:51
telcoM's user avatar
88.8k33 gold badges116116 silver badges237237 bronze badges
- Cool! lots of good info here. "Note that a Wants or WantedBy only says
that the system should startup one service whenever another service [edit:]
or target is also started, but it specifies nothing at all about the
startup/shutdown order." - unfortunately the edit is not quite right, it is
more complicated. man systemd.target says when you are wanted by a target,
you are also automatically ordered before the target. This explains why the
logs show graphical.target is only "started" after all the services are.
Unless the wanted unit (or the target?) has DefaultDependencies=no. –
sourcejedi
Mar 16, 2019 at 14:04
Does this apply for Type=oneshot services which are intended to be
triggered by something else (like a notification service)? Would the oneshot
be run also for each boot? –
nealmcb May 30 at 4:17
@nealmcb If you want the oneshot be triggered for each boot, then you'd
put in the [Install] Wanted-By=.target; but if you want it to only be
triggered by your "something else", then you'd omit it. –
telcoM May 30 at 5:43
=======================================================
Answer 17
If you remove WantedBy=multi-user.target, then systemctl enable your-example
-here will (noisily) fail to do anything.
graphical.target
If you install pure systemd from the source, the "default target" that it
boots to is graphical.target.
Starting graphical.target starts multi-user.target, plus whatever unit(s)
are required to provide a graphical user interface. This extra complexity
was arranged in an attempt to emulate legacy "runlevels".
You really should ignore / gloss over the "runlevel" emulation; it does not
work correctly anyway. Sorry! I guess the reason for emphasizing "graphical"
v.s. "multi-user" historically is that graphics software is 1) not as robust
and mature as the rest of the system and 2) requires a lot of resources.
Typically only a few units are specific to graphical.target. There is a
single service for the GUI itself like gdm.target. There are a few support
services that are mostly used by the GUI here as well.
Edit: Googling suggests that if you don't have a GUI installed, but the
"default target" has been left as graphical.target, then systemd might log a
warning. "Cannot add dependency job for unit display-manager.service,
ignoring: Unit display-manager.service failed to load: No such file or
directory." We want to avoid littering our logs with unnecessary warnings.
So if you did not install a GUI, it is good to use systemctl set-default
multi-user. Although the install system for your OS might have taken care of
this for you already. Other than that, I am strongly in favour of apathy in
this matter :-).
sysinit.target
Some services and other types of units are "involved in early boot". They
are defined to start Before=sysinit.target - either directly or indirectly.
Most services are only started After=sysinit.target - this is automatically
the case, unless the service sets DefaultDependencies=no.
multi-user.target
Most example services do not fall under either of the above categories,
therefore we attach them to multi-user.target. This includes most network
services (e.g. a web server), which are the archetypal system service.
dynamically activated services
Another possibility you might see, is a service unit that is not started
automatically at boot. So it would not need WantedBy=multi-user.target. The
service can instead be triggered or "activated" by something else.
One example of this is a dbus activated service. Dbus can be configured to
start your service on-demand, when a dbus call is made to the service.
For network services, you can use socket-activated services. This might be
easier to find details about, because all the configuration is in systemd
units. For example sshd.socket or ssh.socket is typically available to
activate ssh@.service or sshd@.service. Although, I think it is more common
to start the sshd service at boot time.
As always, the above simplifies and omits details which did not seem to be
required.
Share
Improve this answer
Follow
edited Mar 16, 2019 at 14:09
answered Mar 14, 2019 at 22:31
sourcejedi's user avatar
sourcejedi
48.6k1717 gold badges145145 silver badges302302 bronze badges
Add a comment
4
The multi-user.target is a semantic name, that is, it is associated with a
meaning. Allow me to demonstrate the concept with a counterexample. I will
make the argument that the decision to use multi-user.target depends on the
context.
If you were to create a systemd user unit configuration rather than a system
unit configuration, you might naively follow the conventions of the systemd
system units and use multi-user.target1.
Explanation by Counter-Example
Consider the file /home/jonathan/.config/systemd/user/coolstuff.service
This user will only by used with respect to user jonathan, therefore it
hardly makes sense to call my target "multi-user.target".
[Unit]
Description=Does some cool stuff.
[Service]
ExecStart=/bin/bash -c '/usr/bin/echo "Cool stuff" >> %h/coolstuff.txt'
[Install]
WantedBy=user.target
Note how I opted to use WantedBy=user.target. This is because the scope of
this context is my user account, therefore I opted to use my own semantic
conventions. In other words, multiple users will not be affected by this
unit. On the system level however, it makes more sense to follow
standardized conventions because of the parallel startup sequence. During
startup, many procedures converge on multiple targets. The multi-user.target
is semantically associated with the idea of "read for user engagement /
interaction with the system" (without a windowing system as telcoM
mentioned), therefore it is a safe bet for most system unit files.
Footnotes
Although it would not make sense from within this context, it would
still work.
Share
Improve this answer
Follow
edited Dec 20, 2021 at 10:54
answered May 27, 2020 at 7:47
Jonathan Komar's user avatar
Jonathan Komar
6,04477 gold badges3333 silver badges5252 bronze badges
I doubt it would work. The expectation here is that the service would
not be started because the multi-user.target is simply not known to a
systemd user unit configuration. Creating a systemd user unit configuration
rather than a system unit configuration implies running a systemd --user
instance which has its own targets. You'd want to use the default.target
then. –
duise
May 1 at 8:44
Well @duise, it is not a question of whether it would work. It will work
provided you have a target called user.target. As mentioned explicitly, ”I
opted to use my own semantic conventions.“ All targets are semantic
conventions that serve as latches. You can list your targets using systemctl
list-units —user —type=target. Creating targets is beyond the scope of
this question. –
Jonathan Komar
May 6 at 8:54
=======================================================