Compare commits
2 Commits
ece5e89a84
...
revert
| Author | SHA1 | Date | |
|---|---|---|---|
| 3d1e0991ae | |||
| 99b18de995 |
362
flake.lock
generated
362
flake.lock
generated
@@ -8,11 +8,11 @@
|
|||||||
"systems": "systems"
|
"systems": "systems"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1760836749,
|
"lastModified": 1754433428,
|
||||||
"narHash": "sha256-wyT7Pl6tMFbFrs8Lk/TlEs81N6L+VSybPfiIgzU8lbQ=",
|
"narHash": "sha256-NA/FT2hVhKDftbHSwVnoRTFhes62+7dxZbxj5Gxvghs=",
|
||||||
"owner": "ryantm",
|
"owner": "ryantm",
|
||||||
"repo": "agenix",
|
"repo": "agenix",
|
||||||
"rev": "2f0f812f69f3eb4140157fe15e12739adf82e32a",
|
"rev": "9edb1787864c4f59ae5074ad498b6272b3ec308d",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -29,11 +29,11 @@
|
|||||||
"systems": "systems_2"
|
"systems": "systems_2"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1761238850,
|
"lastModified": 1758874004,
|
||||||
"narHash": "sha256-WGoqR+ULsh1w7yDNAtJiE27HX6zSlGPR4I2pgjAU/SA=",
|
"narHash": "sha256-+RUCBtT01Z595NpGc6Tvms+dJ/C/cn1zdjT9+gE6dbU=",
|
||||||
"owner": "anyrun-org",
|
"owner": "anyrun-org",
|
||||||
"repo": "anyrun",
|
"repo": "anyrun",
|
||||||
"rev": "ae3c499316e9aa568acb3832566a1978ca665748",
|
"rev": "3c571bc1514c4211d1d6c011a1d482f97efd9c5f",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -83,11 +83,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1760101617,
|
"lastModified": 1759499898,
|
||||||
"narHash": "sha256-8jf/3ZCi+B7zYpIyV04+3wm72BD7Z801IlOzsOACR7I=",
|
"narHash": "sha256-UNzYHLWfkSzLHDep5Ckb5tXc0fdxwPIrT+MY4kpQttM=",
|
||||||
"owner": "hyprwm",
|
"owner": "hyprwm",
|
||||||
"repo": "aquamarine",
|
"repo": "aquamarine",
|
||||||
"rev": "1826a9923881320306231b1c2090379ebf9fa4f8",
|
"rev": "655e067f96fd44b3f5685e17f566b0e4d535d798",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -100,10 +100,14 @@
|
|||||||
"inputs": {
|
"inputs": {
|
||||||
"authentik-src": "authentik-src",
|
"authentik-src": "authentik-src",
|
||||||
"flake-compat": "flake-compat",
|
"flake-compat": "flake-compat",
|
||||||
"flake-parts": "flake-parts_2",
|
"flake-parts": [
|
||||||
|
"flake-parts"
|
||||||
|
],
|
||||||
"flake-utils": "flake-utils",
|
"flake-utils": "flake-utils",
|
||||||
"napalm": "napalm",
|
"napalm": "napalm",
|
||||||
"nixpkgs": "nixpkgs_3",
|
"nixpkgs": [
|
||||||
|
"nixpkgs"
|
||||||
|
],
|
||||||
"pyproject-build-systems": "pyproject-build-systems",
|
"pyproject-build-systems": "pyproject-build-systems",
|
||||||
"pyproject-nix": "pyproject-nix",
|
"pyproject-nix": "pyproject-nix",
|
||||||
"systems": "systems_3",
|
"systems": "systems_3",
|
||||||
@@ -119,7 +123,6 @@
|
|||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"ref": "version/2025.8.4",
|
|
||||||
"repo": "authentik-nix",
|
"repo": "authentik-nix",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
@@ -146,15 +149,15 @@
|
|||||||
"flake-schemas": "flake-schemas",
|
"flake-schemas": "flake-schemas",
|
||||||
"home-manager": "home-manager_2",
|
"home-manager": "home-manager_2",
|
||||||
"jovian": "jovian",
|
"jovian": "jovian",
|
||||||
"nixpkgs": "nixpkgs_4",
|
"nixpkgs": "nixpkgs_3",
|
||||||
"rust-overlay": "rust-overlay"
|
"rust-overlay": "rust-overlay"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1761326352,
|
"lastModified": 1759532138,
|
||||||
"narHash": "sha256-DoR4mHaStX6Dg2Gilc2Dqr/XaxXmQTOQS5cZ5xKPQJY=",
|
"narHash": "sha256-sLQIlgDwMP3mEY2PwjGW+cL56QQ2n2WXoZ3GpG5QWOY=",
|
||||||
"owner": "chaotic-cx",
|
"owner": "chaotic-cx",
|
||||||
"repo": "nyx",
|
"repo": "nyx",
|
||||||
"rev": "6492dc810f2f250ef95096910a44f03eea6a594f",
|
"rev": "bad02bbca5b5c6d45539a0d740ad0e21b1ba9afc",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -209,11 +212,11 @@
|
|||||||
"rust-analyzer-src": "rust-analyzer-src"
|
"rust-analyzer-src": "rust-analyzer-src"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1761374215,
|
"lastModified": 1759560021,
|
||||||
"narHash": "sha256-YmnUYXjacFHa8fWCo8gBAHpqlcG8+P5+5YYFhy6hOkg=",
|
"narHash": "sha256-J/rtMKVUAEqOFj0ogvcHKK8HbaKhw+tiNrDOpEM+ZDY=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "fenix",
|
"repo": "fenix",
|
||||||
"rev": "b0fa429fc946e6e716dff3bfb97ce6383eae9359",
|
"rev": "6ffcbf59c119b0c6384c7d98f18cea06a9af7e9c",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -324,14 +327,16 @@
|
|||||||
},
|
},
|
||||||
"flake-parts_2": {
|
"flake-parts_2": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"nixpkgs-lib": "nixpkgs-lib"
|
"nixpkgs-lib": [
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1756770412,
|
"lastModified": 1759362264,
|
||||||
"narHash": "sha256-+uWLQZccFHwqpGqr2Yt5VsW/PbeJVTn9Dk6SHWhNRPw=",
|
"narHash": "sha256-wfG0S7pltlYyZTM+qqlhJ7GMw2fTF4mLKCIVhLii/4M=",
|
||||||
"owner": "hercules-ci",
|
"owner": "hercules-ci",
|
||||||
"repo": "flake-parts",
|
"repo": "flake-parts",
|
||||||
"rev": "4524271976b625a4a605beefd893f270620fd751",
|
"rev": "758cf7296bee11f1706a574c77d072b8a7baa881",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -342,27 +347,7 @@
|
|||||||
},
|
},
|
||||||
"flake-parts_3": {
|
"flake-parts_3": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"nixpkgs-lib": [
|
"nixpkgs-lib": "nixpkgs-lib"
|
||||||
"nixpkgs"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1760948891,
|
|
||||||
"narHash": "sha256-TmWcdiUUaWk8J4lpjzu4gCGxWY6/Ok7mOK4fIFfBuU4=",
|
|
||||||
"owner": "hercules-ci",
|
|
||||||
"repo": "flake-parts",
|
|
||||||
"rev": "864599284fc7c0ba6357ed89ed5e2cd5040f0c04",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "hercules-ci",
|
|
||||||
"repo": "flake-parts",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"flake-parts_4": {
|
|
||||||
"inputs": {
|
|
||||||
"nixpkgs-lib": "nixpkgs-lib_2"
|
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1753121425,
|
"lastModified": 1753121425,
|
||||||
@@ -378,7 +363,7 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"flake-parts_5": {
|
"flake-parts_4": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"nixpkgs-lib": [
|
"nixpkgs-lib": [
|
||||||
"lanzaboote",
|
"lanzaboote",
|
||||||
@@ -399,7 +384,7 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"flake-parts_6": {
|
"flake-parts_5": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"nixpkgs-lib": [
|
"nixpkgs-lib": [
|
||||||
"nvf",
|
"nvf",
|
||||||
@@ -420,7 +405,7 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"flake-parts_7": {
|
"flake-parts_6": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"nixpkgs-lib": [
|
"nixpkgs-lib": [
|
||||||
"tuirun",
|
"tuirun",
|
||||||
@@ -478,8 +463,8 @@
|
|||||||
},
|
},
|
||||||
"fonts": {
|
"fonts": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"flake-parts": "flake-parts_4",
|
"flake-parts": "flake-parts_3",
|
||||||
"nixpkgs": "nixpkgs_5"
|
"nixpkgs": "nixpkgs_4"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1753431871,
|
"lastModified": 1753431871,
|
||||||
@@ -506,11 +491,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1760663237,
|
"lastModified": 1759523803,
|
||||||
"narHash": "sha256-BflA6U4AM1bzuRMR8QqzPXqh8sWVCNDzOdsxXEguJIc=",
|
"narHash": "sha256-PTod9NG+i3XbbnBKMl/e5uHDBYpwIWivQ3gOWSEuIEM=",
|
||||||
"owner": "cachix",
|
"owner": "cachix",
|
||||||
"repo": "git-hooks.nix",
|
"repo": "git-hooks.nix",
|
||||||
"rev": "ca5b894d3e3e151ffc1db040b6ce4dcc75d31c37",
|
"rev": "cfc9f7bb163ad8542029d303e599c0f7eee09835",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -586,11 +571,11 @@
|
|||||||
},
|
},
|
||||||
"hardware": {
|
"hardware": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1760958188,
|
"lastModified": 1759582739,
|
||||||
"narHash": "sha256-2m1S4jl+GEDtlt2QqeHil8Ny456dcGSKJAM7q3j/BFU=",
|
"narHash": "sha256-spZegilADH0q5OngM86u6NmXxduCNv5eX9vCiUPhOYc=",
|
||||||
"owner": "nixos",
|
"owner": "nixos",
|
||||||
"repo": "nixos-hardware",
|
"repo": "nixos-hardware",
|
||||||
"rev": "d6645c340ef7d821602fd2cd199e8d1eed10afbc",
|
"rev": "3441b5242af7577230a78ffb03542add264179ab",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -601,15 +586,15 @@
|
|||||||
},
|
},
|
||||||
"helix-flake": {
|
"helix-flake": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"nixpkgs": "nixpkgs_6",
|
"nixpkgs": "nixpkgs_5",
|
||||||
"rust-overlay": "rust-overlay_2"
|
"rust-overlay": "rust-overlay_2"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1761141169,
|
"lastModified": 1759201995,
|
||||||
"narHash": "sha256-5IZjbTvP5dNTD8CbEYlNbicdGcbCN9SC9ksMm2ZEXH0=",
|
"narHash": "sha256-3STv6fITv8Ar/kl0H7vIA7VV0d2gyLh8UL0BOiVacXg=",
|
||||||
"owner": "helix-editor",
|
"owner": "helix-editor",
|
||||||
"repo": "helix",
|
"repo": "helix",
|
||||||
"rev": "d79cce4e4bfc24dd204f1b294c899ed73f7e9453",
|
"rev": "bfcbef10c513108c7b43317569416c2eefc4ed44",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -625,11 +610,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1761344779,
|
"lastModified": 1759573136,
|
||||||
"narHash": "sha256-6LNSptFYhiAd0M/maJoixJw7V0Kp5BSoMRtIahcfu3M=",
|
"narHash": "sha256-ILSPD0Dm8p0w0fCVzOx98ZH8yFDrR75GmwmH3fS2VnE=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "home-manager",
|
"repo": "home-manager",
|
||||||
"rev": "c644cb018f9fdec55f5ac2afb4713a8c7beb757c",
|
"rev": "5f06ceafc6c9b773a776b9195c3f47bbe1defa43",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -667,11 +652,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1761266473,
|
"lastModified": 1759337100,
|
||||||
"narHash": "sha256-QxCyKWBmuzI+eMhYV1JmbZsiUnBNATRP1EW34OBt5Vg=",
|
"narHash": "sha256-CcT3QvZ74NGfM+lSOILcCEeU+SnqXRvl1XCRHenZ0Us=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "home-manager",
|
"repo": "home-manager",
|
||||||
"rev": "5c71d4a730bd3c972befff343bb074421e345937",
|
"rev": "004753ae6b04c4b18aa07192c1106800aaacf6c3",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -725,11 +710,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1760445448,
|
"lastModified": 1759490292,
|
||||||
"narHash": "sha256-fXGjL6dw31FPFRrmIemzGiNSlfvEJTJNsmadZi+qNhI=",
|
"narHash": "sha256-T6iWzDOXp8Wv0KQOCTHpBcmAOdHJ6zc/l9xaztW6Ivc=",
|
||||||
"owner": "hyprwm",
|
"owner": "hyprwm",
|
||||||
"repo": "hyprgraphics",
|
"repo": "hyprgraphics",
|
||||||
"rev": "50fb9f069219f338a11cf0bcccb9e58357d67757",
|
"rev": "9431db625cd9bb66ac55525479dce694101d6d7a",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -754,11 +739,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1759490292,
|
"lastModified": 1750621377,
|
||||||
"narHash": "sha256-T6iWzDOXp8Wv0KQOCTHpBcmAOdHJ6zc/l9xaztW6Ivc=",
|
"narHash": "sha256-8u6b5oAdX0rCuoR8wFenajBRmI+mzbpNig6hSCuWUzE=",
|
||||||
"owner": "hyprwm",
|
"owner": "hyprwm",
|
||||||
"repo": "hyprgraphics",
|
"repo": "hyprgraphics",
|
||||||
"rev": "9431db625cd9bb66ac55525479dce694101d6d7a",
|
"rev": "b3d628d01693fb9bb0a6690cd4e7b80abda04310",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -812,17 +797,17 @@
|
|||||||
"hyprlang": "hyprlang",
|
"hyprlang": "hyprlang",
|
||||||
"hyprutils": "hyprutils",
|
"hyprutils": "hyprutils",
|
||||||
"hyprwayland-scanner": "hyprwayland-scanner_2",
|
"hyprwayland-scanner": "hyprwayland-scanner_2",
|
||||||
"nixpkgs": "nixpkgs_7",
|
"nixpkgs": "nixpkgs_6",
|
||||||
"pre-commit-hooks": "pre-commit-hooks",
|
"pre-commit-hooks": "pre-commit-hooks",
|
||||||
"systems": "systems_4",
|
"systems": "systems_4",
|
||||||
"xdph": "xdph"
|
"xdph": "xdph"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1761389866,
|
"lastModified": 1759530922,
|
||||||
"narHash": "sha256-RupwqaJ3JF5dF9iuJX+y0EZslmIuRs7+n+wnngtBqak=",
|
"narHash": "sha256-9NgZKpibALekGTPDc2O8lP8vFealQSZkXe+L+S7MMZU=",
|
||||||
"owner": "hyprwm",
|
"owner": "hyprwm",
|
||||||
"repo": "hyprland",
|
"repo": "hyprland",
|
||||||
"rev": "b10b9660004b3dfaf9e11a305d78f24955b089a4",
|
"rev": "76d998743ac10e712238c1016db4d8e8d16f1049",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -839,11 +824,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1759613406,
|
"lastModified": 1759238633,
|
||||||
"narHash": "sha256-PzgQJydp+RlKvwDi807pXPlURdIAVqLppZDga3DwPqg=",
|
"narHash": "sha256-4/AtRCQKXuU49ozZZouWuC+T7vCjQh9HAz3N8Tt5OZE=",
|
||||||
"owner": "hyprwm",
|
"owner": "hyprwm",
|
||||||
"repo": "contrib",
|
"repo": "contrib",
|
||||||
"rev": "32e1a75b65553daefb419f0906ce19e04815aa3a",
|
"rev": "513d71d3f42c05d6a38e215382c5a6ce971bd77d",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -889,11 +874,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1759610243,
|
"lastModified": 1749046714,
|
||||||
"narHash": "sha256-+KEVnKBe8wz+a6dTLq8YDcF3UrhQElwsYJaVaHXJtoI=",
|
"narHash": "sha256-kymV5FMnddYGI+UjwIw8ceDjdeg7ToDVjbHCvUlhn14=",
|
||||||
"owner": "hyprwm",
|
"owner": "hyprwm",
|
||||||
"repo": "hyprland-protocols",
|
"repo": "hyprland-protocols",
|
||||||
"rev": "bd153e76f751f150a09328dbdeb5e4fab9d23622",
|
"rev": "613878cb6f459c5e323aaafe1e6f388ac8a36330",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -1021,11 +1006,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1760023949,
|
"lastModified": 1759572448,
|
||||||
"narHash": "sha256-fu0B4duamVdbkPio/czu1XhsPLRXUJpZLDrSk3nih4U=",
|
"narHash": "sha256-o+r44fqPQM+/hQdjFy9qV9C51Jhty6M4icFVYocyJfA=",
|
||||||
"owner": "hyprwm",
|
"owner": "hyprwm",
|
||||||
"repo": "hyprlock",
|
"repo": "hyprlock",
|
||||||
"rev": "36ec73f166d9434a3f27c96c575198906f77644a",
|
"rev": "c8a6768dca626cf7d7cbc333095f048bc007b6d9",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -1059,11 +1044,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1760120448,
|
"lastModified": 1754481642,
|
||||||
"narHash": "sha256-l/OxM4q/nLVv47OuS4bG2J7k0m+G7/3AMtvrV64XLb0=",
|
"narHash": "sha256-e1phd6KwtUsS9C2ShD+fQvfk2Dgr2JQi+rTDQUW15iE=",
|
||||||
"owner": "hyprwm",
|
"owner": "hyprwm",
|
||||||
"repo": "hyprpaper",
|
"repo": "hyprpaper",
|
||||||
"rev": "1733e0025b194c9bc083f4cd8782c5f151858a58",
|
"rev": "bcb1ffa322369c4898347ab5a7399a3d18494c8f",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -1084,11 +1069,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1759619523,
|
"lastModified": 1759490926,
|
||||||
"narHash": "sha256-r1ed7AR2ZEb2U8gy321/Xcp1ho2tzn+gG1te/Wxsj1A=",
|
"narHash": "sha256-7IbZGJ5qAAfZsGhBHIsP8MBsfuFYS0hsxYHVkkeDG5Q=",
|
||||||
"owner": "hyprwm",
|
"owner": "hyprwm",
|
||||||
"repo": "hyprutils",
|
"repo": "hyprutils",
|
||||||
"rev": "3df7bde01efb3a3e8e678d1155f2aa3f19e177ef",
|
"rev": "94cce794344538c4d865e38682684ec2bbdb2ef3",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -1159,11 +1144,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1755184602,
|
"lastModified": 1750371869,
|
||||||
"narHash": "sha256-RCBQN8xuADB0LEgaKbfRqwm6CdyopE1xIEhNc67FAbw=",
|
"narHash": "sha256-lGk4gLjgZQ/rndUkzmPYcgbHr8gKU5u71vyrjnwfpB4=",
|
||||||
"owner": "hyprwm",
|
"owner": "hyprwm",
|
||||||
"repo": "hyprwayland-scanner",
|
"repo": "hyprwayland-scanner",
|
||||||
"rev": "b3b0f1f40ae09d4447c20608e5a4faf8bf3c492d",
|
"rev": "aa38edd6e3e277ae6a97ea83a69261a5c3aab9fd",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -1206,11 +1191,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1761202163,
|
"lastModified": 1759387127,
|
||||||
"narHash": "sha256-6RySf5VQElrm7RYGWxlIkNttemDp4FF0aH+LX435G2Y=",
|
"narHash": "sha256-uuwJAP92SkHmnI1zo7rrK/gEuHtb97vFZcMa5w+0SZA=",
|
||||||
"owner": "Jovian-Experiments",
|
"owner": "Jovian-Experiments",
|
||||||
"repo": "Jovian-NixOS",
|
"repo": "Jovian-NixOS",
|
||||||
"rev": "47976126007d9658ca4ac4dd933bea8846170fd9",
|
"rev": "0cc290e05882745060fccfe6d7d073f913e0cce7",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -1223,8 +1208,8 @@
|
|||||||
"inputs": {
|
"inputs": {
|
||||||
"crane": "crane",
|
"crane": "crane",
|
||||||
"flake-compat": "flake-compat_4",
|
"flake-compat": "flake-compat_4",
|
||||||
"flake-parts": "flake-parts_5",
|
"flake-parts": "flake-parts_4",
|
||||||
"nixpkgs": "nixpkgs_8",
|
"nixpkgs": "nixpkgs_7",
|
||||||
"pre-commit-hooks-nix": "pre-commit-hooks-nix",
|
"pre-commit-hooks-nix": "pre-commit-hooks-nix",
|
||||||
"rust-overlay": "rust-overlay_3"
|
"rust-overlay": "rust-overlay_3"
|
||||||
},
|
},
|
||||||
@@ -1293,11 +1278,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1761356901,
|
"lastModified": 1759455985,
|
||||||
"narHash": "sha256-YDySchURSJrS1P8zuzmFqypUS7shY6//0e0JiMZeLSI=",
|
"narHash": "sha256-8qDv7NXH3fj1CDXed7c7vJLtrRKDZSo0x6TaWSfelVg=",
|
||||||
"owner": "fufexan",
|
"owner": "fufexan",
|
||||||
"repo": "nix-gaming",
|
"repo": "nix-gaming",
|
||||||
"rev": "a8635e459ff96acbd156a8de613b99d9d6b3676a",
|
"rev": "eb5ab503cbd3cb386e8d85a55a9faed73ec7dc37",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -1346,21 +1331,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"nixpkgs-lib": {
|
"nixpkgs-lib": {
|
||||||
"locked": {
|
|
||||||
"lastModified": 1754788789,
|
|
||||||
"narHash": "sha256-x2rJ+Ovzq0sCMpgfgGaaqgBSwY+LST+WbZ6TytnT9Rk=",
|
|
||||||
"owner": "nix-community",
|
|
||||||
"repo": "nixpkgs.lib",
|
|
||||||
"rev": "a73b9c743612e4244d865a2fdee11865283c04e6",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "nix-community",
|
|
||||||
"repo": "nixpkgs.lib",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nixpkgs-lib_2": {
|
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1751159883,
|
"lastModified": 1751159883,
|
||||||
"narHash": "sha256-urW/Ylk9FIfvXfliA1ywh75yszAbiTEVgpPeinFyVZo=",
|
"narHash": "sha256-urW/Ylk9FIfvXfliA1ywh75yszAbiTEVgpPeinFyVZo=",
|
||||||
@@ -1375,22 +1345,6 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"nixpkgs_10": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1759386674,
|
|
||||||
"narHash": "sha256-wg1Lz/1FC5Q13R+mM5a2oTV9TA9L/CHHTm3/PiLayfA=",
|
|
||||||
"owner": "nixos",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"rev": "625ad6366178f03acd79f9e3822606dd7985b657",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "nixos",
|
|
||||||
"ref": "nixpkgs-unstable",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nixpkgs_2": {
|
"nixpkgs_2": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1758690382,
|
"lastModified": 1758690382,
|
||||||
@@ -1409,11 +1363,11 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs_3": {
|
"nixpkgs_3": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1757745802,
|
"lastModified": 1759147044,
|
||||||
"narHash": "sha256-hLEO2TPj55KcUFUU1vgtHE9UEIOjRcH/4QbmfHNF820=",
|
"narHash": "sha256-3ZPFytJOcLjTChljeaGgoaNj+tOqzgEpqZAvRe3bU90=",
|
||||||
"owner": "NixOS",
|
"owner": "PedroHLC",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1",
|
"rev": "18e83bbe13aa50992777832b52bd0e0d8585fb3b",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -1424,22 +1378,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"nixpkgs_4": {
|
"nixpkgs_4": {
|
||||||
"locked": {
|
|
||||||
"lastModified": 1761114652,
|
|
||||||
"narHash": "sha256-f/QCJM/YhrV/lavyCVz8iU3rlZun6d+dAiC3H+CDle4=",
|
|
||||||
"owner": "NixOS",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"rev": "01f116e4df6a15f4ccdffb1bcd41096869fb385c",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "NixOS",
|
|
||||||
"ref": "nixos-unstable",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nixpkgs_5": {
|
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1753250450,
|
"lastModified": 1753250450,
|
||||||
"narHash": "sha256-i+CQV2rPmP8wHxj0aq4siYyohHwVlsh40kV89f3nw1s=",
|
"narHash": "sha256-i+CQV2rPmP8wHxj0aq4siYyohHwVlsh40kV89f3nw1s=",
|
||||||
@@ -1455,39 +1393,39 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"nixpkgs_5": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1740560979,
|
||||||
|
"narHash": "sha256-Vr3Qi346M+8CjedtbyUevIGDZW8LcA1fTG0ugPY/Hic=",
|
||||||
|
"owner": "nixos",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "5135c59491985879812717f4c9fea69604e7f26f",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nixos",
|
||||||
|
"ref": "nixos-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"nixpkgs_6": {
|
"nixpkgs_6": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1759381078,
|
"lastModified": 1759381078,
|
||||||
"narHash": "sha256-gTrEEp5gEspIcCOx9PD8kMaF1iEmfBcTbO0Jag2QhQs=",
|
"narHash": "sha256-gTrEEp5gEspIcCOx9PD8kMaF1iEmfBcTbO0Jag2QhQs=",
|
||||||
"owner": "nixos",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "7df7ff7d8e00218376575f0acdcc5d66741351ee",
|
"rev": "7df7ff7d8e00218376575f0acdcc5d66741351ee",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "nixos",
|
"owner": "NixOS",
|
||||||
"ref": "nixos-unstable",
|
"ref": "nixos-unstable",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"nixpkgs_7": {
|
"nixpkgs_7": {
|
||||||
"locked": {
|
|
||||||
"lastModified": 1761114652,
|
|
||||||
"narHash": "sha256-f/QCJM/YhrV/lavyCVz8iU3rlZun6d+dAiC3H+CDle4=",
|
|
||||||
"owner": "NixOS",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"rev": "01f116e4df6a15f4ccdffb1bcd41096869fb385c",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "NixOS",
|
|
||||||
"ref": "nixos-unstable",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nixpkgs_8": {
|
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1754243818,
|
"lastModified": 1754243818,
|
||||||
"narHash": "sha256-sEPw2W01UPf0xNGnMGNZIaE1XHkk7O+lLLetYEXVZHk=",
|
"narHash": "sha256-sEPw2W01UPf0xNGnMGNZIaE1XHkk7O+lLLetYEXVZHk=",
|
||||||
@@ -1503,13 +1441,13 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"nixpkgs_9": {
|
"nixpkgs_8": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1761114652,
|
"lastModified": 1759381078,
|
||||||
"narHash": "sha256-f/QCJM/YhrV/lavyCVz8iU3rlZun6d+dAiC3H+CDle4=",
|
"narHash": "sha256-gTrEEp5gEspIcCOx9PD8kMaF1iEmfBcTbO0Jag2QhQs=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "01f116e4df6a15f4ccdffb1bcd41096869fb385c",
|
"rev": "7df7ff7d8e00218376575f0acdcc5d66741351ee",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -1519,20 +1457,36 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"nixpkgs_9": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1759386674,
|
||||||
|
"narHash": "sha256-wg1Lz/1FC5Q13R+mM5a2oTV9TA9L/CHHTm3/PiLayfA=",
|
||||||
|
"owner": "nixos",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "625ad6366178f03acd79f9e3822606dd7985b657",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nixos",
|
||||||
|
"ref": "nixpkgs-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"nvf": {
|
"nvf": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"flake-compat": "flake-compat_5",
|
"flake-compat": "flake-compat_5",
|
||||||
"flake-parts": "flake-parts_6",
|
"flake-parts": "flake-parts_5",
|
||||||
"mnw": "mnw",
|
"mnw": "mnw",
|
||||||
"nixpkgs": "nixpkgs_10",
|
"nixpkgs": "nixpkgs_9",
|
||||||
"systems": "systems_5"
|
"systems": "systems_5"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1761112426,
|
"lastModified": 1759469269,
|
||||||
"narHash": "sha256-fa3fIyXP3xQhsPaZX4WsFwPM9g64EMOucfDEC4o8Nwc=",
|
"narHash": "sha256-DP833ejGUNRRHsJOB3WRTaWWXLNucaDga2ju/fGe+sc=",
|
||||||
"owner": "notashelf",
|
"owner": "notashelf",
|
||||||
"repo": "nvf",
|
"repo": "nvf",
|
||||||
"rev": "9b3e7bcf68ace2f07eb7478c40e45ce79332482b",
|
"rev": "e48638aef3a95377689de0ef940443c64f870a09",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -1551,11 +1505,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1760663237,
|
"lastModified": 1758108966,
|
||||||
"narHash": "sha256-BflA6U4AM1bzuRMR8QqzPXqh8sWVCNDzOdsxXEguJIc=",
|
"narHash": "sha256-ytw7ROXaWZ7OfwHrQ9xvjpUWeGVm86pwnEd1QhzawIo=",
|
||||||
"owner": "cachix",
|
"owner": "cachix",
|
||||||
"repo": "git-hooks.nix",
|
"repo": "git-hooks.nix",
|
||||||
"rev": "ca5b894d3e3e151ffc1db040b6ce4dcc75d31c37",
|
"rev": "54df955a695a84cd47d4a43e08e1feaf90b1fd9b",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -1648,7 +1602,7 @@
|
|||||||
"chaotic": "chaotic",
|
"chaotic": "chaotic",
|
||||||
"fenix": "fenix",
|
"fenix": "fenix",
|
||||||
"flake-compat": "flake-compat_2",
|
"flake-compat": "flake-compat_2",
|
||||||
"flake-parts": "flake-parts_3",
|
"flake-parts": "flake-parts_2",
|
||||||
"fonts": "fonts",
|
"fonts": "fonts",
|
||||||
"git-hooks": "git-hooks",
|
"git-hooks": "git-hooks",
|
||||||
"hardware": "hardware",
|
"hardware": "hardware",
|
||||||
@@ -1661,7 +1615,7 @@
|
|||||||
"hyprpaper": "hyprpaper",
|
"hyprpaper": "hyprpaper",
|
||||||
"lanzaboote": "lanzaboote",
|
"lanzaboote": "lanzaboote",
|
||||||
"nix-gaming": "nix-gaming",
|
"nix-gaming": "nix-gaming",
|
||||||
"nixpkgs": "nixpkgs_9",
|
"nixpkgs": "nixpkgs_8",
|
||||||
"nvf": "nvf",
|
"nvf": "nvf",
|
||||||
"systems": "systems_6",
|
"systems": "systems_6",
|
||||||
"treefmt-nix": "treefmt-nix",
|
"treefmt-nix": "treefmt-nix",
|
||||||
@@ -1672,11 +1626,11 @@
|
|||||||
"rust-analyzer-src": {
|
"rust-analyzer-src": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1761322849,
|
"lastModified": 1759301569,
|
||||||
"narHash": "sha256-KzRamhMnHTBEbYM0lZqozwc9BEYOTBMxVyAtDyiRq3s=",
|
"narHash": "sha256-7StxDed3v2fAWLkl+Hse9FlpjT7Dk7Cn/4vxTFyEhIg=",
|
||||||
"owner": "rust-lang",
|
"owner": "rust-lang",
|
||||||
"repo": "rust-analyzer",
|
"repo": "rust-analyzer",
|
||||||
"rev": "51236f731456f305bac2b48682f8e1fa3032c989",
|
"rev": "472037b789cf593172d6adf3b8d9f7a429f6cd9b",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -1694,11 +1648,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1761273263,
|
"lastModified": 1759458749,
|
||||||
"narHash": "sha256-6d6ojnu6A6sVxIjig8OL6E1T8Ge9st3YGgVwg5MOY+Q=",
|
"narHash": "sha256-WKnbJnm1B2+TO2ZUudgS39EzecQeLl4/bnRtd3y46LI=",
|
||||||
"owner": "oxalica",
|
"owner": "oxalica",
|
||||||
"repo": "rust-overlay",
|
"repo": "rust-overlay",
|
||||||
"rev": "28405834d4fdd458d28e123fae4db148daecec6f",
|
"rev": "bbc3a8ae797d1700e57a4f4bcc4e79af727d4138",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -1715,11 +1669,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1759631821,
|
"lastModified": 1740623427,
|
||||||
"narHash": "sha256-V8A1L0FaU/aSXZ1QNJScxC12uP4hANeRBgI4YdhHeRM=",
|
"narHash": "sha256-3SdPQrZoa4odlScFDUHd4CUPQ/R1gtH4Mq9u8CBiK8M=",
|
||||||
"owner": "oxalica",
|
"owner": "oxalica",
|
||||||
"repo": "rust-overlay",
|
"repo": "rust-overlay",
|
||||||
"rev": "1d7cbdaad90f8a5255a89a6eddd8af24dc89cafe",
|
"rev": "d342e8b5fd88421ff982f383c853f0fc78a847ab",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -1861,11 +1815,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1761311587,
|
"lastModified": 1758728421,
|
||||||
"narHash": "sha256-Msq86cR5SjozQGCnC6H8C+0cD4rnx91BPltZ9KK613Y=",
|
"narHash": "sha256-ySNJ008muQAds2JemiyrWYbwbG+V7S5wg3ZVKGHSFu8=",
|
||||||
"owner": "numtide",
|
"owner": "numtide",
|
||||||
"repo": "treefmt-nix",
|
"repo": "treefmt-nix",
|
||||||
"rev": "2eddae033e4e74bf581c2d1dfa101f9033dbd2dc",
|
"rev": "5eda4ee8121f97b218f7cc73f5172098d458f1d1",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -1876,7 +1830,7 @@
|
|||||||
},
|
},
|
||||||
"tuirun": {
|
"tuirun": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"flake-parts": "flake-parts_7",
|
"flake-parts": "flake-parts_6",
|
||||||
"nixpkgs": [
|
"nixpkgs": [
|
||||||
"nixpkgs"
|
"nixpkgs"
|
||||||
],
|
],
|
||||||
@@ -1949,11 +1903,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1760713634,
|
"lastModified": 1755354946,
|
||||||
"narHash": "sha256-5HXelmz2x/uO26lvW7MudnadbAfoBnve4tRBiDVLtOM=",
|
"narHash": "sha256-zdov5f/GcoLQc9qYIS1dUTqtJMeDqmBmo59PAxze6e4=",
|
||||||
"owner": "hyprwm",
|
"owner": "hyprwm",
|
||||||
"repo": "xdg-desktop-portal-hyprland",
|
"repo": "xdg-desktop-portal-hyprland",
|
||||||
"rev": "753bbbdf6a052994da94062e5b753288cef28dfb",
|
"rev": "a10726d6a8d0ef1a0c645378f983b6278c42eaa0",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -1969,11 +1923,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1761276110,
|
"lastModified": 1759590499,
|
||||||
"narHash": "sha256-k9HfFWBxM7DNGrahC+IZtB8DcZyBW2uUW0HktffX640=",
|
"narHash": "sha256-EBToRzqe5WMz4DQyxOp9/CP+rWjdaZ2EUwbItfNf3VI=",
|
||||||
"ref": "refs/heads/main",
|
"ref": "refs/heads/main",
|
||||||
"rev": "f0b40ea6601bf74bdfb4bfeb2e969122b0115ea7",
|
"rev": "6e606c8bfa6a88209488790388b1005bc489fa66",
|
||||||
"revCount": 140,
|
"revCount": 136,
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://git.sr.ht/~canasta/zen-browser-flake"
|
"url": "https://git.sr.ht/~canasta/zen-browser-flake"
|
||||||
},
|
},
|
||||||
|
|||||||
15
flake.nix
15
flake.nix
@@ -1,7 +1,8 @@
|
|||||||
{
|
{
|
||||||
description = "cnix nix";
|
description = "cnix nix";
|
||||||
|
|
||||||
outputs = inputs:
|
outputs =
|
||||||
|
inputs:
|
||||||
inputs.flake-parts.lib.mkFlake { inherit inputs; } {
|
inputs.flake-parts.lib.mkFlake { inherit inputs; } {
|
||||||
systems = [
|
systems = [
|
||||||
"x86_64-linux"
|
"x86_64-linux"
|
||||||
@@ -16,11 +17,13 @@
|
|||||||
./fmt-hooks.nix
|
./fmt-hooks.nix
|
||||||
];
|
];
|
||||||
|
|
||||||
perSystem = {
|
perSystem =
|
||||||
|
{
|
||||||
config,
|
config,
|
||||||
pkgs,
|
pkgs,
|
||||||
...
|
...
|
||||||
}: {
|
}:
|
||||||
|
{
|
||||||
devShells.default = pkgs.mkShell {
|
devShells.default = pkgs.mkShell {
|
||||||
packages = [
|
packages = [
|
||||||
pkgs.git
|
pkgs.git
|
||||||
@@ -53,7 +56,11 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
authentik = {
|
authentik = {
|
||||||
url = "github:nix-community/authentik-nix/version/2025.8.4";
|
url = "github:nix-community/authentik-nix";
|
||||||
|
inputs = {
|
||||||
|
nixpkgs.follows = "nixpkgs";
|
||||||
|
flake-parts.follows = "flake-parts";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
flake-compat.url = "github:edolstra/flake-compat";
|
flake-compat.url = "github:edolstra/flake-compat";
|
||||||
|
|||||||
@@ -73,8 +73,8 @@
|
|||||||
enable = false;
|
enable = false;
|
||||||
};
|
};
|
||||||
hyprland = {
|
hyprland = {
|
||||||
enable = true;
|
enable = false;
|
||||||
withUWSM = true;
|
withUWSM = false;
|
||||||
};
|
};
|
||||||
inkscape = {
|
inkscape = {
|
||||||
enable = false;
|
enable = false;
|
||||||
@@ -86,7 +86,7 @@
|
|||||||
enable = true;
|
enable = true;
|
||||||
};
|
};
|
||||||
niri = {
|
niri = {
|
||||||
enable = false;
|
enable = true;
|
||||||
};
|
};
|
||||||
pkgs = {
|
pkgs = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
name = "DP-3";
|
name = "DP-3";
|
||||||
width = 2560;
|
width = 2560;
|
||||||
height = 1440;
|
height = 1440;
|
||||||
refreshRate = "143.99";
|
refreshRate = 240;
|
||||||
position = "0x0";
|
position = "0x0";
|
||||||
transform = 0;
|
transform = 0;
|
||||||
bitDepth = 10;
|
bitDepth = 10;
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
name = "HDMI-A-1";
|
name = "HDMI-A-1";
|
||||||
width = 1920;
|
width = 1920;
|
||||||
height = 1080;
|
height = 1080;
|
||||||
refreshRate = "60";
|
refreshRate = 60;
|
||||||
position = "2560x0";
|
position = "2560x0";
|
||||||
# transform = 3;
|
# transform = 3;
|
||||||
workspace = "5";
|
workspace = "5";
|
||||||
@@ -29,7 +29,7 @@
|
|||||||
name = "eDP-1";
|
name = "eDP-1";
|
||||||
width = 1920;
|
width = 1920;
|
||||||
height = 1200;
|
height = 1200;
|
||||||
refreshRate = "60";
|
refreshRate = 60;
|
||||||
workspace = "1";
|
workspace = "1";
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
{
|
{
|
||||||
flake.nixosConfigurations =
|
flake.nixosConfigurations =
|
||||||
let
|
let
|
||||||
clib = import ../lib inputs.nixpkgs.lib;
|
cLib = import ../lib inputs.nixpkgs.lib;
|
||||||
userConfig = "${self}/home";
|
userConfig = "${self}/home";
|
||||||
systemConfig = "${self}/system";
|
systemConfig = "${self}/system";
|
||||||
hostConfig = "${self}/hosts";
|
hostConfig = "${self}/hosts";
|
||||||
@@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
specialArgs = {
|
specialArgs = {
|
||||||
inherit
|
inherit
|
||||||
|
cLib
|
||||||
inputs
|
inputs
|
||||||
outputs
|
outputs
|
||||||
self
|
self
|
||||||
@@ -36,20 +37,17 @@
|
|||||||
smodPath
|
smodPath
|
||||||
;
|
;
|
||||||
};
|
};
|
||||||
specialArgsWithClib = specialArgs // {
|
|
||||||
inherit clib;
|
|
||||||
};
|
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
kima = nixosSystem {
|
kima = nixosSystem {
|
||||||
specialArgs = specialArgsWithClib;
|
inherit specialArgs;
|
||||||
modules = [
|
modules = [
|
||||||
./kima
|
./kima
|
||||||
"${self}/nix"
|
"${self}/nix"
|
||||||
{
|
{
|
||||||
home-manager = {
|
home-manager = {
|
||||||
users.cnst.imports = homeImports."cnst@kima";
|
users.cnst.imports = homeImports."cnst@kima";
|
||||||
extraSpecialArgs = specialArgsWithClib;
|
extraSpecialArgs = specialArgs;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
self.nixosModules.nixos
|
self.nixosModules.nixos
|
||||||
@@ -59,14 +57,14 @@
|
|||||||
];
|
];
|
||||||
};
|
};
|
||||||
bunk = nixosSystem {
|
bunk = nixosSystem {
|
||||||
specialArgs = specialArgsWithClib;
|
inherit specialArgs;
|
||||||
modules = [
|
modules = [
|
||||||
./bunk
|
./bunk
|
||||||
"${self}/nix"
|
"${self}/nix"
|
||||||
{
|
{
|
||||||
home-manager = {
|
home-manager = {
|
||||||
users.cnst.imports = homeImports."cnst@bunk";
|
users.cnst.imports = homeImports."cnst@bunk";
|
||||||
extraSpecialArgs = specialArgsWithClib;
|
extraSpecialArgs = specialArgs;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
self.nixosModules.nixos
|
self.nixosModules.nixos
|
||||||
@@ -99,14 +97,14 @@
|
|||||||
];
|
];
|
||||||
};
|
};
|
||||||
toothpc = nixosSystem {
|
toothpc = nixosSystem {
|
||||||
specialArgs = specialArgsWithClib;
|
inherit specialArgs;
|
||||||
modules = [
|
modules = [
|
||||||
./toothpc
|
./toothpc
|
||||||
"${self}/nix"
|
"${self}/nix"
|
||||||
{
|
{
|
||||||
home-manager = {
|
home-manager = {
|
||||||
users.toothpick.imports = homeImports."toothpick@toothpc";
|
users.toothpick.imports = homeImports."toothpick@toothpc";
|
||||||
extraSpecialArgs = specialArgsWithClib;
|
extraSpecialArgs = specialArgs;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
self.nixosModules.nixos
|
self.nixosModules.nixos
|
||||||
|
|||||||
@@ -29,13 +29,6 @@
|
|||||||
};
|
};
|
||||||
network = {
|
network = {
|
||||||
enable = true;
|
enable = true;
|
||||||
nameservers = [
|
|
||||||
"192.168.88.1"
|
|
||||||
"192.168.88.69"
|
|
||||||
];
|
|
||||||
search = [
|
|
||||||
"taila7448a.ts.net"
|
|
||||||
];
|
|
||||||
interfaces = {
|
interfaces = {
|
||||||
"eno1" = {
|
"eno1" = {
|
||||||
allowedTCPPorts = [
|
allowedTCPPorts = [
|
||||||
@@ -73,7 +66,7 @@
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
gamescope = {
|
gamescope = {
|
||||||
enable = false;
|
enable = true;
|
||||||
};
|
};
|
||||||
gimp = {
|
gimp = {
|
||||||
enable = true;
|
enable = true;
|
||||||
@@ -82,8 +75,8 @@
|
|||||||
enable = false;
|
enable = false;
|
||||||
};
|
};
|
||||||
hyprland = {
|
hyprland = {
|
||||||
enable = true;
|
enable = false;
|
||||||
withUWSM = true;
|
withUWSM = false;
|
||||||
};
|
};
|
||||||
inkscape = {
|
inkscape = {
|
||||||
enable = false;
|
enable = false;
|
||||||
@@ -98,7 +91,7 @@
|
|||||||
enable = true;
|
enable = true;
|
||||||
};
|
};
|
||||||
niri = {
|
niri = {
|
||||||
enable = false;
|
enable = true;
|
||||||
};
|
};
|
||||||
pkgs = {
|
pkgs = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
name = "DP-3";
|
name = "DP-3";
|
||||||
width = 2560;
|
width = 2560;
|
||||||
height = 1440;
|
height = 1440;
|
||||||
refreshRate = "143.99";
|
refreshRate = 240;
|
||||||
position = "0x0";
|
position = "0x0";
|
||||||
transform = 0;
|
transform = 0;
|
||||||
bitDepth = 10;
|
bitDepth = 10;
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
name = "HDMI-A-1";
|
name = "HDMI-A-1";
|
||||||
width = 1920;
|
width = 1920;
|
||||||
height = 1080;
|
height = 1080;
|
||||||
refreshRate = "60";
|
refreshRate = 60;
|
||||||
position = "2560x0";
|
position = "2560x0";
|
||||||
transform = 3;
|
transform = 3;
|
||||||
workspace = "5";
|
workspace = "5";
|
||||||
@@ -29,7 +29,7 @@
|
|||||||
name = "eDP-1";
|
name = "eDP-1";
|
||||||
width = 1920;
|
width = 1920;
|
||||||
height = 1200;
|
height = 1200;
|
||||||
refreshRate = "60";
|
refreshRate = 60;
|
||||||
workspace = "1";
|
workspace = "1";
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -68,10 +68,7 @@ in {
|
|||||||
|
|
||||||
boot = {
|
boot = {
|
||||||
supportedFilesystems = ["zfs"];
|
supportedFilesystems = ["zfs"];
|
||||||
zfs = {
|
zfs.extraPools = ["data"];
|
||||||
package = pkgs.zfs_unstable;
|
|
||||||
extraPools = ["data"];
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
services.zfs = {
|
services.zfs = {
|
||||||
|
|||||||
@@ -109,7 +109,7 @@
|
|||||||
enable = true;
|
enable = true;
|
||||||
};
|
};
|
||||||
dev = {
|
dev = {
|
||||||
enable = true;
|
enable = false;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
mysql-workbench = {
|
mysql-workbench = {
|
||||||
@@ -214,7 +214,7 @@
|
|||||||
flags = "--performance";
|
flags = "--performance";
|
||||||
};
|
};
|
||||||
tailscale = {
|
tailscale = {
|
||||||
enable = false;
|
enable = true;
|
||||||
};
|
};
|
||||||
udisks = {
|
udisks = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
|||||||
@@ -3,30 +3,77 @@
|
|||||||
enable = true;
|
enable = true;
|
||||||
email = "adam@cnst.dev";
|
email = "adam@cnst.dev";
|
||||||
domain = "cnix.dev";
|
domain = "cnix.dev";
|
||||||
ip = "192.168.88.14";
|
|
||||||
user = "share";
|
user = "share";
|
||||||
group = "share";
|
group = "share";
|
||||||
uid = 994;
|
uid = 994;
|
||||||
gid = 993;
|
gid = 993;
|
||||||
|
|
||||||
infra = {
|
traefik = {
|
||||||
|
enable = true;
|
||||||
|
};
|
||||||
|
gitea = {
|
||||||
|
enable = true;
|
||||||
|
};
|
||||||
|
unbound = {
|
||||||
|
enable = true;
|
||||||
|
};
|
||||||
|
homepage-dashboard = {
|
||||||
|
enable = true;
|
||||||
|
};
|
||||||
|
n8n = {
|
||||||
|
enable = true;
|
||||||
|
};
|
||||||
|
bazarr = {
|
||||||
|
enable = true;
|
||||||
|
};
|
||||||
|
prowlarr = {
|
||||||
|
enable = true;
|
||||||
|
};
|
||||||
|
lidarr = {
|
||||||
|
enable = true;
|
||||||
|
};
|
||||||
|
sonarr = {
|
||||||
|
enable = true;
|
||||||
|
};
|
||||||
|
radarr = {
|
||||||
|
enable = true;
|
||||||
|
};
|
||||||
|
jellyseerr = {
|
||||||
|
enable = true;
|
||||||
|
};
|
||||||
|
jellyfin = {
|
||||||
|
enable = true;
|
||||||
|
};
|
||||||
|
uptime-kuma = {
|
||||||
|
enable = true;
|
||||||
|
};
|
||||||
|
vaultwarden = {
|
||||||
|
enable = true;
|
||||||
|
url = "vault.cnst.dev";
|
||||||
|
cloudflared = {
|
||||||
|
tunnelId = "fdd98086-6a4c-44f2-bba0-eb86b833cce5";
|
||||||
|
credentialsFile = config.age.secrets.vaultwardenCloudflared.path;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
www = {
|
||||||
|
enable = true;
|
||||||
|
url = "cnst.dev";
|
||||||
|
cloudflared = {
|
||||||
|
tunnelId = "e5076186-efb7-405a-998c-6155af7fb221";
|
||||||
|
credentialsFile = config.age.secrets.wwwCloudflared.path;
|
||||||
|
};
|
||||||
|
};
|
||||||
authentik = {
|
authentik = {
|
||||||
enable = true;
|
enable = true;
|
||||||
url = "auth.cnst.dev";
|
url = "auth.cnst.dev";
|
||||||
port = 9000;
|
|
||||||
cloudflared = {
|
cloudflared = {
|
||||||
tunnelId = "b66f9368-db9e-4302-8b48-527cda34a635";
|
tunnelId = "b66f9368-db9e-4302-8b48-527cda34a635";
|
||||||
credentialsFile = config.age.secrets.authentikCloudflared.path;
|
credentialsFile = config.age.secrets.authentikCloudflared.path;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
traefik = {
|
nextcloud = {
|
||||||
enable = true;
|
|
||||||
};
|
|
||||||
tailscale = {
|
|
||||||
enable = true;
|
|
||||||
};
|
|
||||||
unbound = {
|
|
||||||
enable = true;
|
enable = true;
|
||||||
|
adminpassFile = config.age.secrets.nextcloudAdminPass.path;
|
||||||
};
|
};
|
||||||
fail2ban = {
|
fail2ban = {
|
||||||
enable = true;
|
enable = true;
|
||||||
@@ -37,242 +84,19 @@
|
|||||||
enable = true;
|
enable = true;
|
||||||
interface = "enp6s0";
|
interface = "enp6s0";
|
||||||
};
|
};
|
||||||
gluetun = {
|
|
||||||
enable = true;
|
|
||||||
};
|
|
||||||
podman = {
|
podman = {
|
||||||
enable = true;
|
enable = true;
|
||||||
};
|
gluetun.enable = true;
|
||||||
www = {
|
|
||||||
enable = true;
|
|
||||||
url = "cnst.dev";
|
|
||||||
port = 8283;
|
|
||||||
cloudflared = {
|
|
||||||
tunnelId = "e5076186-efb7-405a-998c-6155af7fb221";
|
|
||||||
credentialsFile = config.age.secrets.wwwCloudflared.path;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
services = {
|
|
||||||
homepage-dashboard = {
|
|
||||||
enable = true;
|
|
||||||
subdomain = "dash";
|
|
||||||
exposure = "local";
|
|
||||||
port = 8082;
|
|
||||||
};
|
|
||||||
n8n = {
|
|
||||||
enable = true;
|
|
||||||
subdomain = "n8n";
|
|
||||||
exposure = "local";
|
|
||||||
port = 5678;
|
|
||||||
homepage = {
|
|
||||||
name = "n8n";
|
|
||||||
description = "A workflow automation platform";
|
|
||||||
icon = "n8n.svg";
|
|
||||||
category = "Services";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
ollama = {
|
|
||||||
enable = true;
|
|
||||||
subdomain = "ai";
|
|
||||||
exposure = "local";
|
|
||||||
port = 8001;
|
|
||||||
homepage = {
|
|
||||||
name = "ollama";
|
|
||||||
description = "AI platform";
|
|
||||||
icon = "ollama.svg";
|
|
||||||
category = "Services";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
bazarr = {
|
|
||||||
enable = true;
|
|
||||||
subdomain = "bazarr";
|
|
||||||
exposure = "local";
|
|
||||||
port = 6767;
|
|
||||||
homepage = {
|
|
||||||
name = "Bazarr";
|
|
||||||
description = "Subtitle manager";
|
|
||||||
icon = "bazarr.svg";
|
|
||||||
category = "Arr";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
prowlarr = {
|
|
||||||
enable = true;
|
|
||||||
subdomain = "prowlarr";
|
|
||||||
exposure = "local";
|
|
||||||
port = 9696;
|
|
||||||
homepage = {
|
|
||||||
name = "Prowlarr";
|
|
||||||
description = "PVR indexer";
|
|
||||||
icon = "prowlarr.svg";
|
|
||||||
category = "Arr";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
flaresolverr = {
|
|
||||||
enable = true;
|
|
||||||
subdomain = "flaresolverr";
|
|
||||||
exposure = "local";
|
|
||||||
port = 8191;
|
|
||||||
homepage = {
|
|
||||||
name = "FlareSolverr";
|
|
||||||
description = "Proxy to bypass Cloudflare/DDoS-GUARD protection";
|
|
||||||
icon = "flaresolverr.svg";
|
|
||||||
category = "Arr";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
lidarr = {
|
|
||||||
enable = true;
|
|
||||||
subdomain = "lidarr";
|
|
||||||
exposure = "local";
|
|
||||||
port = 8686;
|
|
||||||
homepage = {
|
|
||||||
name = "Lidarr";
|
|
||||||
description = "Music collection manager";
|
|
||||||
icon = "lidarr.svg";
|
|
||||||
category = "Arr";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
sonarr = {
|
|
||||||
enable = true;
|
|
||||||
subdomain = "sonarr";
|
|
||||||
exposure = "local";
|
|
||||||
port = 8989;
|
|
||||||
homepage = {
|
|
||||||
name = "Sonarr";
|
|
||||||
description = "Internet PVR for Usenet and Torrents";
|
|
||||||
icon = "sonarr.svg";
|
|
||||||
category = "Arr";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
radarr = {
|
|
||||||
enable = true;
|
|
||||||
subdomain = "radarr";
|
|
||||||
exposure = "local";
|
|
||||||
port = 7878;
|
|
||||||
homepage = {
|
|
||||||
name = "Radarr";
|
|
||||||
description = "Movie collection manager";
|
|
||||||
icon = "radarr.svg";
|
|
||||||
category = "Arr";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
jellyseerr = {
|
|
||||||
enable = true;
|
|
||||||
subdomain = "jellyseerr";
|
|
||||||
exposure = "local";
|
|
||||||
port = 5055;
|
|
||||||
homepage = {
|
|
||||||
name = "Jellyseerr";
|
|
||||||
description = "Media request and discovery manager";
|
|
||||||
icon = "jellyseerr.svg";
|
|
||||||
category = "Arr";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
jellyfin = {
|
|
||||||
enable = true;
|
|
||||||
subdomain = "fin";
|
|
||||||
exposure = "tailscale";
|
|
||||||
port = 8096;
|
|
||||||
homepage = {
|
|
||||||
name = "Jellyfin";
|
|
||||||
description = "The Free Software Media System";
|
|
||||||
icon = "jellyfin.svg";
|
|
||||||
category = "Media";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
uptime-kuma = {
|
|
||||||
enable = true;
|
|
||||||
subdomain = "uptime";
|
|
||||||
exposure = "local";
|
|
||||||
port = 3001;
|
|
||||||
homepage = {
|
|
||||||
name = "Uptime Kuma";
|
|
||||||
description = "Service monitoring tool";
|
|
||||||
icon = "uptime-kuma.svg";
|
|
||||||
category = "Services";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
gitea = {
|
|
||||||
enable = true;
|
|
||||||
subdomain = "git";
|
|
||||||
exposure = "tunnel";
|
|
||||||
port = 5003;
|
|
||||||
cloudflared = {
|
|
||||||
tunnelId = "33e2fb8e-ecef-4d42-b845-6d15e216e448";
|
|
||||||
credentialsFile = config.age.secrets.giteaCloudflared.path;
|
|
||||||
};
|
|
||||||
homepage = {
|
|
||||||
name = "Gitea";
|
|
||||||
description = "Git with a cup of tea";
|
|
||||||
icon = "gitea.svg";
|
|
||||||
category = "Services";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
vaultwarden = {
|
|
||||||
enable = true;
|
|
||||||
subdomain = "vault";
|
|
||||||
exposure = "tunnel";
|
|
||||||
port = 8222;
|
|
||||||
cloudflared = {
|
|
||||||
tunnelId = "fdd98086-6a4c-44f2-bba0-eb86b833cce5";
|
|
||||||
credentialsFile = config.age.secrets.vaultwardenCloudflared.path;
|
|
||||||
};
|
|
||||||
homepage = {
|
|
||||||
name = "Vaultwarden";
|
|
||||||
description = "Password manager";
|
|
||||||
icon = "vaultwarden-light.svg";
|
|
||||||
category = "Services";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
nextcloud = {
|
|
||||||
enable = true;
|
|
||||||
subdomain = "cloud";
|
|
||||||
exposure = "local";
|
|
||||||
port = 8182;
|
|
||||||
homepage = {
|
|
||||||
name = "Nextcloud";
|
|
||||||
description = "A safe home for all your data";
|
|
||||||
icon = "nextcloud.svg";
|
|
||||||
category = "Services";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
qbittorrent = {
|
qbittorrent = {
|
||||||
enable = true;
|
enable = true;
|
||||||
subdomain = "qbt";
|
|
||||||
exposure = "local";
|
|
||||||
port = 8080;
|
port = 8080;
|
||||||
homepage = {
|
|
||||||
name = "qBittorrent";
|
|
||||||
description = "Torrent client";
|
|
||||||
icon = "qbittorrent.svg";
|
|
||||||
category = "Downloads";
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
slskd = {
|
slskd = {
|
||||||
enable = true;
|
enable = true;
|
||||||
subdomain = "slskd";
|
|
||||||
exposure = "local";
|
|
||||||
port = 5030;
|
|
||||||
homepage = {
|
|
||||||
name = "Soulseek";
|
|
||||||
description = "Web-based Soulseek client";
|
|
||||||
icon = "slskd.svg";
|
|
||||||
category = "Downloads";
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
pihole = {
|
pihole = {
|
||||||
enable = true;
|
enable = true;
|
||||||
subdomain = "pihole";
|
|
||||||
exposure = "local";
|
|
||||||
port = 8053;
|
port = 8053;
|
||||||
homepage = {
|
|
||||||
name = "PiHole";
|
|
||||||
description = "Adblocking and DNS service";
|
|
||||||
icon = "pi-hole.svg";
|
|
||||||
category = "Services";
|
|
||||||
path = "/admin";
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -4,10 +4,6 @@
|
|||||||
username = "cnst";
|
username = "cnst";
|
||||||
mail = "adam@cnst.dev";
|
mail = "adam@cnst.dev";
|
||||||
sshUser = "sobotka";
|
sshUser = "sobotka";
|
||||||
domains = {
|
|
||||||
local = "cnix.dev";
|
|
||||||
public = "cnst.dev";
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
name = "DVI-D-1";
|
name = "DVI-D-1";
|
||||||
width = 1920;
|
width = 1920;
|
||||||
height = 1080;
|
height = 1080;
|
||||||
refreshRate = "144";
|
refreshRate = 144;
|
||||||
position = "0x0";
|
position = "0x0";
|
||||||
transform = 0;
|
transform = 0;
|
||||||
workspace = "1";
|
workspace = "1";
|
||||||
|
|||||||
@@ -1,26 +0,0 @@
|
|||||||
{lib}: let
|
|
||||||
server = {
|
|
||||||
mkDomain = config: service: let
|
|
||||||
localDomain = config.settings.accounts.domains.local;
|
|
||||||
publicDomain = config.settings.accounts.domains.public;
|
|
||||||
tailscaleDomain = "ts.${publicDomain}";
|
|
||||||
in
|
|
||||||
if service.exposure == "tunnel"
|
|
||||||
then publicDomain
|
|
||||||
else if service.exposure == "tailscale"
|
|
||||||
then tailscaleDomain
|
|
||||||
else localDomain;
|
|
||||||
|
|
||||||
mkFullDomain = config: service: let
|
|
||||||
domain = server.mkDomain config service;
|
|
||||||
in "${service.subdomain}.${domain}";
|
|
||||||
|
|
||||||
mkHostDomain = config: service: let
|
|
||||||
domain = server.mkDomain config service;
|
|
||||||
in "${domain}";
|
|
||||||
|
|
||||||
mkSubDomain = config: service: "${service.subdomain}";
|
|
||||||
};
|
|
||||||
in {
|
|
||||||
server = server;
|
|
||||||
}
|
|
||||||
@@ -123,6 +123,27 @@
|
|||||||
server = {
|
server = {
|
||||||
imports = [
|
imports = [
|
||||||
./server
|
./server
|
||||||
|
./server/fail2ban
|
||||||
|
./server/homepage-dashboard
|
||||||
|
./server/nextcloud
|
||||||
|
./server/vaultwarden
|
||||||
|
./server/bazarr
|
||||||
|
./server/prowlarr
|
||||||
|
./server/lidarr
|
||||||
|
./server/radarr
|
||||||
|
./server/sonarr
|
||||||
|
./server/jellyseerr
|
||||||
|
./server/jellyfin
|
||||||
|
./server/n8n
|
||||||
|
./server/podman
|
||||||
|
./server/unbound
|
||||||
|
./server/uptime-kuma
|
||||||
|
./server/keepalived
|
||||||
|
./server/gitea
|
||||||
|
./server/postgres
|
||||||
|
./server/traefik
|
||||||
|
./server/www
|
||||||
|
./server/authentik
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
settings = {
|
settings = {
|
||||||
|
|||||||
@@ -15,16 +15,17 @@ in
|
|||||||
};
|
};
|
||||||
config = mkIf cfg.enable {
|
config = mkIf cfg.enable {
|
||||||
home.packages = [ pkgs.gh ];
|
home.packages = [ pkgs.gh ];
|
||||||
programs = {
|
programs.git = {
|
||||||
git = {
|
|
||||||
enable = true;
|
enable = true;
|
||||||
settings = {
|
userName = osConfig.settings.accounts.username;
|
||||||
# user.signingkey = "${config.home.homeDirectory}/.ssh/id_ed25519.pub";
|
userEmail = osConfig.settings.accounts.mail;
|
||||||
user = {
|
delta = {
|
||||||
name = osConfig.settings.accounts.username;
|
enable = true;
|
||||||
email = osConfig.settings.accounts.mail;
|
options.dark = true;
|
||||||
signingkey = "${config.home.homeDirectory}/.config/git/allowed_signers";
|
|
||||||
};
|
};
|
||||||
|
extraConfig = {
|
||||||
|
# user.signingkey = "${config.home.homeDirectory}/.ssh/id_ed25519.pub";
|
||||||
|
user.signingkey = "${config.home.homeDirectory}/.config/git/allowed_signers";
|
||||||
signing = {
|
signing = {
|
||||||
format = lib.mkDefault "ssh";
|
format = lib.mkDefault "ssh";
|
||||||
key = "${config.home.homeDirectory}/.ssh/id_ed25519";
|
key = "${config.home.homeDirectory}/.ssh/id_ed25519";
|
||||||
@@ -55,14 +56,6 @@ in
|
|||||||
".jj"
|
".jj"
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
delta = {
|
|
||||||
enableGitIntegration = true;
|
|
||||||
enable = true;
|
|
||||||
options.dark = true;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
xdg.configFile."git/allowed_signers".text = ''
|
xdg.configFile."git/allowed_signers".text = ''
|
||||||
${osConfig.settings.accounts.mail} namespaces="git" ${osConfig.settings.accounts.sshKey}
|
${osConfig.settings.accounts.mail} namespaces="git" ${osConfig.settings.accounts.sshKey}
|
||||||
'';
|
'';
|
||||||
|
|||||||
@@ -1,20 +1,26 @@
|
|||||||
{
|
{
|
||||||
|
inputs,
|
||||||
|
pkgs,
|
||||||
lib,
|
lib,
|
||||||
osConfig,
|
osConfig,
|
||||||
clib,
|
cLib,
|
||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
inherit (lib) mkIf;
|
inherit (lib) mkIf mkEnableOption;
|
||||||
cfg = osConfig.nixos.programs.hyprland;
|
cfg = osConfig.nixos.programs.hyprland;
|
||||||
|
|
||||||
|
hyprlockFlake = inputs.hyprlock.packages.${pkgs.system}.hyprlock;
|
||||||
|
# hyprlockPkg = pkgs.hyprlock;
|
||||||
|
#
|
||||||
bg = osConfig.settings.theme.background;
|
bg = osConfig.settings.theme.background;
|
||||||
inherit (clib.theme.bgs) resolve;
|
inherit (cLib.theme.bgs) resolve;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
config = mkIf cfg.enable {
|
config = mkIf cfg.enable {
|
||||||
programs.hyprlock = {
|
programs.hyprlock = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
package = hyprlockFlake;
|
||||||
settings = {
|
settings = {
|
||||||
general = {
|
general = {
|
||||||
# disable_loading_bar = true;
|
# disable_loading_bar = true;
|
||||||
@@ -54,7 +60,6 @@ in
|
|||||||
position = "0, 20";
|
position = "0, 20";
|
||||||
halign = "center";
|
halign = "center";
|
||||||
valign = "center";
|
valign = "center";
|
||||||
font_family = "DepartureMono Nerd Font Mono Italic";
|
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
label = [
|
label = [
|
||||||
@@ -66,7 +71,7 @@ in
|
|||||||
shadow_boost = 0.5;
|
shadow_boost = 0.5;
|
||||||
color = "rgba(FFFFFFFF)";
|
color = "rgba(FFFFFFFF)";
|
||||||
font_size = 25;
|
font_size = 25;
|
||||||
font_family = "DepartureMono Nerd Font Mono Regular";
|
font_family = "Input Mono Compressed";
|
||||||
position = "0, 230";
|
position = "0, 230";
|
||||||
halign = "center";
|
halign = "center";
|
||||||
valign = "center";
|
valign = "center";
|
||||||
@@ -79,7 +84,7 @@ in
|
|||||||
shadow_boost = 0.5;
|
shadow_boost = 0.5;
|
||||||
color = "rgba(FFFFFFFF)";
|
color = "rgba(FFFFFFFF)";
|
||||||
font_size = 85;
|
font_size = 85;
|
||||||
font_family = "DepartureMono Nerd Font Mono Regular";
|
font_family = "Input Mono Compressed";
|
||||||
position = "0, 300";
|
position = "0, 300";
|
||||||
halign = "center";
|
halign = "center";
|
||||||
valign = "center";
|
valign = "center";
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ in
|
|||||||
hyprpicker
|
hyprpicker
|
||||||
libnotify
|
libnotify
|
||||||
pamixer
|
pamixer
|
||||||
loupe
|
oculante
|
||||||
adwaita-icon-theme
|
adwaita-icon-theme
|
||||||
qt5.qtwayland
|
qt5.qtwayland
|
||||||
qt6.qtwayland
|
qt6.qtwayland
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
"group/system"
|
"group/system"
|
||||||
],
|
],
|
||||||
"modules-center": [
|
"modules-center": [
|
||||||
"hyprland/workspaces"
|
"niri/workspaces"
|
||||||
],
|
],
|
||||||
"modules-right": [
|
"modules-right": [
|
||||||
"custom/progress",
|
"custom/progress",
|
||||||
@@ -126,28 +126,16 @@
|
|||||||
"all-outputs": false,
|
"all-outputs": false,
|
||||||
"format": "{icon}",
|
"format": "{icon}",
|
||||||
"format-icons": {
|
"format-icons": {
|
||||||
"1": "1",
|
"urgent": "",
|
||||||
"2": "2",
|
"visible": "",
|
||||||
"3": "3",
|
"empty": ""
|
||||||
"4": "4",
|
|
||||||
"5": "5",
|
|
||||||
"6": "6",
|
|
||||||
"7": "7",
|
|
||||||
"8": "8",
|
|
||||||
"9": "9",
|
|
||||||
"default": "_",
|
|
||||||
"active": "_"
|
|
||||||
},
|
},
|
||||||
"on-click": "activate",
|
"on-click": "activate",
|
||||||
"show-special": false,
|
"show-special": false,
|
||||||
"on-scroll-up": "hyprctl dispatch workspace r-1",
|
"on-scroll-up": "hyprctl dispatch workspace r-1",
|
||||||
"on-scroll-down": "hyprctl dispatch workspace r+1",
|
"on-scroll-down": "hyprctl dispatch workspace r+1",
|
||||||
"persistent-workspaces": {
|
"persistent-workspaces": {
|
||||||
"1": [],
|
"*": 3
|
||||||
"2": [],
|
|
||||||
"3": [],
|
|
||||||
"4": [],
|
|
||||||
"5": []
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"niri/workspaces": {
|
"niri/workspaces": {
|
||||||
|
|||||||
@@ -28,8 +28,8 @@ tooltip label {
|
|||||||
margin: 0 0px;
|
margin: 0 0px;
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
color: #fbf1c7;
|
color: #fbf1c7;
|
||||||
border-top: 4px solid transparent;
|
border-top: 3px solid transparent;
|
||||||
border-bottom: 4px solid transparent;
|
border-bottom: 3px solid transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
#workspaces button:hover {
|
#workspaces button:hover {
|
||||||
@@ -45,7 +45,7 @@ tooltip label {
|
|||||||
background-image: url("assets/button.svg");
|
background-image: url("assets/button.svg");
|
||||||
background-position: center;
|
background-position: center;
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
background-size: 21px 18px;
|
background-size: 18px 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#custom-trayicon {
|
#custom-trayicon {
|
||||||
|
|||||||
@@ -1,14 +1,22 @@
|
|||||||
{
|
{
|
||||||
osConfig,
|
osConfig,
|
||||||
lib,
|
lib,
|
||||||
|
pkgs,
|
||||||
|
inputs,
|
||||||
...
|
...
|
||||||
}: let
|
}:
|
||||||
|
let
|
||||||
inherit (lib) mkIf;
|
inherit (lib) mkIf;
|
||||||
cfg = osConfig.nixos.programs.hyprland;
|
cfg = osConfig.nixos.programs.hyprland;
|
||||||
in {
|
|
||||||
|
hypridleFlake = inputs.hypridle.packages.${pkgs.system}.hypridle;
|
||||||
|
# hypridlePkg = pkgs.hypridle;
|
||||||
|
in
|
||||||
|
{
|
||||||
config = mkIf cfg.enable {
|
config = mkIf cfg.enable {
|
||||||
services.hypridle = {
|
services.hypridle = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
package = hypridleFlake;
|
||||||
settings = {
|
settings = {
|
||||||
general = {
|
general = {
|
||||||
lock_cmd = "hyprlock";
|
lock_cmd = "hyprlock";
|
||||||
|
|||||||
@@ -1,14 +1,18 @@
|
|||||||
{
|
{
|
||||||
lib,
|
lib,
|
||||||
|
pkgs,
|
||||||
|
inputs,
|
||||||
osConfig,
|
osConfig,
|
||||||
clib,
|
cLib,
|
||||||
...
|
...
|
||||||
}: let
|
}:
|
||||||
|
let
|
||||||
inherit (lib) mkIf;
|
inherit (lib) mkIf;
|
||||||
|
|
||||||
cfg = osConfig.nixos.programs.hyprland;
|
cfg = osConfig.nixos.programs.hyprland;
|
||||||
|
hyprpaperFlake = inputs.hyprpaper.packages.${pkgs.system}.default;
|
||||||
bg = osConfig.settings.theme.background;
|
bg = osConfig.settings.theme.background;
|
||||||
bgs = clib.theme.bgs;
|
bgs = cLib.theme.bgs;
|
||||||
|
|
||||||
monitorMappings = [
|
monitorMappings = [
|
||||||
{
|
{
|
||||||
@@ -28,10 +32,12 @@
|
|||||||
bg = bg.primary;
|
bg = bg.primary;
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
in {
|
in
|
||||||
|
{
|
||||||
config = mkIf cfg.enable {
|
config = mkIf cfg.enable {
|
||||||
services.hyprpaper = {
|
services.hyprpaper = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
package = hyprpaperFlake;
|
||||||
|
|
||||||
settings = {
|
settings = {
|
||||||
ipc = "on";
|
ipc = "on";
|
||||||
|
|||||||
@@ -84,15 +84,15 @@ in
|
|||||||
"application/pdf" = "org.pwmt.zathura-pdf-mupdf.desktop";
|
"application/pdf" = "org.pwmt.zathura-pdf-mupdf.desktop";
|
||||||
"inode/directory" = "thunar.desktop";
|
"inode/directory" = "thunar.desktop";
|
||||||
|
|
||||||
"image/apng" = "feh.desktop";
|
"image/apng" = "oculante.desktop";
|
||||||
"image/avif" = "feh.desktop";
|
"image/avif" = "oculante.desktop";
|
||||||
"image/bmp" = "feh.desktop";
|
"image/bmp" = "oculante.desktop";
|
||||||
"image/gif" = "feh.desktop";
|
"image/gif" = "oculante.desktop";
|
||||||
"image/jpeg" = "feh.desktop";
|
"image/jpeg" = "oculante.desktop";
|
||||||
"image/png" = "feh.desktop";
|
"image/png" = "oculante.desktop";
|
||||||
"image/svg+xml" = "feh.desktop";
|
"image/svg+xml" = "oculante.desktop";
|
||||||
"image/tiff" = "feh.desktop";
|
"image/tiff" = "oculante.desktop";
|
||||||
"image/webp" = "feh.desktop";
|
"image/webp" = "oculante.desktop";
|
||||||
|
|
||||||
"video/H264" = [
|
"video/H264" = [
|
||||||
"mpv.desktop"
|
"mpv.desktop"
|
||||||
|
|||||||
@@ -2,29 +2,20 @@
|
|||||||
config,
|
config,
|
||||||
lib,
|
lib,
|
||||||
...
|
...
|
||||||
}: let
|
}:
|
||||||
inherit
|
let
|
||||||
(lib)
|
inherit (lib)
|
||||||
mkIf
|
mkIf
|
||||||
mkEnableOption
|
mkEnableOption
|
||||||
mkOption
|
mkOption
|
||||||
types
|
types
|
||||||
;
|
;
|
||||||
cfg = config.nixos.hardware.network;
|
cfg = config.nixos.hardware.network;
|
||||||
in {
|
in
|
||||||
|
{
|
||||||
options = {
|
options = {
|
||||||
nixos.hardware.network = {
|
nixos.hardware.network = {
|
||||||
enable = mkEnableOption "Enable the custom networking module";
|
enable = mkEnableOption "Enable the custom networking module";
|
||||||
nameservers = mkOption {
|
|
||||||
type = types.listOf types.str;
|
|
||||||
default = [];
|
|
||||||
description = "The list of nameservers ";
|
|
||||||
};
|
|
||||||
search = mkOption {
|
|
||||||
type = types.listOf types.str;
|
|
||||||
default = [];
|
|
||||||
description = "Domain search paths";
|
|
||||||
};
|
|
||||||
interfaces = mkOption {
|
interfaces = mkOption {
|
||||||
type = types.attrsOf (
|
type = types.attrsOf (
|
||||||
types.submodule {
|
types.submodule {
|
||||||
@@ -64,8 +55,6 @@ in {
|
|||||||
networking = {
|
networking = {
|
||||||
networkmanager.enable = true;
|
networkmanager.enable = true;
|
||||||
nftables.enable = true;
|
nftables.enable = true;
|
||||||
nameservers = cfg.nameservers;
|
|
||||||
search = cfg.search;
|
|
||||||
firewall = {
|
firewall = {
|
||||||
enable = true;
|
enable = true;
|
||||||
inherit (cfg) interfaces;
|
inherit (cfg) interfaces;
|
||||||
|
|||||||
@@ -37,9 +37,9 @@ in
|
|||||||
};
|
};
|
||||||
|
|
||||||
gestures = {
|
gestures = {
|
||||||
# workspace_swipe = true;
|
workspace_swipe = true;
|
||||||
workspace_swipe_distance = 400;
|
workspace_swipe_distance = 400;
|
||||||
# workspace_swipe_fingers = 3;
|
workspace_swipe_fingers = 3;
|
||||||
workspace_swipe_cancel_ratio = 0.2;
|
workspace_swipe_cancel_ratio = 0.2;
|
||||||
workspace_swipe_min_speed_to_force = 5;
|
workspace_swipe_min_speed_to_force = 5;
|
||||||
workspace_swipe_direction_lock = true;
|
workspace_swipe_direction_lock = true;
|
||||||
|
|||||||
@@ -49,6 +49,20 @@ in
|
|||||||
"$mod, P, pseudo,"
|
"$mod, P, pseudo,"
|
||||||
"$mod, J, togglesplit,"
|
"$mod, J, togglesplit,"
|
||||||
"$mod, C, exec, hyprctl dispatch exec copyq toggle"
|
"$mod, C, exec, hyprctl dispatch exec copyq toggle"
|
||||||
|
"$mod, left, movefocus, l"
|
||||||
|
"$mod, right, movefocus, r"
|
||||||
|
"$mod, up, movefocus, u"
|
||||||
|
"$mod, down, movefocus, d"
|
||||||
|
"$mod, 1, workspace, 1"
|
||||||
|
"$mod, 2, workspace, 2"
|
||||||
|
"$mod, 3, workspace, 3"
|
||||||
|
"$mod, 4, workspace, 4"
|
||||||
|
"$mod, 5, workspace, 5"
|
||||||
|
"$mod, 6, workspace, 6"
|
||||||
|
"$mod, 7, workspace, 7"
|
||||||
|
"$mod, 8, workspace, 8"
|
||||||
|
"$mod, 9, workspace, 9"
|
||||||
|
"$mod, 0, workspace, 10"
|
||||||
"$mod SHIFT, 1, movetoworkspace, 1"
|
"$mod SHIFT, 1, movetoworkspace, 1"
|
||||||
"$mod SHIFT, 2, movetoworkspace, 2"
|
"$mod SHIFT, 2, movetoworkspace, 2"
|
||||||
"$mod SHIFT, 3, movetoworkspace, 3"
|
"$mod SHIFT, 3, movetoworkspace, 3"
|
||||||
@@ -61,30 +75,6 @@ in
|
|||||||
"$mod SHIFT, 0, movetoworkspace, 10"
|
"$mod SHIFT, 0, movetoworkspace, 10"
|
||||||
"CTRL SHIFT, Escape, exec, ${runOnce "resources"}"
|
"CTRL SHIFT, Escape, exec, ${runOnce "resources"}"
|
||||||
|
|
||||||
"$mod, 1, workspace, 1"
|
|
||||||
"$mod, 2, workspace, 2"
|
|
||||||
"$mod, 3, workspace, 3"
|
|
||||||
"$mod, 4, workspace, 4"
|
|
||||||
"$mod, 5, workspace, 5"
|
|
||||||
"$mod, 6, workspace, 6"
|
|
||||||
"$mod, 7, workspace, 7"
|
|
||||||
"$mod, 8, workspace, 8"
|
|
||||||
"$mod, 9, workspace, 9"
|
|
||||||
"$mod, 0, workspace, 10"
|
|
||||||
|
|
||||||
"$mod, left, movefocus, l"
|
|
||||||
"$mod, right, movefocus, r"
|
|
||||||
"$mod, up, movefocus, u"
|
|
||||||
"$mod, down, movefocus, d"
|
|
||||||
"$mod SHIFT, left, resizeactive, -20 0"
|
|
||||||
"$mod SHIFT, right, resizeactive, 20 0"
|
|
||||||
"$mod SHIFT, up, resizeactive, 0 -20"
|
|
||||||
"$mod SHIFT, down, resizeactive, 0 20"
|
|
||||||
"$mod CTRL, left, swapwindow, l"
|
|
||||||
"$mod CTRL, right, swapwindow, r"
|
|
||||||
"$mod CTRL, up, swapwindow, u"
|
|
||||||
"$mod CTRL, down, swapwindow, d"
|
|
||||||
|
|
||||||
",XF86AudioLowerVolume, exec, volume-control.sh --dec"
|
",XF86AudioLowerVolume, exec, volume-control.sh --dec"
|
||||||
",XF86AudioRaiseVolume, exec, volume-control.sh --inc"
|
",XF86AudioRaiseVolume, exec, volume-control.sh --inc"
|
||||||
",XF86AudioMute, exec, volume-control.sh --toggle"
|
",XF86AudioMute, exec, volume-control.sh --toggle"
|
||||||
@@ -109,7 +99,7 @@ in
|
|||||||
|
|
||||||
(mkIf (host == "kima") {
|
(mkIf (host == "kima") {
|
||||||
programs.hyprland.settings = {
|
programs.hyprland.settings = {
|
||||||
"$terminal" = "alacritty";
|
"$terminal" = "ghostty";
|
||||||
"$browser" = "zen";
|
"$browser" = "zen";
|
||||||
"$browserinc" = "zen --private-window";
|
"$browserinc" = "zen --private-window";
|
||||||
"$mod" = "SUPER";
|
"$mod" = "SUPER";
|
||||||
@@ -121,7 +111,7 @@ in
|
|||||||
|
|
||||||
(mkIf (host == "bunk") {
|
(mkIf (host == "bunk") {
|
||||||
programs.hyprland.settings = {
|
programs.hyprland.settings = {
|
||||||
"$terminal" = "alacritty";
|
"$terminal" = "foot";
|
||||||
"$browser" = "zen";
|
"$browser" = "zen";
|
||||||
"$browserinc" = "zen --private-window";
|
"$browserinc" = "zen --private-window";
|
||||||
"$mod" = "ALT_L";
|
"$mod" = "ALT_L";
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ in
|
|||||||
let
|
let
|
||||||
resolution =
|
resolution =
|
||||||
if m.width != null && m.height != null then
|
if m.width != null && m.height != null then
|
||||||
"${toString m.width}x${toString m.height}@${m.refreshRate}"
|
"${toString m.width}x${toString m.height}@${toString m.refreshRate}"
|
||||||
else
|
else
|
||||||
"preferred";
|
"preferred";
|
||||||
|
|
||||||
|
|||||||
@@ -78,10 +78,10 @@ in
|
|||||||
openssl
|
openssl
|
||||||
xmrig
|
xmrig
|
||||||
ocl-icd
|
ocl-icd
|
||||||
dig
|
|
||||||
]
|
]
|
||||||
|
|
||||||
(mkIf cfg.common.enable [
|
(mkIf cfg.common.enable [
|
||||||
|
qt6.full
|
||||||
swappy
|
swappy
|
||||||
wayfreeze
|
wayfreeze
|
||||||
imagemagick
|
imagemagick
|
||||||
@@ -96,6 +96,9 @@ in
|
|||||||
])
|
])
|
||||||
|
|
||||||
(mkIf cfg.desktop.enable [
|
(mkIf cfg.desktop.enable [
|
||||||
|
protonup
|
||||||
|
winetricks
|
||||||
|
wine
|
||||||
geekbench
|
geekbench
|
||||||
unigine-heaven
|
unigine-heaven
|
||||||
])
|
])
|
||||||
@@ -106,13 +109,15 @@ in
|
|||||||
|
|
||||||
(mkIf cfg.server.enable [
|
(mkIf cfg.server.enable [
|
||||||
nvtopPackages.intel
|
nvtopPackages.intel
|
||||||
|
nvtopPackages.amd
|
||||||
|
dig
|
||||||
helix
|
helix
|
||||||
|
zfs
|
||||||
zfstools
|
zfstools
|
||||||
])
|
])
|
||||||
|
|
||||||
(mkIf cfg.dev.enable [
|
(mkIf cfg.dev.enable [
|
||||||
# lldb_20 # some biuld error atm
|
# lldb_20 # some biuld error atm
|
||||||
sqlite
|
|
||||||
gemini-cli
|
gemini-cli
|
||||||
nfs-utils
|
nfs-utils
|
||||||
gcc
|
gcc
|
||||||
@@ -139,6 +144,7 @@ in
|
|||||||
prettierd
|
prettierd
|
||||||
# php84Packages.php-cs-fixer
|
# php84Packages.php-cs-fixer
|
||||||
shfmt
|
shfmt
|
||||||
|
luaformatter
|
||||||
black
|
black
|
||||||
])
|
])
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
{
|
{
|
||||||
config,
|
config,
|
||||||
lib,
|
lib,
|
||||||
pkgs,
|
|
||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
@@ -18,20 +17,6 @@ in
|
|||||||
enable = true;
|
enable = true;
|
||||||
gamescopeSession.enable = true;
|
gamescopeSession.enable = true;
|
||||||
};
|
};
|
||||||
gamescope = {
|
|
||||||
enable = true;
|
|
||||||
capSysNice = true;
|
|
||||||
args = [
|
|
||||||
"--rt"
|
|
||||||
"--expose-wayland"
|
|
||||||
];
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
environment.systemPackages = with pkgs; [
|
|
||||||
protonup
|
|
||||||
wine
|
|
||||||
winetricks
|
|
||||||
wine-wayland
|
|
||||||
];
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,10 +16,14 @@ in
|
|||||||
services.kanata = {
|
services.kanata = {
|
||||||
enable = true;
|
enable = true;
|
||||||
package = pkgs.kanata-with-cmd;
|
package = pkgs.kanata-with-cmd;
|
||||||
keyboards.default = {
|
keyboards.hhkbse = {
|
||||||
extraDefCfg = ''
|
extraDefCfg = ''
|
||||||
process-unmapped-keys yes
|
process-unmapped-keys yes
|
||||||
'';
|
'';
|
||||||
|
devices = [
|
||||||
|
"/dev/input/by-id/usb-PFU_Limited_HHKB-Hybrid-event-kbd"
|
||||||
|
"/dev/input/event2"
|
||||||
|
];
|
||||||
config = builtins.readFile (./. + "/hhkbse.kbd");
|
config = builtins.readFile (./. + "/hhkbse.kbd");
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ in
|
|||||||
# nodePackages_latest.sql-formatter
|
# nodePackages_latest.sql-formatter
|
||||||
prettierd
|
prettierd
|
||||||
shfmt
|
shfmt
|
||||||
|
luaformatter
|
||||||
black
|
black
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,24 +1,21 @@
|
|||||||
{
|
{
|
||||||
config,
|
config,
|
||||||
lib,
|
lib,
|
||||||
|
pkgs,
|
||||||
self,
|
self,
|
||||||
...
|
...
|
||||||
}: let
|
}: let
|
||||||
unit = "authentik";
|
unit = "authentik";
|
||||||
cfg = config.server.infra.${unit};
|
cfg = config.server.${unit};
|
||||||
srv = config.server.infra;
|
srv = config.server;
|
||||||
in {
|
in {
|
||||||
options.server.infra.${unit} = {
|
options.server.${unit} = {
|
||||||
enable = lib.mkEnableOption {
|
enable = lib.mkEnableOption {
|
||||||
description = "Enable ${unit}";
|
description = "Enable ${unit}";
|
||||||
};
|
};
|
||||||
url = lib.mkOption {
|
url = lib.mkOption {
|
||||||
type = lib.types.str;
|
type = lib.types.str;
|
||||||
default = "auth.${srv.www.url}";
|
default = "auth.${srv.www.domain}";
|
||||||
};
|
|
||||||
port = lib.mkOption {
|
|
||||||
type = lib.types.port;
|
|
||||||
description = "The local port the service runs on";
|
|
||||||
};
|
};
|
||||||
cloudflared = {
|
cloudflared = {
|
||||||
credentialsFile = lib.mkOption {
|
credentialsFile = lib.mkOption {
|
||||||
@@ -34,11 +31,21 @@ in {
|
|||||||
example = "00000000-0000-0000-0000-000000000000";
|
example = "00000000-0000-0000-0000-000000000000";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
homepage = {
|
homepage.name = lib.mkOption {
|
||||||
name = "Authentik";
|
type = lib.types.str;
|
||||||
description = "An open-source IdP for modern SSO";
|
default = "Authentik";
|
||||||
icon = "authentik.svg";
|
};
|
||||||
category = "Services";
|
homepage.description = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "An open-source IdP for modern SSO";
|
||||||
|
};
|
||||||
|
homepage.icon = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "authentik.svg";
|
||||||
|
};
|
||||||
|
homepage.category = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "Services";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -46,18 +53,20 @@ in {
|
|||||||
age.secrets = {
|
age.secrets = {
|
||||||
authentikEnv = {
|
authentikEnv = {
|
||||||
file = "${self}/secrets/authentikEnv.age";
|
file = "${self}/secrets/authentikEnv.age";
|
||||||
|
owner = "authentik";
|
||||||
};
|
};
|
||||||
authentikCloudflared = {
|
authentikCloudflared = {
|
||||||
file = "${self}/secrets/authentikCloudflared.age";
|
file = "${self}/secrets/authentikCloudflared.age";
|
||||||
|
owner = "authentik";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
server.infra = {
|
server = {
|
||||||
fail2ban = {
|
fail2ban = lib.mkIf cfg.enable {
|
||||||
jails = {
|
jails = {
|
||||||
authentik = {
|
authentik = {
|
||||||
serviceName = "authentik";
|
serviceName = "${cfg.url}";
|
||||||
failRegex = ''^.*Username or password is incorrect.*IP:\s*<HOST>'';
|
failRegex = "^.*Username or password is incorrect. Try again. IP: <HOST>. Username: <F-USER>.*</F-USER>.$";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -90,6 +99,7 @@ in {
|
|||||||
middlewares = {
|
middlewares = {
|
||||||
authentik = {
|
authentik = {
|
||||||
forwardAuth = {
|
forwardAuth = {
|
||||||
|
tls.insecureSkipVerify = true;
|
||||||
address = "https://localhost:9443/outpost.goauthentik.io/auth/traefik";
|
address = "https://localhost:9443/outpost.goauthentik.io/auth/traefik";
|
||||||
trustForwardHeader = true;
|
trustForwardHeader = true;
|
||||||
authResponseHeaders = [
|
authResponseHeaders = [
|
||||||
@@ -120,7 +130,7 @@ in {
|
|||||||
routers = {
|
routers = {
|
||||||
auth = {
|
auth = {
|
||||||
entryPoints = ["websecure"];
|
entryPoints = ["websecure"];
|
||||||
rule = "Host(`${cfg.url}`) && PathPrefix(`/outpost.goauthentik.io/`)";
|
rule = "Host(`${cfg.url}`) || HostRegexp(`{subdomain:[a-z0-9]+}.${srv.www.url}`) && PathPrefix(`/outpost.goauthentik.io/`)";
|
||||||
service = "auth";
|
service = "auth";
|
||||||
tls.certResolver = "letsencrypt";
|
tls.certResolver = "letsencrypt";
|
||||||
};
|
};
|
||||||
62
modules/server/bazarr/default.nix
Normal file
62
modules/server/bazarr/default.nix
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}: let
|
||||||
|
unit = "bazarr";
|
||||||
|
srv = config.server;
|
||||||
|
cfg = config.server.${unit};
|
||||||
|
in {
|
||||||
|
options.server.${unit} = {
|
||||||
|
enable = lib.mkEnableOption {
|
||||||
|
description = "Enable ${unit}";
|
||||||
|
};
|
||||||
|
configDir = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "/var/lib/${unit}";
|
||||||
|
};
|
||||||
|
url = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "${unit}.${srv.domain}";
|
||||||
|
};
|
||||||
|
homepage.name = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "Bazarr";
|
||||||
|
};
|
||||||
|
homepage.description = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "Subtitle manager";
|
||||||
|
};
|
||||||
|
homepage.icon = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "bazarr.svg";
|
||||||
|
};
|
||||||
|
homepage.category = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "Arr";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
config = lib.mkIf cfg.enable {
|
||||||
|
services.${unit} = {
|
||||||
|
enable = true;
|
||||||
|
user = srv.user;
|
||||||
|
group = srv.group;
|
||||||
|
};
|
||||||
|
services.traefik = {
|
||||||
|
dynamicConfigOptions = {
|
||||||
|
http = {
|
||||||
|
services.bazarr.loadBalancer.servers = [{url = "http://127.0.0.1:${toString config.services.${unit}.listenPort}";}];
|
||||||
|
routers = {
|
||||||
|
bazarr = {
|
||||||
|
entryPoints = ["websecure"];
|
||||||
|
rule = "Host(`${cfg.url}`)";
|
||||||
|
service = "bazarr";
|
||||||
|
tls.certResolver = "letsencrypt";
|
||||||
|
# middlewares = ["authentik"];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,16 +1,101 @@
|
|||||||
{
|
{
|
||||||
self,
|
|
||||||
lib,
|
lib,
|
||||||
|
config,
|
||||||
|
pkgs,
|
||||||
...
|
...
|
||||||
}: let
|
}: let
|
||||||
clib = import "${self}/lib/server" {inherit lib;};
|
hardDrives = [
|
||||||
in {
|
"/dev/disk/by-label/data"
|
||||||
imports = [
|
|
||||||
{
|
|
||||||
_module.args.clib = clib;
|
|
||||||
}
|
|
||||||
./options.nix
|
|
||||||
./infra
|
|
||||||
./services
|
|
||||||
];
|
];
|
||||||
|
inherit (lib) mkOption types;
|
||||||
|
cfg = config.server;
|
||||||
|
ifTheyExist = groups: builtins.filter (group: builtins.hasAttr group config.users.groups) groups;
|
||||||
|
in {
|
||||||
|
options.server = {
|
||||||
|
enable = lib.mkEnableOption "The server services and configuration variables";
|
||||||
|
email = mkOption {
|
||||||
|
default = "";
|
||||||
|
type = types.str;
|
||||||
|
description = ''
|
||||||
|
Email name to be used to access the server services via Caddy reverse proxy
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
domain = mkOption {
|
||||||
|
default = "";
|
||||||
|
type = types.str;
|
||||||
|
description = ''
|
||||||
|
Domain name to be used to access the server services via Caddy reverse proxy
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
user = lib.mkOption {
|
||||||
|
default = "share";
|
||||||
|
type = lib.types.str;
|
||||||
|
description = ''
|
||||||
|
User to run the server services as
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
group = lib.mkOption {
|
||||||
|
default = "share";
|
||||||
|
type = lib.types.str;
|
||||||
|
description = ''
|
||||||
|
Group to run the server services as
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
uid = lib.mkOption {
|
||||||
|
default = 1000;
|
||||||
|
type = lib.types.int;
|
||||||
|
description = ''
|
||||||
|
UID to run the server services as
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
gid = lib.mkOption {
|
||||||
|
default = 1000;
|
||||||
|
type = lib.types.int;
|
||||||
|
description = ''
|
||||||
|
GID to run the server services as
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
timeZone = lib.mkOption {
|
||||||
|
default = "Europe/Stockholm";
|
||||||
|
type = lib.types.str;
|
||||||
|
description = ''
|
||||||
|
Time zone to be used for the server services
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = lib.mkIf cfg.enable {
|
||||||
|
users = {
|
||||||
|
groups.${cfg.group} = {
|
||||||
|
gid = cfg.gid;
|
||||||
|
};
|
||||||
|
users.${cfg.user} = {
|
||||||
|
uid = cfg.uid;
|
||||||
|
isSystemUser = true;
|
||||||
|
group = cfg.group;
|
||||||
|
extraGroups = ifTheyExist [
|
||||||
|
"audio"
|
||||||
|
"video"
|
||||||
|
"docker"
|
||||||
|
"libvirtd"
|
||||||
|
"qemu-libvirtd"
|
||||||
|
"rtkit"
|
||||||
|
"fail2ban"
|
||||||
|
"vaultwarden"
|
||||||
|
"qbittorrent"
|
||||||
|
"lidarr"
|
||||||
|
"prowlarr"
|
||||||
|
"bazarr"
|
||||||
|
"sonarr"
|
||||||
|
"radarr"
|
||||||
|
"media"
|
||||||
|
"share"
|
||||||
|
"render"
|
||||||
|
"input"
|
||||||
|
"authentik"
|
||||||
|
"traefik"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
111
modules/server/fail2ban/default.nix
Normal file
111
modules/server/fail2ban/default.nix
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
# from @notthebee
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
config,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
cfg = config.server.fail2ban;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.server.fail2ban = {
|
||||||
|
enable = lib.mkEnableOption {
|
||||||
|
description = "Enable cloudflare fail2ban";
|
||||||
|
};
|
||||||
|
apiKeyFile = lib.mkOption {
|
||||||
|
description = "File containing your API key, scoped to Firewall Rules: Edit";
|
||||||
|
type = lib.types.str;
|
||||||
|
example = lib.literalExpression ''
|
||||||
|
Authorization: Bearer Qj06My1wXJEzcW46QCyjFbSMgVtwIGfX63Ki3NOj79o=
|
||||||
|
'''
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
zoneId = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
};
|
||||||
|
jails = lib.mkOption {
|
||||||
|
type = lib.types.attrsOf (
|
||||||
|
lib.types.submodule {
|
||||||
|
options = {
|
||||||
|
serviceName = lib.mkOption {
|
||||||
|
example = "vaultwarden";
|
||||||
|
type = lib.types.str;
|
||||||
|
};
|
||||||
|
failRegex = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
example = "Login failed from IP: <HOST>";
|
||||||
|
};
|
||||||
|
ignoreRegex = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "";
|
||||||
|
};
|
||||||
|
maxRetry = lib.mkOption {
|
||||||
|
type = lib.types.int;
|
||||||
|
default = 3;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
config = lib.mkIf cfg.enable {
|
||||||
|
services.fail2ban = {
|
||||||
|
enable = true;
|
||||||
|
extraPackages = [
|
||||||
|
pkgs.curl
|
||||||
|
pkgs.jq
|
||||||
|
];
|
||||||
|
|
||||||
|
jails = lib.attrsets.mapAttrs (name: value: {
|
||||||
|
settings = {
|
||||||
|
bantime = "30d";
|
||||||
|
findtime = "1h";
|
||||||
|
enabled = true;
|
||||||
|
backend = "systemd";
|
||||||
|
journalmatch = "_SYSTEMD_UNIT=${value.serviceName}.service";
|
||||||
|
port = "http,https";
|
||||||
|
filter = "${name}";
|
||||||
|
maxretry = 3;
|
||||||
|
action = "cloudflare-token-agenix";
|
||||||
|
};
|
||||||
|
}) cfg.jails;
|
||||||
|
};
|
||||||
|
|
||||||
|
environment.etc = lib.attrsets.mergeAttrsList [
|
||||||
|
(lib.attrsets.mapAttrs' (
|
||||||
|
name: value:
|
||||||
|
(lib.nameValuePair "fail2ban/filter.d/${name}.conf" {
|
||||||
|
text = ''
|
||||||
|
[Definition]
|
||||||
|
failregex = ${value.failRegex}
|
||||||
|
ignoreregex = ${value.ignoreRegex}
|
||||||
|
'';
|
||||||
|
})
|
||||||
|
) cfg.jails)
|
||||||
|
{
|
||||||
|
"fail2ban/action.d/cloudflare-token-agenix.conf".text =
|
||||||
|
let
|
||||||
|
notes = "Fail2Ban on ${config.networking.hostName}";
|
||||||
|
cfapi = "https://api.cloudflare.com/client/v4/zones/${cfg.zoneId}/firewall/access_rules/rules";
|
||||||
|
in
|
||||||
|
''
|
||||||
|
[Definition]
|
||||||
|
actionstart =
|
||||||
|
actionstop =
|
||||||
|
actioncheck =
|
||||||
|
actionunban = id=$(curl -s -X GET "${cfapi}" \
|
||||||
|
-H @${cfg.apiKeyFile} -H "Content-Type: application/json" \
|
||||||
|
| jq -r '.result[] | select(.notes == "${notes}" and .configuration.target == "ip" and .configuration.value == "<ip>") | .id')
|
||||||
|
if [ -z "$id" ]; then echo "id for <ip> cannot be found"; exit 0; fi; \
|
||||||
|
curl -s -X DELETE "${cfapi}/$id" \
|
||||||
|
-H @${cfg.apiKeyFile} -H "Content-Type: application/json" \
|
||||||
|
--data '{"cascade": "none"}'
|
||||||
|
actionban = curl -X POST "${cfapi}" -H @${cfg.apiKeyFile} -H "Content-Type: application/json" --data '{"mode":"block","configuration":{"target":"ip","value":"<ip>"},"notes":"${notes}"}'
|
||||||
|
[Init]
|
||||||
|
name = cloudflare-token-agenix
|
||||||
|
'';
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
||||||
125
modules/server/gitea/default.nix
Normal file
125
modules/server/gitea/default.nix
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
# taken from @jtojnar
|
||||||
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}: let
|
||||||
|
unit = "gitea";
|
||||||
|
srv = config.server;
|
||||||
|
cfg = config.server.${unit};
|
||||||
|
in {
|
||||||
|
options.server.${unit} = {
|
||||||
|
enable = lib.mkEnableOption {
|
||||||
|
description = "Enable ${unit}";
|
||||||
|
};
|
||||||
|
url = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "git.${srv.domain}";
|
||||||
|
};
|
||||||
|
port = lib.mkOption {
|
||||||
|
type = lib.types.int;
|
||||||
|
default = 5003;
|
||||||
|
description = "The port to host Gitea on.";
|
||||||
|
};
|
||||||
|
homepage.name = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "Gitea";
|
||||||
|
};
|
||||||
|
homepage.description = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "Git with a cup of tea";
|
||||||
|
};
|
||||||
|
homepage.icon = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "gitea.svg";
|
||||||
|
};
|
||||||
|
homepage.category = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "Services";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
config = lib.mkIf cfg.enable {
|
||||||
|
services.${unit} = {
|
||||||
|
enable = true;
|
||||||
|
appName = "cnix code forge";
|
||||||
|
|
||||||
|
database = {
|
||||||
|
type = "postgres";
|
||||||
|
socket = "/run/postgresql";
|
||||||
|
name = "gitea";
|
||||||
|
user = "gitea";
|
||||||
|
createDatabase = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
lfs = {
|
||||||
|
enable = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
settings = {
|
||||||
|
cors = {
|
||||||
|
ENABLED = true;
|
||||||
|
SCHEME = "https";
|
||||||
|
ALLOW_DOMAIN = cfg.url;
|
||||||
|
};
|
||||||
|
log = {
|
||||||
|
MODE = "console";
|
||||||
|
};
|
||||||
|
mailer = {
|
||||||
|
ENABLED = false;
|
||||||
|
MAILER_TYPE = "sendmail";
|
||||||
|
FROM = "noreply+adam@cnst.dev";
|
||||||
|
SENDMAIL_PATH = "/run/wrappers/bin/sendmail";
|
||||||
|
};
|
||||||
|
picture = {
|
||||||
|
DISABLE_GRAVATAR = true;
|
||||||
|
};
|
||||||
|
repository = {
|
||||||
|
DEFAULT_BRANCH = "main";
|
||||||
|
DEFAULT_REPO_UNITS = "repo.code,repo.issues,repo.pulls";
|
||||||
|
DISABLE_DOWNLOAD_SOURCE_ARCHIVES = true;
|
||||||
|
};
|
||||||
|
indexer = {
|
||||||
|
REPO_INDEXER_ENABLED = true;
|
||||||
|
};
|
||||||
|
server = {
|
||||||
|
DOMAIN = cfg.url;
|
||||||
|
LANDING_PAGE = "explore";
|
||||||
|
HTTP_PORT = cfg.port;
|
||||||
|
ROOT_URL = "https://${cfg.url}/";
|
||||||
|
};
|
||||||
|
security = {
|
||||||
|
DISABLE_GIT_HOOKS = false;
|
||||||
|
};
|
||||||
|
service = {
|
||||||
|
DISABLE_REGISTRATION = true;
|
||||||
|
};
|
||||||
|
session = {
|
||||||
|
COOKIE_SECURE = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
services.traefik = {
|
||||||
|
dynamicConfigOptions = {
|
||||||
|
http = {
|
||||||
|
services.gitea.loadBalancer.servers = [{url = "http://127.0.0.1:5003";}];
|
||||||
|
routers = {
|
||||||
|
gitea = {
|
||||||
|
entryPoints = ["websecure"];
|
||||||
|
rule = "Host(`${cfg.url}`)";
|
||||||
|
service = "gitea";
|
||||||
|
tls.certResolver = "letsencrypt";
|
||||||
|
# middlewares = ["authentik"];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
server.postgresql.databases = [
|
||||||
|
{
|
||||||
|
database = "gitea";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
||||||
236
modules/server/homepage-dashboard/default.nix
Normal file
236
modules/server/homepage-dashboard/default.nix
Normal file
@@ -0,0 +1,236 @@
|
|||||||
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
self,
|
||||||
|
...
|
||||||
|
}: let
|
||||||
|
unit = "homepage-dashboard";
|
||||||
|
cfg = config.server.homepage-dashboard;
|
||||||
|
srv = config.server;
|
||||||
|
in {
|
||||||
|
options.server.homepage-dashboard = {
|
||||||
|
enable = lib.mkEnableOption {
|
||||||
|
description = "Enable ${unit}";
|
||||||
|
};
|
||||||
|
misc = lib.mkOption {
|
||||||
|
default = [];
|
||||||
|
type = lib.types.listOf (
|
||||||
|
lib.types.attrsOf (
|
||||||
|
lib.types.submodule {
|
||||||
|
options = {
|
||||||
|
description = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
};
|
||||||
|
href = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
};
|
||||||
|
siteMonitor = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
};
|
||||||
|
icon = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
config = lib.mkIf cfg.enable {
|
||||||
|
age.secrets = {
|
||||||
|
homepageEnvironment = {
|
||||||
|
file = "${self}/secrets/homepageEnvironment.age";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
services = {
|
||||||
|
glances.enable = true;
|
||||||
|
${unit} = {
|
||||||
|
enable = true;
|
||||||
|
environmentFile = config.age.secrets.homepageEnvironment.path;
|
||||||
|
settings = {
|
||||||
|
layout = [
|
||||||
|
{
|
||||||
|
Glances = {
|
||||||
|
header = false;
|
||||||
|
style = "row";
|
||||||
|
columns = 4;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
{
|
||||||
|
Arr = {
|
||||||
|
header = true;
|
||||||
|
style = "column";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
{
|
||||||
|
Downloads = {
|
||||||
|
header = true;
|
||||||
|
style = "column";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
{
|
||||||
|
Media = {
|
||||||
|
header = true;
|
||||||
|
style = "column";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
{
|
||||||
|
Services = {
|
||||||
|
header = true;
|
||||||
|
style = "column";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
];
|
||||||
|
headerStyle = "clean";
|
||||||
|
statusStyle = "dot";
|
||||||
|
hideVersion = "true";
|
||||||
|
};
|
||||||
|
widgets = [
|
||||||
|
{
|
||||||
|
openmeteo = {
|
||||||
|
label = "Kalmar";
|
||||||
|
timezone = "Europe/Stockholm";
|
||||||
|
units = "metric";
|
||||||
|
cache = 5;
|
||||||
|
latitude = 56.707262;
|
||||||
|
longitude = 16.324541;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
{
|
||||||
|
resources = {
|
||||||
|
label = "SYSTEM";
|
||||||
|
memory = true;
|
||||||
|
cpu = true;
|
||||||
|
uptime = true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
];
|
||||||
|
services = let
|
||||||
|
homepageCategories = [
|
||||||
|
"Arr"
|
||||||
|
"Media"
|
||||||
|
"Downloads"
|
||||||
|
"Services"
|
||||||
|
];
|
||||||
|
hl = config.server;
|
||||||
|
mergedServices = hl // hl.podman;
|
||||||
|
homepageServices = x: (lib.attrsets.filterAttrs (
|
||||||
|
name: value: value ? homepage && value.homepage.category == x
|
||||||
|
)
|
||||||
|
mergedServices);
|
||||||
|
in
|
||||||
|
lib.lists.forEach homepageCategories (cat: {
|
||||||
|
"${cat}" =
|
||||||
|
lib.lists.forEach
|
||||||
|
(lib.attrsets.mapAttrsToList (name: value: {
|
||||||
|
inherit name;
|
||||||
|
url = value.url;
|
||||||
|
homepage = value.homepage;
|
||||||
|
}) (homepageServices "${cat}"))
|
||||||
|
(x: {
|
||||||
|
"${x.homepage.name}" = {
|
||||||
|
icon = x.homepage.icon;
|
||||||
|
description = x.homepage.description;
|
||||||
|
href = "https://${x.url}${x.homepage.path or ""}";
|
||||||
|
siteMonitor = "https://${x.url}${x.homepage.path or ""}";
|
||||||
|
};
|
||||||
|
});
|
||||||
|
})
|
||||||
|
++ [{Misc = cfg.misc;}]
|
||||||
|
++ [
|
||||||
|
{
|
||||||
|
Glances = let
|
||||||
|
port = toString config.services.glances.port;
|
||||||
|
in [
|
||||||
|
{
|
||||||
|
Info = {
|
||||||
|
widget = {
|
||||||
|
type = "glances";
|
||||||
|
url = "http://localhost:${port}";
|
||||||
|
metric = "info";
|
||||||
|
chart = false;
|
||||||
|
version = 4;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
{
|
||||||
|
"CPU Temp" = {
|
||||||
|
widget = {
|
||||||
|
type = "glances";
|
||||||
|
url = "http://localhost:${port}";
|
||||||
|
metric = "sensor:Tctl";
|
||||||
|
chart = false;
|
||||||
|
version = 4;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
{
|
||||||
|
"GPU Radeon" = {
|
||||||
|
widget = {
|
||||||
|
type = "glances";
|
||||||
|
url = "http://localhost:${port}";
|
||||||
|
metric = "sensor:junction";
|
||||||
|
chart = false;
|
||||||
|
version = 4;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
{
|
||||||
|
"GPU Intel" = {
|
||||||
|
widget = {
|
||||||
|
type = "glances";
|
||||||
|
url = "http://localhost:${port}";
|
||||||
|
metric = "sensor:pkg";
|
||||||
|
chart = false;
|
||||||
|
version = 4;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
{
|
||||||
|
Processes = {
|
||||||
|
widget = {
|
||||||
|
type = "glances";
|
||||||
|
url = "http://localhost:${port}";
|
||||||
|
metric = "process";
|
||||||
|
chart = false;
|
||||||
|
version = 4;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
{
|
||||||
|
Network = {
|
||||||
|
widget = {
|
||||||
|
type = "glances";
|
||||||
|
url = "http://localhost:${port}";
|
||||||
|
metric = "network:enp6s0";
|
||||||
|
chart = false;
|
||||||
|
version = 4;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
traefik = {
|
||||||
|
dynamicConfigOptions = {
|
||||||
|
http = {
|
||||||
|
services.homepage.loadBalancer.servers = [
|
||||||
|
{url = "http://127.0.0.1:${toString config.services.${unit}.listenPort}";}
|
||||||
|
];
|
||||||
|
routers = {
|
||||||
|
homepage = {
|
||||||
|
entryPoints = ["websecure"];
|
||||||
|
rule = "Host(`cnix.dev`)";
|
||||||
|
service = "homepage";
|
||||||
|
tls.certResolver = "letsencrypt";
|
||||||
|
# middlewares = ["authentik"];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
{
|
|
||||||
imports = [
|
|
||||||
./authentik
|
|
||||||
./fail2ban
|
|
||||||
./keepalived
|
|
||||||
./podman
|
|
||||||
./postgres
|
|
||||||
./tailscale
|
|
||||||
./traefik
|
|
||||||
./unbound
|
|
||||||
./www
|
|
||||||
];
|
|
||||||
}
|
|
||||||
@@ -1,131 +0,0 @@
|
|||||||
# from @notthebee
|
|
||||||
{
|
|
||||||
lib,
|
|
||||||
config,
|
|
||||||
pkgs,
|
|
||||||
...
|
|
||||||
}: let
|
|
||||||
cfg = config.server.infra.fail2ban;
|
|
||||||
in {
|
|
||||||
options.server.infra.fail2ban = {
|
|
||||||
enable = lib.mkEnableOption {
|
|
||||||
description = "Enable cloudflare fail2ban";
|
|
||||||
};
|
|
||||||
apiKeyFile = lib.mkOption {
|
|
||||||
description = "File containing your API key, scoped to Firewall Rules: Edit";
|
|
||||||
type = lib.types.str;
|
|
||||||
example = lib.literalExpression ''
|
|
||||||
Authorization: Bearer vH6-p0y=i4w3n7TjKqZ@x8D_lR!A9b2cOezXgUuJdE5F
|
|
||||||
'''
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
zoneId = lib.mkOption {
|
|
||||||
type = lib.types.str;
|
|
||||||
};
|
|
||||||
jails = lib.mkOption {
|
|
||||||
type = lib.types.attrsOf (
|
|
||||||
lib.types.submodule {
|
|
||||||
options = {
|
|
||||||
serviceName = lib.mkOption {
|
|
||||||
example = "vaultwarden";
|
|
||||||
type = lib.types.str;
|
|
||||||
};
|
|
||||||
_groupsre = lib.mkOption {
|
|
||||||
type = lib.types.lines;
|
|
||||||
example = ''(?:(?:,?\s*"\w+":(?:"[^"]+"|\w+))*)'';
|
|
||||||
default = "";
|
|
||||||
};
|
|
||||||
failRegex = lib.mkOption {
|
|
||||||
type = lib.types.lines;
|
|
||||||
example = ''
|
|
||||||
^Login failed from IP: <HOST>$
|
|
||||||
^Two-factor challenge failed from <HOST>$
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
ignoreRegex = lib.mkOption {
|
|
||||||
type = lib.types.str;
|
|
||||||
default = "";
|
|
||||||
};
|
|
||||||
datePattern = lib.mkOption {
|
|
||||||
type = lib.types.str;
|
|
||||||
default = "";
|
|
||||||
example = '',?\s*"time"\s*:\s*"%%Y-%%m-%%d[T ]%%H:%%M:%%S(%%z)?"'';
|
|
||||||
description = "Optional datepattern line for the fail2ban filter.";
|
|
||||||
};
|
|
||||||
maxRetry = lib.mkOption {
|
|
||||||
type = lib.types.int;
|
|
||||||
default = 3;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
config = lib.mkIf cfg.enable {
|
|
||||||
services.fail2ban = {
|
|
||||||
enable = true;
|
|
||||||
extraPackages = [
|
|
||||||
pkgs.curl
|
|
||||||
pkgs.jq
|
|
||||||
];
|
|
||||||
|
|
||||||
jails =
|
|
||||||
lib.attrsets.mapAttrs (name: value: {
|
|
||||||
settings = {
|
|
||||||
bantime = "24h";
|
|
||||||
findtime = "10m";
|
|
||||||
enabled = true;
|
|
||||||
backend = "systemd";
|
|
||||||
journalmatch = "_SYSTEMD_UNIT=${value.serviceName}.service";
|
|
||||||
port = "http,https";
|
|
||||||
filter = "${name}";
|
|
||||||
maxretry = 3;
|
|
||||||
action = "cloudflare-token-agenix";
|
|
||||||
};
|
|
||||||
})
|
|
||||||
cfg.jails;
|
|
||||||
};
|
|
||||||
|
|
||||||
environment.etc = lib.attrsets.mergeAttrsList [
|
|
||||||
(lib.attrsets.mapAttrs' (
|
|
||||||
name: value: (lib.nameValuePair "fail2ban/filter.d/${name}.conf" {
|
|
||||||
text =
|
|
||||||
''
|
|
||||||
[Definition]
|
|
||||||
failregex = ${value.failRegex}
|
|
||||||
ignoreregex = ${value.ignoreRegex}
|
|
||||||
''
|
|
||||||
+ lib.optionalString (value.datePattern != "") ''
|
|
||||||
datepattern = ${value.datePattern}
|
|
||||||
''
|
|
||||||
+ lib.optionalString (value._groupsre != "") ''
|
|
||||||
_groupsre = ${value._groupsre}
|
|
||||||
'';
|
|
||||||
})
|
|
||||||
)
|
|
||||||
cfg.jails)
|
|
||||||
{
|
|
||||||
"fail2ban/action.d/cloudflare-token-agenix.conf".text = let
|
|
||||||
notes = "Fail2Ban on ${config.networking.hostName}";
|
|
||||||
cfapi = "https://api.cloudflare.com/client/v4/zones/${cfg.zoneId}/firewall/access_rules/rules";
|
|
||||||
in ''
|
|
||||||
[Definition]
|
|
||||||
actionstart =
|
|
||||||
actionstop =
|
|
||||||
actioncheck =
|
|
||||||
actionunban = id=$(curl -s -X GET "${cfapi}" \
|
|
||||||
-H @${cfg.apiKeyFile} -H "Content-Type: application/json" \
|
|
||||||
| jq -r '.result[] | select(.notes == "${notes}" and .configuration.target == "ip" and .configuration.value == "<ip>") | .id')
|
|
||||||
if [ -z "$id" ]; then echo "id for <ip> cannot be found"; exit 0; fi; \
|
|
||||||
curl -s -X DELETE "${cfapi}/$id" \
|
|
||||||
-H @${cfg.apiKeyFile} -H "Content-Type: application/json" \
|
|
||||||
--data '{"cascade": "none"}'
|
|
||||||
actionban = curl -X POST "${cfapi}" -H @${cfg.apiKeyFile} -H "Content-Type: application/json" --data '{"mode":"block","configuration":{"target":"ip","value":"<ip>"},"notes":"${notes}"}'
|
|
||||||
[Init]
|
|
||||||
name = cloudflare-token-agenix
|
|
||||||
'';
|
|
||||||
}
|
|
||||||
];
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
---
|
|
||||||
filenames:
|
|
||||||
- /var/log/traefik/access.log
|
|
||||||
poll_without_inotify: true
|
|
||||||
labels:
|
|
||||||
type: traefik
|
|
||||||
@@ -1,194 +0,0 @@
|
|||||||
{
|
|
||||||
config,
|
|
||||||
lib,
|
|
||||||
self,
|
|
||||||
...
|
|
||||||
}: let
|
|
||||||
infra = config.server.infra;
|
|
||||||
cfg = config.server.services;
|
|
||||||
|
|
||||||
getPiholeSecret = hostname:
|
|
||||||
if hostname == "ziggy"
|
|
||||||
then [config.age.secrets.piholeZiggy.path]
|
|
||||||
else if hostname == "sobotka"
|
|
||||||
then [config.age.secrets.pihole.path]
|
|
||||||
else throw "Unknown hostname: ${hostname}";
|
|
||||||
in {
|
|
||||||
options.server.infra = {
|
|
||||||
podman.enable = lib.mkEnableOption "Enables Podman";
|
|
||||||
gluetun.enable = lib.mkEnableOption "Enables gluetun";
|
|
||||||
};
|
|
||||||
config = lib.mkIf infra.podman.enable {
|
|
||||||
age.secrets = {
|
|
||||||
pihole.file = "${self}/secrets/${config.networking.hostName}Pihole.age";
|
|
||||||
slskd.file = "${self}/secrets/slskd.age";
|
|
||||||
};
|
|
||||||
|
|
||||||
virtualisation = {
|
|
||||||
containers.enable = true;
|
|
||||||
podman.enable = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
networking.firewall = lib.mkIf cfg.pihole.enable {
|
|
||||||
allowedTCPPorts = [
|
|
||||||
53
|
|
||||||
5335
|
|
||||||
];
|
|
||||||
allowedUDPPorts = [
|
|
||||||
53
|
|
||||||
5335
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
virtualisation.oci-containers.containers = lib.mkMerge [
|
|
||||||
(lib.mkIf infra.gluetun.enable {
|
|
||||||
gluetun = {
|
|
||||||
image = "qmcgaw/gluetun";
|
|
||||||
ports = [
|
|
||||||
"8388:8388"
|
|
||||||
"58846:58846"
|
|
||||||
"8080:8080"
|
|
||||||
"5030:5030"
|
|
||||||
"5031:5031"
|
|
||||||
"50300:50300"
|
|
||||||
];
|
|
||||||
devices = ["/dev/net/tun:/dev/net/tun"];
|
|
||||||
autoStart = true;
|
|
||||||
extraOptions = [
|
|
||||||
"--cap-add=NET_ADMIN"
|
|
||||||
];
|
|
||||||
volumes = ["/var:/gluetun"];
|
|
||||||
environmentFiles = [
|
|
||||||
config.age.secrets.gluetunEnvironment.path
|
|
||||||
];
|
|
||||||
environment = {
|
|
||||||
DEV_MODE = "false";
|
|
||||||
VPN_SERVICE_PROVIDER = "mullvad";
|
|
||||||
VPN_TYPE = "wireguard";
|
|
||||||
SERVER_CITIES = "Stockholm";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
})
|
|
||||||
|
|
||||||
(lib.mkIf cfg.qbittorrent.enable {
|
|
||||||
qbittorrent = {
|
|
||||||
image = "ghcr.io/hotio/qbittorrent:latest";
|
|
||||||
autoStart = true;
|
|
||||||
dependsOn = ["gluetun"];
|
|
||||||
ports = [
|
|
||||||
"8080:8080"
|
|
||||||
"58846:58846"
|
|
||||||
];
|
|
||||||
extraOptions = [
|
|
||||||
"--network=container:gluetun"
|
|
||||||
];
|
|
||||||
volumes = [
|
|
||||||
"/var/lib/qbittorrent:/config:rw"
|
|
||||||
"/mnt/data/media/downloads:/downloads:rw"
|
|
||||||
];
|
|
||||||
environmentFiles = [
|
|
||||||
config.age.secrets.gluetunEnvironment.path
|
|
||||||
];
|
|
||||||
environment = {
|
|
||||||
PUID = "994";
|
|
||||||
PGID = "993";
|
|
||||||
TZ = "Europe/Stockholm";
|
|
||||||
WEBUI_PORT = "${builtins.toString cfg.qbittorrent.port}";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
})
|
|
||||||
|
|
||||||
(lib.mkIf cfg.slskd.enable {
|
|
||||||
slskd = {
|
|
||||||
image = "slskd/slskd:latest";
|
|
||||||
autoStart = true;
|
|
||||||
dependsOn = ["gluetun"];
|
|
||||||
ports = [
|
|
||||||
"5030:5030"
|
|
||||||
"5031:5031"
|
|
||||||
"50300:50300"
|
|
||||||
];
|
|
||||||
extraOptions = [
|
|
||||||
"--network=container:gluetun"
|
|
||||||
];
|
|
||||||
volumes = [
|
|
||||||
"/var/lib/slskd:/app:rw"
|
|
||||||
"/mnt/data/media/downloads:/downloads:rw"
|
|
||||||
];
|
|
||||||
environmentFiles = [
|
|
||||||
config.age.secrets.gluetunEnvironment.path
|
|
||||||
config.age.secrets.slskd.path
|
|
||||||
];
|
|
||||||
environment = {
|
|
||||||
TZ = "Europe/Stockholm";
|
|
||||||
PUID = "981";
|
|
||||||
PGID = "982";
|
|
||||||
SLSKD_REMOTE_CONFIGURATION = "true";
|
|
||||||
SLSKD_REMOTE_FILE_MANAGEMENT = "true";
|
|
||||||
SLSKD_DOWNLOADS_DIR = "/downloads";
|
|
||||||
SLSKD_UMASK = "022";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
})
|
|
||||||
|
|
||||||
(lib.mkIf cfg.pihole.enable {
|
|
||||||
pihole = {
|
|
||||||
autoStart = true;
|
|
||||||
image = "pihole/pihole:2025.08.0";
|
|
||||||
volumes = [
|
|
||||||
"/var/lib/pihole:/etc/pihole/"
|
|
||||||
"/var/lib/dnsmasq.d:/etc/dnsmasq.d/"
|
|
||||||
];
|
|
||||||
environment = {
|
|
||||||
TZ = "Europe/Stockholm";
|
|
||||||
CUSTOM_CACHE_SIZE = "0";
|
|
||||||
WEBTHEME = "default-darker";
|
|
||||||
};
|
|
||||||
environmentFiles = getPiholeSecret config.networking.hostName;
|
|
||||||
ports = [
|
|
||||||
"53:53/tcp"
|
|
||||||
"53:53/udp"
|
|
||||||
"8053:80/tcp"
|
|
||||||
];
|
|
||||||
extraOptions = [
|
|
||||||
"--cap-add=NET_ADMIN"
|
|
||||||
"--cap-add=SYS_NICE"
|
|
||||||
"--cap-add=SYS_TIME"
|
|
||||||
];
|
|
||||||
};
|
|
||||||
})
|
|
||||||
(lib.mkIf cfg.ollama.enable {
|
|
||||||
intel-llm = {
|
|
||||||
autoStart = true;
|
|
||||||
image = "intelanalytics/ipex-llm-inference-cpp-xpu:latest";
|
|
||||||
devices = [
|
|
||||||
"/dev/dri:/dev/dri:rwm"
|
|
||||||
];
|
|
||||||
volumes = [
|
|
||||||
"/var/lib/ollama:/models"
|
|
||||||
];
|
|
||||||
environment = {
|
|
||||||
OLLAMA_ORIGINS = "http://192.168.*";
|
|
||||||
SYCL_PI_LEVEL_ZERO_USE_IMMEDIATE_COMMANDLISTS = "1";
|
|
||||||
ONEAPI_DEVICE_SELECTOR = "level_zero:0";
|
|
||||||
OLLAMA_HOST = "[::]:11434";
|
|
||||||
no_proxy = "localhost,127.0.0.1";
|
|
||||||
DEVICE = "Arc";
|
|
||||||
OLLAMA_NUM_GPU = "999";
|
|
||||||
ZES_ENABLE_SYSMAN = "1";
|
|
||||||
};
|
|
||||||
cmd = [
|
|
||||||
"/bin/sh"
|
|
||||||
"-c"
|
|
||||||
"/llm/scripts/start-ollama.sh && echo 'Startup script finished, container is now idling.' && sleep infinity"
|
|
||||||
];
|
|
||||||
extraOptions = [
|
|
||||||
"--net=host"
|
|
||||||
"--memory=32G"
|
|
||||||
"--shm-size=16g"
|
|
||||||
];
|
|
||||||
};
|
|
||||||
})
|
|
||||||
];
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
{
|
|
||||||
config,
|
|
||||||
lib,
|
|
||||||
self,
|
|
||||||
...
|
|
||||||
}:
|
|
||||||
with lib; let
|
|
||||||
cfg = config.server.infra.tailscale;
|
|
||||||
in {
|
|
||||||
options.server.infra.tailscale = {
|
|
||||||
enable = mkEnableOption "Enable tailscale server configuration";
|
|
||||||
};
|
|
||||||
config = mkIf cfg.enable {
|
|
||||||
age.secrets.sobotkaTsAuth.file = "${self}/secrets/sobotkaTsAuth.age";
|
|
||||||
|
|
||||||
services.tailscale = {
|
|
||||||
enable = true;
|
|
||||||
openFirewall = true;
|
|
||||||
useRoutingFeatures = "server";
|
|
||||||
authKeyFile = config.age.secrets.sobotkaTsAuth.path;
|
|
||||||
extraSetFlags = [
|
|
||||||
"--advertise-exit-node"
|
|
||||||
];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,183 +0,0 @@
|
|||||||
{
|
|
||||||
lib,
|
|
||||||
clib,
|
|
||||||
config,
|
|
||||||
pkgs,
|
|
||||||
self,
|
|
||||||
...
|
|
||||||
}: let
|
|
||||||
inherit (lib) mkEnableOption mkIf types;
|
|
||||||
|
|
||||||
cfg = config.server.infra.traefik;
|
|
||||||
srv = config.server;
|
|
||||||
|
|
||||||
generateRouters = services: config:
|
|
||||||
lib.mapAttrs' (
|
|
||||||
name: service:
|
|
||||||
lib.nameValuePair name {
|
|
||||||
entryPoints = ["websecure"];
|
|
||||||
# FIX 3: Use backticks for the Host rule and interpolation
|
|
||||||
rule = "Host(`${clib.server.mkFullDomain config service}`)";
|
|
||||||
service = name;
|
|
||||||
tls.certResolver = "letsencrypt";
|
|
||||||
}
|
|
||||||
) (lib.filterAttrs (_: s: s.enable) services);
|
|
||||||
|
|
||||||
generateServices = services:
|
|
||||||
lib.mapAttrs' (name: service:
|
|
||||||
lib.nameValuePair name {
|
|
||||||
loadBalancer.servers = [{url = "http://localhost:${toString service.port}";}];
|
|
||||||
}) (lib.filterAttrs (name: service: service.enable) services);
|
|
||||||
|
|
||||||
getCloudflareCredentials = hostname:
|
|
||||||
if hostname == "ziggy"
|
|
||||||
then config.age.secrets.cloudflareDnsCredentialsZiggy.path
|
|
||||||
else if hostname == "sobotka"
|
|
||||||
then config.age.secrets.cloudflareDnsCredentials.path
|
|
||||||
else throw "Unknown hostname: ${hostname}";
|
|
||||||
in {
|
|
||||||
options.server.infra.traefik = {
|
|
||||||
enable = mkEnableOption "Enable global Traefik reverse proxy with ACME";
|
|
||||||
};
|
|
||||||
|
|
||||||
config = mkIf cfg.enable {
|
|
||||||
age.secrets = {
|
|
||||||
traefikEnv = {
|
|
||||||
file = "${self}/secrets/traefikEnv.age";
|
|
||||||
mode = "640";
|
|
||||||
owner = "traefik";
|
|
||||||
group = "traefik";
|
|
||||||
};
|
|
||||||
crowdsecApi.file = "${self}/secrets/crowdsecApi.age";
|
|
||||||
};
|
|
||||||
|
|
||||||
systemd.services.traefik = {
|
|
||||||
serviceConfig = {
|
|
||||||
EnvironmentFile = [config.age.secrets.traefikEnv.path];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
networking.firewall.allowedTCPPorts = [80 443];
|
|
||||||
|
|
||||||
services = {
|
|
||||||
tailscale.permitCertUid = "traefik";
|
|
||||||
traefik = {
|
|
||||||
enable = true;
|
|
||||||
|
|
||||||
staticConfigOptions = {
|
|
||||||
log = {
|
|
||||||
level = "DEBUG";
|
|
||||||
};
|
|
||||||
|
|
||||||
accesslog = {filepath = "/var/lib/traefik/logs/access.log";};
|
|
||||||
|
|
||||||
tracing = {};
|
|
||||||
api = {
|
|
||||||
dashboard = true;
|
|
||||||
insecure = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
certificatesResolvers = {
|
|
||||||
vpn.tailscale = {};
|
|
||||||
letsencrypt = {
|
|
||||||
acme = {
|
|
||||||
email = "adam@cnst.dev";
|
|
||||||
storage = "/var/lib/traefik/cert.json";
|
|
||||||
dnsChallenge = {
|
|
||||||
provider = "cloudflare";
|
|
||||||
resolvers = [
|
|
||||||
"1.1.1.1:53"
|
|
||||||
"1.0.0.1:53"
|
|
||||||
];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
entryPoints = {
|
|
||||||
# redis = {
|
|
||||||
# address = "0.0.0.0:6381";
|
|
||||||
# };
|
|
||||||
# postgres = {
|
|
||||||
# address = "0.0.0.0:5433";
|
|
||||||
# };
|
|
||||||
web = {
|
|
||||||
address = ":80";
|
|
||||||
forwardedHeaders.insecure = true;
|
|
||||||
http.redirections.entryPoint = {
|
|
||||||
to = "websecure";
|
|
||||||
scheme = "https";
|
|
||||||
permanent = true;
|
|
||||||
};
|
|
||||||
# http.middlewares = "crowdsec@file";
|
|
||||||
};
|
|
||||||
|
|
||||||
websecure = {
|
|
||||||
address = ":443";
|
|
||||||
forwardedHeaders.insecure = true;
|
|
||||||
http.tls = {
|
|
||||||
certResolver = "letsencrypt";
|
|
||||||
domains = [
|
|
||||||
{
|
|
||||||
main = "cnix.dev";
|
|
||||||
sans = ["*.cnix.dev"];
|
|
||||||
}
|
|
||||||
{
|
|
||||||
main = "ts.cnst.dev";
|
|
||||||
sans = ["*ts.cnst.dev"];
|
|
||||||
}
|
|
||||||
];
|
|
||||||
};
|
|
||||||
# http.middlewares = "crowdsec@file";
|
|
||||||
};
|
|
||||||
|
|
||||||
experimental = {
|
|
||||||
address = ":1111";
|
|
||||||
forwardedHeaders.insecure = true;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
experimental = {
|
|
||||||
# Install the Crowdsec Bouncer plugin
|
|
||||||
plugins = {
|
|
||||||
#enabled = "true";
|
|
||||||
bouncer = {
|
|
||||||
moduleName = "github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin";
|
|
||||||
version = "v1.4.5";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
dynamicConfigOptions = {
|
|
||||||
http = {
|
|
||||||
services = generateServices srv.services;
|
|
||||||
|
|
||||||
routers =
|
|
||||||
(generateRouters srv.services config)
|
|
||||||
// {
|
|
||||||
api = {
|
|
||||||
entryPoints = ["websecure"];
|
|
||||||
rule = "Host(`traefik.${srv.domain}`)";
|
|
||||||
service = "api@internal";
|
|
||||||
tls.certResolver = "letsencrypt";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
# middlewares = {
|
|
||||||
# crowdsec = {
|
|
||||||
# plugin = {
|
|
||||||
# bouncer = {
|
|
||||||
# enabled = "true";
|
|
||||||
# logLevel = "DEBUG";
|
|
||||||
# crowdsecLapiKeyFile = config.age.secrets.crowdsecApi.path;
|
|
||||||
# crowdsecMode = "live";
|
|
||||||
# crowdsecLapiHost = ":4223";
|
|
||||||
# };
|
|
||||||
# };
|
|
||||||
# };
|
|
||||||
# };
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
66
modules/server/jellyfin/default.nix
Normal file
66
modules/server/jellyfin/default.nix
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}: let
|
||||||
|
service = "jellyfin";
|
||||||
|
cfg = config.server.${service};
|
||||||
|
srv = config.server;
|
||||||
|
in {
|
||||||
|
options.server.${service} = {
|
||||||
|
enable = lib.mkEnableOption {
|
||||||
|
description = "Enable ${service}";
|
||||||
|
};
|
||||||
|
configDir = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "/var/lib/${service}";
|
||||||
|
};
|
||||||
|
url = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "jellyfin.${srv.domain}";
|
||||||
|
};
|
||||||
|
homepage.name = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "Jellyfin";
|
||||||
|
};
|
||||||
|
homepage.description = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "The Free Software Media System";
|
||||||
|
};
|
||||||
|
homepage.icon = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "jellyfin.svg";
|
||||||
|
};
|
||||||
|
homepage.category = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "Media";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
config = lib.mkIf cfg.enable {
|
||||||
|
services.${service} = {
|
||||||
|
enable = true;
|
||||||
|
user = srv.user;
|
||||||
|
group = srv.group;
|
||||||
|
};
|
||||||
|
environment.systemPackages = with pkgs; [
|
||||||
|
jellyfin-ffmpeg
|
||||||
|
];
|
||||||
|
services.traefik = {
|
||||||
|
dynamicConfigOptions = {
|
||||||
|
http = {
|
||||||
|
services.jellyfin.loadBalancer.servers = [{url = "http://127.0.0.1:8096";}];
|
||||||
|
routers = {
|
||||||
|
jellyfin = {
|
||||||
|
entryPoints = ["websecure"];
|
||||||
|
rule = "Host(`${cfg.url}`)";
|
||||||
|
service = "jellyfin";
|
||||||
|
tls.certResolver = "letsencrypt";
|
||||||
|
# middlewares = ["authentik"];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
61
modules/server/jellyseerr/default.nix
Normal file
61
modules/server/jellyseerr/default.nix
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}: let
|
||||||
|
service = "jellyseerr";
|
||||||
|
srv = config.server;
|
||||||
|
cfg = config.server.${service};
|
||||||
|
in {
|
||||||
|
options.server.${service} = {
|
||||||
|
enable = lib.mkEnableOption {
|
||||||
|
description = "Enable ${service}";
|
||||||
|
};
|
||||||
|
url = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "${service}.${srv.domain}";
|
||||||
|
};
|
||||||
|
port = lib.mkOption {
|
||||||
|
type = lib.types.port;
|
||||||
|
default = 5055;
|
||||||
|
};
|
||||||
|
homepage.name = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "Jellyseerr";
|
||||||
|
};
|
||||||
|
homepage.description = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "Media request and discovery manager";
|
||||||
|
};
|
||||||
|
homepage.icon = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "jellyseerr.svg";
|
||||||
|
};
|
||||||
|
homepage.category = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "Arr";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
config = lib.mkIf cfg.enable {
|
||||||
|
services.${service} = {
|
||||||
|
enable = true;
|
||||||
|
port = cfg.port;
|
||||||
|
};
|
||||||
|
services.traefik = {
|
||||||
|
dynamicConfigOptions = {
|
||||||
|
http = {
|
||||||
|
services.jellyseerr.loadBalancer.servers = [{url = "http://127.0.0.1:${toString cfg.port}";}];
|
||||||
|
routers = {
|
||||||
|
jellyseerr = {
|
||||||
|
entryPoints = ["websecure"];
|
||||||
|
rule = "Host(`${cfg.url}`)";
|
||||||
|
service = "jellyseerr";
|
||||||
|
tls.certResolver = "letsencrypt";
|
||||||
|
# middlewares = ["authentik"];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -3,24 +3,27 @@
|
|||||||
config,
|
config,
|
||||||
self,
|
self,
|
||||||
...
|
...
|
||||||
}: let
|
}:
|
||||||
|
let
|
||||||
unit = "keepalived";
|
unit = "keepalived";
|
||||||
cfg = config.server.infra.${unit};
|
cfg = config.server.${unit};
|
||||||
|
|
||||||
hostCfg = hostname:
|
hostCfg =
|
||||||
if hostname == "sobotka"
|
hostname:
|
||||||
then {
|
if hostname == "sobotka" then
|
||||||
|
{
|
||||||
ip = "192.168.88.14";
|
ip = "192.168.88.14";
|
||||||
priority = 20;
|
priority = 20;
|
||||||
state = "MASTER";
|
state = "MASTER";
|
||||||
}
|
}
|
||||||
else if hostname == "ziggy"
|
else if hostname == "ziggy" then
|
||||||
then {
|
{
|
||||||
ip = "192.168.88.12";
|
ip = "192.168.88.12";
|
||||||
priority = 10;
|
priority = 10;
|
||||||
state = "BACKUP";
|
state = "BACKUP";
|
||||||
}
|
}
|
||||||
else throw "No keepalived config defined for host ${hostname}";
|
else
|
||||||
|
throw "No keepalived config defined for host ${hostname}";
|
||||||
|
|
||||||
_self = hostCfg config.networking.hostName;
|
_self = hostCfg config.networking.hostName;
|
||||||
|
|
||||||
@@ -31,8 +34,9 @@
|
|||||||
|
|
||||||
# Remove self from peers
|
# Remove self from peers
|
||||||
peers = builtins.filter (ip: ip != _self.ip) allPeers;
|
peers = builtins.filter (ip: ip != _self.ip) allPeers;
|
||||||
in {
|
in
|
||||||
options.server.infra.${unit} = {
|
{
|
||||||
|
options.server.${unit} = {
|
||||||
enable = lib.mkEnableOption {
|
enable = lib.mkEnableOption {
|
||||||
description = "Enable ${unit}";
|
description = "Enable ${unit}";
|
||||||
};
|
};
|
||||||
62
modules/server/lidarr/default.nix
Normal file
62
modules/server/lidarr/default.nix
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}: let
|
||||||
|
unit = "lidarr";
|
||||||
|
srv = config.server;
|
||||||
|
cfg = config.server.${unit};
|
||||||
|
in {
|
||||||
|
options.server.${unit} = {
|
||||||
|
enable = lib.mkEnableOption {
|
||||||
|
description = "Enable ${unit}";
|
||||||
|
};
|
||||||
|
configDir = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "/var/lib/${unit}";
|
||||||
|
};
|
||||||
|
url = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "${unit}.${srv.domain}";
|
||||||
|
};
|
||||||
|
homepage.name = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "Lidarr";
|
||||||
|
};
|
||||||
|
homepage.description = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "Music collection manager";
|
||||||
|
};
|
||||||
|
homepage.icon = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "lidarr.svg";
|
||||||
|
};
|
||||||
|
homepage.category = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "Arr";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
config = lib.mkIf cfg.enable {
|
||||||
|
services.${unit} = {
|
||||||
|
enable = true;
|
||||||
|
user = srv.user;
|
||||||
|
group = srv.group;
|
||||||
|
};
|
||||||
|
services.traefik = {
|
||||||
|
dynamicConfigOptions = {
|
||||||
|
http = {
|
||||||
|
services.lidarr.loadBalancer.servers = [{url = "http://127.0.0.1:8686";}];
|
||||||
|
routers = {
|
||||||
|
lidarr = {
|
||||||
|
entryPoints = ["websecure"];
|
||||||
|
rule = "Host(`${cfg.url}`)";
|
||||||
|
service = "lidarr";
|
||||||
|
tls.certResolver = "letsencrypt";
|
||||||
|
# middlewares = ["authentik"];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
64
modules/server/n8n/default.nix
Normal file
64
modules/server/n8n/default.nix
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}: let
|
||||||
|
unit = "n8n";
|
||||||
|
srv = config.server;
|
||||||
|
cfg = config.server.${unit};
|
||||||
|
in {
|
||||||
|
options.server.${unit} = {
|
||||||
|
enable = lib.mkEnableOption {
|
||||||
|
description = "Enable ${unit}";
|
||||||
|
};
|
||||||
|
configDir = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "/var/lib/${unit}";
|
||||||
|
};
|
||||||
|
url = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "${unit}.${srv.domain}";
|
||||||
|
};
|
||||||
|
homepage.name = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "n8n";
|
||||||
|
};
|
||||||
|
homepage.description = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "A workflow automation platform";
|
||||||
|
};
|
||||||
|
homepage.icon = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "n8n.svg";
|
||||||
|
};
|
||||||
|
homepage.category = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "Services";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
config = lib.mkIf cfg.enable {
|
||||||
|
services = {
|
||||||
|
n8n = {
|
||||||
|
enable = true;
|
||||||
|
openFirewall = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
traefik = {
|
||||||
|
dynamicConfigOptions = {
|
||||||
|
http = {
|
||||||
|
services.n8n.loadBalancer.servers = [{url = "http://127.0.0.1:5678";}];
|
||||||
|
routers = {
|
||||||
|
n8n = {
|
||||||
|
entryPoints = ["websecure"];
|
||||||
|
rule = "Host(`${cfg.url}`)";
|
||||||
|
service = "n8n";
|
||||||
|
tls.certResolver = "letsencrypt";
|
||||||
|
# middlewares = ["authentik"];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -6,30 +6,64 @@
|
|||||||
...
|
...
|
||||||
}: let
|
}: let
|
||||||
unit = "nextcloud";
|
unit = "nextcloud";
|
||||||
cfg = config.server.services.${unit};
|
cfg = config.server.${unit};
|
||||||
srv = config.server;
|
srv = config.server;
|
||||||
in {
|
in {
|
||||||
|
options.server.${unit} = {
|
||||||
|
enable = lib.mkEnableOption {
|
||||||
|
description = "Enable ${unit}";
|
||||||
|
};
|
||||||
|
adminpassFile = lib.mkOption {
|
||||||
|
type = lib.types.path;
|
||||||
|
};
|
||||||
|
adminuser = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "cnst";
|
||||||
|
};
|
||||||
|
configDir = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "/var/lib/${unit}";
|
||||||
|
};
|
||||||
|
url = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "cloud.${srv.domain}";
|
||||||
|
};
|
||||||
|
homepage.name = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "Nextcloud";
|
||||||
|
};
|
||||||
|
homepage.description = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "A safe home for all your data";
|
||||||
|
};
|
||||||
|
homepage.icon = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "nextcloud.svg";
|
||||||
|
};
|
||||||
|
homepage.category = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "Services";
|
||||||
|
};
|
||||||
|
};
|
||||||
config = lib.mkIf cfg.enable {
|
config = lib.mkIf cfg.enable {
|
||||||
age.secrets = {
|
age.secrets = {
|
||||||
nextcloudAdminPass.file = "${self}/secrets/nextcloudAdminPass.age";
|
nextcloudAdminPass.file = "${self}/secrets/nextcloudAdminPass.age";
|
||||||
nextcloudCloudflared.file = "${self}/secrets/nextcloudCloudflared.age";
|
nextcloudCloudflared.file = "${self}/secrets/nextcloudCloudflared.age";
|
||||||
};
|
};
|
||||||
|
|
||||||
server.infra.fail2ban.jails.nextcloud = {
|
server.fail2ban = lib.mkIf config.server.fail2ban.enable {
|
||||||
serviceName = "${unit}";
|
jails = {
|
||||||
_groupsre = ''(?:(?:,?\s*"\w+":(?:"[^"]+"|\w+))*)'';
|
nextcloud = {
|
||||||
failRegex = ''
|
serviceName = "phpfpm-nextcloud";
|
||||||
^\{%(_groupsre)s,?\s*"remoteAddr":"<HOST>"%(_groupsre)s,?\s*"message":"Login failed:
|
failRegex = "^.*Login failed:.*(Remote IP: <HOST>).*$";
|
||||||
^\{%(_groupsre)s,?\s*"remoteAddr":"<HOST>"%(_groupsre)s,?\s*"message":"Two-factor challenge failed:
|
};
|
||||||
^\{%(_groupsre)s,?\s*"remoteAddr":"<HOST>"%(_groupsre)s,?\s*"message":"Trusted domain error.
|
};
|
||||||
'';
|
|
||||||
datePattern = '',?\s*"time"\s*:\s*"%%Y-%%m-%%d[T ]%%H:%%M:%%S(%%z)?"'';
|
|
||||||
};
|
};
|
||||||
|
|
||||||
services = {
|
services = {
|
||||||
${unit} = {
|
${unit} = {
|
||||||
enable = true;
|
enable = true;
|
||||||
package = pkgs.nextcloud32;
|
package = pkgs.nextcloud31;
|
||||||
hostName = "nextcloud";
|
hostName = "nextcloud";
|
||||||
configureRedis = true;
|
configureRedis = true;
|
||||||
caching = {
|
caching = {
|
||||||
@@ -67,7 +101,7 @@ in {
|
|||||||
dbhost = "/run/postgresql";
|
dbhost = "/run/postgresql";
|
||||||
dbname = "nextcloud";
|
dbname = "nextcloud";
|
||||||
adminuser = "cnst";
|
adminuser = "cnst";
|
||||||
adminpassFile = config.age.secrets.nextcloudAdminPass.path;
|
adminpassFile = cfg.adminpassFile;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -86,9 +120,21 @@ in {
|
|||||||
forceSSL = false;
|
forceSSL = false;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
traefik.dynamicConfigOptions.http = {
|
||||||
|
routers.nextcloud = {
|
||||||
|
entryPoints = ["websecure"];
|
||||||
|
rule = "Host(`${cfg.url}`)";
|
||||||
|
service = "nextcloud";
|
||||||
|
tls.certResolver = "letsencrypt";
|
||||||
|
};
|
||||||
|
services.nextcloud.loadBalancer.servers = [
|
||||||
|
{url = "http://127.0.0.1:8182";}
|
||||||
|
];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
server.infra.postgresql.databases = [
|
server.postgresql.databases = [
|
||||||
{
|
{
|
||||||
database = "nextcloud";
|
database = "nextcloud";
|
||||||
}
|
}
|
||||||
@@ -1,180 +0,0 @@
|
|||||||
{
|
|
||||||
lib,
|
|
||||||
config,
|
|
||||||
...
|
|
||||||
}: let
|
|
||||||
inherit (lib) mkOption types;
|
|
||||||
ifTheyExist = groups: builtins.filter (group: builtins.hasAttr group config.users.groups) groups;
|
|
||||||
cfg = config.server;
|
|
||||||
in {
|
|
||||||
options.server = {
|
|
||||||
enable = lib.mkEnableOption "The server services and configuration variables";
|
|
||||||
email = mkOption {
|
|
||||||
default = "";
|
|
||||||
type = types.str;
|
|
||||||
description = ''
|
|
||||||
Email name to be used to access the server services via Caddy reverse proxy
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
domain = mkOption {
|
|
||||||
default = "";
|
|
||||||
type = types.str;
|
|
||||||
description = ''
|
|
||||||
Domain name to be used to access the server services via Caddy reverse proxy
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
ip = lib.mkOption {
|
|
||||||
type = lib.types.str;
|
|
||||||
default = "127.0.0.1";
|
|
||||||
description = "The local IP of the service.";
|
|
||||||
};
|
|
||||||
user = lib.mkOption {
|
|
||||||
default = "share";
|
|
||||||
type = lib.types.str;
|
|
||||||
description = ''
|
|
||||||
User to run the server services as
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
group = lib.mkOption {
|
|
||||||
default = "share";
|
|
||||||
type = lib.types.str;
|
|
||||||
description = ''
|
|
||||||
Group to run the server services as
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
uid = lib.mkOption {
|
|
||||||
default = 1000;
|
|
||||||
type = lib.types.int;
|
|
||||||
description = ''
|
|
||||||
UID to run the server services as
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
gid = lib.mkOption {
|
|
||||||
default = 1000;
|
|
||||||
type = lib.types.int;
|
|
||||||
description = ''
|
|
||||||
GID to run the server services as
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
timeZone = lib.mkOption {
|
|
||||||
default = "Europe/Stockholm";
|
|
||||||
type = lib.types.str;
|
|
||||||
description = ''
|
|
||||||
Time zone to be used for the server services
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
services = lib.mkOption {
|
|
||||||
type = lib.types.attrsOf (lib.types.submodule ({name, ...}: {
|
|
||||||
options = {
|
|
||||||
enable = lib.mkEnableOption "the service";
|
|
||||||
subdomain = lib.mkOption {
|
|
||||||
type = lib.types.str;
|
|
||||||
default = "";
|
|
||||||
description = "The subdomain for the service (e.g., 'jellyfin')";
|
|
||||||
};
|
|
||||||
exposure = lib.mkOption {
|
|
||||||
type = lib.types.enum ["local" "tunnel" "tailscale"];
|
|
||||||
default = "local";
|
|
||||||
description = "Controls where the service is exposed";
|
|
||||||
};
|
|
||||||
port = lib.mkOption {
|
|
||||||
type = lib.types.int;
|
|
||||||
default = 80;
|
|
||||||
description = "The port to host service on.";
|
|
||||||
};
|
|
||||||
configDir = lib.mkOption {
|
|
||||||
type = lib.types.path;
|
|
||||||
default = "/var/lib/${name}";
|
|
||||||
description = "Configuration directory for ${name}.";
|
|
||||||
};
|
|
||||||
cloudflared = lib.mkOption {
|
|
||||||
type = lib.types.submodule {
|
|
||||||
options = {
|
|
||||||
credentialsFile = lib.mkOption {
|
|
||||||
type = lib.types.str;
|
|
||||||
example = lib.literalExpression ''
|
|
||||||
pkgs.writeText "cloudflare-credentials.json" '''
|
|
||||||
{"AccountTag":"secret","TunnelSecret":"secret","TunnelID":"secret"}
|
|
||||||
'''
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
tunnelId = lib.mkOption {
|
|
||||||
type = lib.types.str;
|
|
||||||
example = "00000000-0000-0000-0000-000000000000";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
description = "Cloudflare tunnel configuration for this service.";
|
|
||||||
};
|
|
||||||
homepage = lib.mkOption {
|
|
||||||
type = lib.types.submodule {
|
|
||||||
options = {
|
|
||||||
name = lib.mkOption {
|
|
||||||
type = lib.types.str;
|
|
||||||
default = "";
|
|
||||||
description = "Display name on the homepage.";
|
|
||||||
};
|
|
||||||
description = lib.mkOption {
|
|
||||||
type = lib.types.str;
|
|
||||||
default = "";
|
|
||||||
description = "A short description for the homepage tile.";
|
|
||||||
};
|
|
||||||
icon = lib.mkOption {
|
|
||||||
type = lib.types.str;
|
|
||||||
default = "Zervices c00l stuff";
|
|
||||||
description = "Icon file name for the homepage tile.";
|
|
||||||
};
|
|
||||||
category = lib.mkOption {
|
|
||||||
type = lib.types.str;
|
|
||||||
default = "";
|
|
||||||
description = "Homepage category grouping.";
|
|
||||||
};
|
|
||||||
path = lib.mkOption {
|
|
||||||
type = lib.types.str;
|
|
||||||
default = "";
|
|
||||||
example = "/admin";
|
|
||||||
description = "Optional path suffix for homepage links (e.g. /admin).";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
description = "Homepage metadata for this service.";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}));
|
|
||||||
};
|
|
||||||
};
|
|
||||||
config = lib.mkIf cfg.enable {
|
|
||||||
users = {
|
|
||||||
groups.${cfg.group} = {
|
|
||||||
gid = cfg.gid;
|
|
||||||
};
|
|
||||||
users.${cfg.user} = {
|
|
||||||
uid = cfg.uid;
|
|
||||||
isSystemUser = true;
|
|
||||||
group = cfg.group;
|
|
||||||
extraGroups = ifTheyExist [
|
|
||||||
"audio"
|
|
||||||
"video"
|
|
||||||
"docker"
|
|
||||||
"libvirtd"
|
|
||||||
"qemu-libvirtd"
|
|
||||||
"rtkit"
|
|
||||||
"fail2ban"
|
|
||||||
"vaultwarden"
|
|
||||||
"qbittorrent"
|
|
||||||
"lidarr"
|
|
||||||
"prowlarr"
|
|
||||||
"bazarr"
|
|
||||||
"sonarr"
|
|
||||||
"radarr"
|
|
||||||
"media"
|
|
||||||
"share"
|
|
||||||
"render"
|
|
||||||
"input"
|
|
||||||
"authentik"
|
|
||||||
"traefik"
|
|
||||||
];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
321
modules/server/podman/default.nix
Normal file
321
modules/server/podman/default.nix
Normal file
@@ -0,0 +1,321 @@
|
|||||||
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
self,
|
||||||
|
...
|
||||||
|
}: let
|
||||||
|
srv = config.server;
|
||||||
|
cfg = config.server.podman;
|
||||||
|
|
||||||
|
piholeUrl =
|
||||||
|
if config.networking.hostName == "sobotka"
|
||||||
|
then "pihole0"
|
||||||
|
else if config.networking.hostName == "ziggy"
|
||||||
|
then "pihole1"
|
||||||
|
else throw "Unknown hostname";
|
||||||
|
|
||||||
|
getPiholeSecret = hostname:
|
||||||
|
if hostname == "ziggy"
|
||||||
|
then [config.age.secrets.piholeZiggy.path]
|
||||||
|
else if hostname == "sobotka"
|
||||||
|
then [config.age.secrets.pihole.path]
|
||||||
|
else throw "Unknown hostname: ${hostname}";
|
||||||
|
in {
|
||||||
|
options.server.podman = {
|
||||||
|
enable = lib.mkEnableOption "Enables Podman";
|
||||||
|
gluetun.enable = lib.mkEnableOption "Enables gluetun";
|
||||||
|
|
||||||
|
qbittorrent = {
|
||||||
|
enable = lib.mkEnableOption "Enable qBittorrent";
|
||||||
|
url = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "qbt.${srv.domain}";
|
||||||
|
};
|
||||||
|
port = lib.mkOption {
|
||||||
|
type = lib.types.int;
|
||||||
|
default = 8080;
|
||||||
|
description = "The port to host qBittorrent on.";
|
||||||
|
};
|
||||||
|
homepage.name = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "qBittorrent";
|
||||||
|
};
|
||||||
|
homepage.description = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "Torrent client";
|
||||||
|
};
|
||||||
|
homepage.icon = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "qbittorrent.svg";
|
||||||
|
};
|
||||||
|
homepage.category = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "Downloads";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
slskd = {
|
||||||
|
enable = lib.mkEnableOption "Enable Soulseek";
|
||||||
|
url = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "slskd.${srv.domain}";
|
||||||
|
};
|
||||||
|
port = lib.mkOption {
|
||||||
|
type = lib.types.int;
|
||||||
|
default = 5030;
|
||||||
|
description = "The port to host Soulseek webui on.";
|
||||||
|
};
|
||||||
|
homepage.name = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "slskd";
|
||||||
|
};
|
||||||
|
homepage.description = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "Web-based Soulseek client";
|
||||||
|
};
|
||||||
|
homepage.icon = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "slskd.svg";
|
||||||
|
};
|
||||||
|
homepage.category = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "Downloads";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
pihole = {
|
||||||
|
enable = lib.mkEnableOption {
|
||||||
|
description = "Enable";
|
||||||
|
};
|
||||||
|
port = lib.mkOption {
|
||||||
|
type = lib.types.int;
|
||||||
|
default = 8053;
|
||||||
|
description = "The port to host PiHole on.";
|
||||||
|
};
|
||||||
|
url = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "${piholeUrl}.${srv.domain}";
|
||||||
|
};
|
||||||
|
homepage.name = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "PiHole";
|
||||||
|
};
|
||||||
|
homepage.description = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "Adblocking and DNS service";
|
||||||
|
};
|
||||||
|
homepage.icon = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "pi-hole.svg";
|
||||||
|
};
|
||||||
|
homepage.category = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "Services";
|
||||||
|
};
|
||||||
|
homepage.path = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "/admin";
|
||||||
|
description = "Optional path suffix for homepage links (e.g. /admin).";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = lib.mkIf cfg.enable {
|
||||||
|
age.secrets = {
|
||||||
|
pihole.file = "${self}/secrets/${config.networking.hostName}Pihole.age";
|
||||||
|
slskd.file = "${self}/secrets/slskd.age";
|
||||||
|
};
|
||||||
|
|
||||||
|
virtualisation = {
|
||||||
|
containers.enable = true;
|
||||||
|
podman.enable = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
networking.firewall = lib.mkIf cfg.pihole.enable {
|
||||||
|
allowedTCPPorts = [
|
||||||
|
53
|
||||||
|
5335
|
||||||
|
];
|
||||||
|
allowedUDPPorts = [
|
||||||
|
53
|
||||||
|
5335
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
services.traefik = lib.mkMerge [
|
||||||
|
(lib.mkIf cfg.pihole.enable {
|
||||||
|
dynamicConfigOptions = {
|
||||||
|
http = {
|
||||||
|
services = {
|
||||||
|
pihole.loadBalancer.servers = [{url = "http://localhost:${toString cfg.pihole.port}";}];
|
||||||
|
};
|
||||||
|
routers = {
|
||||||
|
pihole = {
|
||||||
|
entryPoints = ["websecure"];
|
||||||
|
rule = "Host(`${cfg.pihole.url}`)";
|
||||||
|
service = "pihole";
|
||||||
|
tls.certResolver = "letsencrypt";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
})
|
||||||
|
|
||||||
|
(lib.mkIf cfg.qbittorrent.enable {
|
||||||
|
dynamicConfigOptions = {
|
||||||
|
http = {
|
||||||
|
services = {
|
||||||
|
qbittorrent.loadBalancer.servers = [{url = "http://localhost:${toString cfg.qbittorrent.port}";}];
|
||||||
|
};
|
||||||
|
routers = {
|
||||||
|
qbittorrent = {
|
||||||
|
entryPoints = ["websecure"];
|
||||||
|
rule = "Host(`${cfg.qbittorrent.url}`)";
|
||||||
|
service = "qbittorrent";
|
||||||
|
tls.certResolver = "letsencrypt";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
})
|
||||||
|
|
||||||
|
(lib.mkIf cfg.slskd.enable {
|
||||||
|
dynamicConfigOptions = {
|
||||||
|
http = {
|
||||||
|
services = {
|
||||||
|
slskd.loadBalancer.servers = [{url = "http://localhost:${toString cfg.slskd.port}";}];
|
||||||
|
};
|
||||||
|
routers = {
|
||||||
|
slskd = {
|
||||||
|
entryPoints = ["websecure"];
|
||||||
|
rule = "Host(`${cfg.slskd.url}`)";
|
||||||
|
service = "slskd";
|
||||||
|
tls.certResolver = "letsencrypt";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
})
|
||||||
|
];
|
||||||
|
|
||||||
|
virtualisation.oci-containers.containers = lib.mkMerge [
|
||||||
|
(lib.mkIf cfg.gluetun.enable {
|
||||||
|
gluetun = {
|
||||||
|
image = "qmcgaw/gluetun";
|
||||||
|
ports = [
|
||||||
|
"8388:8388"
|
||||||
|
"58846:58846"
|
||||||
|
"8080:8080"
|
||||||
|
"5030:5030"
|
||||||
|
"5031:5031"
|
||||||
|
"50300:50300"
|
||||||
|
];
|
||||||
|
devices = ["/dev/net/tun:/dev/net/tun"];
|
||||||
|
autoStart = true;
|
||||||
|
extraOptions = [
|
||||||
|
"--cap-add=NET_ADMIN"
|
||||||
|
];
|
||||||
|
volumes = ["/var:/gluetun"];
|
||||||
|
environmentFiles = [
|
||||||
|
config.age.secrets.gluetunEnvironment.path
|
||||||
|
];
|
||||||
|
environment = {
|
||||||
|
DEV_MODE = "false";
|
||||||
|
VPN_SERVICE_PROVIDER = "mullvad";
|
||||||
|
VPN_TYPE = "wireguard";
|
||||||
|
SERVER_CITIES = "Stockholm";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
})
|
||||||
|
|
||||||
|
(lib.mkIf cfg.qbittorrent.enable {
|
||||||
|
qbittorrent = {
|
||||||
|
image = "ghcr.io/hotio/qbittorrent:latest";
|
||||||
|
autoStart = true;
|
||||||
|
dependsOn = ["gluetun"];
|
||||||
|
ports = [
|
||||||
|
"8080:8080"
|
||||||
|
"58846:58846"
|
||||||
|
];
|
||||||
|
extraOptions = [
|
||||||
|
"--network=container:gluetun"
|
||||||
|
];
|
||||||
|
volumes = [
|
||||||
|
"/var/lib/qbittorrent:/config:rw"
|
||||||
|
"/mnt/data/media/downloads:/downloads:rw"
|
||||||
|
];
|
||||||
|
environmentFiles = [
|
||||||
|
config.age.secrets.gluetunEnvironment.path
|
||||||
|
];
|
||||||
|
environment = {
|
||||||
|
PUID = "994";
|
||||||
|
PGID = "993";
|
||||||
|
TZ = "Europe/Stockholm";
|
||||||
|
WEBUI_PORT = "${builtins.toString cfg.qbittorrent.port}";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
})
|
||||||
|
|
||||||
|
(lib.mkIf cfg.slskd.enable {
|
||||||
|
slskd = {
|
||||||
|
image = "slskd/slskd:latest";
|
||||||
|
autoStart = true;
|
||||||
|
dependsOn = ["gluetun"];
|
||||||
|
ports = [
|
||||||
|
"5030:5030"
|
||||||
|
"5031:5031"
|
||||||
|
"50300:50300"
|
||||||
|
];
|
||||||
|
extraOptions = [
|
||||||
|
"--network=container:gluetun"
|
||||||
|
];
|
||||||
|
volumes = [
|
||||||
|
"/var/lib/slskd:/app:rw"
|
||||||
|
"/mnt/data/media/downloads:/downloads:rw"
|
||||||
|
];
|
||||||
|
environmentFiles = [
|
||||||
|
config.age.secrets.gluetunEnvironment.path
|
||||||
|
config.age.secrets.slskd.path
|
||||||
|
];
|
||||||
|
environment = {
|
||||||
|
TZ = "Europe/Stockholm";
|
||||||
|
PUID = "981";
|
||||||
|
PGID = "982";
|
||||||
|
SLSKD_REMOTE_CONFIGURATION = "true";
|
||||||
|
SLSKD_REMOTE_FILE_MANAGEMENT = "true";
|
||||||
|
SLSKD_DOWNLOADS_DIR = "/downloads";
|
||||||
|
SLSKD_UMASK = "022";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
})
|
||||||
|
|
||||||
|
(lib.mkIf cfg.pihole.enable {
|
||||||
|
pihole = {
|
||||||
|
autoStart = true;
|
||||||
|
image = "pihole/pihole:latest";
|
||||||
|
volumes = [
|
||||||
|
"/var/lib/pihole:/etc/pihole/"
|
||||||
|
"/var/lib/dnsmasq.d:/etc/dnsmasq.d/"
|
||||||
|
];
|
||||||
|
environment = {
|
||||||
|
TZ = "Europe/Stockholm";
|
||||||
|
CUSTOM_CACHE_SIZE = "0";
|
||||||
|
WEBTHEME = "default-darker";
|
||||||
|
};
|
||||||
|
environmentFiles = getPiholeSecret config.networking.hostName;
|
||||||
|
ports = [
|
||||||
|
"53:53/tcp"
|
||||||
|
"53:53/udp"
|
||||||
|
"8053:80/tcp"
|
||||||
|
];
|
||||||
|
extraOptions = [
|
||||||
|
"--cap-add=NET_ADMIN"
|
||||||
|
"--cap-add=SYS_NICE"
|
||||||
|
"--cap-add=SYS_TIME"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
})
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -7,10 +7,10 @@
|
|||||||
}: let
|
}: let
|
||||||
inherit (lib) types mkOption;
|
inherit (lib) types mkOption;
|
||||||
|
|
||||||
cfg = config.server.infra.postgresql;
|
cfg = config.server.postgresql;
|
||||||
in {
|
in {
|
||||||
options = {
|
options = {
|
||||||
server.infra.postgresql = {
|
server.postgresql = {
|
||||||
upgradeTargetPackage = mkOption {
|
upgradeTargetPackage = mkOption {
|
||||||
type = types.nullOr types.package;
|
type = types.nullOr types.package;
|
||||||
default = null;
|
default = null;
|
||||||
@@ -7,7 +7,7 @@
|
|||||||
}: let
|
}: let
|
||||||
inherit (lib) types mkOption;
|
inherit (lib) types mkOption;
|
||||||
|
|
||||||
cfg = config.server.infra.postgresql;
|
cfg = config.server.postgresql;
|
||||||
|
|
||||||
database = {name, ...}: {
|
database = {name, ...}: {
|
||||||
options = {
|
options = {
|
||||||
@@ -31,7 +31,7 @@
|
|||||||
};
|
};
|
||||||
in {
|
in {
|
||||||
options = {
|
options = {
|
||||||
server.infra.postgresql = {
|
server.postgresql = {
|
||||||
databases = mkOption {
|
databases = mkOption {
|
||||||
type = types.listOf (types.submodule database);
|
type = types.listOf (types.submodule database);
|
||||||
default = [];
|
default = [];
|
||||||
80
modules/server/prowlarr/default.nix
Normal file
80
modules/server/prowlarr/default.nix
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}: let
|
||||||
|
unit = "prowlarr";
|
||||||
|
srv = config.server;
|
||||||
|
cfg = config.server.${unit};
|
||||||
|
in {
|
||||||
|
options.server.${unit} = {
|
||||||
|
enable = lib.mkEnableOption {
|
||||||
|
description = "Enable ${unit}";
|
||||||
|
};
|
||||||
|
configDir = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "/var/lib/${unit}";
|
||||||
|
};
|
||||||
|
url = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "${unit}.${srv.domain}";
|
||||||
|
};
|
||||||
|
homepage.name = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "Prowlarr";
|
||||||
|
};
|
||||||
|
homepage.description = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "PVR indexer";
|
||||||
|
};
|
||||||
|
homepage.icon = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "prowlarr.svg";
|
||||||
|
};
|
||||||
|
homepage.category = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "Arr";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
config = lib.mkIf cfg.enable {
|
||||||
|
services = {
|
||||||
|
${unit} = {
|
||||||
|
enable = true;
|
||||||
|
};
|
||||||
|
flaresolverr = {
|
||||||
|
enable = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
traefik = {
|
||||||
|
dynamicConfigOptions = {
|
||||||
|
http = {
|
||||||
|
services = {
|
||||||
|
prowlarr = {
|
||||||
|
loadBalancer.servers = [{url = "http://127.0.0.1:9696";}];
|
||||||
|
};
|
||||||
|
flaresolverr = {
|
||||||
|
loadBalancer.servers = [{url = "http://127.0.0.1:8191";}];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
routers = {
|
||||||
|
prowlarr = {
|
||||||
|
entryPoints = ["websecure"];
|
||||||
|
rule = "Host(`${cfg.url}`)";
|
||||||
|
service = "prowlarr";
|
||||||
|
tls.certResolver = "letsencrypt";
|
||||||
|
# middlewares = ["authentik"];
|
||||||
|
};
|
||||||
|
flaresolverr = {
|
||||||
|
entryPoints = ["websecure"];
|
||||||
|
rule = "Host(`flaresolverr.${srv.domain}`)";
|
||||||
|
service = "flaresolverr";
|
||||||
|
tls.certResolver = "letsencrypt";
|
||||||
|
# middlewares = ["authentik"];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
62
modules/server/radarr/default.nix
Normal file
62
modules/server/radarr/default.nix
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}: let
|
||||||
|
unit = "radarr";
|
||||||
|
srv = config.server;
|
||||||
|
cfg = config.server.${unit};
|
||||||
|
in {
|
||||||
|
options.server.${unit} = {
|
||||||
|
enable = lib.mkEnableOption {
|
||||||
|
description = "Enable ${unit}";
|
||||||
|
};
|
||||||
|
configDir = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "/var/lib/${unit}";
|
||||||
|
};
|
||||||
|
url = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "${unit}.${srv.domain}";
|
||||||
|
};
|
||||||
|
homepage.name = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "Radarr";
|
||||||
|
};
|
||||||
|
homepage.description = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "Film collection manager";
|
||||||
|
};
|
||||||
|
homepage.icon = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "radarr.svg";
|
||||||
|
};
|
||||||
|
homepage.category = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "Arr";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
config = lib.mkIf cfg.enable {
|
||||||
|
services.${unit} = {
|
||||||
|
enable = true;
|
||||||
|
user = srv.user;
|
||||||
|
group = srv.group;
|
||||||
|
};
|
||||||
|
services.traefik = {
|
||||||
|
dynamicConfigOptions = {
|
||||||
|
http = {
|
||||||
|
services.radarr.loadBalancer.servers = [{url = "http://127.0.0.1:7878";}];
|
||||||
|
routers = {
|
||||||
|
radarr = {
|
||||||
|
entryPoints = ["websecure"];
|
||||||
|
rule = "Host(`${cfg.url}`)";
|
||||||
|
service = "radarr";
|
||||||
|
tls.certResolver = "letsencrypt";
|
||||||
|
# middlewares = ["authentik"];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
{
|
|
||||||
config,
|
|
||||||
lib,
|
|
||||||
...
|
|
||||||
}: let
|
|
||||||
unit = "bazarr";
|
|
||||||
srv = config.server;
|
|
||||||
cfg = config.server.services.${unit};
|
|
||||||
in {
|
|
||||||
config = lib.mkIf cfg.enable {
|
|
||||||
services.${unit} = {
|
|
||||||
enable = true;
|
|
||||||
user = srv.user;
|
|
||||||
group = srv.group;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
{
|
|
||||||
imports = [
|
|
||||||
./bazarr
|
|
||||||
./flaresolverr
|
|
||||||
./gitea
|
|
||||||
./homepage-dashboard
|
|
||||||
./jellyfin
|
|
||||||
./jellyseerr
|
|
||||||
./lidarr
|
|
||||||
./n8n
|
|
||||||
./nextcloud
|
|
||||||
./ollama
|
|
||||||
./prowlarr
|
|
||||||
./radarr
|
|
||||||
./sonarr
|
|
||||||
./uptime-kuma
|
|
||||||
./vaultwarden
|
|
||||||
];
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
{
|
|
||||||
config,
|
|
||||||
lib,
|
|
||||||
...
|
|
||||||
}: let
|
|
||||||
unit = "flaresolverr";
|
|
||||||
cfg = config.server.services.${unit};
|
|
||||||
in {
|
|
||||||
config = lib.mkIf cfg.enable {
|
|
||||||
services = {
|
|
||||||
${unit} = {
|
|
||||||
enable = true;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,94 +0,0 @@
|
|||||||
{
|
|
||||||
config,
|
|
||||||
lib,
|
|
||||||
self,
|
|
||||||
...
|
|
||||||
}: let
|
|
||||||
unit = "gitea";
|
|
||||||
cfg = config.server.services.${unit};
|
|
||||||
domain = "${cfg.subdomain}.${config.server.infra.www.url}";
|
|
||||||
in {
|
|
||||||
config = lib.mkIf cfg.enable {
|
|
||||||
age.secrets.giteaCloudflared.file = "${self}/secrets/giteaCloudflared.age";
|
|
||||||
|
|
||||||
server.infra = {
|
|
||||||
fail2ban.jails.${unit} = {
|
|
||||||
serviceName = "${unit}";
|
|
||||||
failRegex = ''.*(Failed authentication attempt|invalid credentials|Attempted access of unknown user).* from <HOST>'';
|
|
||||||
};
|
|
||||||
|
|
||||||
postgresql.databases = [
|
|
||||||
{database = "gitea";}
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
services = {
|
|
||||||
cloudflared = {
|
|
||||||
enable = true;
|
|
||||||
tunnels.${cfg.cloudflared.tunnelId} = {
|
|
||||||
credentialsFile = cfg.cloudflared.credentialsFile;
|
|
||||||
default = "http_status:404";
|
|
||||||
ingress."${domain}".service = "http://localhost:${toString cfg.port}";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
gitea = {
|
|
||||||
enable = true;
|
|
||||||
appName = "cnix code forge";
|
|
||||||
|
|
||||||
database = {
|
|
||||||
type = "postgres";
|
|
||||||
socket = "/run/postgresql";
|
|
||||||
name = "gitea";
|
|
||||||
user = "gitea";
|
|
||||||
createDatabase = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
lfs.enable = true;
|
|
||||||
|
|
||||||
settings = {
|
|
||||||
cors = {
|
|
||||||
ENABLED = true;
|
|
||||||
SCHEME = "https";
|
|
||||||
ALLOW_DOMAIN = domain;
|
|
||||||
};
|
|
||||||
|
|
||||||
log.MODE = "console";
|
|
||||||
|
|
||||||
mailer = {
|
|
||||||
ENABLED = false;
|
|
||||||
MAILER_TYPE = "sendmail";
|
|
||||||
FROM = "noreply+adam@cnst.dev";
|
|
||||||
SENDMAIL_PATH = "/run/wrappers/bin/sendmail";
|
|
||||||
};
|
|
||||||
|
|
||||||
picture.DISABLE_GRAVATAR = true;
|
|
||||||
|
|
||||||
repository = {
|
|
||||||
DEFAULT_BRANCH = "main";
|
|
||||||
DEFAULT_REPO_UNITS = "repo.code,repo.issues,repo.pulls";
|
|
||||||
DISABLE_DOWNLOAD_SOURCE_ARCHIVES = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
indexer.REPO_INDEXER_ENABLED = true;
|
|
||||||
|
|
||||||
oauth2_client = {
|
|
||||||
ENABLE_AUTO_REGISTRATION = true;
|
|
||||||
ACCOUNT_LINKING = "auto";
|
|
||||||
};
|
|
||||||
|
|
||||||
server = {
|
|
||||||
DOMAIN = domain;
|
|
||||||
LANDING_PAGE = "explore";
|
|
||||||
HTTP_PORT = cfg.port;
|
|
||||||
ROOT_URL = "https://${domain}/";
|
|
||||||
};
|
|
||||||
|
|
||||||
security.DISABLE_GIT_HOOKS = false;
|
|
||||||
service.DISABLE_REGISTRATION = true;
|
|
||||||
session.COOKIE_SECURE = true;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,227 +0,0 @@
|
|||||||
{
|
|
||||||
config,
|
|
||||||
lib,
|
|
||||||
self,
|
|
||||||
clib,
|
|
||||||
...
|
|
||||||
}: let
|
|
||||||
unit = "homepage-dashboard";
|
|
||||||
cfg = config.server.services.${unit};
|
|
||||||
srv = config.server;
|
|
||||||
in {
|
|
||||||
config = lib.mkIf cfg.enable {
|
|
||||||
age.secrets = {
|
|
||||||
homepageEnvironment = {
|
|
||||||
file = "${self}/secrets/homepageEnvironment.age";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
services = {
|
|
||||||
glances.enable = true;
|
|
||||||
|
|
||||||
${unit} = {
|
|
||||||
enable = true;
|
|
||||||
environmentFile = config.age.secrets.homepageEnvironment.path;
|
|
||||||
|
|
||||||
settings = {
|
|
||||||
color = "stone";
|
|
||||||
theme = "dark";
|
|
||||||
headerStyle = "clean";
|
|
||||||
statusStyle = "dot";
|
|
||||||
hideVersion = true;
|
|
||||||
useEqualHeights = true;
|
|
||||||
|
|
||||||
layout = [
|
|
||||||
{
|
|
||||||
Glances = {
|
|
||||||
header = false;
|
|
||||||
style = "row";
|
|
||||||
columns = 4;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
{
|
|
||||||
Arr = {
|
|
||||||
header = true;
|
|
||||||
style = "column";
|
|
||||||
};
|
|
||||||
}
|
|
||||||
{
|
|
||||||
Downloads = {
|
|
||||||
header = true;
|
|
||||||
style = "column";
|
|
||||||
};
|
|
||||||
}
|
|
||||||
{
|
|
||||||
Media = {
|
|
||||||
header = true;
|
|
||||||
style = "column";
|
|
||||||
};
|
|
||||||
}
|
|
||||||
{
|
|
||||||
Services = {
|
|
||||||
header = true;
|
|
||||||
style = "column";
|
|
||||||
};
|
|
||||||
}
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
widgets = [
|
|
||||||
{
|
|
||||||
openmeteo = {
|
|
||||||
label = "Kalmar";
|
|
||||||
timezone = "Europe/Stockholm";
|
|
||||||
units = "metric";
|
|
||||||
cache = 5;
|
|
||||||
latitude = 56.707262;
|
|
||||||
longitude = 16.324541;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
{
|
|
||||||
resources = {
|
|
||||||
label = "SYSTEM";
|
|
||||||
memory = true;
|
|
||||||
cpu = true;
|
|
||||||
uptime = false;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
services = let
|
|
||||||
homepageCategories = [
|
|
||||||
"Arr"
|
|
||||||
"Media"
|
|
||||||
"Downloads"
|
|
||||||
"Services"
|
|
||||||
];
|
|
||||||
allServices = srv.services;
|
|
||||||
|
|
||||||
getDomain = s: clib.server.mkHostDomain config s;
|
|
||||||
|
|
||||||
homepageServicesFor = category:
|
|
||||||
lib.filterAttrs
|
|
||||||
(
|
|
||||||
name: value:
|
|
||||||
name
|
|
||||||
!= unit
|
|
||||||
&& value ? homepage
|
|
||||||
&& value.homepage.category == category
|
|
||||||
)
|
|
||||||
allServices;
|
|
||||||
in
|
|
||||||
lib.lists.forEach homepageCategories (cat: {
|
|
||||||
"${cat}" =
|
|
||||||
lib.lists.forEach
|
|
||||||
(lib.attrsets.mapAttrsToList (name: _value: name) (homepageServicesFor cat))
|
|
||||||
(x: let
|
|
||||||
service = allServices.${x};
|
|
||||||
domain = getDomain service;
|
|
||||||
in {
|
|
||||||
"${service.homepage.name}" = {
|
|
||||||
icon = service.homepage.icon;
|
|
||||||
description = service.homepage.description;
|
|
||||||
href = "https://${service.subdomain}.${domain}${service.homepage.path or ""}";
|
|
||||||
siteMonitor = "https://${service.subdomain}.${domain}${x.homepage.path or ""}";
|
|
||||||
};
|
|
||||||
});
|
|
||||||
})
|
|
||||||
++ [
|
|
||||||
{
|
|
||||||
Glances = let
|
|
||||||
glancesShared = {
|
|
||||||
type = "glances";
|
|
||||||
url = "http://localhost:${toString config.services.glances.port}";
|
|
||||||
chart = true;
|
|
||||||
version = 4;
|
|
||||||
};
|
|
||||||
in [
|
|
||||||
{
|
|
||||||
Memory = {
|
|
||||||
widget =
|
|
||||||
glancesShared
|
|
||||||
// {
|
|
||||||
metric = "memory";
|
|
||||||
refreshInterval = 2000;
|
|
||||||
pointsLimit = 30;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
{
|
|
||||||
"CPU Usage" = {
|
|
||||||
widget =
|
|
||||||
glancesShared
|
|
||||||
// {
|
|
||||||
metric = "cpu";
|
|
||||||
refreshInterval = 2000;
|
|
||||||
pointsLimit = 30;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
"CPU Temp" = {
|
|
||||||
widget =
|
|
||||||
glancesShared
|
|
||||||
// {
|
|
||||||
metric = "sensor:Tctl";
|
|
||||||
refreshInterval = 5000;
|
|
||||||
pointsLimit = 20;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
{
|
|
||||||
"GPU Radeon" = {
|
|
||||||
widget =
|
|
||||||
glancesShared
|
|
||||||
// {
|
|
||||||
metric = "sensor:junction";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
{
|
|
||||||
"GPU Intel" = {
|
|
||||||
widget =
|
|
||||||
glancesShared
|
|
||||||
// {
|
|
||||||
metric = "sensor:pkg";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
{
|
|
||||||
"ZFS Pool" = {
|
|
||||||
widget =
|
|
||||||
glancesShared
|
|
||||||
// {
|
|
||||||
metric = "fs:/mnt/data";
|
|
||||||
refreshInterval = 30000;
|
|
||||||
pointsLimit = 20;
|
|
||||||
diskUnits = "bytes";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
Processes = {
|
|
||||||
widget =
|
|
||||||
glancesShared
|
|
||||||
// {
|
|
||||||
metric = "process";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
{
|
|
||||||
Network = {
|
|
||||||
widget =
|
|
||||||
glancesShared
|
|
||||||
// {
|
|
||||||
metric = "network:enp6s0";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
];
|
|
||||||
}
|
|
||||||
];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
{
|
|
||||||
config,
|
|
||||||
lib,
|
|
||||||
pkgs,
|
|
||||||
...
|
|
||||||
}: let
|
|
||||||
unit = "jellyfin";
|
|
||||||
cfg = config.server.services.${unit};
|
|
||||||
srv = config.server;
|
|
||||||
in {
|
|
||||||
config = lib.mkIf cfg.enable {
|
|
||||||
services.${unit} = {
|
|
||||||
enable = true;
|
|
||||||
user = srv.user;
|
|
||||||
group = srv.group;
|
|
||||||
};
|
|
||||||
environment.systemPackages = with pkgs; [
|
|
||||||
jellyfin-ffmpeg
|
|
||||||
];
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
{
|
|
||||||
config,
|
|
||||||
lib,
|
|
||||||
...
|
|
||||||
}: let
|
|
||||||
unit = "jellyseerr";
|
|
||||||
cfg = config.server.services.${unit};
|
|
||||||
in {
|
|
||||||
config = lib.mkIf cfg.enable {
|
|
||||||
services.${unit} = {
|
|
||||||
enable = true;
|
|
||||||
port = cfg.port;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
{
|
|
||||||
config,
|
|
||||||
lib,
|
|
||||||
...
|
|
||||||
}: let
|
|
||||||
unit = "lidarr";
|
|
||||||
srv = config.server;
|
|
||||||
cfg = config.server.services.${unit};
|
|
||||||
in {
|
|
||||||
config = lib.mkIf cfg.enable {
|
|
||||||
services.${unit} = {
|
|
||||||
enable = true;
|
|
||||||
user = srv.user;
|
|
||||||
group = srv.group;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
{
|
|
||||||
config,
|
|
||||||
lib,
|
|
||||||
...
|
|
||||||
}: let
|
|
||||||
unit = "n8n";
|
|
||||||
cfg = config.server.services.${unit};
|
|
||||||
in {
|
|
||||||
config = lib.mkIf cfg.enable {
|
|
||||||
services = {
|
|
||||||
n8n = {
|
|
||||||
enable = true;
|
|
||||||
openFirewall = true;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
{
|
|
||||||
config,
|
|
||||||
lib,
|
|
||||||
pkgs,
|
|
||||||
...
|
|
||||||
}: let
|
|
||||||
unit = "ollama";
|
|
||||||
cfg = config.server.services.${unit};
|
|
||||||
in {
|
|
||||||
config = lib.mkIf cfg.enable {
|
|
||||||
environment.systemPackages = with pkgs; [
|
|
||||||
ollama
|
|
||||||
intel-compute-runtime
|
|
||||||
intel-graphics-compiler
|
|
||||||
level-zero
|
|
||||||
];
|
|
||||||
services.open-webui = {
|
|
||||||
enable = true;
|
|
||||||
host = "0.0.0.0";
|
|
||||||
port = 8001;
|
|
||||||
environment = {
|
|
||||||
ANONYMIZED_TELEMETRY = "False";
|
|
||||||
BYPASS_MODEL_ACCESS_CONTROL = "True";
|
|
||||||
OLLAMA_BASE_URL = "http://localhost:11434";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
{
|
|
||||||
config,
|
|
||||||
lib,
|
|
||||||
...
|
|
||||||
}: let
|
|
||||||
unit = "prowlarr";
|
|
||||||
cfg = config.server.services.${unit};
|
|
||||||
in {
|
|
||||||
config = lib.mkIf cfg.enable {
|
|
||||||
services = {
|
|
||||||
${unit} = {
|
|
||||||
enable = true;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
{
|
|
||||||
config,
|
|
||||||
lib,
|
|
||||||
...
|
|
||||||
}: let
|
|
||||||
unit = "radarr";
|
|
||||||
srv = config.server;
|
|
||||||
cfg = config.server.services.${unit};
|
|
||||||
in {
|
|
||||||
config = lib.mkIf cfg.enable {
|
|
||||||
services.${unit} = {
|
|
||||||
enable = true;
|
|
||||||
user = srv.user;
|
|
||||||
group = srv.group;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
{
|
|
||||||
config,
|
|
||||||
lib,
|
|
||||||
...
|
|
||||||
}: let
|
|
||||||
unit = "sonarr";
|
|
||||||
srv = config.server;
|
|
||||||
cfg = config.server.services.${unit};
|
|
||||||
in {
|
|
||||||
config = lib.mkIf cfg.enable {
|
|
||||||
services.${unit} = {
|
|
||||||
enable = true;
|
|
||||||
user = srv.user;
|
|
||||||
group = srv.group;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
{
|
|
||||||
config,
|
|
||||||
lib,
|
|
||||||
...
|
|
||||||
}: let
|
|
||||||
unit = "uptime-kuma";
|
|
||||||
cfg = config.server.services.${unit};
|
|
||||||
in {
|
|
||||||
config = lib.mkIf cfg.enable {
|
|
||||||
services = {
|
|
||||||
${unit} = {
|
|
||||||
enable = true;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
# from @fufexan & @notthebee
|
|
||||||
{
|
|
||||||
config,
|
|
||||||
lib,
|
|
||||||
self,
|
|
||||||
...
|
|
||||||
}: let
|
|
||||||
unit = "vaultwarden";
|
|
||||||
cfg = config.server.services.${unit};
|
|
||||||
domain = "${cfg.subdomain}.${config.server.infra.www.url}";
|
|
||||||
in {
|
|
||||||
config = lib.mkIf cfg.enable {
|
|
||||||
age.secrets = {
|
|
||||||
vaultwardenCloudflared.file = "${self}/secrets/vaultwardenCloudflared.age";
|
|
||||||
vaultwardenEnvironment.file = "${self}/secrets/vaultwardenEnvironment.age";
|
|
||||||
};
|
|
||||||
|
|
||||||
server.infra.fail2ban.jails.${unit} = {
|
|
||||||
serviceName = "${unit}";
|
|
||||||
failRegex = ''^.*?Username or password is incorrect\. Try again\. IP: <ADDR>\. Username:.*$'';
|
|
||||||
};
|
|
||||||
|
|
||||||
services = {
|
|
||||||
cloudflared = {
|
|
||||||
enable = true;
|
|
||||||
tunnels.${cfg.cloudflared.tunnelId} = {
|
|
||||||
credentialsFile = cfg.cloudflared.credentialsFile;
|
|
||||||
default = "http_status:404";
|
|
||||||
ingress."${domain}".service = "http://localhost:${toString cfg.port}";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
vaultwarden = {
|
|
||||||
enable = true;
|
|
||||||
environmentFile = config.age.secrets.vaultwardenEnvironment.path;
|
|
||||||
|
|
||||||
backupDir = "/var/backup/vaultwarden";
|
|
||||||
|
|
||||||
config = {
|
|
||||||
DOMAIN = "https://${domain}";
|
|
||||||
SIGNUPS_ALLOWED = false;
|
|
||||||
ROCKET_ADDRESS = "127.0.0.1";
|
|
||||||
ROCKET_PORT = cfg.port;
|
|
||||||
IP_HEADER = "CF-Connecting-IP";
|
|
||||||
|
|
||||||
logLevel = "warn";
|
|
||||||
extendedLogging = true;
|
|
||||||
useSyslog = true;
|
|
||||||
invitationsAllowed = true;
|
|
||||||
showPasswordHint = false;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
systemd.services.backup-vaultwarden.serviceConfig = {
|
|
||||||
User = "root";
|
|
||||||
Group = "root";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
62
modules/server/sonarr/default.nix
Normal file
62
modules/server/sonarr/default.nix
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}: let
|
||||||
|
unit = "sonarr";
|
||||||
|
srv = config.server;
|
||||||
|
cfg = config.server.${unit};
|
||||||
|
in {
|
||||||
|
options.server.${unit} = {
|
||||||
|
enable = lib.mkEnableOption {
|
||||||
|
description = "Enable ${unit}";
|
||||||
|
};
|
||||||
|
configDir = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "/var/lib/${unit}";
|
||||||
|
};
|
||||||
|
url = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "${unit}.${srv.domain}";
|
||||||
|
};
|
||||||
|
homepage.name = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "Sonarr";
|
||||||
|
};
|
||||||
|
homepage.description = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "Series collection manager";
|
||||||
|
};
|
||||||
|
homepage.icon = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "sonarr.svg";
|
||||||
|
};
|
||||||
|
homepage.category = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "Arr";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
config = lib.mkIf cfg.enable {
|
||||||
|
services.${unit} = {
|
||||||
|
enable = true;
|
||||||
|
user = srv.user;
|
||||||
|
group = srv.group;
|
||||||
|
};
|
||||||
|
services.traefik = {
|
||||||
|
dynamicConfigOptions = {
|
||||||
|
http = {
|
||||||
|
services.sonarr.loadBalancer.servers = [{url = "http://127.0.0.1:8989";}];
|
||||||
|
routers = {
|
||||||
|
sonarr = {
|
||||||
|
entryPoints = ["websecure"];
|
||||||
|
rule = "Host(`${cfg.url}`)";
|
||||||
|
service = "sonarr";
|
||||||
|
tls.certResolver = "letsencrypt";
|
||||||
|
# middlewares = ["authentik"];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
100
modules/server/traefik/default.nix
Normal file
100
modules/server/traefik/default.nix
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
{
|
||||||
|
lib,
|
||||||
|
config,
|
||||||
|
pkgs,
|
||||||
|
self,
|
||||||
|
...
|
||||||
|
}: let
|
||||||
|
inherit (lib) mkEnableOption mkIf types;
|
||||||
|
|
||||||
|
cfg = config.server.traefik;
|
||||||
|
getCloudflareCredentials = hostname:
|
||||||
|
if hostname == "ziggy"
|
||||||
|
then config.age.secrets.cloudflareDnsCredentialsZiggy.path
|
||||||
|
else if hostname == "sobotka"
|
||||||
|
then config.age.secrets.cloudflareDnsCredentials.path
|
||||||
|
else throw "Unknown hostname: ${hostname}";
|
||||||
|
in {
|
||||||
|
options.server.traefik = {
|
||||||
|
enable = mkEnableOption "Enable global Traefik reverse proxy with ACME";
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkIf cfg.enable {
|
||||||
|
age.secrets.traefikEnv = {
|
||||||
|
file = "${self}/secrets/traefikEnv.age";
|
||||||
|
mode = "640";
|
||||||
|
owner = "root";
|
||||||
|
group = "traefik";
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.services.traefik = {
|
||||||
|
serviceConfig = {
|
||||||
|
EnvironmentFile = [config.age.secrets.traefikEnv.path];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
networking.firewall.allowedTCPPorts = [80 443];
|
||||||
|
|
||||||
|
services = {
|
||||||
|
tailscale.permitCertUid = "traefik";
|
||||||
|
traefik = {
|
||||||
|
enable = true;
|
||||||
|
|
||||||
|
staticConfigOptions = {
|
||||||
|
log = {
|
||||||
|
level = "DEBUG";
|
||||||
|
};
|
||||||
|
|
||||||
|
tracing = {};
|
||||||
|
api = {
|
||||||
|
dashboard = true;
|
||||||
|
};
|
||||||
|
certificatesResolvers = {
|
||||||
|
tailscale.tailscale = {};
|
||||||
|
letsencrypt = {
|
||||||
|
acme = {
|
||||||
|
email = "adam@cnst.dev";
|
||||||
|
storage = "/var/lib/traefik/cert.json";
|
||||||
|
dnsChallenge = {
|
||||||
|
provider = "cloudflare";
|
||||||
|
resolvers = [
|
||||||
|
"1.1.1.1:53"
|
||||||
|
"1.0.0.1:53"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
entryPoints = {
|
||||||
|
redis = {
|
||||||
|
address = "0.0.0.0:6381";
|
||||||
|
};
|
||||||
|
postgres = {
|
||||||
|
address = "0.0.0.0:5433";
|
||||||
|
};
|
||||||
|
web = {
|
||||||
|
address = "0.0.0.0:80";
|
||||||
|
http.redirections.entryPoint = {
|
||||||
|
to = "websecure";
|
||||||
|
scheme = "https";
|
||||||
|
permanent = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
websecure = {
|
||||||
|
address = "0.0.0.0:443";
|
||||||
|
http.tls = {
|
||||||
|
certResolver = "letsencrypt";
|
||||||
|
domains = [
|
||||||
|
{
|
||||||
|
main = "cnix.dev";
|
||||||
|
sans = ["*.cnix.dev"];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -5,20 +5,7 @@
|
|||||||
...
|
...
|
||||||
}: let
|
}: let
|
||||||
unit = "unbound";
|
unit = "unbound";
|
||||||
cfg = config.server.infra.${unit};
|
cfg = config.server.${unit};
|
||||||
srv = config.server;
|
|
||||||
|
|
||||||
svcNames = lib.attrNames srv.services;
|
|
||||||
|
|
||||||
localARecords = builtins.concatLists (map (
|
|
||||||
name: let
|
|
||||||
s = srv.services.${name};
|
|
||||||
in
|
|
||||||
if s != null && s.enable && s.subdomain != null
|
|
||||||
then [''"${s.subdomain}.${srv.domain}. A ${srv.ip}"'']
|
|
||||||
else []
|
|
||||||
)
|
|
||||||
svcNames);
|
|
||||||
|
|
||||||
hostIp = hostname:
|
hostIp = hostname:
|
||||||
if hostname == "ziggy"
|
if hostname == "ziggy"
|
||||||
@@ -27,12 +14,11 @@
|
|||||||
then "192.168.88.14"
|
then "192.168.88.14"
|
||||||
else throw "No IP defined for host ${hostname}";
|
else throw "No IP defined for host ${hostname}";
|
||||||
in {
|
in {
|
||||||
options.server.infra.${unit} = {
|
options.server.${unit} = {
|
||||||
enable = lib.mkEnableOption {
|
enable = lib.mkEnableOption {
|
||||||
description = "Enable ${unit}";
|
description = "Enable ${unit}";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config = lib.mkIf cfg.enable {
|
config = lib.mkIf cfg.enable {
|
||||||
services = {
|
services = {
|
||||||
# resolved.enable = lib.mkForce false;
|
# resolved.enable = lib.mkForce false;
|
||||||
@@ -111,11 +97,6 @@ in {
|
|||||||
"255.255.255.255/32"
|
"255.255.255.255/32"
|
||||||
"2001:db8::/32"
|
"2001:db8::/32"
|
||||||
];
|
];
|
||||||
local-data =
|
|
||||||
[
|
|
||||||
''"traefik.${config.settings.accounts.domains.local}. A 192.168.88.14"''
|
|
||||||
]
|
|
||||||
++ localARecords;
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
62
modules/server/uptime-kuma/default.nix
Normal file
62
modules/server/uptime-kuma/default.nix
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}: let
|
||||||
|
unit = "uptime-kuma";
|
||||||
|
cfg = config.server.${unit};
|
||||||
|
srv = config.server;
|
||||||
|
in {
|
||||||
|
options.server.${unit} = {
|
||||||
|
enable = lib.mkEnableOption {
|
||||||
|
description = "Enable ${unit}";
|
||||||
|
};
|
||||||
|
configDir = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "/var/lib/uptime-kuma";
|
||||||
|
};
|
||||||
|
url = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "uptime.${srv.domain}";
|
||||||
|
};
|
||||||
|
homepage.name = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "Uptime Kuma";
|
||||||
|
};
|
||||||
|
homepage.description = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "Service monitoring tool";
|
||||||
|
};
|
||||||
|
homepage.icon = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "uptime-kuma.svg";
|
||||||
|
};
|
||||||
|
homepage.category = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "Services";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
config = lib.mkIf cfg.enable {
|
||||||
|
services = {
|
||||||
|
${unit} = {
|
||||||
|
enable = true;
|
||||||
|
};
|
||||||
|
traefik = {
|
||||||
|
dynamicConfigOptions = {
|
||||||
|
http = {
|
||||||
|
services.uptime-kuma.loadBalancer.servers = [{url = "http://127.0.0.1:3001";}];
|
||||||
|
routers = {
|
||||||
|
uptime-kuma = {
|
||||||
|
entryPoints = ["websecure"];
|
||||||
|
rule = "Host(`${cfg.url}`)";
|
||||||
|
service = "uptime-kuma";
|
||||||
|
tls.certResolver = "letsencrypt";
|
||||||
|
# middlewares = ["authentik"];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
89
modules/server/vaultwarden/default.nix
Normal file
89
modules/server/vaultwarden/default.nix
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
# from @fufexan & @notthebee
|
||||||
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
self,
|
||||||
|
...
|
||||||
|
}: let
|
||||||
|
inherit (lib) mkIf mkEnableOption;
|
||||||
|
vcfg = config.services.vaultwarden.config;
|
||||||
|
cfg = config.server.vaultwarden;
|
||||||
|
in {
|
||||||
|
options = {
|
||||||
|
server.vaultwarden = {
|
||||||
|
enable = mkEnableOption "Enables vaultwarden";
|
||||||
|
url = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "${cfg.domain}";
|
||||||
|
};
|
||||||
|
cloudflared = {
|
||||||
|
credentialsFile = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
example = lib.literalExpression ''
|
||||||
|
pkgs.writeText "cloudflare-credentials.json" '''
|
||||||
|
{"AccountTag":"secret"."TunnelSecret":"secret","TunnelID":"secret"}
|
||||||
|
'''
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
tunnelId = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
example = "00000000-0000-0000-0000-000000000000";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkIf cfg.enable {
|
||||||
|
age.secrets = {
|
||||||
|
vaultwardenCloudflared.file = "${self}/secrets/vaultwardenCloudflared.age";
|
||||||
|
vaultwardenEnvironment.file = "${self}/secrets/vaultwardenEnvironment.age";
|
||||||
|
};
|
||||||
|
|
||||||
|
server = {
|
||||||
|
fail2ban = lib.mkIf config.server.fail2ban.enable {
|
||||||
|
jails = {
|
||||||
|
vaultwarden = {
|
||||||
|
serviceName = "vaultwarden";
|
||||||
|
failRegex = "^.*Username or password is incorrect. Try again. IP: <HOST>. Username: <F-USER>.*</F-USER>.$";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.services.backup-vaultwarden.serviceConfig = {
|
||||||
|
User = "root";
|
||||||
|
Group = "root";
|
||||||
|
};
|
||||||
|
|
||||||
|
services = {
|
||||||
|
vaultwarden = {
|
||||||
|
enable = true;
|
||||||
|
environmentFile = config.age.secrets.vaultwardenEnvironment.path;
|
||||||
|
|
||||||
|
backupDir = "/var/backup/vaultwarden";
|
||||||
|
|
||||||
|
config = {
|
||||||
|
DOMAIN = "https://${cfg.url}";
|
||||||
|
SIGNUPS_ALLOWED = false;
|
||||||
|
ROCKET_ADDRESS = "127.0.0.1";
|
||||||
|
ROCKET_PORT = 8222;
|
||||||
|
IP_HEADER = "CF-Connecting-IP";
|
||||||
|
|
||||||
|
logLevel = "warn";
|
||||||
|
extendedLogging = true;
|
||||||
|
useSyslog = true;
|
||||||
|
invitationsAllowed = false;
|
||||||
|
showPasswordHint = false;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
cloudflared = {
|
||||||
|
enable = true;
|
||||||
|
tunnels.${cfg.cloudflared.tunnelId} = {
|
||||||
|
credentialsFile = cfg.cloudflared.credentialsFile;
|
||||||
|
default = "http_status:404";
|
||||||
|
ingress."${cfg.url}".service = "http://${vcfg.ROCKET_ADDRESS}:${toString vcfg.ROCKET_PORT}";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,13 +1,15 @@
|
|||||||
{
|
{
|
||||||
lib,
|
lib,
|
||||||
config,
|
config,
|
||||||
|
pkgs,
|
||||||
self,
|
self,
|
||||||
...
|
...
|
||||||
}: let
|
}: let
|
||||||
inherit (lib) mkIf mkEnableOption mkOption types;
|
inherit (lib) mkOption mkEnableOption mkIf types;
|
||||||
cfg = config.server.infra.www;
|
cfg = config.server.www;
|
||||||
|
srv = config.server;
|
||||||
in {
|
in {
|
||||||
options.server.infra.www = {
|
options.server.www = {
|
||||||
enable = mkEnableOption {
|
enable = mkEnableOption {
|
||||||
description = "Enable personal website";
|
description = "Enable personal website";
|
||||||
};
|
};
|
||||||
@@ -18,12 +20,6 @@ in {
|
|||||||
Public domain name to be used to access the server services via Traefik reverse proxy
|
Public domain name to be used to access the server services via Traefik reverse proxy
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
port = lib.mkOption {
|
|
||||||
type = lib.types.int;
|
|
||||||
default = 8283;
|
|
||||||
description = "The port to host webservice on.";
|
|
||||||
};
|
|
||||||
|
|
||||||
cloudflared = {
|
cloudflared = {
|
||||||
credentialsFile = lib.mkOption {
|
credentialsFile = lib.mkOption {
|
||||||
type = lib.types.str;
|
type = lib.types.str;
|
||||||
@@ -45,14 +41,12 @@ in {
|
|||||||
wwwCloudflared.file = "${self}/secrets/wwwCloudflared.age";
|
wwwCloudflared.file = "${self}/secrets/wwwCloudflared.age";
|
||||||
};
|
};
|
||||||
|
|
||||||
server.infra = {
|
server = {
|
||||||
fail2ban = {
|
fail2ban = lib.mkIf config.server.www.enable {
|
||||||
jails = {
|
jails = {
|
||||||
nginx-404 = {
|
www = {
|
||||||
serviceName = "nginx";
|
serviceName = "cnst.dev";
|
||||||
failRegex = ''^.*\[error\].*directory index of.* is forbidden.*client: <HOST>.*$'';
|
failRegex = "^.*Username or password is incorrect. Try again. IP: <HOST>. Username: <F-USER>.*</F-USER>.$";
|
||||||
ignoreRegex = '''';
|
|
||||||
maxRetry = 5;
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -70,23 +64,14 @@ in {
|
|||||||
virtualHosts."webfinger" = {
|
virtualHosts."webfinger" = {
|
||||||
forceSSL = false;
|
forceSSL = false;
|
||||||
serverName = cfg.url;
|
serverName = cfg.url;
|
||||||
root = "/var/www/webfinger";
|
root = "/etc/webfinger";
|
||||||
|
|
||||||
locations."= /.well-known/webfinger" = {
|
locations."= /.well-known/webfinger" = {
|
||||||
root = "/var/www/webfinger";
|
root = "/etc/webfinger";
|
||||||
extraConfig = ''
|
extraConfig = ''
|
||||||
default_type application/jrd+json;
|
default_type application/jrd+json;
|
||||||
try_files /.well-known/webfinger =404;
|
try_files /.well-known/webfinger =404;
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
locations."= /robots.txt" = {
|
|
||||||
root = "/var/www/webfinger";
|
|
||||||
extraConfig = ''
|
|
||||||
default_type text/plain;
|
|
||||||
try_files /robots.txt =404;
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -100,8 +85,7 @@ in {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
environment.etc = {
|
environment.etc."webfinger/.well-known/webfinger".text = ''
|
||||||
"webfinger/.well-known/webfinger".text = ''
|
|
||||||
{
|
{
|
||||||
"subject": "acct:adam@${cfg.url}",
|
"subject": "acct:adam@${cfg.url}",
|
||||||
"links": [
|
"links": [
|
||||||
@@ -113,12 +97,6 @@ in {
|
|||||||
}
|
}
|
||||||
'';
|
'';
|
||||||
|
|
||||||
"webfinger/robots.txt".text = ''
|
|
||||||
User-agent: *
|
|
||||||
Disallow: /
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
services.traefik.dynamicConfigOptions.http = {
|
services.traefik.dynamicConfigOptions.http = {
|
||||||
routers.webfinger = {
|
routers.webfinger = {
|
||||||
entryPoints = ["websecure"];
|
entryPoints = ["websecure"];
|
||||||
@@ -2,7 +2,8 @@
|
|||||||
lib,
|
lib,
|
||||||
config,
|
config,
|
||||||
...
|
...
|
||||||
}: let
|
}:
|
||||||
|
let
|
||||||
inherit (lib) mkOption types;
|
inherit (lib) mkOption types;
|
||||||
|
|
||||||
sshKeys = {
|
sshKeys = {
|
||||||
@@ -15,14 +16,14 @@
|
|||||||
keyName = config.settings.accounts.sshUser or null;
|
keyName = config.settings.accounts.sshUser or null;
|
||||||
|
|
||||||
selectedKey =
|
selectedKey =
|
||||||
if keyName != null
|
if keyName != null then
|
||||||
then
|
|
||||||
lib.attrByPath [
|
lib.attrByPath [
|
||||||
keyName
|
keyName
|
||||||
] (builtins.abort "No SSH key defined for hostname/key '${toString keyName}'")
|
] (builtins.abort "No SSH key defined for hostname/key '${toString keyName}'") sshKeys
|
||||||
sshKeys
|
else
|
||||||
else builtins.abort "No accounts.sshUser provided, cannot select SSH key.";
|
builtins.abort "No accounts.sshUser provided, cannot select SSH key.";
|
||||||
in {
|
in
|
||||||
|
{
|
||||||
options.settings.accounts = {
|
options.settings.accounts = {
|
||||||
username = mkOption {
|
username = mkOption {
|
||||||
type = types.str;
|
type = types.str;
|
||||||
@@ -45,21 +46,5 @@ in {
|
|||||||
default = null;
|
default = null;
|
||||||
description = "Optional override for selecting an SSH key by name";
|
description = "Optional override for selecting an SSH key by name";
|
||||||
};
|
};
|
||||||
domains = lib.mkOption {
|
|
||||||
type = lib.types.submodule {
|
|
||||||
options = {
|
|
||||||
local = lib.mkOption {
|
|
||||||
type = lib.types.str;
|
|
||||||
default = "127.0.0.1";
|
|
||||||
description = "The local domain of the host";
|
|
||||||
};
|
|
||||||
public = lib.mkOption {
|
|
||||||
type = lib.types.str;
|
|
||||||
default = "example.com";
|
|
||||||
description = "The public domain of the host";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,8 +21,8 @@ in
|
|||||||
example = 1080;
|
example = 1080;
|
||||||
};
|
};
|
||||||
refreshRate = mkOption {
|
refreshRate = mkOption {
|
||||||
type = types.str;
|
type = types.int;
|
||||||
default = "60";
|
default = 60;
|
||||||
};
|
};
|
||||||
transform = mkOption {
|
transform = mkOption {
|
||||||
type = types.int;
|
type = types.int;
|
||||||
|
|||||||
@@ -4,8 +4,5 @@
|
|||||||
allowUnfree = true;
|
allowUnfree = true;
|
||||||
input-fonts.acceptLicense = true;
|
input-fonts.acceptLicense = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
overlays = [
|
|
||||||
];
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,9 @@
|
|||||||
"aarch64-linux"
|
"aarch64-linux"
|
||||||
];
|
];
|
||||||
|
|
||||||
perSystem = {pkgs, ...}: {
|
perSystem =
|
||||||
|
{ pkgs, ... }:
|
||||||
|
{
|
||||||
packages = {
|
packages = {
|
||||||
# instant repl with automatic flake loading
|
# instant repl with automatic flake loading
|
||||||
repl = pkgs.callPackage ./repl { };
|
repl = pkgs.callPackage ./repl { };
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
age-encryption.org/v1
|
|
||||||
-> ssh-ed25519 t9iOEg lf7aPbZX2v3WGzE/KI/069DBObphqrDtjq7rhNriGl8
|
|
||||||
Vv+Pqk6DbcE5R1A9135gVKroCex1xKsCLPETZdT3yTg
|
|
||||||
-> ssh-ed25519 KUYMFA XxtBSmCwrQCZ9G3VcCrbzTdMshTK1pjlHPYj7fke818
|
|
||||||
9tO2EcnHPD6v3TNeuZdL+zP39SM5R5q7om5sCFDB8lg
|
|
||||||
-> ssh-ed25519 76RhUQ I6O/fYFRqYxExC9uLijZr6/kFze7uze0cIudCsl2jTo
|
|
||||||
WAwb822vVj5UtUAdE1oVJ0/q6nQbWqdx0OHuGEogO7M
|
|
||||||
-> ssh-ed25519 Jf8sqw gWBoe4HhXNw7Ih58lQ/L2vBoQfbU1ht8+ZSLUx/4TWk
|
|
||||||
xor0ieJ2UI5bK4rSlCM0dX61PVbxYE37FNry0YSmHG4
|
|
||||||
--- Cp8b3eTb3NfjPFvBE12a2c+Yni2jW6DZUK10IaXmmvo
|
|
||||||
w<EFBFBD>xq<EFBFBD><EFBFBD>z:<3A>.{<7B>?<3F><><EFBFBD>f<EFBFBD><66><1D><><16><>A<EFBFBD>jT<6A><54>{<7B>J <20><>
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
age-encryption.org/v1
|
|
||||||
-> ssh-ed25519 t9iOEg RnlIwFO8LSwzj94G0Uru9qibXqOOpCU2kWWdNa2tRFU
|
|
||||||
lIC3K/jjBMKRfLfepoNYIkBe5rhHuR0l3Uf1Xuk8uZg
|
|
||||||
-> ssh-ed25519 KUYMFA k16GBRcaaSwJm/8+Vm2QBOu05u6eEro/7YYj7kbuNSU
|
|
||||||
VCpt918MBBFfFZKKypV9pSwz/Zhsxr+Ob6YjFuJ/oL0
|
|
||||||
-> ssh-ed25519 76RhUQ FIKn3nuOT1ywu6pmYBbpC54HhpJGeMFejp5c0XibfAY
|
|
||||||
WDsh/5G4wXYt21yIDxmI6u1l/xPOdZRxgTazf6QLXP8
|
|
||||||
-> ssh-ed25519 Jf8sqw 2EvD96Ec8h97ACoOBYzn1Ugx4ZyYSHIRnsmtB5lb/XQ
|
|
||||||
mFY8O8qwWWihsLe5ayB5iGm1JUY2B/9el/XSf5sPe7M
|
|
||||||
--- uuwibRk7LS4/lUx9gwL+x5NMrxLjGM1Yf55bzjxQTKM
|
|
||||||
<EFBFBD>H<>Ԅ6K<36>A<01>~<7E><>)!B<08><>^S!Wd<><64>$.:S'c<>d<EFBFBD><64><EFBFBD>_WW<57>Bj<42>,<2C><>l<EFBFBD><6C><EFBFBD><EFBFBD><EFBFBD>V<>S<EFBFBD><53>h<EFBFBD>
|
|
||||||
h<EFBFBD><EFBFBD><12><>k
|
|
||||||
Binary file not shown.
@@ -1,11 +0,0 @@
|
|||||||
age-encryption.org/v1
|
|
||||||
-> ssh-ed25519 t9iOEg MLi7IOM8QlpvlCMSmo4SwZbTwZ9pyysSbiMMuWD/dyU
|
|
||||||
cotV5TJf7oyyXIaAmu8n9Ie1rl27i8w7hsduwtQFnis
|
|
||||||
-> ssh-ed25519 KUYMFA BhFQ/RXOH8L7gl/FSabAUv28fbaod+muvTGSV3rYQSs
|
|
||||||
fWqwAkhSAmg6YB+yEtj0e83Q4XO/r+TBnMTN7vXBNqU
|
|
||||||
-> ssh-ed25519 76RhUQ b1fDfGPNdJ9c3wtr8ww0mW5K4fKJxpxxTZy/ZCECWzs
|
|
||||||
qhbvucUrv7dzOPKUmUaRs/AtXtwQfy/qp5HnaYzZ5eQ
|
|
||||||
-> ssh-ed25519 Jf8sqw 19D2ztjyxJfGQAiUOTdgWyC0ZFso/wrC9VPEkmI34U8
|
|
||||||
PavT5O8M6Zc2Num9Hb2sY+F3UmMPqRgjUZxuvP6AhyM
|
|
||||||
--- uYOcbsL7JWoDF2mRUDLhXrbp6ssLFbQ9+a6RhAXNNPA
|
|
||||||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD> X<><58>PC<50><43>h<EFBFBD>;
|
|
||||||
11
secrets/nginxEnv.age
Normal file
11
secrets/nginxEnv.age
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
age-encryption.org/v1
|
||||||
|
-> ssh-ed25519 t9iOEg pfPhWigjvnJ5tfVv8qPpk3VYvLH9I01HVVbpu+r2NjY
|
||||||
|
Kaj8aZv+9pSYjwoE7EHWGHfsZIPFZOgUVaKf8VxWKcQ
|
||||||
|
-> ssh-ed25519 KUYMFA 9Xy82Cl3HUQcFDcJMxxnnIfLOngW8xLfVE0S1wRliGg
|
||||||
|
mOOcyJp5+ZqFwdkZkHC63+cMA0ToGcuI6kqMjAJ9jJk
|
||||||
|
-> ssh-ed25519 76RhUQ +OvUSQwpy6+xxlom8bJFn8CBdSKECa9YY0U+YYNYdGM
|
||||||
|
MWfmfGzd6/lOPvggUG8uJgBAp1CTqSdk+NDkk7vSQEQ
|
||||||
|
-> ssh-ed25519 Jf8sqw jQR/wT/+f63cJdFzR/Ogw6pdiYXoyVNu1+UCni2BYSM
|
||||||
|
Iicwg/XJJskvWFmAbxFDh3gSJyjid5fw9JXmDJPhzkU
|
||||||
|
--- xK8vBWioTgSDPHkKh7SJxstCzYtUSmTz6QuN/+niFME
|
||||||
|
<08><>f<<3C>`VR<56><52>p<><70>)>|<7C>+aئI<D8A6>g<08><0B><><EFBFBD><EFBFBD><EFBFBD><19><>x<EFBFBD><78>HH+<2B>緭<EFBFBD><E7B7AD>o>$4H<><48><EFBFBD>缂<EFBFBD>B?<3F>l6TSqμ<71>Ǿ<EFBFBD><C7BE>Kj-l
|
||||||
@@ -48,7 +48,6 @@ in {
|
|||||||
"homepageEnvironment.age".publicKeys = kima ++ sobotka;
|
"homepageEnvironment.age".publicKeys = kima ++ sobotka;
|
||||||
"cloudflareFirewallApiKey.age".publicKeys = kima ++ sobotka;
|
"cloudflareFirewallApiKey.age".publicKeys = kima ++ sobotka;
|
||||||
"vaultwardenCloudflared.age".publicKeys = kima ++ sobotka;
|
"vaultwardenCloudflared.age".publicKeys = kima ++ sobotka;
|
||||||
"giteaCloudflared.age".publicKeys = kima ++ sobotka;
|
|
||||||
"nextcloudCloudflared.age".publicKeys = kima ++ sobotka;
|
"nextcloudCloudflared.age".publicKeys = kima ++ sobotka;
|
||||||
"nextcloudAdminPass.age".publicKeys = kima ++ sobotka;
|
"nextcloudAdminPass.age".publicKeys = kima ++ sobotka;
|
||||||
"cloudflareDnsApiToken.age".publicKeys = kima ++ sobotka;
|
"cloudflareDnsApiToken.age".publicKeys = kima ++ sobotka;
|
||||||
@@ -62,9 +61,6 @@ in {
|
|||||||
"traefikEnv.age".publicKeys = kima ++ sobotka;
|
"traefikEnv.age".publicKeys = kima ++ sobotka;
|
||||||
"wwwCloudflared.age".publicKeys = kima ++ sobotka;
|
"wwwCloudflared.age".publicKeys = kima ++ sobotka;
|
||||||
"authentikCloudflared.age".publicKeys = kima ++ sobotka;
|
"authentikCloudflared.age".publicKeys = kima ++ sobotka;
|
||||||
"sobotkaTsAuth.age".publicKeys = kima ++ sobotka;
|
|
||||||
"mikrotikSecret.age".publicKeys = kima ++ sobotka;
|
|
||||||
"crowdsecApi.age".publicKeys = kima ++ sobotka;
|
|
||||||
|
|
||||||
# Ziggy-specific
|
# Ziggy-specific
|
||||||
"cloudflareDnsCredentialsZiggy.age".publicKeys = kima ++ ziggy;
|
"cloudflareDnsCredentialsZiggy.age".publicKeys = kima ++ ziggy;
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
age-encryption.org/v1
|
|
||||||
-> ssh-ed25519 t9iOEg fftdt8orBZoM0sDRAXf0TScDLosNWWWIg7JmmuunuWM
|
|
||||||
2IfpTH6ptSyLnBtBStkk7SINct6LtBHrL6h22BVNb+k
|
|
||||||
-> ssh-ed25519 KUYMFA HI04mnVOGPRsRhnqCkbO4My/sBq5v/3UYxDVcfIe4RM
|
|
||||||
fcSApUYCnJlpzVW5e77CFoSHamEmP+6ztMmzp2WlJvY
|
|
||||||
-> ssh-ed25519 76RhUQ c2FbmTXGl/F+1acZFEJUoenkxiIGdoXkT67VgxvoFHg
|
|
||||||
eWExqblEp5VIeXuPEuvj4QAIWtFX5KLfMyh6/fZ9bnA
|
|
||||||
-> ssh-ed25519 Jf8sqw IAcUf70EufTyjsva8XIlXOfPxwXvtr9AFl0LwrdAMgc
|
|
||||||
bY098fejLaFbUMX0iF89gz8kiOGZHI8JIg4NzX4ItFw
|
|
||||||
--- WNqpLyRM2EqISbZky++NbKLw4GCEgwbz2O5+VO7aKzE
|
|
||||||
<EFBFBD><EFBFBD><1A><>(5<0F>q <09><>m<EFBFBD>C<EFBFBD><43>G<EFBFBD>r<><72><16><><EFBFBD><EFBFBD>ޒ3<DE92><33><17><1F>7<><37><EFBFBD>rG<72>i<EFBFBD>c7<63>i<EFBFBD>P<EFBFBD><50>l<EFBFBD><19>7<EFBFBD><<3C>r?cGo<47>^ǚ<>W<0E>V<EFBFBD><56>f,2<>Qg!<21>t_<74>
|
|
||||||
Binary file not shown.
Reference in New Issue
Block a user