JRehkemper.de

Setup a local offline Mirror for Flatpaks

Flatpak is a great way to distribute Packages, since it is distribution-agnositc. Furthermore it is open source and everyone can host their own repository to distribute their software.
That’s great but in reality most of the apps are in the big Flathub Repository, which makes for a greate appstore-like experience. Wheather the Packages are directly uploaded to Flathub or just mirrored there does not make a difference for us end-users.

But what if you want to use Flatpaks in an offline environment?
There is the possibility to create an offline repository and transfer it with an usb-drive, which is great, but it does not scale very well.

In my case I wanted a server on the network, which is allowed to mirror the packages from Flathub and distribute them to my clients, which have no internet access. Just like we are doing it with RPMs for years.

In this article I will describe how I got it working.

Flatpak und OSTree

To create a Flatpak mirror we need to focus on OSTree for a second. Or libostree to be specific (ostree mostly refers to the cli-tool, while libostree is the underlying technology).

What is OSTree

libostree is like git for filesystems. Basicly it is a way to transfer and update a unified filesystem to clients, just like an image, but with less overhead.
When I create an Image of a filesystem and deploy it to my client, the whole Image has to be transfered. That’s expected. But if I now need to update my Image and want to push it to my client, the client needs to download the whole image again. That is a lot of overhead, for maybe just a small change.
libostree solves this by using diffs, just like git does. Therefore we can just ship the diff to our client and it can apply all the changes.
One thing worth mentioning is, that every update with ostree requires a reboot to load the new version. No matter how small the change.

OSTree Repositories

OSTree Filesystems are stored in Repositories. Every Filesystem or deployment gets it’s own Ref (if you know git, just think of Refs as a Branch). That way I can have different configurations for different clients in the same repository.
If I do an update, my client can contact the repository server and request the diff of the new update. Since the client know on which Ref (Branch) it is, it will always get the right updates.

Back to Flatpak

That’s all greate, but what has ostree to do with flatpak?
Flatpak uses ostree repositories to distribute software. Every Flatkpak installs a certain filestructure on the client, usually in /var/lib/flatpak/app. Therefore they can be treated like regular ostree filesystem on the repository, eventhough they are not complete filesystems.
Every app gets it’s own Ref in the repository. And by specifing the Ref we can selectivly mirror Flatpaks to our own repository.

Setup of the Server

Now I’ve talked a lot about the theory behind all this. Let’s start installing the mirror server.
I am using an AlmaLinux (RedHat-Based) Server, but you should be able to adapt most of it to other Distributions as well.

Webserver

Of course we need a Webserver. I will use nginx, but httpd should work as well.

$ sudo dnf install nginx

Next I will change the root path in the nginx.conf to /var/www/html/ but that is just optional. For easier troubleshooting I will allow autoindex as well. That way I can browse the filestructure with a webbrowser, but that is not strictly necessary.

$ sudo vim /etc/nginx/nginx.conf
server {
	root /var/www/html;
    autoindex on;
}

Now I will create the directory for my webserver

$ sudo mkdir /var/www/html

and start the service.

$ sudo systemctl enable --now nginx

Next we need to open the firewall-ports.

$ sudo firewall-cmd --add-port=80/tcp
$ sudo firewall-cmd --runtime-to-permanent

Create the OSTree Repository

Next we will create the Repository on the webserver. Therefore we need to install ostree and flatpak.

$ sudo dnf install flatkpak ostree

Next we can initialize a new reposiotry. This will create a new directory named like the repository. Make sure that you are currently in /var/www/html, otherwise the directory will be in the wrong location.
The repo-name may be whatevery you like, but for the mirror to work, we need to specify the collection-id of org.flathub.Stable.

$ pwd
/var/www/html

$ ostree --repo=org.flathub.stable init --mode=archive --collection-id=org.flathub.Stable

Now we can tell the repo that it will mirror flathub, by giving it a remote repository.

$ ostree --repo=org.flathub.stable remote add --set gpg-verify-summary=false flathub https://dl.flathub.org/repo/

Usually you would want to import the gpg-key to verify the packages, but that didn’t work in my case, so I disabled the verifiction for now.
You can double check that in the org.flathub.Stable/config.
There should be the follwing line.

[remote "flathub"]
gpg-verify=false

Last but not least, we need to create a summary file. The summary is somewhat like the repodata of an rpm repository. It provides metadata about all the packages in the repository.
We need to update this summary everytime, we add or update a package. Otherwise clients will never notice the changes.

flatpak build-update-repo .

Mirroring Packages

Now that the groundwork is done, we can start to mirror our first package. The basic command looks like this.

ostree --repo=<path/to/repo> pull --mirror <remote> <ref>

The repois our local directory/repository.
The remote is Flathub in our case.
The ref specifies the app we want to mirror.
Refs follow the following structure:

<app or runtime>/<id>/<arch>/<version>

# example
app/org.gnome.gedit/x86_64/stable
runtime/org.gnome.Platform/x86_64/47

So if we want to mirror gedit we would run the follwing command. Remember to update the summary.

$ ostree --repo=org.flathub.stable pull --mirror flathub app/org.gnome.gedit/x86_64/stable
$ flatpak build-update-repo org.flathub.stable

Setup the Client

Now we need a client to install the Packages onto. Keep in mind, in this scenario the client has no internet-access.
Let’s start by installing Flatpak.

$ sudo dnf install flatkpak

Next we need to specify our repository as the remote for this client. That way it knows where to look for packages and updates.

$ flatpak remote-add --no-gpg-verify flathub http://<repo-server>/org.flathub.stable

Again, since we did not setup gpg-keys, we have to disable the verification.

Now if we try to install gedit, we get an error.

flatpak install org.gnome.gedit
error: The application org.gnome.gedit/x86_64/stable requires the runtime org.gnome.Platform/x86_64/47 which was not found

That’s because every Flatpak needs a runtime, which is specified in the manifest of the Flatpak.
But that is not a problem. We can simply mirror the runtime on the server as well.
There will be alot of Packages sharing the same runtime, so you don’t have to mirror a new runtime for every new app.

Back on the Repo-Server, just execute another mirror command and update the summary.

$ ostree --repo=org.flathub.stable/ pull --mirror flathub runtime/org.gnome.Platform/x86_64/47
$ flatpak build-update-repo org.flathub.stable

And now if we run the same install command again on our client, the installation succeeds.

Managing your Repository

If you want to mirror new updates for your software, just pull it again.

$ ostree --repo=org.flathub.stable pull --mirror flathub app/org.gnome.gedit/x86_64/stable
$ flatpak build-update-repo org.flathub.stable

If you want to list all Packages in your Repository, you have to list all your refs.

$ ostree refs --repo /var/www/html/org.flathub.stable

Should you want to delete a Package on your repository, you need to delete the corresponding ref.

$ ostree refs --repo /var/www/html/org.flathub.stable --delete org.gnome.gedit
$ flatpak build-update-repo org.flathub.stable
profile picture of the author

Jannik Rehkemper

I'm an professional Linux Administrator and Hobby Programmer. My training as an IT-Professional started in 2019 and ended in 2022. Since 2023 I'm working as an Linux Administrator.