feat(gui-client): polish Linux bundling (#9181)

Tauri's `deb` and `rpm` bundler have support for configuring maintainer
scripts. We can therefore just use those instead of tearing apart the
`deb` file that it creates and rebuilding it ourselves.

Our `rpm` packaging is currently completely broken as well. I couldn't
get it to work on CentOS 9 at all due to missing dependencies, likely
introduced by our move to Tauri v2. It installs fine on CentOS 10
though, assuming that the user has the EPEL repository installed which
provides the WebView dependency. I extended the docs to reflect this.

Hence, with this PR, we drop support for CentOS 9 and now require CentOS
10. This allows us to remove a lot of cruft from our bundling process
and instead entirely rely on the Tauri provided bundler.

Lastly, for consistency with other platforms, the name of the
application in places like app drawers has been changed from "Firezone
Client" to just "Firezone".

---------

Signed-off-by: Thomas Eizinger <thomas@eizinger.io>
This commit is contained in:
Thomas Eizinger
2025-05-21 01:34:16 +10:00
committed by GitHub
parent d53deaf0d8
commit 042d03af2a
17 changed files with 59 additions and 338 deletions

View File

@@ -116,7 +116,7 @@ jobs:
- name: Upload deb / msi package
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: ${{ env.ARTIFACT_DST }}-pkg
name: ${{ env.ARTIFACT_DST }}-${{ matrix.pkg-extension }}
path: ${{ env.ARTIFACT_SRC }}.${{ matrix.pkg-extension }}
if-no-files-found: error
- name: Upload rpm package

View File

@@ -1,87 +1,9 @@
#!/usr/bin/env bash
# These steps must be synchronized with `gui-smoke-test` in `_rust.yml`.
set -euo pipefail
# Dir where all the bundles are built
BUNDLES_DIR=../target/release/bundle/deb
# Prep the RPM container
docker build . -f ../Dockerfile-rpm -t rpmbuild
# Bundle all web assets
pnpm vite build
# Get rid of any existing debs, since we need to discover the path later
rm -rf "$BUNDLES_DIR"
# Compile Rust and bundle
pnpm tauri build
# Build the RPM file
docker run \
--rm \
-v $PWD/..:/root/rpmbuild \
-v /usr/lib:/root/libs \
-w /root/rpmbuild/gui-client \
rpmbuild \
rpmbuild \
-bb src-tauri/rpm_files/firezone-gui-client.spec \
--define "_topdir /root/rpmbuild/gui-client/rpmbuild"
# Un-mess-up the permissions Docker gave it
sudo chown --recursive $USER:$USER rpmbuild
# Give it a predictable name
cp rpmbuild/RPMS/*/firezone-client-gui-*rpm "firezone-client-gui.rpm"
# Delete the deb that Tauri built. We're going to modify and rebuild it.
rm "$BUNDLES_DIR"/*.deb
# There should be only one directory in `bundle/deb`, we need to modify
# files inside that dir
INTERMEDIATE_DIR=$(ls -d "$BUNDLES_DIR"/*/)
# Delete the archives, we will re-create them.
rm "$INTERMEDIATE_DIR"/*.tar.gz
# The directory layout of `$BUNDLES_DIR` now looks like this:
# └── firezone-client-gui_1.x.y_$arch
# ├── control
# │   ├── control
# │   └── md5sums
# ├── data
# │   └── usr
# │   ├── bin
# │   │   └── firezone-client-gui
# │   ├── lib
# │   │   ├── systemd
# │   │   │   └── system
# │   │   │   └── firezone-client-tunnel.service
# │   │   └── sysusers.d
# │   │   └── firezone-client-tunnel.conf
# │   └── share
# │   ├── applications
# │   │   └── firezone-client-gui.desktop
# │   └── icons
# │   └── ...
# └── debian-binary
# Add the scripts
cp src-tauri/deb_files/postinst src-tauri/deb_files/prerm src-tauri/deb_files/preinst "$INTERMEDIATE_DIR/control/"
# Add the Tunnel service
cp ../target/release/firezone-client-tunnel "$INTERMEDIATE_DIR/data/usr/bin/"
pushd "$INTERMEDIATE_DIR"
# Rebuild the control tarball
tar -C "control" -czf "control.tar.gz" control md5sums preinst postinst prerm
# Rebuild the data tarball
tar -C "data" -czf "data.tar.gz" usr
# Rebuild the deb package, and give it a predictable name that
# `tauri-rename-linux.sh` can fix
ar rcs "../firezone-client-gui.deb" debian-binary control.tar.gz data.tar.gz
popd

View File

@@ -3,6 +3,6 @@ Categories=
Comment=Firezone
Exec={{exec}}
Icon={{icon}}
Name=Firezone Client
Name=Firezone
Terminal=false
Type=Application

View File

@@ -1,8 +0,0 @@
[Desktop Entry]
Categories=
Comment=Firezone
Exec=firezone-client-gui
Icon=firezone-client-gui
Name=Firezone Client
Terminal=false
Type=Application

View File

@@ -1,202 +0,0 @@
Name: firezone-client-gui
# mark:next-gui-version
Version: 1.4.14
Release: 1%{?dist}
Summary: The GUI Client for Firezone
URL: https://firezone.dev
License: Apache-2.0
Requires: systemd-resolved
BuildRequires: systemd-rpm-macros
# For some reason, the Ubuntu version of `rpmbuild` notices that we're providing our own WebKit and other libs, but the CentOS version doesn't. So we explicitly tell it not to worry about all these libs.
%global __requires_exclude ^(libdbus-1|libgdk-3|libgio-2.0|libglib-2.0|libgtk-3|libjavascriptcoregtk-4.1|libm|libsoup-3.0|libwebkit2gtk-4.1).so.*
%description
%prep
%pre
# Stop and disable the old service. The service may no longer exist so we ensure this never fails.
systemctl disable "$OLD_SERVICE_NAME" >/dev/null 2>&1 || true
systemctl stop "$OLD_SERVICE_NAME" >/dev/null 2>&1 || true
%build
%install
mkdir -p \
"%{buildroot}/usr/bin" \
"%{buildroot}/usr/lib/dev.firezone.client/unused"
BINS="%{_topdir}/../../target/release"
cp "$BINS/firezone-client-tunnel" "%{buildroot}/usr/bin/"
cp "$BINS/firezone-client-gui" "%{buildroot}/usr/lib/dev.firezone.client/"
cp "%{_topdir}/../src-tauri/rpm_files/gui-shim.sh" "%{buildroot}/usr/bin/firezone-client-gui"
LIBS="/root/libs/$(uname -m)-linux-gnu"
# DNF expects libc and ld-linux to be packaged, because it checks the exes with ldd or something, but if we actually use them, the GUI process will segfault. So just dump them somewhere unused.
UNUSED_DIR="%{buildroot}/usr/lib/dev.firezone.client/unused"
%ifarch aarch64
cp \
"$LIBS/ld-linux-aarch64.so.1" \
"$LIBS/libc.so.6" \
"$UNUSED_DIR"
%endif
%ifarch x86_64
cp \
"$LIBS/ld-linux-x86-64.so.2" \
"$LIBS/libc.so.6" \
"$UNUSED_DIR"
%endif
cp \
"$LIBS/libappindicator3.so.1" \
"$LIBS/libayatana-appindicator3.so.1" \
"$LIBS/libayatana-ido3-0.4.so.0" \
"$LIBS/libayatana-indicator3.so.7" \
"$LIBS/libdbus-1.so.3" \
"$LIBS/libdbusmenu-glib.so.4" \
"$LIBS/libdbusmenu-gtk3.so.4" \
"$LIBS/libfreetype.so.6" \
"$LIBS/libgdk-3.so.0" \
"$LIBS/libgio-2.0.so.0" \
"$LIBS/libglib-2.0.so.0" \
"$LIBS/libgmodule-2.0.so.0" \
"$LIBS/libgtk-3.so.0" \
"$LIBS/libicudata.so.70" \
"$LIBS/libicui18n.so.70" \
"$LIBS/libicuuc.so.70" \
"$LIBS/libjavascriptcoregtk-4.1.so.0" \
"$LIBS/libjpeg.so.8" \
"$LIBS/libm.so.6" \
"$LIBS/libmanette-0.2.so.0" \
"$LIBS/libpcre.so.3" \
"$LIBS/libpcre2-8.so.0" \
"$LIBS/libsoup-3.0.so.0" \
"$LIBS/libstdc++.so.6" \
"$LIBS/libwayland-client.so.0" \
"$LIBS/libwayland-server.so.0" \
"$LIBS/libwebkit2gtk-4.1.so.0" \
"$LIBS/libxcb.so.1" \
"$LIBS/libxcb-shm.so.0" \
"$LIBS/libX11.so.6" \
"$LIBS/libX11-xcb.so.1" \
"%{buildroot}/usr/lib/dev.firezone.client/"
ls -lash "%{buildroot}/usr/lib/dev.firezone.client"
WEBKIT_DIR="$(uname -m)-linux-gnu/webkit2gtk-4.1"
mkdir -p "%{buildroot}/usr/lib/$WEBKIT_DIR"
cp \
"/root/libs/$WEBKIT_DIR/WebKitNetworkProcess" \
"/root/libs/$WEBKIT_DIR/WebKitWebProcess" \
"%{buildroot}/usr/lib/$WEBKIT_DIR"
ICONS="%{buildroot}/usr/share/icons/hicolor"
mkdir -p \
"%{buildroot}/usr/lib/systemd/system" \
"%{buildroot}/usr/lib/sysusers.d" \
"%{buildroot}/usr/share/applications" \
"$ICONS/32x32/apps" \
"$ICONS/128x128/apps" \
"$ICONS/512x512/apps"
cp \
"%{_topdir}/../src-tauri/deb_files/firezone-client-tunnel.service" \
"%{buildroot}/usr/lib/systemd/system/"
cp \
"%{_topdir}/../src-tauri/deb_files/sysusers.conf" \
"%{buildroot}/usr/lib/sysusers.d/firezone-client-tunnel.conf"
cp \
"%{_topdir}/../src-tauri/rpm_files/firezone-client-gui.desktop" \
"%{buildroot}/usr/share/applications/"
cp \
"%{_topdir}/../src-tauri/icons/32x32.png" \
"$ICONS/32x32/apps/firezone-client-gui.png"
cp \
"%{_topdir}/../src-tauri/icons/128x128.png" \
"$ICONS/128x128/apps/firezone-client-gui.png"
cp \
"%{_topdir}/../src-tauri/icons/icon.png" \
"$ICONS/512x512/apps/firezone-client-gui.png"
%files
/usr/bin/firezone-client-tunnel
/usr/bin/firezone-client-gui
/usr/lib/dev.firezone.client/firezone-client-gui
/usr/lib/dev.firezone.client/libappindicator3.so.1
/usr/lib/dev.firezone.client/libayatana-appindicator3.so.1
/usr/lib/dev.firezone.client/libayatana-ido3-0.4.so.0
/usr/lib/dev.firezone.client/libayatana-indicator3.so.7
/usr/lib/dev.firezone.client/libdbus-1.so.3
/usr/lib/dev.firezone.client/libdbusmenu-glib.so.4
/usr/lib/dev.firezone.client/libdbusmenu-gtk3.so.4
/usr/lib/dev.firezone.client/libfreetype.so.6
/usr/lib/dev.firezone.client/libgdk-3.so.0
/usr/lib/dev.firezone.client/libgio-2.0.so.0
/usr/lib/dev.firezone.client/libglib-2.0.so.0
/usr/lib/dev.firezone.client/libgmodule-2.0.so.0
/usr/lib/dev.firezone.client/libgtk-3.so.0
/usr/lib/dev.firezone.client/libicudata.so.70
/usr/lib/dev.firezone.client/libicui18n.so.70
/usr/lib/dev.firezone.client/libicuuc.so.70
/usr/lib/dev.firezone.client/libjavascriptcoregtk-4.1.so.0
/usr/lib/dev.firezone.client/libjpeg.so.8
/usr/lib/dev.firezone.client/libm.so.6
/usr/lib/dev.firezone.client/libmanette-0.2.so.0
/usr/lib/dev.firezone.client/libpcre.so.3
/usr/lib/dev.firezone.client/libpcre2-8.so.0
/usr/lib/dev.firezone.client/libsoup-3.0.so.0
/usr/lib/dev.firezone.client/libstdc++.so.6
/usr/lib/dev.firezone.client/libwayland-client.so.0
/usr/lib/dev.firezone.client/libwayland-server.so.0
/usr/lib/dev.firezone.client/libwebkit2gtk-4.1.so.0
/usr/lib/dev.firezone.client/libxcb.so.1
/usr/lib/dev.firezone.client/libxcb-shm.so.0
/usr/lib/dev.firezone.client/libX11.so.6
/usr/lib/dev.firezone.client/libX11-xcb.so.1
/usr/lib/systemd/system/firezone-client-tunnel.service
/usr/lib/sysusers.d/firezone-client-tunnel.conf
/usr/share/applications/firezone-client-gui.desktop
/usr/share/icons/hicolor/32x32/apps/firezone-client-gui.png
/usr/share/icons/hicolor/128x128/apps/firezone-client-gui.png
/usr/share/icons/hicolor/512x512/apps/firezone-client-gui.png
%ifarch aarch64
/usr/lib/aarch64-linux-gnu/webkit2gtk-4.1/WebKitNetworkProcess
/usr/lib/aarch64-linux-gnu/webkit2gtk-4.1/WebKitWebProcess
/usr/lib/dev.firezone.client/unused/ld-linux-aarch64.so.1
/usr/lib/dev.firezone.client/unused/libc.so.6
%endif
%ifarch x86_64
/usr/lib/x86_64-linux-gnu/webkit2gtk-4.1/WebKitNetworkProcess
/usr/lib/x86_64-linux-gnu/webkit2gtk-4.1/WebKitWebProcess
/usr/lib/dev.firezone.client/unused/ld-linux-x86-64.so.2
/usr/lib/dev.firezone.client/unused/libc.so.6
%endif
%post
%systemd_post firezone-client-tunnel.service
%preun
%systemd_preun firezone-client-tunnel.service
%postun
%systemd_postun_with_restart firezone-client-tunnel.service

View File

@@ -1,6 +0,0 @@
#!/usr/bin/env bash
# Installed as `/usr/bin/firezone-client-gui` on RPM systems since we bundle a bunch of libs
set -euo pipefail
LD_LIBRARY_PATH=/usr/lib/dev.firezone.client exec /usr/lib/dev.firezone.client/firezone-client-gui

View File

@@ -9,18 +9,35 @@
"shortDescription": "Firezone",
"linux": {
"deb": {
"preInstallScript": "./linux_package/preinst",
"postInstallScript": "./linux_package/postinst",
"preRemoveScript": "./linux_package/prerm",
"files": {
"/usr/lib/systemd/system/firezone-client-tunnel.service": "./deb_files/firezone-client-tunnel.service",
"/usr/lib/sysusers.d/firezone-client-tunnel.conf": "./deb_files/sysusers.conf"
"/usr/lib/systemd/system/firezone-client-tunnel.service": "./linux_package/firezone-client-tunnel.service",
"/usr/lib/sysusers.d/firezone-client-tunnel.conf": "./linux_package/sysusers.conf",
"/usr/bin/firezone-client-tunnel": "../../target/release/firezone-client-tunnel"
},
"desktopTemplate": "./deb_files/firezone-client-gui.desktop"
"desktopTemplate": "./linux_package/firezone-client-gui.desktop"
},
"rpm": {
"postInstallScript": "./linux_package/postinst",
"preRemoveScript": "./linux_package/prerm",
"files": {
"/usr/lib/systemd/system/firezone-client-tunnel.service": "./linux_package/firezone-client-tunnel.service",
"/usr/lib/sysusers.d/firezone-client-tunnel.conf": "./linux_package/sysusers.conf",
"/usr/bin/firezone-client-tunnel": "../../target/release/firezone-client-tunnel"
},
"desktopTemplate": "./linux_package/firezone-client-gui.desktop"
}
},
"targets": ["deb", "msi"],
"targets": ["deb", "msi", "rpm"],
"windows": {
"wix": {
"bannerPath": "./win_files/banner.png",
"componentRefs": ["RemoveOldFirezoneService", "FirezoneClientTunnelService"],
"componentRefs": [
"RemoveOldFirezoneService",
"FirezoneClientTunnelService"
],
"dialogImagePath": "./win_files/install_dialog.png",
"fragmentPaths": ["./win_files/service.wxs"],
"template": "./win_files/main.wxs"

View File

@@ -5,24 +5,16 @@
set -euox pipefail
# For debugging
ls "$TARGET_DIR/release" "$TARGET_DIR/release/bundle/deb"
ls "$TARGET_DIR/release" "$TARGET_DIR/release/bundle/deb" "$TARGET_DIR/release/bundle/rpm"
# Used for release artifact
# In release mode the name comes from tauri.conf.json
# Using a glob for the source, there will only be one exe and one deb anyway
cp "$TARGET_DIR/release/firezone-client-gui" "$BINARY_DEST_PATH"
cp "$TARGET_DIR/release/firezone-gui-client.dwp" "$BINARY_DEST_PATH.dwp"
cp "$TARGET_DIR/release/bundle/deb/firezone-client-gui.deb" "$BINARY_DEST_PATH.deb"
cp "$TARGET_DIR/../gui-client/firezone-client-gui.rpm" "$BINARY_DEST_PATH.rpm"
# TODO: Debug symbols for Linux
# Using a glob for the source, there will only be one deb anyway
cp $TARGET_DIR/release/bundle/deb/firezone-client-gui*.deb "$BINARY_DEST_PATH.deb"
cp $TARGET_DIR/release/bundle/rpm/firezone-client-gui*.rpm "$BINARY_DEST_PATH.rpm"
function make_hash() {
sha256sum "$1" >"$1.sha256sum.txt"
}
# Windows calls it `x64`, Debian `amd64`. Standardize on `x86_64` here since that's
# what Rust uses.
make_hash "$BINARY_DEST_PATH"
make_hash "$BINARY_DEST_PATH.dwp"
make_hash "$BINARY_DEST_PATH.deb"
make_hash "$BINARY_DEST_PATH.rpm"

View File

@@ -138,7 +138,6 @@ function gui() {
find website -type f -name "route.ts" -exec sed "${SEDARG[@]}" -e '/mark:current-gui-version/{n;s/[0-9]\{1,\}\.[0-9]\{1,\}\.[0-9]\{1,\}/'"${current_gui_version}"'/g;}' {} \;
find .github -type f -exec sed "${SEDARG[@]}" -e '/mark:next-gui-version/{n;s/[0-9]\{1,\}\.[0-9]\{1,\}\.[0-9]\{1,\}/'"${next_gui_version}"'/g;}' {} \;
find rust -path rust/gui-client/node_modules -prune -o -path rust/target -prune -o -name "Cargo.toml" -exec sed "${SEDARG[@]}" -e '/mark:next-gui-version/{n;s/[0-9]\{1,\}\.[0-9]\{1,\}\.[0-9]\{1,\}/'"${next_gui_version}"'/;}' {} \;
find rust -path rust/gui-client/node_modules -prune -o -path rust/target -prune -o -name "*.spec" -exec sed "${SEDARG[@]}" -e '/mark:next-gui-version/{n;s/[0-9]\{1,\}\.[0-9]\{1,\}\.[0-9]\{1,\}/'"${next_gui_version}"'/;}' {} \;
cargo_update_workspace
}

View File

@@ -24,7 +24,7 @@ function debug_exit() {
sudo cp "rust/target/debug/$BINARY_NAME" "/usr/bin/$BINARY_NAME"
# Set up the systemd service
sudo cp "rust/gui-client/src-tauri/deb_files/$SERVICE_NAME.service" /usr/lib/systemd/system/
sudo cp "rust/gui-client/src-tauri/linux_package/$SERVICE_NAME.service" /usr/lib/systemd/system/
sudo cp "scripts/tests/systemd/env" "/etc/default/firezone-client-tunnel"
# The firezone group must exist before the daemon starts

View File

@@ -15,7 +15,7 @@ present to authenticate with your identity provider interactively.
## Prerequisites
- **x86-64** or **ARM64** CPU architecture
- Ubuntu **22.04** or higher, or CentOS 9 or higher. Other distributions may
- Ubuntu **22.04** or higher, or CentOS 10 or higher. Other distributions may
work, but are not officially supported.
- **systemd-resolved**. Ubuntu already uses this by default.
@@ -44,49 +44,51 @@ reboot
To auto-start the Client when you log in, run
`firezone-client-gui debug set-autostart true`
## Installation (CentOS)
## Installation (CentOS 10)
### Step 1: Install system tray
### Step 1: Install repositories
GNOME Shell 40 in CentOS 9 does not have a system tray by default. Use these
These are required for both GNOME extensions and the WebKit and other dependencies
of the Firezone Client.
1. `sudo dnf config-manager --set-enabled crb`
1. `sudo dnf install epel-release`
### Step 2: Install system tray
GNOME Shell in CentOS does not have a system tray by default. Use these
steps to install it. For other desktops like xfce4 or KDE, the system tray may
already work properly.
1. `sudo dnf install epel-release` (Needed to get GNOME extensions)
2. `sudo dnf install gnome-shell-extension-appindicator`
3. Log out and back in to restart GNOME
4. `gnome-extensions enable appindicatorsupport@rgcjonas.gmail.com`
1. `sudo dnf install gnome-shell-extension-appindicator`
1. Log out and back in to restart GNOME
1. `gnome-extensions enable appindicatorsupport@rgcjonas.gmail.com`
1. Optionally: To manage GNOME extensions via a GUI, install `gnome-extensions-app`
### Step 2: Install Firezone
### Step 3: Install Firezone
1. Download the RPM:
[Download the latest Linux GUI `.rpm` from GitHub Releases](https://www.github.com/firezone/firezone/releases)
2. `sudo dnf install systemd-resolved` (Installing it explicitly prevents it
1. `sudo dnf install systemd-resolved` (Installing it explicitly prevents it
from being auto-removed if Firezone is removed)
3. `sudo dnf install ./firezone-client-gui-*.rpm`
4. `sudo usermod -aG firezone-client $USER`
5. `sudo systemctl enable firezone-client-tunnel.service` (See
https://www.freedesktop.org/software/systemd/man/latest/systemd.preset.html,
"It is not recommended to ship preset files within the respective software
packages implementing the units". The Fedora family of distros also seem to
have their own policy that installing a service should not auto-start or
enable it.)
6. Reboot to finish adding yourself to the group. Logging out and back in is not
1. `sudo dnf install ./firezone-client-gui-*.rpm`
1. `sudo usermod -aG firezone-client $USER`
1. Reboot to finish adding yourself to the group. Logging out and back in is not
enough. This also starts the new services for us.
7. `sudo cp /etc/resolv.conf /etc/resolv.conf.before-firezone` Back up your
1. `sudo cp /etc/resolv.conf /etc/resolv.conf.before-firezone` Back up your
resolv.conf file. If anything goes wrong with your DNS, you can copy this
back into place.
8. `sudo ln --force --symbolic /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf`
1. `sudo ln --force --symbolic /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf`
This puts `systemd-resolved`, and therefore Firezone, in control of the
system's DNS. `systemd-resolved` does not do this automatically, since it's
under `/etc`.
9. Run `Firezone Client` from the app menu.
1. Run `Firezone` from the app menu.
## Usage
### Signing in
1. Start the GUI by running `Firezone Client` from your desktop environment's
1. Start the GUI by running `Firezone` from your desktop environment's
application menu or from an interactive shell.
1. At the Welcome screen, click `Sign in`. This will open the Firezone sign-in
page in your default web browser.

View File

@@ -29,6 +29,11 @@ export default function GUI({ os }: { os: OS }) {
to `firezone-client-tunnel.service`.
</ChangeItem>
)}
{os === OS.Linux && (
<ChangeItem pull="9181">
Increases minimum supported CentOS version to 10.
</ChangeItem>
)}
</Unreleased>
<Entry version="1.4.13" date={new Date("2025-05-14")}>
<ChangeItem pull="9014">