Skip to content
Oeiuwq Faith Blog OpenSource Porfolio

adeci/drv-thru

can I get uhhhhh

adeci/drv-thru.json
{
"createdAt": "2026-06-23T06:56:18Z",
"defaultBranch": "main",
"description": "can I get uhhhhh",
"fullName": "adeci/drv-thru",
"homepage": null,
"language": "Rust",
"name": "drv-thru",
"pushedAt": "2026-06-25T20:47:53Z",
"stargazersCount": 3,
"topics": [
"build-with-buildbot"
],
"updatedAt": "2026-06-25T20:47:58Z",
"url": "https://github.com/adeci/drv-thru"
}

drv-thru

P2P Nix builds!

Run drv-thru on a NixOS builder, create one time redeemable build tickets or set up persistent access. Anyone with a ticket can build on your machine without getting an account there. Missing inputs upload from their Nix store; finished outputs come back as signed Nix store paths.

drv-thru demo showing a ticketed remote Nix build

You need one NixOS builder and one NixOS client. For ticket builds on a multi-user Nix client, the client must trust the builder’s signing key through the drv-thru helper.

Add the module on the machine that should run builds:

{ inputs, ... }:
{
imports = [ inputs.drv-thru.nixosModules.default ];
services.drv-thru.server.enable = true;
}

Rebuild, then print the builder’s signing key:

Terminal window
sudo nixos-rebuild switch
sudo cat /var/lib/drv-thru/signing-public.key

Save that key. The client needs it in the next step.

Create a ticket on the builder:

Terminal window
drv-thru ticket create

Send the printed drvthru... ticket to the client.

Add the client module and allow the builder signing key:

{ inputs, ... }:
{
imports = [ inputs.drv-thru.nixosModules.default ];
services.drv-thru.client = {
enable = true;
ticketHelper.trustedBuilderPublicKeys = [
"drv-thru:builder-signing-public-key"
];
};
}

Rebuild the client:

Terminal window
sudo nixos-rebuild switch
Terminal window
drv-thru build nixpkgs#hello --ticket "drvthru..."

That evaluates locally, uploads missing inputs to the builder, runs the build there, then imports the signed output back into the client’s Nix store.

Use this when one client should keep using the same builder without tickets.

On the client, print its Iroh key:

Terminal window
drv-thru key show

On the builder, allow that client:

services.drv-thru.server.trustedClients.alex = {
publicKey = "client-iroh-endpoint-id";
maxBuildTime = "30m";
maxUploadBytes = "20G";
};

On the client, trust the builder’s signing key:

services.drv-thru.client = {
enable = true;
trustedBuilders.leviathan.publicKey = "drv-thru:builder-signing-public-key";
};

Then save the builder address for your user:

Terminal window
mkdir -p ~/.config/drv-thru
cat > ~/.config/drv-thru/builders.json <<'EOF'
{
"builders": {
"leviathan": {
"endpoint_id": "builder-iroh-endpoint-id",
"relay_url": null
}
}
}
EOF

On the builder, drv-thru status prints the server endpoint id. Then build without a ticket:

Terminal window
drv-thru build nixpkgs#hello --builder leviathan

You can still pass the endpoint directly:

Terminal window
drv-thru build nixpkgs#hello --server "builder-iroh-endpoint-id"
Terminal window
nix run github:adeci/drv-thru#drv-thru -- build nixpkgs#hello --ticket "drvthru..."

This only runs the CLI. It does not install the local helper or change Nix trust settings.

Create a ticket with custom limits:

Terminal window
drv-thru ticket create \
--name friend \
--expires 2h \
--uses 1 \
--max-build-time 30m \
--max-upload-bytes 20G

Bind a ticket to one client endpoint:

Terminal window
drv-thru ticket create --bind-client "client-iroh-endpoint-id"

Inspect and manage tickets on the builder:

Terminal window
drv-thru ticket inspect "drvthru..."
drv-thru ticket list
drv-thru ticket reveal "ticket-id"
drv-thru ticket revoke "ticket-id"

Defaults: tickets expire after 2 hours, allow one use, allow 30 minutes of build time, and allow 20 GiB of input upload. list does not print bearer secrets; reveal does.

Terminal window
NIXPKGS_ALLOW_UNSUPPORTED_SYSTEM=1 drv-thru build . --impure --ticket "drvthru..."
drv-thru build . --refresh --ticket "drvthru..."
drv-thru build . --override-input nixpkgs github:NixOS/nixpkgs/nixos-unstable --ticket "drvthru..."
drv-thru build . --rebuild --ticket "drvthru..."
drv-thru build nixpkgs#hello --ticket "drvthru..." --no-nom

--impure, --refresh, and --override-input affect local evaluation before inputs upload. --rebuild asks the remote builder to rebuild and check the derivation. --no-nom uses plain logs.

If the requested outputs are already valid in the local Nix store, drv-thru skips the remote builder and prints the local output paths.

Terminal window
drv-thru status
drv-thru status --watch

Run these on the builder to see active builds and the waiting queue.

There are two separate trust decisions:

  • who may spend CPU and disk on the builder
  • whose build outputs may enter the client’s Nix store

Tickets and server.trustedClients.* control builder access.

A builder endpoint id is an address, not an auth secret. Keep it local if you do not want people probing reachability, but access still requires a trusted client key or a ticket. Named builders can live in /etc/drv-thru/builders.json from the NixOS module or in ~/.config/drv-thru/builders.json for one user; the user file overrides the system file.

Nix trusted users, client.builders, client.trustedBuilders, and ticketHelper.trustedBuilderPublicKeys control output import trust.

A ticket alone is not enough for an untrusted multi-user Nix client to import outputs from a new builder. One of these must also be true:

  • the local user is a trusted Nix user
  • the builder signing key is in nix.settings.trusted-public-keys
  • the user can access the drv-thru import helper socket and the builder key is in the helper allowlist

The helper is a local root service. It only accepts allowlisted builder keys, loopback HTTP cache URLs, and exact /nix/store/... paths. It does not run arbitrary commands or arbitrary Nix options.

Outputs move back through Nix’s signed binary cache path:

  • the builder signs .narinfo files
  • the client mirrors the needed cache files over Iroh
  • local Nix imports the paths after checking signatures

The server keeps a persistent signed cache under /var/lib/drv-thru/cache. First request for a large uncached closure may spend time filling cache entries; later builds reuse them.

Raw nix-store --export / nix-store --import is still used for server-side input upload. It is not used for client output import.

services.drv-thru = {
package = inputs.drv-thru.packages.${pkgs.stdenv.hostPlatform.system}.default;
server = {
enable = true;
dataDir = "/var/lib/drv-thru";
secretKeyFile = "/var/lib/drv-thru/secret.key";
maxConcurrentBuilds = 1;
outputCacheMaxParallelFills = null; # auto
recentBuildsLimit = 20;
trustedClients.alex = {
publicKey = "client-iroh-endpoint-id";
maxBuildTime = "30m";
maxUploadBytes = "20G";
};
};
client = {
enable = true;
narFetches = null; # auto
builders.leviathan = {
endpointId = null;
endpointIdFile = "/run/secrets/drv-thru-leviathan-endpoint-id";
relayUrl = null;
publicKey = "drv-thru:builder-signing-public-key";
};
trustedBuilders.other.publicKey = "drv-thru:other-builder-signing-public-key";
ticketHelper = {
enable = true; # defaults to client.enable
group = "wheel";
trustedBuilderPublicKeys = [
"drv-thru:ticket-only-builder-signing-public-key"
];
};
};
};

Module state lives in /var/lib/drv-thru. Wheel users can create and inspect tickets. The server Iroh secret key and signing secret key stay private to the drv-thru service user.