// LEARN LINUX TV • ARTICLE

How to Keep Flatpaks Updated with a systemd Service

Tired of running flatpak update by hand? In this tutorial, you’ll learn how to create a systemd service and timer that keeps your Flatpak apps updated automatically in the background. We’ll write the unit files, enable the timer, check that it’s working, and look at the logs. This works on any distro that uses systemd. It’s also a practical introduction to systemd timers, which you can use to schedule just about any task on Linux.

If you’re finding this content helpful, please consider supporting me! For example, you can check out my 30% Linux Foundation Course/Cert Discount or my brand-new Switching to Linux book.

YouTube player

Overview

And first, I want to give you a brief overview of what we’ll be building today. Like I mentioned earlier, I’m going to show you how to set up automatic updates for Flatpaks, but how exactly are we going to go about it?

We’re going to create two things, a service and a timer. Services and Timers are types of Systemd Units, and specifically the service will do the bulk of the update work, while the timer will be what triggers it to start in the first place. What we’ll do in the next section is start building these, and I’ll explain everything as we go.

For a bit of a preview, the Systemd service we create can be run manually at any time, and when you start it up, it will go through your Flatpaks and update them, and it’ll even go as far as to remove unused dependencies too. In this case, I’m starting the service, and just like any other service we can follow the output with journalctl.

The timer that we’ll be creating will allow us to trigger this service automatically, so you won’t have to remember to start it. But you can always manually start the service anytime to update flatpaks, you don’t have to wait for the timer.

There’s a couple more things to know before we begin. First, this tutorial will only work on distros that are based on systemd. A simple test is to run this command:

ps -p 1 -o comm=

If it returns “systemd”, then that means you’re good to go. If it shows something else, that probably means your distro doesn’t use systemd and this tutorial won’t work in your configuration.

Finally, this tutorial assumes you’ve already set up flatpak support on your distro. Most distributions support this, and some even have it built in. If you haven’t set up Flatpak yet, you can visit the URL that you see on the screen to view the documentation page. Just choose your distro and follow the instructions. You can also check out my dedicated Flatpak video, and I’ll leave a card for that right here.

So, if you’re using a distro based on Systemd and you’ve already set up Flatpak, then we can continue along and start building this solution.

The Service Unit

The first thing we’re going to do is build the service unit. As an aside, let’s clear up some confusion about systemd-related terms. A “Unit” in systemd refers to an object that Systemd can control, such as services, mounts, timers, and so on. So a “service” in Systemd is a type of Unit, and the timer we’ll be building later is also a type of Unit.

Anyway, to start building this, we’ll start by creating the service file itself:

sudo nano /etc/systemd/system/flatpak-manager.service

Inside the file, we’ll place the following (explain it):

[Unit]
Description=Flatpak Manager
Documentation=man:flatpak(1)
Wants=network-online.target
After=network-online.target

# Laptops: don't pull down hundreds of MB while on battery.
# Always true on a desktop, so it's safe to leave in.
ConditionACPower=true

[Service]
Type=oneshot

# This unit runs flatpak as root (no desktop session), so root's XDG_DATA_DIRS
# doesn't list the Flatpak export dirs -- which makes `flatpak update` print a
# harmless "not in the search path set by XDG_DATA_DIRS" warning. Point it at the
# system export dir here so the update runs cleanly.
Environment=XDG_DATA_DIRS=/var/lib/flatpak/exports/share:/usr/local/share:/usr/share

# Update flatpak packages (system):
ExecStart=/usr/bin/flatpak --system update --noninteractive

# Remove unused flatpak runtimes (system).
# The leading "-" means a failure here won't fail the whole unit:
ExecStart=-/usr/bin/flatpak --system uninstall --unused --noninteractive

# Configure scheduling options:
TimeoutStartSec=30min
Nice=10
IOSchedulingClass=idle

# No [Install] section: this unit is started by the timer, not enabled directly.

And now that we’ve created a new unit, we’ll reload systemd:

sudo systemctl daemon-reload

And we can now also check the status of our new unit:

systemctl status flatpak-manager.service

You’ll notice that the service isn’t enabled, or at least it shouldn’t be. This refers to whether or not the service automatically starts at boot. In this case, we don’t want to enable it because there’s no need for that – the timer will start it. But, just like any other service, we can always start it manually anytime we want to update Flatpaks:

sudo systemctl start flatpak-manager.service

As soon as we launch it, our Flatpaks will be updated and unused dependencies will be removed. So essentially, we have half the solution in place right now. But we’re human, and we may not remember to run this service periodically, and that’s what the Timer helps us out with.

The Timer Unit

And here’s where our solution comes together. Since Systemd Timers let us launch a process, script or program at predetermined times, we can set up our flatpak manger service to run automatically. To get started, we’ll create another file:

sudo nano /etc/systemd/system/flatpak-manager.service

And now we have an empty file – and I’ll give you the contents shortly. But one thing to know is that the names should match, other than the file extension. I’ll explain why shortly, but for now let’s go over the contents of this file:

[Unit]
Description=Run Flatpak Manager daily

[Timer]
# The unit to start. Implied by the filename (flatpakmanager.service),
# spelled out here so it's obvious how the two files are linked:
Unit=flatpak-manager.service

# When to run. Try `systemd-analyze calendar daily` to preview the schedule.
OnCalendar=daily

# If the machine was off when the timer should have fired, run at next boot:
Persistent=true

# Spread the load: fire at a random point in the hour after the scheduled time.
RandomizedDelaySec=1h

[Install]
WantedBy=timers.target

Notice that in this case, we’re specifically calling out flatpak-manager.service as being the Unit to start when this timer triggers. You don’t have to include this line though, if the file names of your service and timer match (other than the extension) then Systemd will start the right service automatically, since it looks for a matching file name first. But again, we’re calling it out explicitly here – but it’s common that when you’re working with Timers they won’t include this line, as Systemd can figure it out if the names match.

Anyway, we’ll reload Systemd again:

sudo systemctl daemon-reload

And now, we’ll enable the timer. I want to reiterate – there’s no reason to start the systemd service or enable it, the timer will do that. But the timer itself does need to be started and enabled though, and we can take care of both with this command:

sudo systemctl enable --now flatpak-manager.timer

Let’s check the status:

systemctl status flatpak-manager.service

And there we go! From this point forward, our Flatpaks will automatically update in the background. And if you haven’t worked with Systemd timers before, now you’ve had some practice with that.