From dcee65159a13f7f02523285815de0ce8b9161e4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20W=C3=B3jcik?= Date: Mon, 22 Dec 2025 11:06:56 +0100 Subject: [PATCH 01/12] read version from Cargo.toml --- nix/package.nix | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/nix/package.nix b/nix/package.nix index da00eaae..53724b47 100644 --- a/nix/package.nix +++ b/nix/package.nix @@ -8,7 +8,8 @@ makeDesktopItem, }: let pname = "defguard-client"; - version = "1.6.2"; # TODO: Get this from Cargo.toml or git + # Automatically read version from Cargo.toml + version = (builtins.fromTOML (builtins.readFile ../src-tauri/Cargo.toml)).workspace.package.version; desktopItem = makeDesktopItem { name = pname; From 626a3b1eec9a42f0cd56cab9f436c61180f8b654 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20W=C3=B3jcik?= Date: Tue, 23 Dec 2025 09:50:57 +0100 Subject: [PATCH 02/12] restructure package build process --- nix/package.nix | 39 ++++++++++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/nix/package.nix b/nix/package.nix index 53724b47..455ee473 100644 --- a/nix/package.nix +++ b/nix/package.nix @@ -30,6 +30,7 @@ gdk-pixbuf glib glib-networking + gtk3 gtk4 harfbuzz librsvg @@ -54,7 +55,7 @@ pnpm.configHook # configures cargo to use pre-fetched dependencies rustPlatform.cargoSetupHook - # helper to add dynamic library paths + # helper to add runtime binary deps paths pkgs.makeWrapper ]; in @@ -85,34 +86,50 @@ in }; buildPhase = '' - pnpm tauri build + runHook preBuild + + pnpm tauri build --verbose + + runHook postBuild ''; - postInstall = '' + installPhase = '' + runHook preInstall + mkdir -p $out/bin # copy client binary - cp src-tauri/target/release/${pname} $out/bin/ + install -Dm755 src-tauri/target/release/${pname} $out/bin/${pname} # copy background service binary - cp src-tauri/target/release/defguard-service $out/bin/ + install -Dm755 src-tauri/target/release/defguard-service $out/bin/defguard-service # copy CLI binary - cp src-tauri/target/release/dg $out/bin/ - - # add required library to client binary RPATH - wrapProgram $out/bin/${pname} \ - --prefix LD_LIBRARY_PATH : ${lib.makeLibraryPath [pkgs.libayatana-appindicator pkgs.desktop-file-utils]} + install -Dm755 src-tauri/target/release/dg $out/bin/dg + # install desktop entry mkdir -p $out/share/applications cp ${desktopItem}/share/applications/* $out/share/applications/ + + # install icon files + mkdir -p $out/share/icons/hicolor/{32x32,128x128}/apps + install -Dm644 src-tauri/icons/32x32.png $out/share/icons/hicolor/32x32/apps/${pname}.png + install -Dm644 src-tauri/icons/128x128.png $out/share/icons/hicolor/128x128/apps/${pname}.png + + runHook postInstall + ''; + + postFixup = '' + # Add desktop-file-utils to PATH + wrapProgram $out/bin/${pname} \ + --prefix PATH : ${lib.makeBinPath [pkgs.desktop-file-utils]} ''; meta = with lib; { description = "Defguard VPN Client"; homepage = "https://defguard.net"; # license = licenses.gpl3Only; - maintainers = with maintainers; []; + maintainers = with maintainers; [wojcik91]; platforms = platforms.linux; }; }) From a9d9208fce9ef6eb3b1dd9c5b46e15106f552485 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20W=C3=B3jcik?= Date: Wed, 7 Jan 2026 09:14:55 +0100 Subject: [PATCH 03/12] update inputs --- flake.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/flake.lock b/flake.lock index 3582629c..414a7a65 100644 --- a/flake.lock +++ b/flake.lock @@ -44,11 +44,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1765644376, - "narHash": "sha256-yqHBL2wYGwjGL2GUF2w3tofWl8qO9tZEuI4wSqbCrtE=", + "lastModified": 1767364772, + "narHash": "sha256-fFUnEYMla8b7UKjijLnMe+oVFOz6HjijGGNS1l7dYaQ=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "23735a82a828372c4ef92c660864e82fbe2f5fbe", + "rev": "16c7794d0a28b5a37904d55bcca36003b9109aaa", "type": "github" }, "original": { @@ -99,11 +99,11 @@ "nixpkgs": "nixpkgs_2" }, "locked": { - "lastModified": 1765766816, - "narHash": "sha256-m2au5a2x9L3ikyBi0g3/NRJSjmHVDvT42mn+O6FlyPs=", + "lastModified": 1767581716, + "narHash": "sha256-FUbiUzdrGkLou37OGfb4vCLPnqdSIvtmJBxjh2iljiE=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "4f53a635709d82652567f51ef7af4365fbc0c88b", + "rev": "1d3f83babdd21e16bf5cfe0f1efcb4f49ee1bc2c", "type": "github" }, "original": { From efca7b3a316d201a9fd84768609dee2e5f4bb7ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20W=C3=B3jcik?= Date: Wed, 7 Jan 2026 09:17:37 +0100 Subject: [PATCH 04/12] update binary dependencies --- nix/package.nix | 44 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 35 insertions(+), 9 deletions(-) diff --git a/nix/package.nix b/nix/package.nix index 455ee473..29a0114c 100644 --- a/nix/package.nix +++ b/nix/package.nix @@ -6,10 +6,12 @@ rustc, cargo, makeDesktopItem, + pnpmConfigHook, + fetchPnpmDeps, }: let pname = "defguard-client"; # Automatically read version from Cargo.toml - version = (builtins.fromTOML (builtins.readFile ../src-tauri/Cargo.toml)).workspace.package.version; + version = (fromTOML (builtins.readFile ../src-tauri/Cargo.toml)).workspace.package.version; desktopItem = makeDesktopItem { name = pname; @@ -31,7 +33,7 @@ glib glib-networking gtk3 - gtk4 + # gtk4 harfbuzz librsvg libsoup_3 @@ -39,7 +41,11 @@ webkitgtk_4_1 openssl libayatana-appindicator + libayatana-indicator + ayatana-ido + libdbusmenu-gtk3 desktop-file-utils + iproute2 ]; nativeBuildInputs = [ @@ -52,11 +58,12 @@ pkgs.protobuf pnpm # configures pnpm to use pre-fetched dependencies - pnpm.configHook + pnpmConfigHook # configures cargo to use pre-fetched dependencies rustPlatform.cargoSetupHook # helper to add runtime binary deps paths pkgs.makeWrapper + pkgs.wrapGAppsHook3 ]; in stdenv.mkDerivation (finalAttrs: rec { @@ -72,8 +79,10 @@ in lockFile = ../src-tauri/Cargo.lock; }; + # dontUseCargoBuild = true; + # prefetch pnpm dependencies - pnpmDeps = pkgs.pnpm.fetchDeps { + pnpmDeps = fetchPnpmDeps { inherit (finalAttrs) pname @@ -82,7 +91,7 @@ in ; fetcherVersion = 2; - hash = "sha256-v47yaNnt7vLDPR7WVLSonmZBBOkYWnmTUqMiPZ/WCGo="; + hash = "sha256-DysOn+v37aUxqvIy/afbTcIRCMRM9jSN8xF3qbcR/uM="; }; buildPhase = '' @@ -107,6 +116,10 @@ in # copy CLI binary install -Dm755 src-tauri/target/release/dg $out/bin/dg + # Copy resources directory (for tray icons, etc.) + mkdir -p $out/lib/${pname} + cp -r src-tauri/resources $out/lib/${pname}/ + # install desktop entry mkdir -p $out/share/applications cp ${desktopItem}/share/applications/* $out/share/applications/ @@ -119,10 +132,23 @@ in runHook postInstall ''; - postFixup = '' - # Add desktop-file-utils to PATH - wrapProgram $out/bin/${pname} \ - --prefix PATH : ${lib.makeBinPath [pkgs.desktop-file-utils]} + # add extra args to wrapGAppsHook3 wrapper + preFixup = '' + gappsWrapperArgs+=( + --prefix PATH : ${ + lib.makeBinPath [ + # `defguard-service` needs `ip` to manage wireguard + pkgs.iproute2 + # `defguard-client` needs `update-desktop-database` + pkgs.desktop-file-utils + ] + } + --prefix LD_LIBRARY_PATH : ${ + lib.makeLibraryPath [ + pkgs.libayatana-appindicator + ] + } + ) ''; meta = with lib; { From 534caee1d0f3e18380dfd695c4e1389ed03a6b2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20W=C3=B3jcik?= Date: Wed, 7 Jan 2026 09:21:27 +0100 Subject: [PATCH 05/12] cleanup --- nix/package.nix | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/nix/package.nix b/nix/package.nix index 29a0114c..af619f3d 100644 --- a/nix/package.nix +++ b/nix/package.nix @@ -33,7 +33,6 @@ glib glib-networking gtk3 - # gtk4 harfbuzz librsvg libsoup_3 @@ -61,7 +60,7 @@ pnpmConfigHook # configures cargo to use pre-fetched dependencies rustPlatform.cargoSetupHook - # helper to add runtime binary deps paths + # helper to add runtime binary & library deps paths pkgs.makeWrapper pkgs.wrapGAppsHook3 ]; @@ -79,8 +78,6 @@ in lockFile = ../src-tauri/Cargo.lock; }; - # dontUseCargoBuild = true; - # prefetch pnpm dependencies pnpmDeps = fetchPnpmDeps { inherit @@ -91,7 +88,7 @@ in ; fetcherVersion = 2; - hash = "sha256-DysOn+v37aUxqvIy/afbTcIRCMRM9jSN8xF3qbcR/uM="; + hash = ""; }; buildPhase = '' From 125543033f9ef6ea6689bc3e536156f0da6189b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20W=C3=B3jcik?= Date: Wed, 7 Jan 2026 09:37:02 +0100 Subject: [PATCH 06/12] update hash --- nix/package.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nix/package.nix b/nix/package.nix index af619f3d..4f6c2971 100644 --- a/nix/package.nix +++ b/nix/package.nix @@ -88,7 +88,7 @@ in ; fetcherVersion = 2; - hash = ""; + hash = "sha256-Xtn0FIq097sLEl/iodLeVVOYxVLx1ePJ8UjJUmgB2f0="; }; buildPhase = '' From d40af30708753fd92a3637dc857336d18e58e21d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20W=C3=B3jcik?= Date: Wed, 7 Jan 2026 09:40:41 +0100 Subject: [PATCH 07/12] add some comments to nixos module --- nix/nixos-module.nix | 3 +++ 1 file changed, 3 insertions(+) diff --git a/nix/nixos-module.nix b/nix/nixos-module.nix index b21b0b1f..89ee9e02 100644 --- a/nix/nixos-module.nix +++ b/nix/nixos-module.nix @@ -31,8 +31,10 @@ in { }; config = mkIf cfg.enable { + # Add client package environment.systemPackages = [cfg.package]; + # Setup systemd service for the intrerface management daemon systemd.services.defguard-service = { description = "Defguard VPN Service"; wantedBy = ["multi-user.target"]; @@ -65,6 +67,7 @@ in { }; }; + # Setup defguard user & group users.users.defguard = { isSystemUser = true; group = "defguard"; From 308164766a4b52df2bb41785a4fefbc07094a67c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20W=C3=B3jcik?= Date: Wed, 7 Jan 2026 10:05:37 +0100 Subject: [PATCH 08/12] adjust logs directory --- nix/nixos-module.nix | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/nix/nixos-module.nix b/nix/nixos-module.nix index 89ee9e02..f6e6a08e 100644 --- a/nix/nixos-module.nix +++ b/nix/nixos-module.nix @@ -46,8 +46,8 @@ in { RestartSec = 5; User = "defguard"; Group = "defguard"; - StateDirectory = "defguard"; - LogsDirectory = "defguard"; + StateDirectory = "defguard-service"; + LogsDirectory = "defguard-service"; # Add capabilities to manage network interfaces CapabilityBoundingSet = "CAP_NET_ADMIN CAP_NET_RAW CAP_SYS_MODULE"; AmbientCapabilities = "CAP_NET_ADMIN CAP_NET_RAW CAP_SYS_MODULE"; @@ -73,6 +73,7 @@ in { group = "defguard"; }; + # Make sure the group exists users.groups.defguard = {}; }; } From ed24a24004ebd169626f2cd1ca6996c72d4874b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20W=C3=B3jcik?= Date: Wed, 7 Jan 2026 12:44:55 +0100 Subject: [PATCH 09/12] add more logs --- src-tauri/src/service/daemon.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src-tauri/src/service/daemon.rs b/src-tauri/src/service/daemon.rs index 6ecf251f..bab6ccf3 100644 --- a/src-tauri/src/service/daemon.rs +++ b/src-tauri/src/service/daemon.rs @@ -508,11 +508,10 @@ pub async fn run_server(config: Config) -> anyhow::Result<()> { // Remove existing socket if it exists if Path::new(DAEMON_SOCKET_PATH).exists() { + debug!("Removing existing socket file at {DAEMON_SOCKET_PATH}"); fs::remove_file(DAEMON_SOCKET_PATH)?; } - let uds = UnixListener::bind(DAEMON_SOCKET_PATH)?; - // change owner group for socket file // get the group ID by name let group = Group::from_name(DAEMON_SOCKET_GROUP)?.ok_or_else(|| { @@ -521,12 +520,16 @@ pub async fn run_server(config: Config) -> anyhow::Result<()> { })?; // change ownership - keep current user, change group + debug!("Changing owner group of socket file at {DAEMON_SOCKET_PATH} to group {DAEMON_SOCKET_GROUP}"); chown(DAEMON_SOCKET_PATH, None, Some(group.gid))?; // Set socket permissions to allow client access // 0o660 allows read/write for owner and group only + debug!("Setting permissions for socket file at {DAEMON_SOCKET_PATH} to 0x660"); fs::set_permissions(DAEMON_SOCKET_PATH, fs::Permissions::from_mode(0o660))?; + debug!("Binding socket file at {DAEMON_SOCKET_PATH}"); + let uds = UnixListener::bind(DAEMON_SOCKET_PATH)?; let uds_stream = UnixListenerStream::new(uds); info!("Defguard daemon version {VERSION} started, listening on socket {DAEMON_SOCKET_PATH}",); From dd0d2d0686cb7544abda9040391f4dcf1beacc5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20W=C3=B3jcik?= Date: Wed, 7 Jan 2026 12:45:07 +0100 Subject: [PATCH 10/12] simplify systemd service config --- nix/nixos-module.nix | 38 ++++++++++---------------------------- 1 file changed, 10 insertions(+), 28 deletions(-) diff --git a/nix/nixos-module.nix b/nix/nixos-module.nix index f6e6a08e..f3833d09 100644 --- a/nix/nixos-module.nix +++ b/nix/nixos-module.nix @@ -42,38 +42,20 @@ in { after = ["network-online.target"]; serviceConfig = { ExecStart = "${cfg.package}/bin/defguard-service --log-level ${cfg.logLevel} --stats-period ${toString cfg.statsPeriod}"; - Restart = "on-failure"; - RestartSec = 5; - User = "defguard"; + ExecReload = "/bin/kill -HUP $MAINPID"; Group = "defguard"; - StateDirectory = "defguard-service"; - LogsDirectory = "defguard-service"; - # Add capabilities to manage network interfaces - CapabilityBoundingSet = "CAP_NET_ADMIN CAP_NET_RAW CAP_SYS_MODULE"; - AmbientCapabilities = "CAP_NET_ADMIN CAP_NET_RAW CAP_SYS_MODULE"; - # Allow access to /dev/net/tun for TUN/TAP devices - DeviceAllow = "/dev/net/tun rw"; - # Access to /sys for network configuration - BindReadOnlyPaths = [ - "/sys" - "/proc" - ]; - # Protect the system while giving necessary access - ProtectSystem = "strict"; - ProtectHome = true; - NoNewPrivileges = true; - # Allow the service to manage network namespaces - PrivateNetwork = false; + Restart = "on-failure"; + RestartSec = 2; + KillMode = "process"; + KillSignal = "SIGINT"; + LimitNOFILE = 65536; + LimitNPROC = "infinity"; + TasksMax = "infinity"; + OOMScoreAdjust = -1000; }; }; - # Setup defguard user & group - users.users.defguard = { - isSystemUser = true; - group = "defguard"; - }; - - # Make sure the group exists + # Make sure the defguard group exists users.groups.defguard = {}; }; } From ad035d51e4c02620fd140df79337f18f47bb9c36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20W=C3=B3jcik?= Date: Wed, 7 Jan 2026 13:35:41 +0100 Subject: [PATCH 11/12] add more runtime dependencies --- nix/package.nix | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/nix/package.nix b/nix/package.nix index 4f6c2971..76c31bc8 100644 --- a/nix/package.nix +++ b/nix/package.nix @@ -45,6 +45,8 @@ libdbusmenu-gtk3 desktop-file-utils iproute2 + lsb-release + openresolv ]; nativeBuildInputs = [ @@ -134,10 +136,13 @@ in gappsWrapperArgs+=( --prefix PATH : ${ lib.makeBinPath [ - # `defguard-service` needs `ip` to manage wireguard + # `defguard-service` needs `ip` to manage WireGuard pkgs.iproute2 - # `defguard-client` needs `update-desktop-database` + # `defguard-service` needs `resolvconf` to manage DNS + pkgs.openresolv + # `defguard-client` needs `update-desktop-database` and `lsb_release` pkgs.desktop-file-utils + pkgs.lsb-release ] } --prefix LD_LIBRARY_PATH : ${ From 31c384287f6536fb0ad143d1d95746bb53e97048 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20W=C3=B3jcik?= Date: Wed, 7 Jan 2026 14:17:08 +0100 Subject: [PATCH 12/12] restore operation order --- src-tauri/src/service/daemon.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src-tauri/src/service/daemon.rs b/src-tauri/src/service/daemon.rs index bab6ccf3..e8d1d097 100644 --- a/src-tauri/src/service/daemon.rs +++ b/src-tauri/src/service/daemon.rs @@ -512,6 +512,9 @@ pub async fn run_server(config: Config) -> anyhow::Result<()> { fs::remove_file(DAEMON_SOCKET_PATH)?; } + debug!("Binding socket file at {DAEMON_SOCKET_PATH}"); + let uds = UnixListener::bind(DAEMON_SOCKET_PATH)?; + // change owner group for socket file // get the group ID by name let group = Group::from_name(DAEMON_SOCKET_GROUP)?.ok_or_else(|| { @@ -528,8 +531,6 @@ pub async fn run_server(config: Config) -> anyhow::Result<()> { debug!("Setting permissions for socket file at {DAEMON_SOCKET_PATH} to 0x660"); fs::set_permissions(DAEMON_SOCKET_PATH, fs::Permissions::from_mode(0o660))?; - debug!("Binding socket file at {DAEMON_SOCKET_PATH}"); - let uds = UnixListener::bind(DAEMON_SOCKET_PATH)?; let uds_stream = UnixListenerStream::new(uds); info!("Defguard daemon version {VERSION} started, listening on socket {DAEMON_SOCKET_PATH}",);