26

After searching plenty through plenty a post, Youtube video, and "documentation" on the matter of systemd, I'm still at a loss.

The link (https://wiki.archlinux.org/index.php/systemd#Create_custom_target) seemed promising, but was a bit vague (to me).

Question

How would one go about creating a custom systemd target (IE: foo.target ) so that one may boot with select .service units?

Example

  1. System boots default.target (symlink of "foo.target")
  2. "foo.target" only starts a barebones X server and GUI program, say "gvim".

Reason

I'm simply looking to create a custom target for quickly launching one X program. I'd be nice to exclude all the services I don't need.

Thanks in advance!

3 Answers 3

33

Reading through man 5 systemd.unit and man 5 systemd.target tells us that unit files are used to define targets as well as everything else systemd. There is no documentation specifically on how to create a target, so it's hard to determine the how it should be done, but it is not too different from creating a service.

When you create your target, you will need to make symlinks to the target.wants directory from the systemd services directory. Then you can set/boot your target. Here's how it might look given your example.

/etc/systemd/system/foo.target

This is the target's unit file. If graphical.target is taken as an example, we can create our own target using it as a base.

[Unit]
Description=Foobar boot target
Requires=multi-user.target
Wants=foobar.service
Conflicts=rescue.service rescue.target
After=multi-user.target rescue.service rescue.target
AllowIsolate=yes

To explain the options taken from the systemd manpages;

  • Description -- Describes the target. You should understand
  • Requires -- Hard dependencies of the target. You should let the basic system start before you start your own service(s)
  • Wants -- Soft dependencies. The target does not require these to start.
  • Conflicts -- If a unit has a Conflicts setting on another unit, starting the former will stop the latter and vice versa.
  • After -- Boots after these services
  • AllowIsolate -- Really up to you and your environment. Details are available in the manpage systemd.unit(5)

/etc/systemd/system/foo.target.wants/

This is the directory where you will link the services you create/require for your target. It is equivalent to the Wants= option in the unit file. Create this directory and then create symlinks like so; ln -s /usr/lib/systemd/system/bar.service /etc/systemd/system/foo.target.wants/bar.service. This creates a symlink from bar.service in the system directory to your foo.target.wants directory.


I think creating a unit file for a service is kind of out of the scope of this answer, and that question is definitely more documented so I'll leave that out for now. When you create your unit file, just symlink it into the target.wants directory or add it to the Wants= directive.

4
  • I followed the above to create a new target and added a few targets to my service. However, none of those services is started up by systemd. Is there a complete example that demonstrates services within the newly added target working?
    – linuxfan
    Jan 5, 2017 at 18:14
  • 1
    See necromancer's stack post if you're looking for simple steps to set up a custom service to run at boot. Jan 28, 2017 at 5:17
  • @linuxfan I add foo.target to the Requires field and Before field of multi-user.target, and it like Requires: base.target foo.target. After that I reboot my Arch Linux vm, and foobar.service will run as daemon automatically.
    – L_K
    Jun 22, 2017 at 1:30
  • 3
    Nice answer, but it doesn't actually seem to work as you'd expect. 1. Just because it's in wants doesn't mean the service will start with that target. 2. The multi-user.target seems to have some kind of hidden things that make it work.
    – Otheus
    Aug 17, 2017 at 11:56
9

Something not mentioned in previous answers is that in order to get a custom systemd target to work like e.g. multi-user.target on boot, you have to specify it as part of the boot process in some way.

Basically what you want to do is check what your current default is: systemctl get-default. It will most probably be graphical.target or multi-user.target.

You then need to create a symlink in /etc/systemd/system to your new default target and make sure that your target is an extension of the boot process.

ln -s /etc/systemd/system/foo.target /etc/systemd/system/default.target

Check with:

systemctl daemon-reload
systemctl get-default

If multi-user.target was your previous default you'll want to have it configured in your custom unit like this, as mentioned by m32:

[Unit]
Description=Foobar boot target
Requires=multi-user.target
Wants=foobar.service
Conflicts=rescue.service rescue.target
After=multi-user.target rescue.service rescue.target
AllowIsolate=yes

Note the important bit here is that multi-user.target is specified as Requires. See the answer from @m32 for details on what everything means.

What you are doing here is extending the boot process with your custom unit. Setting it as the default for systemd instructs systemd to load that unit on boot. The configuration of that target then pulls in any other targets which goes on until it reaches the most basic targets. At least that's how I understand it now.

Then like mentioned in the other answers you can go about specifying your units in the Wants= directive in foo.target and add the WantedBy=foo.target to the install section of your units. Note that you still need to activate any units you want to start on boot with systemd enable foobar.service.

So to sum it up:

  1. Create your target as extension of existing targets
  2. Create the symlink to make it your default target
  3. Specify that target in all units you want to start with it
  4. Enable any units you want to start at boot that way

This document about runlevels has a bit more details: https://www.landoflinux.com/linux_runlevels_systemd.html

2

I highly suggest taking a looking at these yourself for examples before you go down that task,

vim /lib/systemd/system/*.target

Note if you're making your own target you don't have to manually link anything in.

You can just add the service to the /etc/systemd/system and run systemctl enable on it. So long as it's WantedBy or RequiredBy systemd will do all the work for you.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .