the headline setup
Your Mac is the window.
Your Mac is slow for agents, especially the filesystem. A headless box isn’t, and it stays up. Keep the Mac as the window. Kolu runs on the box, and you open it from the Mac as a real app.
This is not remoting into a Linux desktop. There is no Linux GUI. Kolu is a website the box serves; the Mac is a browser that you pin as an app.
You need a headless Linux machine with Nix — NixOS or Ubuntu, or any other Linux with Nix — a Mac, and a Tailscale account on both.
-
Run kolu as a user service on the Linux box.
Same home-manager module on both. Then linger, so the user systemd starts at boot on a box nobody is logged into. The full module, logs, and address options are on Deployment.
NixOS. Import the module in that user’s home-manager config:
{ pkgs, kolu, ... }: { imports = [ kolu.homeManagerModules.default ]; services.kolu = { enable = true; package = kolu.packages.${pkgs.stdenv.hostPlatform.system}.default; }; }Rebuild as usual (
nixos-rebuild switch). On a headless box also setusers.users.<you>.linger = truein the system config so the user systemd starts at boot.Ubuntu (and other non-NixOS Linux). Install Nix with flakes if you do not have it — the NixOS Asia guide. Then a standalone home-manager flake; replace
youand useaarch64-linuxon ARM:{ description = "kolu on this box"; inputs = { nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable"; home-manager.url = "github:nix-community/home-manager"; home-manager.inputs.nixpkgs.follows = "nixpkgs"; kolu.url = "github:juspay/kolu"; }; outputs = { nixpkgs, home-manager, kolu, ... }: let system = "x86_64-linux"; in { homeConfigurations.you = home-manager.lib.homeManagerConfiguration { pkgs = nixpkgs.legacyPackages.${system}; modules = [ kolu.homeManagerModules.default ({ pkgs, ... }: { home.username = "you"; home.homeDirectory = "/home/you"; home.stateVersion = "24.11"; services.kolu = { enable = true; package = kolu.packages.${pkgs.stdenv.hostPlatform.system}.default; }; }) ]; }; }; }From that directory:
nix run home-manager -- switch --flake .#you sudo loginctl enable-linger youLinger is what keeps the service up after SSH disconnects. If the switch starts compiling from source, enable the binary cache first.
Either way, open http://127.0.0.1:7681 on the box (or via ssh port-forward). You should see an empty canvas. That is kolu running.
-
Give it a private HTTPS URL with Tailscale Serve.
Install Tailscale on the Linux box and on the Mac, signed into the same account. In the Tailscale admin console, turn on MagicDNS and HTTPS Certificates. On the box:
tailscale serve --bg 7681Tailscale prints a tailnet URL:
https://your-box.your-tailnet.ts.net/Keep kolu bound to
127.0.0.1. Serve is the only exposed surface. The longer tunnel notes are on From another device. -
Allow that origin, then rebuild.
Tailscale presents a browser origin kolu did not start with. Add the exact URL from the previous step:
services.kolu.allowedOrigins = [ "https://your-box.your-tailnet.ts.net" ];Apply again (
nixos-rebuild switch, orhome-manager switch --flake .#youon Ubuntu). Without this, the page may load and then fail to talk to the server. -
Open the printed URL in a browser on the Mac.
Use the full
https://<machine>.<tailnet>.ts.netaddress — not the bare machine name, and not the100.xaddress. Those stay plain HTTP and do not unlock install prompts, badges, or notifications. -
Pin it as an app.
In Chrome, Edge, Brave, or Arc: Install. In Safari 17+: File → Add to Dock. Browser-by-browser paths are on Install as an App.
Kolu is now in the macOS Apps launcher, in its own window. The agents still run on the Linux box.