# Server host — runs nix-ota-server AND nix-serve (the binary cache), # fronted by nginx with Let's Encrypt TLS. # # Layout under https://ota.example.com/ : # / -> nix-ota-server dashboard + API (port 8080) # /cache/ -> nix-serve binary cache (port 5000) # # The cache and the control plane are on the same DNS name so devices # only need one URL. They can be split if you prefer. { config, pkgs, lib, ... }: { imports = [ # Replace with your hardware config. # ./hardware-configuration.nix ]; networking.hostName = "ota"; networking.firewall.allowedTCPPorts = [ 80 443 ]; ########################################################################### # 1. The control server. ########################################################################### services.nix-ota-server = { enable = true; listen = "127.0.0.1:8080"; # Put your real secret here. With sops-nix: # publishTokenFile = config.sops.secrets."nix-ota/publish-token".path; # For the demo we just write a literal file; replace this in production. publishTokenFile = pkgs.writeText "publish-token" "CHANGE-ME-LONG-RANDOM-STRING"; }; ########################################################################### # 2. The binary cache (nix-serve). Skip this if you use Attic / S3 / Cachix. ########################################################################### services.nix-serve = { enable = true; port = 5000; bindAddress = "127.0.0.1"; # Generate once with: # nix-store --generate-binary-cache-key ota.example.com-1 \ # /var/lib/nix-serve/key /var/lib/nix-serve/pub.key # Then commit the .pub file (it's public) and keep `key` secret. secretKeyFile = "/var/lib/nix-serve/key"; }; # Tell the local Nix daemon to trust paths signed by our cache so # `nix copy --to` from operators works without --no-check-sigs. nix.settings.trusted-public-keys = [ # paste the contents of /var/lib/nix-serve/pub.key here "ota.example.com-1:REPLACE_WITH_PUBLIC_KEY" ]; ########################################################################### # 3. Reverse proxy + TLS. ########################################################################### services.nginx = { enable = true; recommendedProxySettings = true; recommendedTlsSettings = true; virtualHosts."ota.example.com" = { enableACME = true; forceSSL = true; locations."/" = { proxyPass = "http://127.0.0.1:8080"; }; locations."/cache/" = { proxyPass = "http://127.0.0.1:5000/"; # nix-serve doesn't need any special headers. }; }; }; security.acme = { acceptTerms = true; defaults.email = "ops@example.com"; }; system.stateVersion = "24.05"; }