diff --git a/modules/nixos/linux/incus/incus-pet/example/hello-web/README.md b/modules/nixos/linux/incus/incus-pet/example/hello-web/README.md new file mode 100644 index 0000000..af57845 --- /dev/null +++ b/modules/nixos/linux/incus/incus-pet/example/hello-web/README.md @@ -0,0 +1,40 @@ +# hello-web — incus-pet reference example + +Smallest possible flake that satisfies the [incus-pet contract](../../SKILL.md). +A static HTTP server (`darkhttpd` wrapping a one-page `index.html`) packaged +through the full stack: + +- `packages..default` — the binary +- `nixosModules.default` — `services.hello-web.{enable, package, host, port}` + a systemd unit +- `nixosModules.incus` — the deploy contract (binds 8080 inside a `hello-web` container) + +## Build it standalone + +```sh +nix build path:./modules/nixos/linux/incus/incus-pet/example/hello-web + +# Then run it locally — listens on 0.0.0.0:8080. +./result/bin/hello-web & +curl http://127.0.0.1:8080 +``` + +## Deploy it as an incus-pet container + +From a host that has the incus daemon and the `incus-pet` CLI on PATH: + +```sh +nix run path:.#incus-pet -- deploy \ + path:./modules/nixos/linux/incus/incus-pet/example/hello-web \ + hello-web --port 8081 --listen 100.122.32.106 + +curl http://100.122.32.106:8081 +``` + +`incus-pet list` will show the running container; `incus-pet rm hello-web` +tears it down. + +## What to read next + +The flake here is meant to be a working template. Compare the three +outputs (`packages.default`, `nixosModules.default`, `nixosModules.incus`) +side-by-side with what srid/anywhen ships — same shape, scaled down. diff --git a/modules/nixos/linux/incus/incus-pet/example/hello-web/flake.lock b/modules/nixos/linux/incus/incus-pet/example/hello-web/flake.lock new file mode 100644 index 0000000..5966c45 --- /dev/null +++ b/modules/nixos/linux/incus/incus-pet/example/hello-web/flake.lock @@ -0,0 +1,27 @@ +{ + "nodes": { + "nixpkgs": { + "locked": { + "lastModified": 1779357205, + "narHash": "sha256-cCO8aTqss5x9Ky8GWkpY0Hy5fyTZEbtifSUV8QjSzic=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "f83fc3c307e74bc5fd5adb7eb6b8b13ffd2a36e1", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "nixpkgs": "nixpkgs" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/modules/nixos/linux/incus/incus-pet/example/hello-web/flake.nix b/modules/nixos/linux/incus/incus-pet/example/hello-web/flake.nix new file mode 100644 index 0000000..66380c6 --- /dev/null +++ b/modules/nixos/linux/incus/incus-pet/example/hello-web/flake.nix @@ -0,0 +1,115 @@ +# hello-web — minimal incus-pet example. +# +# Self-contained reference flake that ships the three outputs incus-pet +# consumes: +# +# - packages..default a tiny static-file server (darkhttpd +# wrapped to read HOST/PORT from env) +# - nixosModules.default services.hello-web.{enable, package, +# host, port} + a systemd unit +# - nixosModules.incus the deploy contract — wires the +# service to bind 8080 inside an incus +# container at hostname "hello-web" +# +# Deploy with (from a host that has the incus daemon + incus-pet CLI): +# +# nix run github:srid/nixos-config#incus-pet -- \ +# deploy --port 8081 --listen +{ + inputs.nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; + + outputs = { self, nixpkgs, ... }: + let + systems = [ "x86_64-linux" "aarch64-linux" ]; + eachSystem = f: nixpkgs.lib.genAttrs systems + (system: f nixpkgs.legacyPackages.${system}); + in + { + packages = eachSystem (pkgs: + let + www = pkgs.writeTextDir "index.html" '' + + + hello-web +

Hello from incus-pet

+

Served by darkhttpd inside an incus container.

+ ''; + hello-web = pkgs.writeShellApplication { + name = "hello-web"; + runtimeInputs = [ pkgs.darkhttpd ]; + text = '' + HOST="''${HOST:-0.0.0.0}" + PORT="''${PORT:-8080}" + exec darkhttpd ${www} --addr "$HOST" --port "$PORT" + ''; + meta.mainProgram = "hello-web"; + }; + in + { + default = hello-web; + hello-web = hello-web; + }); + + nixosModules.default = { config, lib, pkgs, ... }: + let + cfg = config.services.hello-web; + in + { + options.services.hello-web = { + enable = lib.mkEnableOption "hello-web example server"; + package = lib.mkOption { + type = lib.types.package; + description = "The hello-web package to run (must expose bin/hello-web via meta.mainProgram)."; + }; + host = lib.mkOption { + type = lib.types.str; + default = "0.0.0.0"; + description = "Address the HTTP server binds to."; + }; + port = lib.mkOption { + type = lib.types.port; + default = 8080; + description = "Port the HTTP server listens on."; + }; + }; + + config = lib.mkIf cfg.enable { + systemd.services.hello-web = { + description = "hello-web example HTTP server"; + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" ]; + environment = { + HOST = cfg.host; + PORT = toString cfg.port; + }; + serviceConfig = { + ExecStart = lib.getExe cfg.package; + Restart = "on-failure"; + RestartSec = 2; + DynamicUser = true; + }; + }; + }; + }; + + # incus-pet contract — see SKILL.md in the incus-pet tree. + nixosModules.incus = { config, lib, pkgs, ... }: { + imports = [ self.nixosModules.default ]; + + incus.container = { + enable = true; + hostname = lib.mkDefault "hello-web"; + }; + system.stateVersion = "25.05"; + + services.hello-web = { + enable = true; + package = lib.mkDefault self.packages.${pkgs.stdenv.hostPlatform.system}.default; + host = lib.mkDefault "0.0.0.0"; + port = 8080; # fixed by the incus-pet contract + }; + }; + + formatter = eachSystem (pkgs: pkgs.nixpkgs-fmt); + }; +}