Jump to content
Not connected, Your IP: 216.73.216.40
Sign in to follow this  
183aTr78f9o

Getting Linux Suite working on NixOS

Recommended Posts

I've started using NixOS a few weeks ago and I've been trying to get Linux Suite working on it lately.

I have zero experience writing Nix derivations so I basically tried to replicate the install.sh script from the tarball.
Note that I've been trying to get it working for my use case (x86_64 only).

What I got working:
 

 

  • Binaries / resource files copied to the Nix Store and binaries somewhat working

i.e. I can run
 
❯ goldcrest --version
 

Used nix-ld for this:

programs.nix-ld = {
  enable = true;
  libraries = with pkgs; [
    dbus
    openssl
    libgcc
  ];
};

Since bluetit seems to expect resource files to be present in /etc/airvpn, I used environment.etc to copy them from the Nix store.
Regarding D-Bus config files, since /etc/dbus-1 directory already exists and is a symlink to /etc/static/dbus-1, I wasn't able to write in this directory.
I had to use system.activationScripts to copy the two D-Bus config files in one of the possible paths (see get_dbus_path() function in the install script).
 
  • airvpn group created (I don't need airvpn user)
  • bluetit.service / bluetit-suspend.service / bluetit-resume.service units written with systemd.services Nix option
  • Custom bluetit.rc with my own settings and sensitive values set as agenix secrets.
  • Zsh completions (only added Zsh because that's my interactive shell, I don't use Bash)

Ideally of course, a proper Nix derivation would "Nixify" everything: airvpn user/group creation, all bluetit.rc options, whether the systemd units should be enabled or not, shell completions... but that's far beyond my abilities.

What I couldn't get working:
 
  • cuckoo binary ownership and permissions

The installer script has:
chown root:airvpn $BIN_DIR/cuckoo
chmod u+s $BIN_DIR/cuckoo

but I couldn't replicate this. Nix would give "permission denied" every time when rebuilding the system.
root:airvpn ownership wouldn't work because the airvpn group wasn't created yet. I tried setting a gid to the airvpn group and use root:1000 instead but that didn't make any difference.

Likewise, chmod u+s would result in "permission denied" error. I guess we're just not supposed to change files ownership in the Nix Store. Not sure why the chmod u+s wouldn't work though, considering the other chmod commands work. Maybe it's not that big of a deal, I don't know.
 
  • any VPN connection

This is obviously the biggest issue, making the program completely useless for now. Despite having binaries apparently working, I couldn't connect to any AirVPN server.

First, I got DNSManagerException: systemctl: command not found:
 
❯ journalctl -b -u bluetit.service

systemd[1]: Starting AirVPN Bluetit Daemon...
bluetit[21208]: Starting Bluetit - AirVPN WireGuard/OpenVPN3 Service 2.0.0 - 22 July 2025
bluetit[21208]: OpenVPN core 3.12 AirVPN (20250606) linux x86_64 64-bit
bluetit[21208]: Copyright (C) 2012- OpenVPN Inc. All rights reserved.
bluetit[21208]: SSL Library: OpenSSL 3.4.2 1 Jul 2025
bluetit[21208]: AirVPN WireGuard Client 2.0.0 Linux x86_64 64-bit
bluetit[21242]: Bluetit daemon started with PID 21242
bluetit[21242]: Reading run control directives from file /etc/airvpn/bluetit.rc
bluetit[21242]: Network check mode is airvpn
bluetit[21242]: Creating AirVPN Boot server list
systemd[1]: Started AirVPN Bluetit Daemon.
bluetit[21242]: Added server http://63.33.78.166
bluetit[21242]: Added server http://54.93.175.114
bluetit[21242]: Added server http://82.196.3.205
bluetit[21242]: Added server http://63.33.116.50
bluetit[21242]: Added server http://[2a03:b0c0:0:1010::9b:c001]
bluetit[21242]: Added server http://bootme.org
bluetit[21242]: Boot server http://bootme.org resolved into IPv4 82.196.3.205/32 IPv6 2a03:b0c0:0:1010::9b:c001/128
bluetit[21242]: AirVPN Boot server list successfully created. Added 6 servers.
bluetit[21242]: AirVPN connectivity attempt 1 in progress
bluetit[21242]: Successfully connected to AirVPN server <redacted>
bluetit[21242]: External network is reachable via IPv4 gateway <redacted> through interface <redacted>
bluetit[21242]: Successfully connected to D-Bus
bluetit[21242]: DNSManagerException: systemctl: command not found
bluetit[21242]: Sending event 'event_end_of_session'
bluetit[21242]: Bluetit successfully terminated
systemd[1]: bluetit.service: Main process exited, code=exited, status=1/FAILURE
systemd[1]: bluetit.service: Failed with result 'exit-code'.
systemd[1]: bluetit.service: Consumed 37ms CPU time, 7.3M memory peak, 12.4M read from disk, 120K written to disk, 60B incoming IP traffic, 164B outgoing IP traffic.

I first tried adding
Environment = "PATH=/run/current-system/sw/bin:$PATH";
to systemd.services.bluetit.serviceConfig, but that didn't make any difference.

Creating a symlink allowed to get rid of the error:
 
❯ sudo ln -s /run/current-system/sw/bin/systemctl /bin/systemctl
But still:
 
  • With networklockpersist on: "NetFilterException: No usable firewall found in this system"
  • With networklockpersist iptables: "NetFilterException: iptables or iptables legacy is not available in this system"
  • With networklockpersist nftables: "NetFilterException: nftables is not available in this system"

Creating symlinks also allowed to get rid of the errors:
❯ sudo ln -s /run/current-system/sw/bin/iptables /bin/iptables
❯ sudo ln -s /run/current-system/sw/bin/iptables-save /bin/iptables-save
❯ sudo ln -s /run/current-system/sw/bin/iptables-restore /bin/iptables-restore

❯ sudo ln -s /run/current-system/sw/bin/ip6tables /bin/ip6tables
❯ sudo ln -s /run/current-system/sw/bin/ip6tables-restore /bin/ip6tables-restore
❯ sudo ln -s /run/current-system/sw/bin/ip6tables-save /bin/ip6tables-save

❯ sudo ln -s /run/current-system/sw/bin/nft /bin/nft

Then, more errors. With networklockpersist iptables:
 
Goldcrest - AirVPN Bluetit Client 2.0.0 - 22 July 2025

Reading run control directives from file /root/.config/goldcrest.rc
Bluetit - AirVPN WireGuard/OpenVPN3 Service 2.0.0 - 22 July 2025
OpenVPN core 3.12 AirVPN (20250606) linux x86_64 64-bit
Copyright (C) 2012- OpenVPN Inc. All rights reserved.
OpenSSL 3.4.2 1 Jul 2025
AirVPN WireGuard Client 2.0.0 Linux x86_64 64-bit
Successfully restored DNS and network filter settings
WARNING: Backup copy of resolv.conf not found. DNS settings do not need to be restored.
Scanning for system DNS addresses
Found system IPv4 DNS <redacted>
Found 1 system DNS address
Command not found
Command not found
WARNING: Backup copy of network filter not found. Network settings do not need to be restored.
Network filter and lock are using /bin/iptables
ERROR: system 'modules.builtin' does not exist.
ERROR: system 'modules.builtin' does not exist.
ERROR: system 'modules.builtin' does not exist.
ERROR: system 'modules.builtin' does not exist.
ERROR: system 'modules.builtin' does not exist.
ERROR: system 'modules.builtin' does not exist.
ERROR: system 'modules.builtin' does not exist.
ERROR: system 'modules.builtin' does not exist.
ERROR: system 'modules.builtin' does not exist.
ERROR: system 'modules.builtin' does not exist.
Network filter successfully initialized
Private network is allowed to pass the network filter
Ping output is allowed to pass the network filter
IPv6 NDP is allowed to pass the network filter
Network Lock Error: Unknown error 256 (stderr: iptables-restore: line 1 failed)
Bluetit session terminated

With networklockpersist nftables:
 
Goldcrest - AirVPN Bluetit Client 2.0.0 - 22 July 2025

Reading run control directives from file /root/.config/goldcrest.rc
Bluetit - AirVPN WireGuard/OpenVPN3 Service 2.0.0 - 22 July 2025
OpenVPN core 3.12 AirVPN (20250606) linux x86_64 64-bit
Copyright (C) 2012- OpenVPN Inc. All rights reserved.
OpenSSL 3.4.2 1 Jul 2025
AirVPN WireGuard Client 2.0.0 Linux x86_64 64-bit
Successfully restored DNS and network filter settings
WARNING: Backup copy of resolv.conf not found. DNS settings do not need to be restored.
Scanning for system DNS addresses
Found system IPv4 DNS <redacted> 
Found 1 system DNS address
Network filter successfully restored
Network filter and lock are using nftables
ERROR: system 'modules.builtin' does not exist.
Network filter successfully initialized
Private network is allowed to pass the network filter
Ping output is allowed to pass the network filter
IPv6 NDP is allowed to pass the network filter
Persistent network filter and lock successfully enabled. Private network is allowed.
Bluetit session terminated

With networklockpersist off (default):
 
bluetit[8754]: Starting WireGuard boot connection
bluetit[8754]: ERROR: system 'modules.builtin' does not exist.
bluetit[8754]: ERROR: cannot load wireguard system module
bluetit[8754]: Cannot load wireguard system module
bluetit[8754]: Logging out AirVPN user 183aTr78f9o
bluetit[8754]: AirVPN Manifest successfully retrieved from server
bluetit[8754]: AirVPN Manifest update interval is now set to 30 minutes
bluetit[8754]: Session network filter and lock are now disabled
bluetit[8754]: Sending event 'event_end_of_session'

At this point, I don't know what do try next.
The main issue is likely that due to NixOS not following FHS (Filesystem Hierarchy Standard), bluetit can't find anything (binaries, kernel modules...) to work.

Since Nixpkgs no longer accepts package requests, I thought I'd just ask here if someone could help or even write a proper derivation from scratch.

My (terrible/sadly broken) derivation:
 
{
  config,
  lib,
  pkgs,
  ...
}:

let
  version = "2.0.0";
  airvpn-linux-suite = pkgs.stdenv.mkDerivation {
    pname = "airvpn-linux-suite";
    inherit version;

    src = pkgs.fetchurl {
      url = "https://eddie.website/repository/AirVPN-Suite/${version}/AirVPN-Suite-x86_64-${version}.tar.gz";
      # sha256 = lib.fakeSha256;
      sha256 = "Jt83PPHwBv/GraubQV4I7Shn+UwMvkVW2q9VIAbYDw0=";
    };

    installPhase = ''
      mkdir -p $out/sbin
      mkdir -p $out/bin
      mkdir -m=750 -p $out/etc/airvpn
      mkdir -p $out/etc/dbus-1/system.d
      mkdir -p $out/etc/systemd/system
      mkdir -p $out/share/zsh/site-functions

      cp --preserve=mode bin/bluetit $out/sbin/

      for f in "goldcrest" "hummingbird" "cuckoo" "airsu"; do
        cp --preserve=mode bin/$f $out/bin
      done

      for f in "airvpn-manifest.xml" "connection_priority.txt" "connection_sequence.csv" \
        "country_continent.csv" "country_names.csv" \
        "continent_names.csv" "nsswitch.conf"; do
        cp etc/airvpn/$f $out/etc/airvpn/
      done

      chmod 660 $out/etc/airvpn/*

      cp etc/dbus-1/system.d/* $out/etc/dbus-1/system.d/
      chmod 644 $out/etc/dbus-1/system.d/org.airvpn.*

      cp etc/site-functions/* $out/share/zsh/site-functions/
    '';

    meta = with lib; {
      description = "AirVPN free and open source suite based on AirVPN OpenVPN 3 library fork";
      homepage = "https://www.airvpn.org/";
      license = licenses.gpl3Plus;
      platforms = [ "x86_64-linux" ];
      maintainers = [ maintainers.183aTr78f9o ];
    };
  };

  customBluetitRC =
    # ini
    ''
    # full bluetit.rc here with custom settings
    '';
in
{
  environment.systemPackages = [ airvpn-linux-suite ];

  users.groups.airvpn = { };

  systemd.services = {
    bluetit = {
      description = "AirVPN Bluetit Daemon";
      unitConfig = {
        After = [
          "network-online.target"
          "firewalld.service"
          "ufw.service"
          "dbus-daemon.service"
          "dbus.socket"
        ];
        Wants = [
          "network-online.target"
          "firewalld.service"
          "ufw.service"
          "dbus-daemon.service"
          "dbus.socket"
        ];
      };
      serviceConfig = {
        Type = "forking";
        PIDFile = "/etc/airvpn/bluetit.lock";
        ExecStart = "${airvpn-linux-suite}/sbin/bluetit";
        Environment = "PATH=/run/current-system/sw/bin:$PATH";
        TimeoutStopSec = 90;
        KillSignal = "SIGTERM";
        KillMode = "mixed";
        SendSIGKILL = "no";
      };

      wantedBy = [ "multi-user.target" ];
    };

    bluetit-resume = {
      description = "AirVPN Bluetit Daemon Resume after Suspend, Sleep, Hibernate";
      unitConfig = {
        After = [
          "network-online.target"
          "firewalld.service"
          "ufw.service"
          "dbus-daemon.service"
          "dbus.socket"

          "suspend.target"
          "suspend-then-hibernate.target"
          "hibernate.target"
          "hybrid-sleep.target"
          "sleep.target"
        ];
        Wants = [
          "network-online.target"
          "firewalld.service"
          "ufw.service"
          "dbus-daemon.service"
          "dbus.socket"
        ];
      };

      serviceConfig = {
        Type = "forking";
        ExecStart = "${pkgs.systemd}/bin/systemctl start bluetit.service";
      };

      wantedBy = [
        "suspend.target"
        "suspend-then-hibernate.target"
        "hibernate.target"
        "hybrid-sleep.target"
        "sleep.target"
      ];
    };

    bluetit-suspend = {
      description = "AirVPN Bluetit Daemon Suspend, Sleep, Hibernate";

      unitConfig = {
        Before = [
          "suspend.target"
          "suspend-then-hibernate.target"
          "hibernate.target"
          "hybrid-sleep.target"
          "sleep.target"
        ];
      };

      serviceConfig = {
        Type = "forking";
        ExecStart = "${pkgs.systemd}/bin/systemctl stop bluetit.service";
      };

      wantedBy = [
        "suspend.target"
        "suspend-then-hibernate.target"
        "hibernate.target"
        "hybrid-sleep.target"
        "sleep.target"
      ];
    };
  };

  environment.etc = {
    "airvpn/airvpn-manifest.xml" = {
      source = "${airvpn-linux-suite}/etc/airvpn/airvpn-manifest.xml";
      mode = "0660";
    };

    "airvpn/bluetit.rc" = {
      text = customBluetitRC;
      mode = "0660";
    };

    "airvpn/connection_priority.txt" = {
      source = "${airvpn-linux-suite}/etc/airvpn/connection_priority.txt";
      mode = "0660";
    };

    "airvpn/connection_sequence.csv" = {
      source = "${airvpn-linux-suite}/etc/airvpn/connection_sequence.csv";
      mode = "0660";
    };

    "airvpn/country_continent.csv" = {
      source = "${airvpn-linux-suite}/etc/airvpn/country_continent.csv";
      mode = "0660";
    };

    "airvpn/country_names.csv" = {
      source = "${airvpn-linux-suite}/etc/airvpn/country_names.csv";
      mode = " 0660";
    };

    "airvpn/continent_names.csv" = {
      source = "${airvpn-linux-suite}/etc/airvpn/continent_names.csv";
      mode = "0660";
    };

    "airvpn/nsswitch.conf" = {
      source = "${airvpn-linux-suite}/etc/airvpn/nsswitch.conf";
      mode = "0660";
    };
  };

  system.activationScripts."airvpn-dbus-conf" =
    # sh
    ''
      destPath="/usr/local/etc/dbus-1/system.d"

      mkdir -m=755 -p "$destPath"

      cp "${airvpn-linux-suite}/etc/dbus-1/system.d/org.airvpn.client.conf" "$destPath/"
      chmod 644 "$destPath/org.airvpn.client.conf"

      cp "${airvpn-linux-suite}/etc/dbus-1/system.d/org.airvpn.server.conf" "$destPath/"
      chmod 644 "$destPath/org.airvpn.server.conf"

      systemctl reload dbus 2>/dev/null || true
    '';
}

Share this post


Link to post

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Security Check
    Play CAPTCHA Audio
    Refresh Image
Sign in to follow this  

×
×
  • Create New...