Setting up a simple binary F-Droid repo
In this article I want to show how to set up a simple binary repo for use with any F-Droid client. It won’t be as convenient as Repomaker (instead of a GUI we’ll have to do some command-line work), but on the pro side you’ll be always up-to-date with the tools the F-Droid project itself uses, and thus can easily get help there. My guide here is targeted at Debian-based systems; if you use something else, you’ll need to substitute (e.g. the package installer commands).
FdroidServer
fdroidserver is what the F-Droid project itself uses. And its setup as „simple binary repo“ is what the IzzyOnDroid repo runs on.
While there’s an fdroidserver
package in the repos of our Linux distribution, that’s usually pretty outaged1. We could have gone with that (apt install fdroidserver
) and be done with the setup, but then we’d probably run on old code the F-Droid team would have a hard time supporting us with. And we’d miss much of the newer features, plus running out of sync with the official documentation.
Hence let us use the manual approach, which also gives us more flexibility – for example it’s quite easy to get fixes or new features in as soon as they are committed: no waiting for the packagers of your distribution, just switch into the fdroidserver
directory and do a git pull
.
Installing required dependencies
Those might change over time (and e.g. a newer OpenJDK might be recommended). At the time of my writing this, we need to install:
sudo apt install openjdk-11-jdk apksigner fastjar jarwrapper androguard
sudo apt install python3-yaml python3-pyasn1-modules python3-paramiko python3-ruamel.yaml python3-git
sudo apt install python3-qrcode python3-defusedxml
# optional:
# sudo apt install yamllint
Setting up a (fake) AndroidSDK
Note: with recent versions of fdroidserver
(at least since 12/2021) this is no longer needed and can be skipped.
We’d also need parts of the Android buildtools. Installing the entire AndroidSDK is a bit overkill if you only want to run a simple binary repo (and not compile apps yourself). Fdroidserver only looks for (and needs) very few of that to run a „simple binary repo“ (mostly aapt
), so you could either go with android-tools-adb
(or directly adb
) and android-tools-fastboot
(or directly fastboot
) installed via apt install
(so your Linux system also takes care for updates) – or download the minimal ADB and Fastboot packages from IzzyOnDroid (updates may be delayed with them) and place the binaries manually – which avoids the dependencies dragged in by above packages.
With those tools available, we need to fake a real AndroidSDK to make fdroidserver believe it’s there (and to stop complaining it cannot find it). The following establishes this in the bin/android-sdk
sub-directory of your Linux home directory. My example here uses the manually downloaded files from IzzyOnDroid, which I installed into the bin/
sub-directory of my Linux home:
mkdir ~/bin/android-sdk
cd ~/bin/android-sdk
ln -s . build-tools
ln -s . platform-tools
ln -s . tools
ln -s ~/bin/adb .
ln -s ~/bin/aapt .
ln -s ~/bin/fastboot .
ln -s /etc/alternatives/keytool .
Install and set up fdroidserver
We’ve already set up the dependencies manually, and will now use the latest code from the development
repository. This of course requires you to have a working Git set up. The following assumes an installation
to /opt/fdroidserver
(to keep it easy) – you can of course use any other location of your choice (/opt
will require you to have write permission there).
cd /opt
# Get and setup the software (only required once)
git clone https://gitlab.com/fdroid/fdroidserver.git
# make an alias (best integrate it with `.bashrc`)
alias fdroid=/opt/fdroidserver/fdroid
Create your first repo
You’ll probably want to make your repository (publicly) accessible, which is usually done via a web server.
Again, you can pick any location of your choice. Going by „known structures“, let’s use /var/www/fdroid
for our example here:
# create the directory our repo shall reside in
sudo mkdir /var/www/fdroid
# have it owned by us, but let the web server have its access permissions via group
sudo chown <MyUser>:www-data /var/www/fdroid
sudo chmod 755
# initialize the repo
cd /var/www/fdroid
fdroid init
# this will complain about "No Android SDK found" (but initialize the repo fine). So let’s
# fix up the config, especially `keydname` while we’re on it. See below for details.
# then delete the `keystore.p12` file and run
fdroid update --create-key
# verify index and keystore
jarsigner -verify -verbose repo/index-v1.jar
keytool -keystore keystore.p12 -list -v # use the password from keystorepass in your config
# now apply some safeguards. After this, only the owner (our user) can run F-Droid operations:
sudo chmod 0600 /var/www/fdroid/config.yml /var/www/fdroid/keystore.p12
Adjustments for the config.yaml
(just look for and edit the corresponding sections):
# Only needed if a "fake AndroidSDK" was set up (or the real one was not found):
# have the sdk_path point to where we faked it. This assumes you have set it up
# in the home of the user running the `fdroid` commands later; to be on the safe
# side, just use an absulute path:
sdk_path: ~/bin/android-sdk
# details for our repo_ and archive_ (in the example, they are commented out.
# Adjust them to your liking. URLs here must point to your real web server where
# you want to make your repo publicly available).
# Basically, you’ll only need repo_ and set archive_older to 0 if you want no
# archiving at all.
# How many (older) APKs to keep when newer come in:
archive_older: 3
# to keep things simple, you MAY wish to:
make_current_version_link: false
# The distinguished name used for all keys.
# Make sure to set this BEFORE you make your repo public and better do NOT change
# it afterwards – as this defines a.o. how your index will be signed. If you change
# it later, your users will receive a signature error on update and will be confused
# (which is why my repo still runs with the "example keydname" as I’ve noticed that
# too late).
# keydname (syntax): CN=myDomain.com, O=MyOrganisationName, OU=MyDevelopmentUnit, L=MyTown, C=MyCountry
# please substitute your own values – ACME, Inc is just a place-holder here to show you how it looks like!
keydname: CN=acme.com, O=ACME, OU=ACMEDev, L=Berlin, C=DE
#--=[ if you don’t use a remote web server to publish to, you can skip the following ]=--
# serverwebroot points to the SSH counter-part on your public server
serverwebroot: www.example.com:/var/www/fdroid
# should you need a specific SSH key, you can define that as in the comment:
identity_file: ~/.ssh/fdroid_id_rsa
Now, after deleting the keystore.p12
file and re-creating it via fdroid update --create-key
, running jarsigner -verify -verbose repo/index-v1.jar
should first confirm your keydname
settings (ending with jar verified.
). Following that you’ll receive several warnings which are safe to ignore:
- entries whose certificate chain is invalid (well, we have no „chain“ because…)
- signer certificate is self-signed (yepp, we did that)
- SHA1 digest algorithm is considered a security risk (nothing we can do about that, must be fixed by fdroidserver devs)
- SHA1withRSA signature algorithm is considered a security risk (same story)
- jar contains signatures that do not include a timestamp (yupp, again)
Feeding your new repo
We have a simple binary repo here, so it should be simple with binaries. Copy some .apk
files into your new repo (make sure to place them inside repo/
– so with our above examples, this would be /var/www/fdroid/repo/
), then have fdroidserver update it and create the corresponding metadata by running fdroid update -c
. Metadata need to created only once per package, so if you e.g. now put v1 of com.example.app
in there, you won’t need to create metadata again for v2 later. On subsequent runs when only updating descriptions or apps, you’ll only need to run fdroid update
.
Recommended file naming: <package_name>_<versionCode>.apk
– so with our dummy example, the file should be /var/www/fdroid/repo/com.example.app_1.apk
.
fdroid update -c
will now have generated an initial metadata file for our new app(s), which can be found in the metadata/
sub-directory. The name again corresponds to the package name, and in our example would be /var/www/fdroid/repo/com.example.app.yml
. A reference to all available fields can
be found in F-Droid’s Build Metadata Reference. As we’re talking about a simple binary repo here, all build-specific data can be skipped for us. Let me show a basic example from an existing app in my repo for what’s needed for starters:
Categories:
- Money
License: MIT
AuthorName: Zap
AuthorEmail: zap@jackmallers.com
AuthorWebSite: https://www.zaphq.io/
SourceCode: https://github.com/LN-Zap/zap-android
IssueTracker: https://github.com/LN-Zap/zap-android/issues
Translation: https://github.com/LN-Zap/zap-android/blob/master/docs/TRANSLATING.md
AutoName: Zap
Summary: Bitcoin Lightning Wallet
Description: |-
<p><i>Zap</i> Wallet makes Bitcoin usable for everyone. Trustlessly send and
receive Bitcoin instantly with minimal fees via the Lightning Network.
Manage your private keys, multiple wallets, and open channels, to get
connected with peers on the Lightning Network and start transacting today.
Zap is available on all platforms, so you can stay connected and transact
whether you are at home or on the move.</p>
<p><i>Zap</i> is also available for iOS, Mac, Linux and Windows.</p>
ArchivePolicy: 1 versions
The Author*
fields are optional and can be skipped, same for IssueTracker
, Translation
and AutoName
. I’ve included the use of ArchivePolicy
here as it might come in handy: it says to only ever keep 1 APK in the repo and move older ones to archive/
where you then can simply rm *.apk
to clean up should you not serve it publicly.
Syncing to a remote
As this was most likely your development machine, and the real website resides somewhere else, you need to create the proper remote setup as well. So go to your web server for that and…
# create the directory our repo shall reside in
sudo mkdir /var/www/fdroid
# give the web server read+exec access, and the user you connect to via rsync read+write+exec
sudo chown <MyUser>:www-data /var/www/fdroid
sudo chmod 755
Now, to publish your updated local repo, simply run fdroid deploy
from within your local repository (in our example, from within /var/www/fdroid
).
Some optional, but recommended adjustments to your webserver config
When a user wants to share an app link out of the official F-Droid client app, F-Droid cannot know about your server setup. Thus it constructs an URL similar to the structures used at f-droid.org – which you will need to let your web server know about so it redirects properly. Details on that can be found here. This is about the link pointing to app details looked up by web browser, thus the target depends on how you have set that front-end up (and which one you use – maybe part of a separate article).
Keep your software up-to-date
For those packages installed via apt
, our Linux system will take care. If you installed the adb
binaries manually, you’ll have to manually check for updates. That leaves the fdroidserver
software we’ve installed via Git. So from time to time you should cd
into that directory (in our example here, cd /opt/fdroidserver
) and run git pull
.
Fine Tuning
Continued with the follow-up article: Extend the „simple binary repo“: Screenshots & more.
References
- F-Droid Server Manual
- Setting up your own app store with F-Droid
- F-Droid Documentation
- a Docker container implementing the above recipe
- scripts to automatically set up an Apache based web server on Debian for use with an F-Droid repository, e.g. on a „blank machine“ at a web hoster
-
update: for users of Ubuntu, theres also a PPA available. ↩︎