Adding a new service¶
The full path from "I want to run X" to "X is deployed and reachable".
Decide where and how¶
Two questions first:
- Which host? Applications go on midgard. Only ingress/monitoring infrastructure goes on yggdrasil (principles).
- Module or container?
Prefer this when nixpkgs packages the service well. Create
services/<name>.nix:
{...}: {
services.<name> = {
enable = true;
# bind to localhost or a tailnet-reachable port,
# never open the firewall
};
}
Use when upstream packages better as a container (midgard only, pinned tag):
{...}: {
virtualisation.oci-containers.containers.<name> = {
image = "ghcr.io/org/app:1.2.3"; # never :latest
ports = ["127.0.0.1:8090:8080"];
};
}
Checklist¶
- Create the module under
services/<name>.nix - Wire it in:
hosts/<host>/default.niximports (host-specific) orflake.nixmodules list (shared) - Secrets, if any: add to
secrets/*.yamlvia sops, declaresops.secrets."..."(see Secrets) - Exposure, if needed:
- Caddy virtualHost in
services/ingress.nix - Public service → hostname in
services/cloudflared.nixingress; tailnet-only →@tailnetmatcher pattern instead - DNS record in Cloudflare (public: Tunnel CNAME, tailnet-only: yggdrasil's tailnet address)
- Caddy virtualHost in
- Monitoring: add an Uptime Kuma check for public endpoints
- Validate:
nix flake check --no-build - Deploy:
just test <host>, verify, thenjust switch <host> - Commit
Verify¶
# on the host
systemctl status <name>
curl -fsS http://127.0.0.1:<port>/
# from a tailnet client, if exposed
curl -fsS https://<name>.ridewithmin.com/
If it goes wrong¶
just test activations disappear on reboot. For a switched deploy, roll
back on the host:
sudo nixos-rebuild switch --rollback