Compare commits

...

6 commits

34 changed files with 282 additions and 1402 deletions

View file

@ -1,68 +1,14 @@
{
lib,
pkgs,
config,
...
}: {
imports = [../../modules/homebox.nix];
wireguard.elisabeth = {
client.via = "elisabeth";
firewallRuleForNode.elisabeth.allowedTCPPorts = [config.services.forgejo.settings.server.HTTP_PORT];
firewallRuleForNode.elisabeth.allowedTCPPorts = [3000];
};
systemd.services.homebox = {
after = ["network.target"];
environment = {
HBOX_OPTIONS_ALLOW_REGISTRATION = "false";
services.homebox = {
enable = true;
settings = {
HBOX_WEB_PORT = "3000";
};
script = ''
${lib.getExe pkgs.homebox} \
--mode production \
--web-port 3000 \
--storage-data ./data \
--storage-sqlite-url "./data/homebox.db?_pragma=busy_timeout=999&_pragma=journal_mode=WAL&_fk=1" \
--options-allow-registration false
'';
serviceConfig = {
User = "homebox";
Group = "homebox";
DynamicUser = true;
StateDirectory = "homebox";
WorkingDirectory = "/var/lib/homebox";
LimitNOFILE = "1048576";
PrivateTmp = true;
PrivateDevices = true;
StateDirectoryMode = "0700";
Restart = "always";
# Hardening
CapabilityBoundingSet = "";
LockPersonality = true;
MemoryDenyWriteExecute = true;
PrivateUsers = true;
ProtectClock = true;
ProtectControlGroups = true;
ProtectHome = true;
ProtectHostname = true;
ProtectKernelLogs = true;
ProtectKernelModules = true;
ProtectKernelTunables = true;
ProtectProc = "invisible";
ProcSubset = "pid";
ProtectSystem = "strict";
RestrictAddressFamilies = [
"AF_INET"
"AF_INET6"
"AF_NETLINK"
];
RestrictNamespaces = true;
RestrictRealtime = true;
SystemCallArchitectures = "native";
SystemCallFilter = [
"@system-service"
"@pkey"
];
UMask = "0077";
};
wantedBy = ["multi-user.target"];
};
environment.persistence."/persist".directories = [
{

View file

@ -122,6 +122,7 @@ in {
groups."rss.access" = {};
groups."firefly.access" = {};
groups."ollama.access" = {};
groups."adguardhome.access" = {
};
systems.oauth2.oauth2-proxy = {
@ -131,12 +132,14 @@ in {
scopeMaps."adguardhome.access" = ["openid" "email" "profile"];
scopeMaps."rss.access" = ["openid" "email" "profile"];
scopeMaps."firefly.access" = ["openid" "email" "profile"];
scopeMaps."ollama.access" = ["openid" "email" "profile"];
preferShortUsername = true;
claimMaps.groups = {
joinType = "array";
valuesByGroup."adguardhome.access" = ["adguardhome_access"];
valuesByGroup."rss.access" = ["ttrss_access"];
valuesByGroup."firefly.access" = ["firefly_access"];
valuesByGroup."ollama.access" = ["ollama_access"];
};
};

View file

@ -3,8 +3,6 @@
lib,
...
}: {
disabledModules = ["services/networking/netbird/server.nix"];
imports = [../../modules/netbird/server.nix];
wireguard.elisabeth = {
client.via = "elisabeth";
firewallRuleForNode.elisabeth.allowedTCPPorts = [80 3000 3001];

View file

@ -1,10 +1,32 @@
{
networking.firewall.allowedTCPPorts = [11434];
{config, ...}: {
wireguard.elisabeth = {
client.via = "elisabeth";
firewallRuleForNode.elisabeth.allowedTCPPorts = [config.services.open-webui.port];
};
networking.firewall.allowedTCPPorts = [config.services.open-webui.port];
services.ollama = {
listenAddress = "0.0.0.0:11434";
host = "localhost";
port = 3001;
enable = true;
};
services.open-webui = {
host = "0.0.0.0";
port = 3000;
enable = true;
environment = {
OLLAMA_BASE_URL = "http://localhost:3001";
ANONYMIZED_TELEMETRY = "False";
DO_NOT_TRACK = "True";
SCARF_NO_ANALYTICS = "True";
TRANSFORMERS_CACHE = "/var/lib/open-webui/cache/huggingface";
WEBUI_AUTH_TRUSTED_EMAIL_HEADER = "X-Email";
};
};
environment.persistence."/state".directories = [
{
directory = "/var/lib/private/open-webui";
mode = "0700";
}
{
directory = "/var/lib/private/ollama";
mode = "0700";

View file

@ -12,11 +12,11 @@
"systems": "systems"
},
"locked": {
"lastModified": 1715290355,
"narHash": "sha256-2T7CHTqBXJJ3ZC6R/4TXTcKoXWHcvubKNj9SfomURnw=",
"lastModified": 1716561646,
"narHash": "sha256-UIGtLO89RxKt7RF2iEgPikSdU53r6v/6WYB0RW3k89I=",
"owner": "ryantm",
"repo": "agenix",
"rev": "8d37c5bdeade12b6479c85acd133063ab53187a0",
"rev": "c2fc0762bbe8feb06a2e59a364fa81b3a57671c9",
"type": "github"
},
"original": {
@ -37,11 +37,11 @@
"pre-commit-hooks": "pre-commit-hooks"
},
"locked": {
"lastModified": 1713903302,
"narHash": "sha256-qPy0BYFTenmyG4EU+oXej0V/i4jSsVvWbGGrv9Sb0kQ=",
"lastModified": 1717947583,
"narHash": "sha256-vN/pfiAzYH4i3cUb5pLqkXgPoAPtaxjUXv5aRpbKShU=",
"owner": "oddlama",
"repo": "agenix-rekey",
"rev": "8da0392e75373711604a07907de25ec9d5277384",
"rev": "4551006c2807ab361ea4db5e171afb4798da4fc2",
"type": "github"
},
"original": {
@ -270,11 +270,11 @@
]
},
"locked": {
"lastModified": 1713532798,
"narHash": "sha256-wtBhsdMJA3Wa32Wtm1eeo84GejtI43pMrFrmwLXrsEc=",
"lastModified": 1717408969,
"narHash": "sha256-Q0OEFqe35fZbbRPPRdrjTUUChKVhhWXz3T9ZSKmaoVY=",
"owner": "numtide",
"repo": "devshell",
"rev": "12e914740a25ea1891ec619bb53cf5e6ca922e40",
"rev": "1ebbe68d57457c8cae98145410b164b5477761f4",
"type": "github"
},
"original": {
@ -336,11 +336,11 @@
]
},
"locked": {
"lastModified": 1713532798,
"narHash": "sha256-wtBhsdMJA3Wa32Wtm1eeo84GejtI43pMrFrmwLXrsEc=",
"lastModified": 1717408969,
"narHash": "sha256-Q0OEFqe35fZbbRPPRdrjTUUChKVhhWXz3T9ZSKmaoVY=",
"owner": "numtide",
"repo": "devshell",
"rev": "12e914740a25ea1891ec619bb53cf5e6ca922e40",
"rev": "1ebbe68d57457c8cae98145410b164b5477761f4",
"type": "github"
},
"original": {
@ -356,11 +356,11 @@
]
},
"locked": {
"lastModified": 1716291492,
"narHash": "sha256-Qvfoa99WdYIneGrrLFIKQCevLgB5vnxvwJe5aWbGYZY=",
"lastModified": 1717915259,
"narHash": "sha256-VsGPboaleIlPELHY5cNTrXK4jHVmgUra8uC6h7KVC5c=",
"owner": "nix-community",
"repo": "disko",
"rev": "f1654e07728008d354c704d265fc710e3f5f42ee",
"rev": "1bbdb06f14e2621290b250e631cf3d8948e4d19b",
"type": "github"
},
"original": {
@ -435,11 +435,11 @@
},
"flake-compat_5": {
"locked": {
"lastModified": 1688025799,
"narHash": "sha256-ktpB4dRtnksm9F5WawoIkEneh1nrEvuxb5lJFt1iOyw=",
"lastModified": 1717312683,
"narHash": "sha256-FrlieJH50AuvagamEvWMIE6D2OAnERuDboFDYAED/dE=",
"owner": "nix-community",
"repo": "flake-compat",
"rev": "8bf105319d44f6b9f0d764efa4fdef9f1cc9ba1c",
"rev": "38fd3954cf65ce6faf3d0d45cd26059e059f07ea",
"type": "github"
},
"original": {
@ -561,11 +561,11 @@
]
},
"locked": {
"lastModified": 1715865404,
"narHash": "sha256-/GJvTdTpuDjNn84j82cU6bXztE0MSkdnTWClUCRub78=",
"lastModified": 1717285511,
"narHash": "sha256-iKzJcpdXih14qYVcZ9QC9XuZYnPc6T8YImb6dX166kw=",
"owner": "hercules-ci",
"repo": "flake-parts",
"rev": "8dc45382d5206bd292f9c2768b8058a8fd8311d9",
"rev": "2a55567fcf15b1b1c7ed712a2c6fadaec7412ea8",
"type": "github"
},
"original": {
@ -574,21 +574,6 @@
"type": "github"
}
},
"flake-root": {
"locked": {
"lastModified": 1713493429,
"narHash": "sha256-ztz8JQkI08tjKnsTpfLqzWoKFQF4JGu2LRz8bkdnYUk=",
"owner": "srid",
"repo": "flake-root",
"rev": "bc748b93b86ee76e2032eecda33440ceb2532fcd",
"type": "github"
},
"original": {
"owner": "srid",
"repo": "flake-root",
"type": "github"
}
},
"flake-utils": {
"inputs": {
"systems": "systems_3"
@ -769,6 +754,33 @@
"type": "github"
}
},
"git-hooks": {
"inputs": {
"flake-compat": "flake-compat_7",
"gitignore": "gitignore_5",
"nixpkgs": [
"nixvim",
"nixpkgs"
],
"nixpkgs-stable": [
"nixvim",
"nixpkgs"
]
},
"locked": {
"lastModified": 1717664902,
"narHash": "sha256-7XfBuLULizXjXfBYy/VV+SpYMHreNRHk9nKMsm1bgb4=",
"owner": "cachix",
"repo": "git-hooks.nix",
"rev": "cc4d466cb1254af050ff7bdf47f6d404a7c646d1",
"type": "github"
},
"original": {
"owner": "cachix",
"repo": "git-hooks.nix",
"type": "github"
}
},
"gitignore": {
"inputs": {
"nixpkgs": [
@ -861,7 +873,7 @@
"inputs": {
"nixpkgs": [
"nixvim",
"pre-commit-hooks",
"git-hooks",
"nixpkgs"
]
},
@ -924,11 +936,11 @@
]
},
"locked": {
"lastModified": 1715930644,
"narHash": "sha256-W9pyM3/vePxrffHtzlJI6lDS3seANQ+Nqp+i58O46LI=",
"lastModified": 1717931644,
"narHash": "sha256-Sz8Wh9cAiD5FhL8UWvZxBfnvxETSCVZlqWSYWaCPyu0=",
"owner": "nix-community",
"repo": "home-manager",
"rev": "e3ad5108f54177e6520535768ddbf1e6af54b59d",
"rev": "3d65009effd77cb0d6e7520b68b039836a7606cf",
"type": "github"
},
"original": {
@ -945,11 +957,11 @@
]
},
"locked": {
"lastModified": 1715930644,
"narHash": "sha256-W9pyM3/vePxrffHtzlJI6lDS3seANQ+Nqp+i58O46LI=",
"lastModified": 1717525419,
"narHash": "sha256-5z2422pzWnPXHgq2ms8lcCfttM0dz+hg+x1pCcNkAws=",
"owner": "nix-community",
"repo": "home-manager",
"rev": "e3ad5108f54177e6520535768ddbf1e6af54b59d",
"rev": "a7117efb3725e6197dd95424136f79147aa35e5b",
"type": "github"
},
"original": {
@ -981,11 +993,11 @@
},
"impermanence": {
"locked": {
"lastModified": 1708968331,
"narHash": "sha256-VUXLaPusCBvwM3zhGbRIJVeYluh2uWuqtj4WirQ1L9Y=",
"lastModified": 1717932370,
"narHash": "sha256-7C5lCpiWiyPoIACOcu2mukn/1JRtz6HC/1aEMhUdcw0=",
"owner": "nix-community",
"repo": "impermanence",
"rev": "a33ef102a02ce77d3e39c25197664b7a636f9c30",
"rev": "27979f1c3a0d3b9617a3563e2839114ba7d48d3f",
"type": "github"
},
"original": {
@ -1027,11 +1039,11 @@
"nixpkgs-lib": "nixpkgs-lib"
},
"locked": {
"lastModified": 1716120557,
"narHash": "sha256-rvNq9YolMY1DRMgwdAti8qwNDjkhTsotSWa15/Ch7+A=",
"lastModified": 1717935050,
"narHash": "sha256-UWi8G3J+pS+9LVMdjrpLJwncdiMQWrnuUd5ygxCHeNc=",
"owner": "nix-community",
"repo": "lib-aggregate",
"rev": "5fa64b174daa22fe0d20ebbcc0ec2c7905b503f1",
"rev": "1b6ea3be6ba37d4d3ba6e5041e2f152bb684ba2c",
"type": "github"
},
"original": {
@ -1064,11 +1076,11 @@
"spectrum": "spectrum"
},
"locked": {
"lastModified": 1715787097,
"narHash": "sha256-TPp2j0ttvBvkk4oXidvo8Y071zEab0BtcNsC3ZEkluI=",
"lastModified": 1717441449,
"narHash": "sha256-juxjgmLnFbl+/hhIO2cVtIa6caCO4pLKlZWUMwAOznM=",
"owner": "astro",
"repo": "microvm.nix",
"rev": "fa673bf8656fe6f28253b83971a36999bc9995d2",
"rev": "e3a4dd5b381fb580804105594cc9c71dc45abdb5",
"type": "github"
},
"original": {
@ -1085,11 +1097,11 @@
]
},
"locked": {
"lastModified": 1715901937,
"narHash": "sha256-eMyvWP56ZOdraC2IOvZo0/RTDcrrsqJ0oJWDC76JTak=",
"lastModified": 1716993688,
"narHash": "sha256-vo5k2wQekfeoq/2aleQkBN41dQiQHNTniZeVONWiWLs=",
"owner": "lnl7",
"repo": "nix-darwin",
"rev": "ffc01182f90118119930bdfc528c1ee9a39ecef8",
"rev": "c0d5b8c54d6828516c97f6be9f2d00c63a363df4",
"type": "github"
},
"original": {
@ -1106,11 +1118,11 @@
"treefmt-nix": "treefmt-nix"
},
"locked": {
"lastModified": 1715804156,
"narHash": "sha256-GtIHP86Cz1kD9xZO/cKbNQACHKdoT9WFbLJAq6W2EDY=",
"lastModified": 1717698186,
"narHash": "sha256-e3/cvm7bAn0RsTBcPfHwuYOi2lwoO4jpTn4nmMSvHfU=",
"owner": "nix-community",
"repo": "nix-eval-jobs",
"rev": "bb95091f6c6f38f6cfc215a1797a2dd466312c8b",
"rev": "b6169e08e76e10b673d1b54f944cddb1e7cbea97",
"type": "github"
},
"original": {
@ -1148,11 +1160,11 @@
]
},
"locked": {
"lastModified": 1716170277,
"narHash": "sha256-fCAiox/TuzWGVaAz16PxrR4Jtf9lN5dwWL2W74DS0yI=",
"lastModified": 1717919703,
"narHash": "sha256-4i/c31+dnpv6KdUA3BhbMDS9Lvg/CDin78caYJlq0bY=",
"owner": "nix-community",
"repo": "nix-index-database",
"rev": "e0638db3db43b582512a7de8c0f8363a162842b9",
"rev": "a157a81d0a4bc909b2b6666dd71909bcdc8cd0d6",
"type": "github"
},
"original": {
@ -1244,11 +1256,11 @@
},
"nixos-hardware": {
"locked": {
"lastModified": 1716173274,
"narHash": "sha256-FC21Bn4m6ctajMjiUof30awPBH/7WjD0M5yqrWepZbY=",
"lastModified": 1717828156,
"narHash": "sha256-YvstO0lobf3JWQuAfZCLYRTROC2ZDEgtWeQtWbO49p4=",
"owner": "nixos",
"repo": "nixos-hardware",
"rev": "d9e0b26202fd500cf3e79f73653cce7f7d541191",
"rev": "057a7996d012f342a38a26261ee529cebb1755ef",
"type": "github"
},
"original": {
@ -1296,11 +1308,11 @@
},
"nixpkgs-lib": {
"locked": {
"lastModified": 1716079763,
"narHash": "sha256-DGRfb7fO7c3XDS3twmuaV5NAGPPdU3W7Q35fjIZc8iY=",
"lastModified": 1717894324,
"narHash": "sha256-4q6ZO3BqHgdd3Aacb/xiQXB4g9TQKpQg/praTpD9vbI=",
"owner": "nix-community",
"repo": "nixpkgs.lib",
"rev": "0df131b5ee4d928a4b664b6d0cd99cf134d6ab6b",
"rev": "13eac98dc5233fe7e52f0cd0e2cba7dcd77feca5",
"type": "github"
},
"original": {
@ -1399,11 +1411,11 @@
]
},
"locked": {
"lastModified": 1716308443,
"narHash": "sha256-vPJ4VnR1EyW4ft6XlwHst3BMVMqsjXmCtV8ze0+Ox9k=",
"lastModified": 1717946219,
"narHash": "sha256-FtVXsRY/El4TAVUuM9BnJH2F5tSxd0UMK/AvVzZRsZA=",
"owner": "nix-community",
"repo": "nixpkgs-wayland",
"rev": "112d54c8a35e974ec03581e44f35d973a89446aa",
"rev": "8c7518a4167eb65ca62da3ab49578e728ee9a769",
"type": "github"
},
"original": {
@ -1414,11 +1426,11 @@
},
"nixpkgs_2": {
"locked": {
"lastModified": 1716137900,
"narHash": "sha256-sowPU+tLQv8GlqtVtsXioTKeaQvlMz/pefcdwg8MvfM=",
"lastModified": 1717786204,
"narHash": "sha256-4q0s6m0GUcN7q+Y2DqD27iLvbcd1G50T2lv08kKxkSI=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "6c0b7a92c30122196a761b440ac0d46d3d9954f1",
"rev": "051f920625ab5aabe37c920346e3e69d7d34400e",
"type": "github"
},
"original": {
@ -1481,21 +1493,20 @@
"devshell": "devshell_5",
"flake-compat": "flake-compat_6",
"flake-parts": "flake-parts_3",
"flake-root": "flake-root",
"git-hooks": "git-hooks",
"home-manager": "home-manager_2",
"nix-darwin": "nix-darwin",
"nixpkgs": [
"nixpkgs"
],
"pre-commit-hooks": "pre-commit-hooks_4",
"treefmt-nix": "treefmt-nix_2"
},
"locked": {
"lastModified": 1716294469,
"narHash": "sha256-1RdJkVa+axdzLhbeoWJoC3BPODxfx+/Rv7HE+e4CK/Y=",
"lastModified": 1717922156,
"narHash": "sha256-C/TgTnKY4iWXnBmKocV9KeV+OtZGCh+1Pcw26Elx7JM=",
"owner": "nix-community",
"repo": "nixvim",
"rev": "1c9f2a23a6cb9406c35980f4af1a4356f56771e9",
"rev": "8a462dc9570bce1de5a7dd1beabd83f95958315b",
"type": "github"
},
"original": {
@ -1620,33 +1631,6 @@
}
},
"pre-commit-hooks_4": {
"inputs": {
"flake-compat": "flake-compat_7",
"gitignore": "gitignore_5",
"nixpkgs": [
"nixvim",
"nixpkgs"
],
"nixpkgs-stable": [
"nixvim",
"nixpkgs"
]
},
"locked": {
"lastModified": 1715870890,
"narHash": "sha256-nacSOeXtUEM77Gn0G4bTdEOeFIrkCBXiyyFZtdGwuH0=",
"owner": "cachix",
"repo": "pre-commit-hooks.nix",
"rev": "fa606cccd7b0ccebe2880051208e4a0f61bfc8c1",
"type": "github"
},
"original": {
"owner": "cachix",
"repo": "pre-commit-hooks.nix",
"type": "github"
}
},
"pre-commit-hooks_5": {
"inputs": {
"flake-compat": "flake-compat_8",
"gitignore": "gitignore_6",
@ -1656,11 +1640,11 @@
"nixpkgs-stable": "nixpkgs-stable_5"
},
"locked": {
"lastModified": 1716213921,
"narHash": "sha256-xrsYFST8ij4QWaV6HEokCUNIZLjjLP1bYC60K8XiBVA=",
"lastModified": 1717664902,
"narHash": "sha256-7XfBuLULizXjXfBYy/VV+SpYMHreNRHk9nKMsm1bgb4=",
"owner": "cachix",
"repo": "pre-commit-hooks.nix",
"rev": "0e8fcc54b842ad8428c9e705cb5994eaf05c26a0",
"rev": "cc4d466cb1254af050ff7bdf47f6d404a7c646d1",
"type": "github"
},
"original": {
@ -1689,7 +1673,7 @@
"nixpkgs": "nixpkgs_2",
"nixpkgs-wayland": "nixpkgs-wayland",
"nixvim": "nixvim",
"pre-commit-hooks": "pre-commit-hooks_5",
"pre-commit-hooks": "pre-commit-hooks_4",
"spicetify-nix": "spicetify-nix",
"stylix": "stylix",
"systems": "systems_12",
@ -1771,11 +1755,11 @@
"nixpkgs": "nixpkgs_5"
},
"locked": {
"lastModified": 1716206302,
"narHash": "sha256-5Qc3aQGVyPEOuN82zVamStaV81HebHvLjk3fGfpyCPY=",
"lastModified": 1717866166,
"narHash": "sha256-iOeRZXIhFpQJdxzNJ3nUAANyDfLqCslRhjGhLD2RstM=",
"owner": "danth",
"repo": "stylix",
"rev": "81df8443556335016d6f0bc22630a95776a56d8b",
"rev": "ca3247ed8cfbf369f3fe1b7a421579812a95c101",
"type": "github"
},
"original": {
@ -2009,11 +1993,11 @@
]
},
"locked": {
"lastModified": 1715940852,
"narHash": "sha256-wJqHMg/K6X3JGAE9YLM0LsuKrKb4XiBeVaoeMNlReZg=",
"lastModified": 1717850719,
"narHash": "sha256-npYqVg+Wk4oxnWrnVG7416fpfrlRhp/lQ6wQ4DHI8YE=",
"owner": "numtide",
"repo": "treefmt-nix",
"rev": "2fba33a182602b9d49f0b2440513e5ee091d838b",
"rev": "4fc1c45a5f50169f9f29f6a98a438fb910b834ed",
"type": "github"
},
"original": {

View file

@ -117,7 +117,7 @@
{
secretsConfig = {
# This should be a link to one of the age public keys is './keys'
masterIdentities = ["/run/decrypt.key.pub"];
masterIdentities = [./keys/PatC.pub];
extraEncryptionPubkeys = [./secrets/recipients.txt];
};
agenix-rekey = agenix-rekey.configure {

View file

@ -1,19 +0,0 @@
[patricknix]
type = "nixos"
system = "x86_64-linux"
[desktopnix]
type = "nixos"
system = "x86_64-linux"
[gojo]
type = "nixos"
system = "x86_64-linux"
[maddy]
type = "nixos"
system = "x86_64-linux"
[elisabeth]
type = "nixos"
system = "x86_64-linux"

View file

@ -50,9 +50,6 @@
dockerCompat = true;
};
system.activationScripts.decryptKey.text = ''
ln -f -s ${../../keys/PatC.key} /run/decrypt.key.pub
'';
boot.binfmt.emulatedSystems = ["aarch64-linux" "riscv64-linux"];
nix.settings.system-features = ["kvm" "nixos-test"];
@ -63,4 +60,5 @@
services.netbird.enable = true;
# Do not cleanup nix store to prevent having to rebuild packages onca a month
nix.gc.automatic = lib.mkForce false;
nixpkgs.hostPlatform = "x86_64-linux";
}

View file

@ -33,4 +33,5 @@
variant = "bone";
};
};
nixpkgs.hostPlatform = "x86_64-linux";
}

View file

@ -13,7 +13,7 @@
forgejo = "forge";
immich = "immich";
nextcloud = "nc";
ollama = "ollama";
ollama = "ai";
paperless = "ppl";
ttrss = "rss";
vaultwarden = "pw";
@ -72,7 +72,8 @@ in {
# pass information via X-User and X-Email headers to backend,
# requires running with --set-xauthrequest flag
auth_request_set $user $upstream_http_x_auth_request_preferred_username;
auth_request_set $email $upstream_http_x_auth_request_email;
# Set the email to our own domain in case user change their mail
auth_request_set $email "''${upstream_http_x_auth_request_preferred_username}@${config.secrets.secrets.global.domains.web}";
proxy_set_header X-User $user;
proxy_set_header X-Email $email;
@ -162,9 +163,8 @@ in {
(proxyProtect "ttrss" {port = 80;} true)
(blockOf "yourspotify" {port = 80;})
(blockOf "homebox" {})
((proxyProtect "firefly" {port = 80;} true)
// {
})
(proxyProtect "ollama" {} true)
(proxyProtect "firefly" {port = 80;} true)
(blockOf "apispotify" {
port = 3000;
upstream = "yourspotify";

View file

@ -1,43 +0,0 @@
{
inputs,
lib,
...
}: {
imports = [
inputs.nixos-hardware.nixosModules.common-cpu-intel
inputs.nixos-hardware.nixosModules.common-gpu-intel
inputs.nixos-hardware.nixosModules.common-pc-laptop
inputs.nixos-hardware.nixosModules.common-pc-laptop-ssd
../../config/basic
../../config/optional/dev.nix
../../config/optional/graphical.nix
../../config/optional/wayland.nix
../../config/optional/xserver.nix
../../config/optional/printing.nix
../../config/hardware/bluetooth.nix
../../config/hardware/laptop.nix
../../config/hardware/physical.nix
../../config/hardware/pipewire.nix
../../config/hardware/yubikey.nix
./net.nix
./fs.nix
../../users/simon
];
stylix.fonts.sizes = {
#terminal = 9;
#applications = 9;
#desktop = 8;
};
services.xserver = {
layout = "de";
xkbVariant = "neo";
libinput = {
touchpad = lib.mkForce {
accelSpeed = "0.5";
};
};
};
}

View file

@ -1,30 +0,0 @@
{
config,
lib,
...
}: {
disko.devices = {
disk = {
ssd = {
type = "disk";
device = "/dev/disk/by-id/${config.secrets.secrets.local.disko.ssd}";
content = with lib.disko.gpt; {
type = "gpt";
partitions = {
boot = partEfi "260MB";
rpool = {
content = {
type = "zfs";
pool = "rpool";
};
};
};
};
};
};
zpool = with lib.disko.zfs; {
rpool = mkZpool {datasets = impermanenceZfsDatasets;};
};
};
fileSystems."/state".neededForBoot = true;
}

View file

@ -1,24 +0,0 @@
{config, ...}: {
networking = {
inherit (config.secrets.secrets.local.networking) hostId;
wireless.iwd.enable = true;
};
systemd.network.networks = {
"01-wlan1" = {
DHCP = "yes";
matchConfig.MACAddress = config.secrets.secrets.local.networking.wlan1.mac;
networkConfig = {
IPv6PrivacyExtensions = "yes";
MulticastDNS = true;
};
dns = ["1.1.1.1"];
dhcpV4Config.RouteMetric = 40;
dhcpV6Config.RouteMetric = 40;
};
};
age.secrets.eduroam = {
rekeyFile = ./secrets/iwd/eduroam.8021x.age;
path = "/var/lib/iwd/eduroam.8021x";
};
}

View file

@ -1 +0,0 @@
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIH+6isyj+sdzilpFSgGjw3xUfoJ1s307OJGcuzmgJL+L

View file

@ -1,17 +0,0 @@
age-encryption.org/v1
-> X25519 FvDDqK/3eca0id5we/szPNjtkeNg44MPJJa/DkxA8yY
bERDGRpArN1wKKvYEDZuP4ktvBj3yYj5ophx5PLC9hU
-> piv-p256 XTQkUA AxE8qOeoW7GCN++vsXmKs1p92iiNHuV/DEPR4K1h64gy
UUfWj4rXavZA28BM/hBKqLF1MJcakFpEIdzd/78SoVY
-> piv-p256 ZFgiIw AtMYu+DvAD//JL7rZfEkkeGyxakvqzArsTjVwe6IRDZI
fdTmmtSM1Wy2y+0INVKYbCItuKh/qSipRa/OHeNQoEY
-> piv-p256 5vmPtQ A/pjTZCYMU8jMEN1lIDPTsnuMxclc+7tSDZ/jc+vHptt
6KAF06R1l47U2RdCkJK+lFc67SMR/+hvxfi2qrJDyS0
-> piv-p256 ZFgiIw A0N/CAMSA29+Sqbol4PCs7wYYJT4AvAKd0DKe0hfy8Bp
Vlo9T4FZNRK8kR5OuxrAVUe5Tx5x9NAeaI2gKIJeNEA
-> dZ2v|-grease *(F:08]t
IZuQlw2zI1CelSB69O6XeKI2qG83Cu/bRhusaMtUYfGH5iskbPdh0OJ6ohadEusT
sYUVi0mBry7L
--- Y5cpADckhrStO9mPQXw8h448VBYUXCiKEYucO8qNHg4
6¨ÉôUsüÖ½èK¶tJ4ð8<C3B0>ËŸ¸÷%7³¿ËÛ° ãÌ'óîæ¤o•<6F>˜êˆ]ß-7nÝ|bx<62>¢­¶MŸ“ Ú<C39A>¬»m$š¡÷¾<C3B7>X⇸S<C2B8>âæßsUf±|<7C>K6¡ÒŽ©vL<76>._.ì+¬ïùV
¥ÿsÅm­”ÁÖ­Àÿ·nªÜ·~Pñ¸5p!g÷€W×½kÑþ`û+»y}ñî£

Binary file not shown.

View file

@ -14,4 +14,5 @@
};
boot.mode = "bios";
boot.initrd.availableKernelModules = ["virtio_pci" "virtio_net" "virtio_scsi" "virtio_blk"];
nixpkgs.hostPlatform = "x86_64-linux";
}

View file

@ -51,8 +51,5 @@
};
};
};
system.activationScripts.decryptKey.text = ''
ln -f -s ${../../keys/PatC.key} /run/decrypt.key.pub
'';
services.netbird.enable = true;
nixpkgs.hostPlatform = "x86_64-linux";
}

93
modules/homebox.nix Normal file
View file

@ -0,0 +1,93 @@
{
lib,
config,
pkgs,
...
}: let
cfg = config.services.homebox;
inherit
(lib)
mkEnableOption
mkPackageOption
mkDefault
types
mkIf
;
in {
options.services.homebox = {
enable = mkEnableOption "homebox";
package = mkPackageOption pkgs "homebox" {};
settings = lib.mkOption {
type = types.attrsOf types.str;
defaultText = ''
HBOX_STORAGE_DATA = "/var/lib/homebox/data";
HBOX_STORAGE_SQLITE_URL = "/var/lib/homebox/data/homebox.db?_pragma=busy_timeout=999&_pragma=journal_mode=WAL&_fk=1";
HBOX_OPTIONS_ALLOW_REGISTRATION = "false";
HBOX_MODE = "production";
'';
description = ''
The homebox configuration as Environment variables. For definitions and available options see the upstream documentation at:
[docs](https://hay-kot.github.io/homebox/quick-start/#env-variables-configuration).
'';
};
};
config = mkIf cfg.enable {
services.homebox.settings = {
HBOX_STORAGE_DATA = mkDefault "/var/lib/homebox/data";
HBOX_STORAGE_SQLITE_URL = mkDefault "/var/lib/homebox/data/homebox.db?_pragma=busy_timeout=999&_pragma=journal_mode=WAL&_fk=1";
HBOX_OPTIONS_ALLOW_REGISTRATION = mkDefault "false";
HBOX_MODE = mkDefault "production";
};
systemd.services.homebox = {
after = ["network.target"];
environment = cfg.settings;
serviceConfig = {
User = "homebox";
Group = "homebox";
ExecStart = lib.getExe cfg.package;
DynamicUser = true;
StateDirectory = "homebox";
WorkingDirectory = "/var/lib/homebox";
LimitNOFILE = "1048576";
PrivateTmp = true;
PrivateDevices = true;
StateDirectoryMode = "0700";
Restart = "always";
# Hardening
CapabilityBoundingSet = "";
LockPersonality = true;
MemoryDenyWriteExecute = true;
PrivateUsers = true;
ProtectClock = true;
ProtectControlGroups = true;
ProtectHome = true;
ProtectHostname = true;
ProtectKernelLogs = true;
ProtectKernelModules = true;
ProtectKernelTunables = true;
ProtectProc = "invisible";
ProcSubset = "pid";
ProtectSystem = "strict";
RestrictAddressFamilies = [
"AF_INET"
"AF_INET6"
"AF_NETLINK"
];
RestrictNamespaces = true;
RestrictRealtime = true;
SystemCallArchitectures = "native";
SystemCallFilter = [
"@system-service"
"@pkey"
];
RestrictSUIDSGID = true;
PrivateMounts = true;
# System Call Filtering
UMask = "0077";
};
wantedBy = ["multi-user.target"];
};
};
meta.maintainers = with lib.maintainers; [patrickdag];
}

View file

@ -1,162 +0,0 @@
{
config,
lib,
pkgs,
...
}: let
inherit
(lib)
getExe
literalExpression
mkAfter
mkEnableOption
mkIf
mkMerge
mkOption
optionalAttrs
optionalString
;
inherit
(lib.types)
bool
listOf
nullOr
path
port
str
;
cfg = config.services.netbird.server.coturn;
in {
options.services.netbird.server.coturn = {
enable = mkEnableOption "a Coturn server for Netbird, will also open the firewall on the configured range";
useAcmeCertificates = mkOption {
type = bool;
default = false;
description = ''
Whether to use ACME certificates corresponding to the given domain for the server.
'';
};
domain = mkOption {
type = str;
description = "The domain under which the coturn server runs.";
};
user = mkOption {
type = str;
default = "netbird";
description = ''
The username used by netbird to connect to the coturn server.
'';
};
password = mkOption {
type = nullOr str;
default = null;
description = ''
The password of the user used by netbird to connect to the coturn server.
Be advised this will be world readable in the nix store.
'';
};
passwordFile = mkOption {
type = nullOr path;
default = null;
description = ''
The path to a file containing the password of the user used by netbird to connect to the coturn server.
'';
};
openPorts = mkOption {
type = listOf port;
default = with config.services.coturn; [
listening-port
alt-listening-port
tls-listening-port
alt-tls-listening-port
];
defaultText = literalExpression ''
with config.services.coturn; [
listening-port
alt-listening-port
tls-listening-port
alt-tls-listening-port
];
'';
description = ''
The list of ports used by coturn for listening to open in the firewall.
'';
};
};
config = mkIf cfg.enable (mkMerge [
{
assertions = [
{
assertion = (cfg.password == null) != (cfg.passwordFile == null);
message = "Exactly one of `password` or `passwordFile` must be given for the coturn setup.";
}
];
services.coturn =
{
enable = true;
realm = cfg.domain;
lt-cred-mech = true;
no-cli = true;
extraConfig = ''
fingerprint
user=${cfg.user}:${
if cfg.password != null
then cfg.password
else "@password@"
}
no-software-attribute
'';
}
// (optionalAttrs cfg.useAcmeCertificates {
cert = "@cert@";
pkey = "@pkey@";
});
systemd.services.coturn = let
dir = config.security.acme.certs.${cfg.domain}.directory;
preStart' =
(optionalString (cfg.passwordFile != null) ''
${getExe pkgs.replace-secret} @password@ ${cfg.passwordFile} /run/coturn/turnserver.cfg
'')
+ (optionalString cfg.useAcmeCertificates ''
${getExe pkgs.replace-secret} @cert@ "$CREDENTIALS_DIRECTORY/cert.pem" /run/coturn/turnserver.cfg
${getExe pkgs.replace-secret} @pkey@ "$CREDENTIALS_DIRECTORY/pkey.pem" /run/coturn/turnserver.cfg
'');
in
(optionalAttrs (preStart' != "") {preStart = mkAfter preStart';})
// (optionalAttrs cfg.useAcmeCertificates {
serviceConfig.LoadCredential = [
"cert.pem:${dir}/fullchain.pem"
"pkey.pem:${dir}/key.pem"
];
});
security.acme.certs = mkIf cfg.useAcmeCertificates {${cfg.domain}.postRun = "systemctl restart coturn.service";};
networking.firewall = {
allowedUDPPorts = cfg.openPorts;
allowedTCPPorts = cfg.openPorts;
allowedUDPPortRanges = with config.services.coturn; [
{
from = min-port;
to = max-port;
}
];
};
}
]);
}

View file

@ -1,189 +0,0 @@
{
config,
lib,
pkgs,
...
}: let
inherit
(lib)
boolToString
concatStringsSep
hasAttr
isBool
mapAttrs
mkDefault
mkEnableOption
mkIf
mkOption
mkPackageOption
;
inherit
(lib.types)
attrsOf
bool
either
package
str
submodule
;
toStringEnv = value:
if isBool value
then boolToString value
else toString value;
cfg = config.services.netbird.server.dashboard;
in {
options.services.netbird.server.dashboard = {
enable = mkEnableOption "the static netbird dashboard frontend";
package = mkPackageOption pkgs "netbird-dashboard" {};
enableNginx = mkEnableOption "Nginx reverse-proxy to serve the dashboard.";
domain = mkOption {
type = str;
default = "localhost";
description = "The domain under which the dashboard runs.";
};
managementServer = mkOption {
type = str;
description = "The address of the management server, used for the API endpoints.";
};
settings = mkOption {
type = submodule {freeformType = attrsOf (either str bool);};
defaultText = ''
{
AUTH_AUDIENCE = "netbird";
AUTH_CLIENT_ID = "netbird";
AUTH_SUPPORTED_SCOPES = "openid profile email";
NETBIRD_TOKEN_SOURCE = "idToken";
USE_AUTH0 = false;
}
'';
description = ''
An attribute set that will be used to substitute variables when building the dashboard.
Any values set here will be templated into the frontend and be public for anyone that can reach your website.
The exact values sadly aren't documented anywhere.
A starting point when searching for valid values is this [script](https://github.com/netbirdio/dashboard/blob/main/docker/init_react_envs.sh)
The only mandatory value is 'AUTH_AUTHORITY' as we cannot set a default value here.
'';
};
finalDrv = mkOption {
readOnly = true;
type = package;
description = ''
The derivation containing the final templated dashboard.
'';
};
};
config = mkIf cfg.enable {
assertions = [
{
assertion = hasAttr "AUTH_AUTHORITY" cfg.settings;
message = "The setting AUTH_AUTHORITY is required for the dasboard to function.";
}
];
services.netbird.server.dashboard = {
settings =
{
# Due to how the backend and frontend work this secret will be templated into the backend
# and then served statically from your website
# This enables you to login without the normally needed indirection through the backend
# but this also means anyone that can reach your website can
# fetch this secret, which is why there is no real need to put it into
# special options as its public anyway
# As far as I know leaking this secret is just
# an information leak as one can fetch some basic app
# informations from the IDP
# To actually do something one still needs to have login
# data and this secret so this being public will not
# suffice for anything just decreasing security
AUTH_CLIENT_SECRET = "";
NETBIRD_MGMT_API_ENDPOINT = cfg.managementServer;
NETBIRD_MGMT_GRPC_API_ENDPOINT = cfg.managementServer;
}
// (mapAttrs (_: mkDefault) {
# Those values have to be easily overridable
AUTH_AUDIENCE = "netbird"; # must be set for your devices to be able to log in
AUTH_CLIENT_ID = "netbird";
AUTH_SUPPORTED_SCOPES = "openid profile email";
NETBIRD_TOKEN_SOURCE = "idToken";
USE_AUTH0 = false;
});
# The derivation containing the templated dashboard
finalDrv =
pkgs.runCommand "netbird-dashboard"
{
nativeBuildInputs = [pkgs.gettext];
env =
{
ENV_STR = concatStringsSep " " [
"$AUTH_AUDIENCE"
"$AUTH_AUTHORITY"
"$AUTH_CLIENT_ID"
"$AUTH_CLIENT_SECRET"
"$AUTH_REDIRECT_URI"
"$AUTH_SILENT_REDIRECT_URI"
"$AUTH_SUPPORTED_SCOPES"
"$NETBIRD_DRAG_QUERY_PARAMS"
"$NETBIRD_GOOGLE_ANALYTICS_ID"
"$NETBIRD_HOTJAR_TRACK_ID"
"$NETBIRD_MGMT_API_ENDPOINT"
"$NETBIRD_MGMT_GRPC_API_ENDPOINT"
"$NETBIRD_TOKEN_SOURCE"
"$USE_AUTH0"
];
}
// (mapAttrs (_: toStringEnv) cfg.settings);
}
''
cp -R ${cfg.package} build
find build -type d -exec chmod 755 {} \;
OIDC_TRUSTED_DOMAINS="build/OidcTrustedDomains.js"
envsubst "$ENV_STR" < "$OIDC_TRUSTED_DOMAINS.tmpl" > "$OIDC_TRUSTED_DOMAINS"
for f in $(grep -R -l AUTH_SUPPORTED_SCOPES build/); do
mv "$f" "$f.copy"
envsubst "$ENV_STR" < "$f.copy" > "$f"
rm "$f.copy"
done
cp -R build $out
'';
};
services.nginx = mkIf cfg.enableNginx {
enable = true;
virtualHosts.${cfg.domain} = {
locations = {
"/" = {
root = cfg.finalDrv;
tryFiles = "$uri $uri.html $uri/ =404";
};
"/404.html".extraConfig = ''
internal;
'';
};
extraConfig = ''
error_page 404 /404.html;
'';
};
};
};
}

View file

@ -1,461 +0,0 @@
{
config,
lib,
pkgs,
utils,
...
}: let
inherit
(lib)
any
concatMap
getExe'
literalExpression
mkEnableOption
mkIf
mkOption
mkPackageOption
optional
recursiveUpdate
;
inherit
(lib.types)
bool
enum
listOf
port
str
;
inherit (utils) escapeSystemdExecArgs genJqSecretsReplacementSnippet;
stateDir = "/var/lib/netbird-mgmt";
settingsFormat = pkgs.formats.json {};
defaultSettings = {
Stuns = [
{
Proto = "udp";
URI = "stun:${cfg.turnDomain}:3478";
Username = "";
Password = null;
}
];
TURNConfig = {
Turns = [
{
Proto = "udp";
URI = "turn:${cfg.turnDomain}:${builtins.toString cfg.turnPort}";
Username = "netbird";
Password = "netbird";
}
];
CredentialsTTL = "12h";
Secret = "not-secure-secret";
TimeBasedCredentials = false;
};
Signal = {
Proto = "https";
URI = "${cfg.domain}:443";
Username = "";
Password = null;
};
ReverseProxy = {
TrustedHTTPProxies = [];
TrustedHTTPProxiesCount = 0;
TrustedPeers = ["0.0.0.0/0"];
};
Datadir = "${stateDir}/data";
DataStoreEncryptionKey = "very-insecure-key";
StoreConfig = {
Engine = "sqlite";
};
HttpConfig = {
Address = "127.0.0.1:${builtins.toString cfg.port}";
IdpSignKeyRefreshEnabled = true;
OIDCConfigEndpoint = cfg.oidcConfigEndpoint;
};
IdpManagerConfig = {
ManagerType = "none";
ClientConfig = {
Issuer = "";
TokenEndpoint = "";
ClientID = "netbird";
ClientSecret = "";
GrantType = "client_credentials";
};
ExtraConfig = {};
Auth0ClientCredentials = null;
AzureClientCredentials = null;
KeycloakClientCredentials = null;
ZitadelClientCredentials = null;
};
DeviceAuthorizationFlow = {
Provider = "none";
ProviderConfig = {
Audience = "netbird";
Domain = null;
ClientID = "netbird";
TokenEndpoint = null;
DeviceAuthEndpoint = "";
Scope = "openid profile email";
UseIDToken = false;
};
};
PKCEAuthorizationFlow = {
ProviderConfig = {
Audience = "netbird";
ClientID = "netbird";
ClientSecret = "";
AuthorizationEndpoint = "";
TokenEndpoint = "";
Scope = "openid profile email";
RedirectURLs = ["http://localhost:53000"];
UseIDToken = false;
};
};
};
managementConfig = recursiveUpdate defaultSettings cfg.settings;
managementFile = settingsFormat.generate "config.json" managementConfig;
cfg = config.services.netbird.server.management;
in {
options.services.netbird.server.management = {
enable = mkEnableOption "Netbird Management Service.";
package = mkPackageOption pkgs "netbird" {};
domain = mkOption {
type = str;
description = "The domain under which the management API runs.";
};
turnDomain = mkOption {
type = str;
description = "The domain of the TURN server to use.";
};
turnPort = mkOption {
type = port;
default = 3478;
description = ''
The port of the TURN server to use.
'';
};
dnsDomain = mkOption {
type = str;
default = "netbird.selfhosted";
description = "Domain used for peer resolution.";
};
singleAccountModeDomain = mkOption {
type = str;
default = "netbird.selfhosted";
description = ''
Enables single account mode.
This means that all the users will be under the same account grouped by the specified domain.
If the installation has more than one account, the property is ineffective.
'';
};
disableAnonymousMetrics = mkOption {
type = bool;
default = true;
description = "Disables push of anonymous usage metrics to NetBird.";
};
disableSingleAccountMode = mkOption {
type = bool;
default = false;
description = ''
If set to true, disables single account mode.
The `singleAccountModeDomain` property will be ignored and every new user will have a separate NetBird account.
'';
};
port = mkOption {
type = port;
default = 8011;
description = "Internal port of the management server.";
};
extraOptions = mkOption {
type = listOf str;
default = [];
description = ''
Additional options given to netbird-mgmt as commandline arguments.
'';
};
oidcConfigEndpoint = mkOption {
type = str;
description = "The oidc discovery endpoint.";
example = "https://example.eu.auth0.com/.well-known/openid-configuration";
};
settings = mkOption {
inherit (settingsFormat) type;
defaultText = literalExpression ''
defaultSettings = {
Stuns = [
{
Proto = "udp";
URI = "stun:''${cfg.turnDomain}:3478";
Username = "";
Password = null;
}
];
TURNConfig = {
Turns = [
{
Proto = "udp";
URI = "turn:''${cfg.turnDomain}:3478";
Username = "netbird";
Password = "netbird";
}
];
CredentialsTTL = "12h";
Secret = "not-secure-secret";
TimeBasedCredentials = false;
};
Signal = {
Proto = "https";
URI = "''${cfg.domain}:443";
Username = "";
Password = null;
};
ReverseProxy = {
TrustedHTTPProxies = [ ];
TrustedHTTPProxiesCount = 0;
TrustedPeers = [ "0.0.0.0/0" ];
};
Datadir = "''${stateDir}/data";
DataStoreEncryptionKey = "genEVP6j/Yp2EeVujm0zgqXrRos29dQkpvX0hHdEUlQ=";
StoreConfig = { Engine = "sqlite"; };
HttpConfig = {
Address = "127.0.0.1:''${builtins.toString cfg.port}";
IdpSignKeyRefreshEnabled = true;
OIDCConfigEndpoint = cfg.oidcConfigEndpoint;
};
IdpManagerConfig = {
ManagerType = "none";
ClientConfig = {
Issuer = "";
TokenEndpoint = "";
ClientID = "netbird";
ClientSecret = "";
GrantType = "client_credentials";
};
ExtraConfig = { };
Auth0ClientCredentials = null;
AzureClientCredentials = null;
KeycloakClientCredentials = null;
ZitadelClientCredentials = null;
};
DeviceAuthorizationFlow = {
Provider = "none";
ProviderConfig = {
Audience = "netbird";
Domain = null;
ClientID = "netbird";
TokenEndpoint = null;
DeviceAuthEndpoint = "";
Scope = "openid profile email offline_access api";
UseIDToken = false;
};
};
PKCEAuthorizationFlow = {
ProviderConfig = {
Audience = "netbird";
ClientID = "netbird";
ClientSecret = "";
AuthorizationEndpoint = "";
TokenEndpoint = "";
Scope = "openid profile email offline_access api";
RedirectURLs = "http://localhost:53000";
UseIDToken = false;
};
};
};
'';
default = {};
description = ''
Configuration of the netbird management server.
Options containing secret data should be set to an attribute set containing the attribute _secret
- a string pointing to a file containing the value the option should be set to.
See the example to get a better picture of this: in the resulting management.json file,
the `DataStoreEncryptionKey` key will be set to the contents of the /run/agenix/netbird_mgmt-data_store_encryption_key file.
'';
example = {
DataStoreEncryptionKey = {
_secret = "/run/agenix/netbird_mgmt-data_store_encryption_key";
};
};
};
logLevel = mkOption {
type = enum [
"ERROR"
"WARN"
"INFO"
"DEBUG"
];
default = "INFO";
description = "Log level of the netbird services.";
};
enableNginx = mkEnableOption "Nginx reverse-proxy for the netbird management service.";
};
config = mkIf cfg.enable {
warnings =
concatMap
(
{
check,
name,
}:
optional check "${name} is world-readable in the Nix Store, you should provide it as a _secret."
)
[
{
check = builtins.isString managementConfig.TURNConfig.Secret;
name = "The TURNConfig.secret";
}
{
check = builtins.isString managementConfig.DataStoreEncryptionKey;
name = "The DataStoreEncryptionKey";
}
{
check = any (T: (T ? Password) && builtins.isString T.Password) managementConfig.TURNConfig.Turns;
name = "A Turn configuration's password";
}
];
systemd.services.netbird-management = {
description = "The management server for Netbird, a wireguard VPN";
documentation = ["https://netbird.io/docs/"];
after = ["network.target"];
wantedBy = ["multi-user.target"];
restartTriggers = [managementFile];
preStart = genJqSecretsReplacementSnippet managementConfig "${stateDir}/management.json";
serviceConfig = {
ExecStart = escapeSystemdExecArgs (
[
(getExe' cfg.package "netbird-mgmt")
"management"
# Config file
"--config"
"${stateDir}/management.json"
# Data directory
"--datadir"
"${stateDir}/data"
# DNS domain
"--dns-domain"
cfg.dnsDomain
# Port to listen on
"--port"
cfg.port
# Log to stdout
"--log-file"
"console"
# Log level
"--log-level"
cfg.logLevel
#
"--idp-sign-key-refresh-enabled"
# Domain for internal resolution
"--single-account-mode-domain"
cfg.singleAccountModeDomain
]
++ (optional cfg.disableAnonymousMetrics "--disable-anonymous-metrics")
++ (optional cfg.disableSingleAccountMode "--disable-single-account-mode")
++ cfg.extraOptions
);
Restart = "always";
RuntimeDirectory = "netbird-mgmt";
StateDirectory = [
"netbird-mgmt"
"netbird-mgmt/data"
];
WorkingDirectory = stateDir;
# hardening
LockPersonality = true;
MemoryDenyWriteExecute = true;
NoNewPrivileges = true;
PrivateMounts = true;
PrivateTmp = true;
ProtectClock = true;
ProtectControlGroups = true;
ProtectHome = true;
ProtectHostname = true;
ProtectKernelLogs = true;
ProtectKernelModules = true;
ProtectKernelTunables = true;
ProtectSystem = true;
RemoveIPC = true;
RestrictNamespaces = true;
RestrictRealtime = true;
RestrictSUIDSGID = true;
};
stopIfChanged = false;
};
services.nginx = mkIf cfg.enableNginx {
enable = true;
virtualHosts.${cfg.domain} = {
locations = {
"/api".proxyPass = "http://localhost:${builtins.toString cfg.port}";
"/management.ManagementService/".extraConfig = ''
# This is necessary so that grpc connections do not get closed early
# see https://stackoverflow.com/a/67805465
client_body_timeout 1d;
grpc_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
grpc_pass grpc://localhost:${builtins.toString cfg.port};
grpc_read_timeout 1d;
grpc_send_timeout 1d;
grpc_socket_keepalive on;
'';
};
};
};
};
}

View file

@ -1,42 +0,0 @@
# Netbird server {#module-services-netbird-server}
NetBird is a VPN built on top of WireGuard® making it easy to create secure private networks for your organization or home.
## Quickstart {#module-services-netbird-server-quickstart}
To fully setup Netbird as a self-hosted server, we need both a Coturn server and an identity provider, the list of supported SSOs and their setup are available [on Netbird's documentation](https://docs.netbird.io/selfhosted/selfhosted-guide#step-3-configure-identity-provider-idp).
There are quite a few settings that need to be passed to Netbird for it to function, and a minimal config looks like :
```nix
services.netbird.server = {
enable = true;
domain = "netbird.example.selfhosted";
enableNginx = true;
coturn = {
enable = true;
passwordFile = "/path/to/a/secret/password";
};
management = {
oidcConfigEndpoint = "https://sso.example.selfhosted/oauth2/openid/netbird/.well-known/openid-configuration";
settings = {
TURNConfig = {
Turns = [
{
Proto = "udp";
URI = "turn:netbird.example.selfhosted:3478";
Username = "netbird";
Password._secret = "/path/to/a/secret/password";
}
];
};
};
};
};
```

View file

@ -1,89 +0,0 @@
{
config,
lib,
...
}: let
inherit
(lib)
mkDefault
mkEnableOption
mkIf
mkOption
optionalAttrs
;
inherit (lib.types) str;
cfg = config.services.netbird.server;
in {
meta = {
maintainers = with lib.maintainers; [thubrecht patrickdag];
doc = ./server.md;
};
# Import the separate components
imports = [
./coturn.nix
./dashboard.nix
./management.nix
./signal.nix
];
options.services.netbird.server = {
enable = mkEnableOption "Netbird Server stack, comprising the dashboard, management API and signal service";
enableNginx = mkEnableOption "Nginx reverse-proxy for the netbird server services.";
domain = mkOption {
type = str;
description = "The domain under which the netbird server runs.";
};
};
config = mkIf cfg.enable {
services.netbird.server = {
dashboard = {
domain = mkDefault cfg.domain;
enable = mkDefault cfg.enable;
enableNginx = mkDefault cfg.enableNginx;
managementServer = "https://${cfg.domain}";
};
management =
{
domain = mkDefault cfg.domain;
enable = mkDefault cfg.enable;
enableNginx = mkDefault cfg.enableNginx;
}
// (optionalAttrs cfg.coturn.enable rec {
turnDomain = cfg.domain;
turnPort = config.services.coturn.tls-listening-port;
# We cannot merge a list of attrsets so we have to redefine the whole list
settings = {
TURNConfig.Turns = mkDefault [
{
Proto = "udp";
URI = "turn:${turnDomain}:${builtins.toString turnPort}";
Username = "netbird";
Password =
if (cfg.coturn.password != null)
then cfg.coturn.password
else {_secret = cfg.coturn.passwordFile;};
}
];
};
});
signal = {
domain = mkDefault cfg.domain;
enable = mkDefault cfg.enable;
enableNginx = mkDefault cfg.enableNginx;
};
coturn = {
domain = mkDefault cfg.domain;
};
};
};
}

View file

@ -1,120 +0,0 @@
{
config,
lib,
pkgs,
utils,
...
}: let
inherit
(lib)
getExe'
mkEnableOption
mkIf
mkPackageOption
mkOption
;
inherit (lib.types) enum port str;
inherit (utils) escapeSystemdExecArgs;
cfg = config.services.netbird.server.signal;
in {
options.services.netbird.server.signal = {
enable = mkEnableOption "Netbird's Signal Service";
package = mkPackageOption pkgs "netbird" {};
enableNginx = mkEnableOption "Nginx reverse-proxy for the netbird signal service.";
domain = mkOption {
type = str;
description = "The domain name for the signal service.";
};
port = mkOption {
type = port;
default = 8012;
description = "Internal port of the signal server.";
};
logLevel = mkOption {
type = enum [
"ERROR"
"WARN"
"INFO"
"DEBUG"
];
default = "INFO";
description = "Log level of the netbird signal service.";
};
};
config = mkIf cfg.enable {
systemd.services.netbird-signal = {
after = ["network.target"];
wantedBy = ["multi-user.target"];
serviceConfig = {
ExecStart = escapeSystemdExecArgs [
(getExe' cfg.package "netbird-signal")
"run"
# Port to listen on
"--port"
cfg.port
# Log to stdout
"--log-file"
"console"
# Log level
"--log-level"
cfg.logLevel
];
Restart = "always";
RuntimeDirectory = "netbird-mgmt";
StateDirectory = "netbird-mgmt";
WorkingDirectory = "/var/lib/netbird-mgmt";
# hardening
LockPersonality = true;
MemoryDenyWriteExecute = true;
NoNewPrivileges = true;
PrivateMounts = true;
PrivateTmp = true;
ProtectClock = true;
ProtectControlGroups = true;
ProtectHome = true;
ProtectHostname = true;
ProtectKernelLogs = true;
ProtectKernelModules = true;
ProtectKernelTunables = true;
ProtectSystem = true;
RemoveIPC = true;
RestrictNamespaces = true;
RestrictRealtime = true;
RestrictSUIDSGID = true;
};
stopIfChanged = false;
};
services.nginx = mkIf cfg.enableNginx {
enable = true;
virtualHosts.${cfg.domain} = {
locations."/signalexchange.SignalExchange/".extraConfig = ''
# This is necessary so that grpc connections do not get closed early
# see https://stackoverflow.com/a/67805465
client_body_timeout 1d;
grpc_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
grpc_pass grpc://localhost:${builtins.toString cfg.port};
grpc_read_timeout 1d;
grpc_send_timeout 1d;
grpc_socket_keepalive on;
'';
};
};
};
}

View file

@ -1,5 +1,6 @@
{self, ...}: nodeName: nodeAttrs: let
inherit (self.hosts.${nodeName}) system;
#FIXME inherit nodeAttrs. system;
system = "x86_64-linux";
pkgs = self.pkgs.${system};
disko-script = pkgs.writeShellScriptBin "disko-script" "${nodeAttrs.config.system.build.diskoScript}";

View file

@ -5,15 +5,15 @@ inputs: let
concatMapAttrs
filterAttrs
flip
mapAttrs
genAttrs
mapAttrs'
nameValuePair
nixosSystem
;
# Creates a new nixosSystem with the correct specialArgs, pkgs and name definition
mkHost = {minimal}: name: hostCfg: let
pkgs = self.pkgs.${hostCfg.system};
mkHost = {minimal}: name: let
pkgs = self.pkgs.x86_64-linux;
in
nixosSystem {
specialArgs = {
@ -28,7 +28,6 @@ inputs: let
# inputs.nixpkgs.nixosModules.readOnlyPkgs, since some nixosModules
# like nixseparatedebuginfod depend on adding packages via nixpkgs.overlays.
# So we just mimic the options and overlays defined by the passed pkgs set.
nixpkgs.hostPlatform = hostCfg.system;
nixpkgs.overlays = pkgs.overlays;
nixpkgs.config = pkgs.config;
node.name = name;
@ -41,12 +40,10 @@ inputs: let
# Load the list of hosts that this flake defines, which
# associates the minimum amount of metadata that is necessary
# to instanciate hosts correctly.
hosts = builtins.fromTOML (builtins.readFile ../hosts.toml);
# Get all hosts of type "nixos"
nixosHosts = filterAttrs (_: x: x.type == "nixos") hosts;
hosts = builtins.attrNames (filterAttrs (_: type: type == "directory") (builtins.readDir ../hosts));
# Process each nixosHosts declaration and generatea nixosSystem definitions
nixosConfigurations = flip mapAttrs nixosHosts (mkHost {minimal = false;});
minimalConfigurations = flip mapAttrs nixosHosts (mkHost {minimal = true;});
nixosConfigurations = genAttrs hosts (mkHost {minimal = false;});
minimalConfigurations = genAttrs hosts (mkHost {minimal = true;});
# True NixOS nodes can define additional guest nodes that are built
# together with it. We collect all defined guests from each node here

View file

@ -30,8 +30,8 @@
patches =
old.patches
++ [
"${provisionSrc}/patches/${old.version}-oauth2-basic-secret-modify.patch"
"${provisionSrc}/patches/${old.version}-recover-account.patch"
"${provisionSrc}/patches/1.2.0-oauth2-basic-secret-modify.patch"
"${provisionSrc}/patches/1.2.0-recover-account.patch"
];
passthru.enableSecretProvisioning = true;
doCheck = false;

View file

@ -129,6 +129,10 @@ in
meta = with lib; {
mainProgram = "api";
homepage = "https://hay-kot.github.io/homebox/";
maintainers = with maintainers; [patrickdag];
license = licenses.agpl3Only;
description = "A inventory and organization system built for the Home User";
platforms = platforms.all;
};
}

View file

@ -0,0 +1,16 @@
age-encryption.org/v1
-> X25519 Fpotjtu7lksK7LzYZTkTP7OXF2etf6k/jAs3qT63pyg
Az3CTRHiYmqI9mVSvt61WgbQa1Sw7tTI/GwuwGNm2Rk
-> piv-p256 ZFgiIw AwwKW8KYhA3dsUgANUxvffEiFLOadwllahNrchfzQTfq
AO08XTSUINWT5eY1EgPqHHSY/y0gsgszz3psNnGSauA
-> piv-p256 XTQkUA AuxujxLf1wM1siHqnkbayQ6C4KZbsAzdUO/8dsiTRohe
1AUfKkOngKRI4jPG820VihSIP5ms9jH8MvHlEBiwVAE
-> piv-p256 ZFgiIw AqLEvSEzM5D4K/W67DVz7icte3mw5+FqFtBiv4Ba2xua
mbrEOcAnkiXq1Phh1SlnTjDuhLma+4hqv8FMceymOzQ
-> piv-p256 5vmPtQ AzENFlgqOyGbU/FXskgenHamZs/H+78mS9PWsYoXXqae
pyx2IlIw+p+7dAUg5Ohj1cKxW/9S51LjR2A47aNgH0c
-> AJ/nN^^b-grease P%To4qn; llf1 (\|f~06
ROV54+I9IMrCY2DvOXDRsY4otebllTMp6ddWYA
--- PGvDf7ZhjEQzcNDXVlDw4Qehrs/lg7hi22vu/2lo0N8
ˆ¤rëyÔ<79>±³{<7B>f#ßç`M}Ñ”<iö÷<C3B6>d=ÇÔp¾bÍnÿÂåEËé<C38B>-
¹$thòˆû:;.9ñ

View file

@ -0,0 +1 @@
wODUgMHl+qSCB8O1purynIY/AaPyIJ4kCFCEHmRedEk=

View file

@ -0,0 +1,15 @@
age-encryption.org/v1
-> X25519 809OJmSe9sRVNlpr7tsymq+N/N3RLwBggFHdew4p5lU
ef/ZzFm1aqytRapx0iZilQyT9O/xuA97plZbz5LL5O4
-> piv-p256 ZFgiIw Aowpy6rEm9eHFxEmwJ35I10linQONgIS13H/Nm0fi+j9
rRiW2Y2V5kpmdqGjN72EyKe9nf5fQS4UrUqZAtshkx8
-> piv-p256 XTQkUA AtkeDTc+jaagxDYjzJrSsHZTCF3KxpSTMU2ZMxuoawDG
YDRFtbrl8QH5YHlTcBLBdxHzx+pqMXLtSSvd/FokSE4
-> piv-p256 ZFgiIw ArgQyaNwkuKD1GVVGKmwcHq11pzcgGK9uJpvWFkQ1Zqy
Jvue35/d/2CKV6qcVZIW2Q+LUp67CpcMUapfJQGqh84
-> piv-p256 5vmPtQ AjMLgWeCMKLwl3205anSTdwYfQ5HG2pmZH5UOU8fnhi5
BL+6ZYMBuakv2PZCzcb/W8+UCgGryY/uA3Z0NdMxcc8
-> :`n-grease Iq:z[/t( c6Ca. j FSx5@D?
uH1pwc6u0ytrAqS9cTXoD64rJBuosYo
--- 5BCa7IK4dbXfsXiqMnBHBmLR/qAXbbyqaVRiWun5KJ4
eõFsfáB„µ¿ì`%­ªÔŠñÄþ8ÀCˆ;Q²™ên·À<C2B7>ÙŽÐz<C390>ÉÊ$<24>ß…©Ì»<C38C>¢‹¶ÉR$Ð5œÚsKl¾TÂ