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 repo
is 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