Compare commits
50 Commits
1d2f934c98
...
monitors
| Author | SHA1 | Date | |
|---|---|---|---|
| b1a4574f17 | |||
| 3d8deae6f3 | |||
| cd978f5eb6 | |||
| 64df7abad5 | |||
| 8efa649d47 | |||
| 2dc09e23a0 | |||
| 8fd2a7d9ad | |||
| 113892b75d | |||
| 001dfbf27f | |||
| 3deca06206 | |||
| 07333b4544 | |||
| 63f495fa0d | |||
| d2bd385367 | |||
| 57cb48a11c | |||
| 6b7ca2b194 | |||
| e578a280db | |||
| 01ca3d7ebe | |||
| 46aa5a9deb | |||
| 549037fe69 | |||
| 0cb6862dcd | |||
| 9e4454ff57 | |||
| 15a20dd8e0 | |||
| 3306598f8a | |||
| 93f227ba7e | |||
| 9d20eff7f9 | |||
| 94d3f2ad35 | |||
| 1d5bc22274 | |||
| f2386a851e | |||
| c9edc99a85 | |||
| 67e83e3e4e | |||
| 923c810972 | |||
| 6ab35f4e91 | |||
| 593f0e619c | |||
| 688e23d229 | |||
| 725a3ed27e | |||
| e45dc0d223 | |||
| bc78dd7302 | |||
| 94c34f8675 | |||
| fda7d972c4 | |||
| f6bb6672bb | |||
| 68f1cb9b09 | |||
| e721a2088b | |||
| 551a47989c | |||
| 2cb07c45a7 | |||
| 4666731676 | |||
| 8fe6382c48 | |||
| 068f47e9a2 | |||
| 27bd976a60 | |||
| 9adfb329af | |||
| 757c3081fd |
398
flake.lock
generated
398
flake.lock
generated
@@ -8,11 +8,11 @@
|
||||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1754433428,
|
||||
"narHash": "sha256-NA/FT2hVhKDftbHSwVnoRTFhes62+7dxZbxj5Gxvghs=",
|
||||
"lastModified": 1760836749,
|
||||
"narHash": "sha256-wyT7Pl6tMFbFrs8Lk/TlEs81N6L+VSybPfiIgzU8lbQ=",
|
||||
"owner": "ryantm",
|
||||
"repo": "agenix",
|
||||
"rev": "9edb1787864c4f59ae5074ad498b6272b3ec308d",
|
||||
"rev": "2f0f812f69f3eb4140157fe15e12739adf82e32a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -23,16 +23,17 @@
|
||||
},
|
||||
"anyrun": {
|
||||
"inputs": {
|
||||
"anyrun-provider": "anyrun-provider",
|
||||
"flake-parts": "flake-parts",
|
||||
"nixpkgs": "nixpkgs_2",
|
||||
"systems": "systems_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1758121794,
|
||||
"narHash": "sha256-IlnFA/a9Clgbt+FuavIKWtauhtH4Fo/rGJIjJDDeYRs=",
|
||||
"lastModified": 1760083914,
|
||||
"narHash": "sha256-I9IMO9d+z71oeqOz6gOre07tK2Du3vp2FcOW3x4FDXw=",
|
||||
"owner": "anyrun-org",
|
||||
"repo": "anyrun",
|
||||
"rev": "c787318f590102b68fbd2e5b02ea47e96f4ecb62",
|
||||
"rev": "3050aa30e25957bbb9e1ac91a44d3979eccadf59",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -41,6 +42,27 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"anyrun-provider": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"anyrun",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1758817837,
|
||||
"narHash": "sha256-J3Jl4Z8SJHj+ogyohPeypT5LmQtCupdBteFezwiEZ9E=",
|
||||
"owner": "anyrun-org",
|
||||
"repo": "anyrun-provider",
|
||||
"rev": "b20650aa1bf80ae86b5bf5253d21fc0ddb7985c7",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "anyrun-org",
|
||||
"repo": "anyrun-provider",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"aquamarine": {
|
||||
"inputs": {
|
||||
"hyprutils": [
|
||||
@@ -61,11 +83,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1755946532,
|
||||
"narHash": "sha256-POePremlUY5GyA1zfbtic6XLxDaQcqHN6l+bIxdT5gc=",
|
||||
"lastModified": 1759499898,
|
||||
"narHash": "sha256-UNzYHLWfkSzLHDep5Ckb5tXc0fdxwPIrT+MY4kpQttM=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "aquamarine",
|
||||
"rev": "81584dae2df6ac79f6b6dae0ecb7705e95129ada",
|
||||
"rev": "655e067f96fd44b3f5685e17f566b0e4d535d798",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -92,11 +114,11 @@
|
||||
"uv2nix": "uv2nix"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1758177015,
|
||||
"narHash": "sha256-PCUWdbaxayY3YfSjVlyddBMYoGvSaRysd5AmZ8gqSFs=",
|
||||
"lastModified": 1759322529,
|
||||
"narHash": "sha256-yiv/g/tiJI3PI95F7vhTnaf1TDsIkFLrmmFTjWfb6pQ=",
|
||||
"owner": "nix-community",
|
||||
"repo": "authentik-nix",
|
||||
"rev": "4c626ed84cc0f1278bfba0f534efd6cba2788d75",
|
||||
"rev": "69fac057b2e553ee17c9a09b822d735823d65a6c",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -108,16 +130,16 @@
|
||||
"authentik-src": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1758035356,
|
||||
"narHash": "sha256-DkvxDwHCfSqEpZ9rRXNR8MP0Mz/y1kHAr38exrHQ39c=",
|
||||
"lastModified": 1759190535,
|
||||
"narHash": "sha256-pIzDaoDWc58cY/XhsyweCwc4dfRvkaT/zqsV1gDSnCI=",
|
||||
"owner": "goauthentik",
|
||||
"repo": "authentik",
|
||||
"rev": "680feaefa17934471a6b33ebc35caf5b64120404",
|
||||
"rev": "8d3a289d12c7de2f244c76493af7880f70d08af2",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "goauthentik",
|
||||
"ref": "version/2025.8.3",
|
||||
"ref": "version/2025.8.4",
|
||||
"repo": "authentik",
|
||||
"type": "github"
|
||||
}
|
||||
@@ -131,11 +153,11 @@
|
||||
"rust-overlay": "rust-overlay"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1758540151,
|
||||
"narHash": "sha256-5emcCJqkkpInzhyCGUXXcktPjNQInRHzCvHzP/2XspY=",
|
||||
"lastModified": 1760747305,
|
||||
"narHash": "sha256-SsuuyaFp4TbJ+ofti9EXot9gIOk4vZqccat/zERVQN4=",
|
||||
"owner": "chaotic-cx",
|
||||
"repo": "nyx",
|
||||
"rev": "c2bc079a4179295eee766d00b9ae264e68e13db9",
|
||||
"rev": "9838e14b30857ac0a50dbe98a5ba2233d6ccb2de",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -190,11 +212,11 @@
|
||||
"rust-analyzer-src": "rust-analyzer-src"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1758523473,
|
||||
"narHash": "sha256-8zsEI6eLilOSNQ9Mp6NL1XG7J7TQSqWB9Rsux0TCfqk=",
|
||||
"lastModified": 1760856120,
|
||||
"narHash": "sha256-yH1K/WDJpwIIw7e3wKdRgwHAZ38LXgcGE2Ecvk3I6GU=",
|
||||
"owner": "nix-community",
|
||||
"repo": "fenix",
|
||||
"rev": "2176d4c89be105a792122b66afc412dcce275b0d",
|
||||
"rev": "b435bfccee71c6591dbce2fcfabe3e17e98c09fa",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -290,11 +312,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1754487366,
|
||||
"narHash": "sha256-pHYj8gUBapuUzKV/kN/tR3Zvqc7o6gdFB9XKXIp1SQ8=",
|
||||
"lastModified": 1756770412,
|
||||
"narHash": "sha256-+uWLQZccFHwqpGqr2Yt5VsW/PbeJVTn9Dk6SHWhNRPw=",
|
||||
"owner": "hercules-ci",
|
||||
"repo": "flake-parts",
|
||||
"rev": "af66ad14b28a127c5c0f3bbb298218fc63528a18",
|
||||
"rev": "4524271976b625a4a605beefd893f270620fd751",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -310,11 +332,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1756770412,
|
||||
"narHash": "sha256-+uWLQZccFHwqpGqr2Yt5VsW/PbeJVTn9Dk6SHWhNRPw=",
|
||||
"lastModified": 1760813311,
|
||||
"narHash": "sha256-lbHQ7FXGzt6/IygWvJ1lCq+Txcut3xYYd6VIpF1ojkg=",
|
||||
"owner": "hercules-ci",
|
||||
"repo": "flake-parts",
|
||||
"rev": "4524271976b625a4a605beefd893f270620fd751",
|
||||
"rev": "4e627ac2e1b8f1de7f5090064242de9a259dbbc8",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -370,11 +392,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1756770412,
|
||||
"narHash": "sha256-+uWLQZccFHwqpGqr2Yt5VsW/PbeJVTn9Dk6SHWhNRPw=",
|
||||
"lastModified": 1759362264,
|
||||
"narHash": "sha256-wfG0S7pltlYyZTM+qqlhJ7GMw2fTF4mLKCIVhLii/4M=",
|
||||
"owner": "hercules-ci",
|
||||
"repo": "flake-parts",
|
||||
"rev": "4524271976b625a4a605beefd893f270620fd751",
|
||||
"rev": "758cf7296bee11f1706a574c77d072b8a7baa881",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -469,11 +491,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1758108966,
|
||||
"narHash": "sha256-ytw7ROXaWZ7OfwHrQ9xvjpUWeGVm86pwnEd1QhzawIo=",
|
||||
"lastModified": 1760663237,
|
||||
"narHash": "sha256-BflA6U4AM1bzuRMR8QqzPXqh8sWVCNDzOdsxXEguJIc=",
|
||||
"owner": "cachix",
|
||||
"repo": "git-hooks.nix",
|
||||
"rev": "54df955a695a84cd47d4a43e08e1feaf90b1fd9b",
|
||||
"rev": "ca5b894d3e3e151ffc1db040b6ce4dcc75d31c37",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -549,11 +571,11 @@
|
||||
},
|
||||
"hardware": {
|
||||
"locked": {
|
||||
"lastModified": 1757943327,
|
||||
"narHash": "sha256-w6cDExPBqbq7fTLo4dZ1ozDGeq3yV6dSN4n/sAaS6OM=",
|
||||
"lastModified": 1760106635,
|
||||
"narHash": "sha256-2GoxVaKWTHBxRoeUYSjv0AfSOx4qw5CWSFz2b+VolKU=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixos-hardware",
|
||||
"rev": "67a709cfe5d0643dafd798b0b613ed579de8be05",
|
||||
"rev": "9ed85f8afebf2b7478f25db0a98d0e782c0ed903",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -568,11 +590,11 @@
|
||||
"rust-overlay": "rust-overlay_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1758548657,
|
||||
"narHash": "sha256-Y4PRLA9vpgR6olcHrcdQcPjZ2ukb4L3xnS5xJLS+ugU=",
|
||||
"lastModified": 1760832569,
|
||||
"narHash": "sha256-wg925OdUZdhjJub5XfpBTWQ3EOJYH7JnaBWHfh849J4=",
|
||||
"owner": "helix-editor",
|
||||
"repo": "helix",
|
||||
"rev": "37fe42d05d4d65e0c8112a10cc40cfbdc95e8a3c",
|
||||
"rev": "97aee4950fd9a08a78415cd8992354ae5cf3aaf0",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -588,11 +610,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1758545873,
|
||||
"narHash": "sha256-0VP5cVd6DyibHNPC/IJ5Ut+KuNYUeKmr5ltzf+IcpjA=",
|
||||
"lastModified": 1760887455,
|
||||
"narHash": "sha256-/xU8iYZjolWbMUNBQF6af5zgGs73Qw21WMgz1tLs3Yw=",
|
||||
"owner": "nix-community",
|
||||
"repo": "home-manager",
|
||||
"rev": "de5369834ff1f75246c46be89ef993392e961c26",
|
||||
"rev": "aeabc1ac63e6ebb8ba4714c4abdfe0556f2de765",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -630,11 +652,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1758464306,
|
||||
"narHash": "sha256-i56XRXqjwJRdVYmpzVUQ0ktqBBHqNzQHQMQvFRF/acQ=",
|
||||
"lastModified": 1760662441,
|
||||
"narHash": "sha256-mlDqR1Ntgs9uYYEAUR1IhamKBO0lxoNS4zGLzEZaY0A=",
|
||||
"owner": "nix-community",
|
||||
"repo": "home-manager",
|
||||
"rev": "939e91e1cff1f99736c5b02529658218ed819a2a",
|
||||
"rev": "722792af097dff5790f1a66d271a47759f477755",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -688,11 +710,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1758192433,
|
||||
"narHash": "sha256-CR6RnqEJSTiFgA6KQY4TTLUWbZ8RBnb+hxQqesuQNzQ=",
|
||||
"lastModified": 1759490292,
|
||||
"narHash": "sha256-T6iWzDOXp8Wv0KQOCTHpBcmAOdHJ6zc/l9xaztW6Ivc=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprgraphics",
|
||||
"rev": "c44e749dd611521dee940d00f7c444ee0ae4cfb7",
|
||||
"rev": "9431db625cd9bb66ac55525479dce694101d6d7a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -717,11 +739,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1750621377,
|
||||
"narHash": "sha256-8u6b5oAdX0rCuoR8wFenajBRmI+mzbpNig6hSCuWUzE=",
|
||||
"lastModified": 1759490292,
|
||||
"narHash": "sha256-T6iWzDOXp8Wv0KQOCTHpBcmAOdHJ6zc/l9xaztW6Ivc=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprgraphics",
|
||||
"rev": "b3d628d01693fb9bb0a6690cd4e7b80abda04310",
|
||||
"rev": "9431db625cd9bb66ac55525479dce694101d6d7a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -781,11 +803,11 @@
|
||||
"xdph": "xdph"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1758542519,
|
||||
"narHash": "sha256-dAMZsDFYTSqPkBbQHvQoCCiyX7Z07nyPKThKq8yFq9c=",
|
||||
"lastModified": 1760874867,
|
||||
"narHash": "sha256-w2JettCPyqWKMYoJRCTc5/nsSvGrSV9jG4kbn8Q0pZk=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprland",
|
||||
"rev": "70a7047ee175d2e7fca1575d50a3738ac40fd2c6",
|
||||
"rev": "59ff7b2f891d06f4097128faf7027a3863542167",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -802,11 +824,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1758531979,
|
||||
"narHash": "sha256-iRv5afKzuu6SkwztqMwZ33161CzBJsyeRHp0uviN9TI=",
|
||||
"lastModified": 1759613406,
|
||||
"narHash": "sha256-PzgQJydp+RlKvwDi807pXPlURdIAVqLppZDga3DwPqg=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "contrib",
|
||||
"rev": "de79078fd59140067e53cd00ebdf17f96ce27846",
|
||||
"rev": "32e1a75b65553daefb419f0906ce19e04815aa3a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -920,11 +942,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1757694755,
|
||||
"narHash": "sha256-j+w5QUUr2QT/jkxgVKecGYV8J7fpzXCMgzEEr6LG9ug=",
|
||||
"lastModified": 1759080228,
|
||||
"narHash": "sha256-RgDoAja0T1hnF0pTc56xPfLfFOO8Utol2iITwYbUhTk=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprland-qtutils",
|
||||
"rev": "5ffdfc13ed03df1dae5084468d935f0a3f2c9a4c",
|
||||
"rev": "629b15c19fa4082e4ce6be09fdb89e8c3312aed7",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -949,11 +971,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1756810301,
|
||||
"narHash": "sha256-wgZ3VW4VVtjK5dr0EiK9zKdJ/SOqGIBXVG85C3LVxQA=",
|
||||
"lastModified": 1758927902,
|
||||
"narHash": "sha256-LZgMds7M94+vuMql2bERQ6LiFFdhgsEFezE4Vn+Ys3A=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprlang",
|
||||
"rev": "3d63fb4a42c819f198deabd18c0c2c1ded1de931",
|
||||
"rev": "4dafa28d4f79877d67a7d1a654cddccf8ebf15da",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -984,11 +1006,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1758124489,
|
||||
"narHash": "sha256-YiVF/8Me3vVKJBEgGpQhn0HF09EWfXZGaWLzAaJBrO4=",
|
||||
"lastModified": 1760023949,
|
||||
"narHash": "sha256-fu0B4duamVdbkPio/czu1XhsPLRXUJpZLDrSk3nih4U=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprlock",
|
||||
"rev": "7f769fa993cb492982d7bf25676c68ddbcc0268e",
|
||||
"rev": "36ec73f166d9434a3f27c96c575198906f77644a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -1022,11 +1044,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1754481642,
|
||||
"narHash": "sha256-e1phd6KwtUsS9C2ShD+fQvfk2Dgr2JQi+rTDQUW15iE=",
|
||||
"lastModified": 1760120448,
|
||||
"narHash": "sha256-l/OxM4q/nLVv47OuS4bG2J7k0m+G7/3AMtvrV64XLb0=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprpaper",
|
||||
"rev": "bcb1ffa322369c4898347ab5a7399a3d18494c8f",
|
||||
"rev": "1733e0025b194c9bc083f4cd8782c5f151858a58",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -1047,11 +1069,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1756117388,
|
||||
"narHash": "sha256-oRDel6pNl/T2tI+nc/USU9ZP9w08dxtl7hiZxa0C/Wc=",
|
||||
"lastModified": 1759619523,
|
||||
"narHash": "sha256-r1ed7AR2ZEb2U8gy321/Xcp1ho2tzn+gG1te/Wxsj1A=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprutils",
|
||||
"rev": "b2ae3204845f5f2f79b4703b441252d8ad2ecfd0",
|
||||
"rev": "3df7bde01efb3a3e8e678d1155f2aa3f19e177ef",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -1122,11 +1144,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1750371869,
|
||||
"narHash": "sha256-lGk4gLjgZQ/rndUkzmPYcgbHr8gKU5u71vyrjnwfpB4=",
|
||||
"lastModified": 1755184602,
|
||||
"narHash": "sha256-RCBQN8xuADB0LEgaKbfRqwm6CdyopE1xIEhNc67FAbw=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprwayland-scanner",
|
||||
"rev": "aa38edd6e3e277ae6a97ea83a69261a5c3aab9fd",
|
||||
"rev": "b3b0f1f40ae09d4447c20608e5a4faf8bf3c492d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -1169,11 +1191,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1757230583,
|
||||
"narHash": "sha256-4uqu7sFPOaVTCogsxaGMgbzZ2vK40GVGMfUmrvK3/LY=",
|
||||
"lastModified": 1760534924,
|
||||
"narHash": "sha256-OIOCC86DxTxp1VG7xAiM+YABtVqp6vTkYIoAiGQMqso=",
|
||||
"owner": "Jovian-Experiments",
|
||||
"repo": "Jovian-NixOS",
|
||||
"rev": "fc3960e6c32c9d4f95fff2ef84444284d24d3bea",
|
||||
"rev": "100b4e000032b865563a9754e5bca189bc544764",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -1207,11 +1229,11 @@
|
||||
},
|
||||
"mnw": {
|
||||
"locked": {
|
||||
"lastModified": 1756659871,
|
||||
"narHash": "sha256-v6Rh4aQ6RKjM2N02kK9Usn0Ix7+OY66vNpeklc1MnGE=",
|
||||
"lastModified": 1758834834,
|
||||
"narHash": "sha256-Y7IvY4F8vajZyp3WGf+KaiIVwondEkMFkt92Cr9NZmg=",
|
||||
"owner": "Gerg-L",
|
||||
"repo": "mnw",
|
||||
"rev": "ed6cc3e48557ba18266e598a5ebb6602499ada16",
|
||||
"rev": "cfbc7d1cc832e318d0863a5fc91d940a96034001",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -1246,62 +1268,6 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"niri": {
|
||||
"inputs": {
|
||||
"niri-stable": "niri-stable",
|
||||
"niri-unstable": "niri-unstable",
|
||||
"nixpkgs": "nixpkgs_8",
|
||||
"nixpkgs-stable": "nixpkgs-stable",
|
||||
"xwayland-satellite-stable": "xwayland-satellite-stable",
|
||||
"xwayland-satellite-unstable": "xwayland-satellite-unstable"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1758445565,
|
||||
"narHash": "sha256-eTC6gRzq1yXYy+HhDJ4IBdOvHCfTBRxMis6AdPCjxUQ=",
|
||||
"owner": "sodiboo",
|
||||
"repo": "niri-flake",
|
||||
"rev": "b98cd80e3bdd67a636291ce91953eec1c1b25dae",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "sodiboo",
|
||||
"repo": "niri-flake",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"niri-stable": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1756556321,
|
||||
"narHash": "sha256-RLD89dfjN0RVO86C/Mot0T7aduCygPGaYbog566F0Qo=",
|
||||
"owner": "YaLTeR",
|
||||
"repo": "niri",
|
||||
"rev": "01be0e65f4eb91a9cd624ac0b76aaeab765c7294",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "YaLTeR",
|
||||
"ref": "v25.08",
|
||||
"repo": "niri",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"niri-unstable": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1758370095,
|
||||
"narHash": "sha256-1/QacQbqle22hjwS1QjLlTpmIdSRYLKZ+NLHvo1r95E=",
|
||||
"owner": "YaLTeR",
|
||||
"repo": "niri",
|
||||
"rev": "6451d6be4f7046bd3d02bbe22dc50bb7b94235a5",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "YaLTeR",
|
||||
"repo": "niri",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nix-gaming": {
|
||||
"inputs": {
|
||||
"flake-parts": [
|
||||
@@ -1312,11 +1278,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1758420014,
|
||||
"narHash": "sha256-a7IGWXPRppgXMRpBosBl2Afr5DICt21ogeZL45uVkX0=",
|
||||
"lastModified": 1760839259,
|
||||
"narHash": "sha256-9KYm1Oh3jB2Xf0LiFxIBFgOuqRN4FNW4PKfrxXDV418=",
|
||||
"owner": "fufexan",
|
||||
"repo": "nix-gaming",
|
||||
"rev": "cd931e08409954b2e3595b1532039f8052dd8198",
|
||||
"rev": "6aa0613ecf363840e011006b05aefa094b78b053",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -1379,45 +1345,13 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs-stable": {
|
||||
"locked": {
|
||||
"lastModified": 1758346548,
|
||||
"narHash": "sha256-afXE7AJ7MY6wY1pg/Y6UPHNYPy5GtUKeBkrZZ/gC71E=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "b2a3852bd078e68dd2b3dfa8c00c67af1f0a7d20",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-25.05",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs_10": {
|
||||
"locked": {
|
||||
"lastModified": 1756696532,
|
||||
"narHash": "sha256-6FWagzm0b7I/IGigOv9pr6LL7NQ86mextfE8g8Q6HBg=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "58dcbf1ec551914c3756c267b8b9c8c86baa1b2f",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nixos",
|
||||
"ref": "nixpkgs-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs_2": {
|
||||
"locked": {
|
||||
"lastModified": 1755186698,
|
||||
"narHash": "sha256-wNO3+Ks2jZJ4nTHMuks+cxAiVBGNuEBXsT29Bz6HASo=",
|
||||
"lastModified": 1758690382,
|
||||
"narHash": "sha256-NY3kSorgqE5LMm1LqNwGne3ZLMF2/ILgLpFr1fS4X3o=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "fbcf476f790d8a217c3eab4e12033dc4a0f6d23c",
|
||||
"rev": "e643668fd71b949c53f8626614b21ff71a07379d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -1429,11 +1363,11 @@
|
||||
},
|
||||
"nixpkgs_3": {
|
||||
"locked": {
|
||||
"lastModified": 1758479131,
|
||||
"narHash": "sha256-KTCOYqnEUYSdk+DychTkXkOqgxYO2mLp9AzAw5mwAxA=",
|
||||
"lastModified": 1760703608,
|
||||
"narHash": "sha256-MMIIShabm9KnYTmm0WbJ2h+jxI86gfE7NcByVOaBNNU=",
|
||||
"owner": "PedroHLC",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "94700b18eb20d3ec71e3f6cd32e30d03648664ba",
|
||||
"rev": "95d8e5f411dc2fcc7f73a72766aaabfab1a1c456",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -1461,11 +1395,11 @@
|
||||
},
|
||||
"nixpkgs_5": {
|
||||
"locked": {
|
||||
"lastModified": 1740560979,
|
||||
"narHash": "sha256-Vr3Qi346M+8CjedtbyUevIGDZW8LcA1fTG0ugPY/Hic=",
|
||||
"lastModified": 1759381078,
|
||||
"narHash": "sha256-gTrEEp5gEspIcCOx9PD8kMaF1iEmfBcTbO0Jag2QhQs=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "5135c59491985879812717f4c9fea69604e7f26f",
|
||||
"rev": "7df7ff7d8e00218376575f0acdcc5d66741351ee",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -1477,11 +1411,11 @@
|
||||
},
|
||||
"nixpkgs_6": {
|
||||
"locked": {
|
||||
"lastModified": 1758198701,
|
||||
"narHash": "sha256-7To75JlpekfUmdkUZewnT6MoBANS0XVypW6kjUOXQwc=",
|
||||
"lastModified": 1759381078,
|
||||
"narHash": "sha256-gTrEEp5gEspIcCOx9PD8kMaF1iEmfBcTbO0Jag2QhQs=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "0147c2f1d54b30b5dd6d4a8c8542e8d7edf93b5d",
|
||||
"rev": "7df7ff7d8e00218376575f0acdcc5d66741351ee",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -1509,11 +1443,11 @@
|
||||
},
|
||||
"nixpkgs_8": {
|
||||
"locked": {
|
||||
"lastModified": 1758277210,
|
||||
"narHash": "sha256-iCGWf/LTy+aY0zFu8q12lK8KuZp7yvdhStehhyX1v8w=",
|
||||
"lastModified": 1760524057,
|
||||
"narHash": "sha256-EVAqOteLBFmd7pKkb0+FIUyzTF61VKi7YmvP1tw4nEw=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "8eaee110344796db060382e15d3af0a9fc396e0e",
|
||||
"rev": "544961dfcce86422ba200ed9a0b00dd4b1486ec5",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -1525,16 +1459,16 @@
|
||||
},
|
||||
"nixpkgs_9": {
|
||||
"locked": {
|
||||
"lastModified": 1758277210,
|
||||
"narHash": "sha256-iCGWf/LTy+aY0zFu8q12lK8KuZp7yvdhStehhyX1v8w=",
|
||||
"owner": "NixOS",
|
||||
"lastModified": 1759386674,
|
||||
"narHash": "sha256-wg1Lz/1FC5Q13R+mM5a2oTV9TA9L/CHHTm3/PiLayfA=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "8eaee110344796db060382e15d3af0a9fc396e0e",
|
||||
"rev": "625ad6366178f03acd79f9e3822606dd7985b657",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-unstable",
|
||||
"owner": "nixos",
|
||||
"ref": "nixpkgs-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
@@ -1544,15 +1478,15 @@
|
||||
"flake-compat": "flake-compat_5",
|
||||
"flake-parts": "flake-parts_5",
|
||||
"mnw": "mnw",
|
||||
"nixpkgs": "nixpkgs_10",
|
||||
"nixpkgs": "nixpkgs_9",
|
||||
"systems": "systems_5"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1758271661,
|
||||
"narHash": "sha256-ENqd2/33uP5vB44ClDjjAV+J78oF8q1er4QUZuT8Z7g=",
|
||||
"lastModified": 1760153667,
|
||||
"narHash": "sha256-F7KmXT/Izse6Q6CkD5GCImoGPaDJxl03Kd7eD+eY/bU=",
|
||||
"owner": "notashelf",
|
||||
"repo": "nvf",
|
||||
"rev": "b7571df4d6e9ac08506a738ddceeec0b141751b0",
|
||||
"rev": "9df9d51fd9fc8f9a8fc377f984ea3b7ae796172d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -1680,9 +1614,8 @@
|
||||
"hyprlock": "hyprlock",
|
||||
"hyprpaper": "hyprpaper",
|
||||
"lanzaboote": "lanzaboote",
|
||||
"niri": "niri",
|
||||
"nix-gaming": "nix-gaming",
|
||||
"nixpkgs": "nixpkgs_9",
|
||||
"nixpkgs": "nixpkgs_8",
|
||||
"nvf": "nvf",
|
||||
"systems": "systems_6",
|
||||
"treefmt-nix": "treefmt-nix",
|
||||
@@ -1693,11 +1626,11 @@
|
||||
"rust-analyzer-src": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1758437297,
|
||||
"narHash": "sha256-bfB1uXmAc8ECK5fj8YIMNvzukNdDS30J1zCKSAavg1c=",
|
||||
"lastModified": 1760714286,
|
||||
"narHash": "sha256-WOt9KquZ1BXjMcVyHpMeliqNRL6BfRvBHFGfRDriDx4=",
|
||||
"owner": "rust-lang",
|
||||
"repo": "rust-analyzer",
|
||||
"rev": "e7d7cb415a3cca2b09aae9c6bbe06d129a511cba",
|
||||
"rev": "1e20331e42449dfc0b44bce84147a06772d045d7",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -1715,11 +1648,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1758422215,
|
||||
"narHash": "sha256-JvF5SXhp1wBHbfEVAWgJCDVSO8iknfDqXfqMch5YWg0=",
|
||||
"lastModified": 1760668505,
|
||||
"narHash": "sha256-Ed0cGwPZtLRiSvMx4KgPx8bhLYzn5jiJ7s5o5vj4oG0=",
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"rev": "6f3988eb5885f1e2efa874a480d91de09a7f9f0b",
|
||||
"rev": "18234d2c11b10eaec9ccc3a1089a5ea872ec8858",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -1736,11 +1669,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1740623427,
|
||||
"narHash": "sha256-3SdPQrZoa4odlScFDUHd4CUPQ/R1gtH4Mq9u8CBiK8M=",
|
||||
"lastModified": 1759631821,
|
||||
"narHash": "sha256-V8A1L0FaU/aSXZ1QNJScxC12uP4hANeRBgI4YdhHeRM=",
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"rev": "d342e8b5fd88421ff982f383c853f0fc78a847ab",
|
||||
"rev": "1d7cbdaad90f8a5255a89a6eddd8af24dc89cafe",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -1882,11 +1815,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1758206697,
|
||||
"narHash": "sha256-/DbPkh6PZOgfueCbs3uzlk4ASU2nPPsiVWhpMCNkAd0=",
|
||||
"lastModified": 1760889407,
|
||||
"narHash": "sha256-ppIp04fmz+BaTpJs1nIOmPADg02asfQFrFbhb3SmxsE=",
|
||||
"owner": "numtide",
|
||||
"repo": "treefmt-nix",
|
||||
"rev": "128222dc911b8e2e18939537bed1762b7f3a04aa",
|
||||
"rev": "3f258dead9fed51f53862366d3a6bc1b622ee7cb",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -1983,39 +1916,6 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"xwayland-satellite-stable": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1755491097,
|
||||
"narHash": "sha256-m+9tUfsmBeF2Gn4HWa6vSITZ4Gz1eA1F5Kh62B0N4oE=",
|
||||
"owner": "Supreeeme",
|
||||
"repo": "xwayland-satellite",
|
||||
"rev": "388d291e82ffbc73be18169d39470f340707edaa",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "Supreeeme",
|
||||
"ref": "v0.7",
|
||||
"repo": "xwayland-satellite",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"xwayland-satellite-unstable": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1757179758,
|
||||
"narHash": "sha256-TIvyWzRt1miQj6Cf5Wy8Qz43XIZX7c4vTVwRLAT5S4Y=",
|
||||
"owner": "Supreeeme",
|
||||
"repo": "xwayland-satellite",
|
||||
"rev": "970728d0d9d1eada342bb8860af214b601139e58",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "Supreeeme",
|
||||
"repo": "xwayland-satellite",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"zen-browser": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
@@ -2023,11 +1923,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1757279270,
|
||||
"narHash": "sha256-q9XVkyORjd+5uZKuSbErz0nEzlKLR3TRwLtxPgkiJVI=",
|
||||
"lastModified": 1759969704,
|
||||
"narHash": "sha256-T7f/invcFIKHrBqD+FLf/C/HOGmpYfbZUzTDxFscpOA=",
|
||||
"ref": "refs/heads/main",
|
||||
"rev": "2a6161f5ef9c2c65ce1e324fa0d3e0adc12a9c95",
|
||||
"revCount": 130,
|
||||
"rev": "1173c777dc8daddcc4959260a7b00fd8abc884c5",
|
||||
"revCount": 137,
|
||||
"type": "git",
|
||||
"url": "https://git.sr.ht/~canasta/zen-browser-flake"
|
||||
},
|
||||
|
||||
@@ -144,8 +144,6 @@
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
|
||||
niri.url = "github:sodiboo/niri-flake";
|
||||
|
||||
# Custom
|
||||
tuirun = {
|
||||
url = "git+https://git.sr.ht/~canasta/tuirun";
|
||||
|
||||
@@ -73,8 +73,8 @@
|
||||
enable = false;
|
||||
};
|
||||
hyprland = {
|
||||
enable = false;
|
||||
withUWSM = false;
|
||||
enable = true;
|
||||
withUWSM = true;
|
||||
};
|
||||
inkscape = {
|
||||
enable = false;
|
||||
@@ -86,7 +86,7 @@
|
||||
enable = true;
|
||||
};
|
||||
niri = {
|
||||
enable = true;
|
||||
enable = false;
|
||||
};
|
||||
pkgs = {
|
||||
enable = true;
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
name = "DP-3";
|
||||
width = 2560;
|
||||
height = 1440;
|
||||
refreshRate = 240;
|
||||
refreshRate = "240";
|
||||
position = "0x0";
|
||||
transform = 0;
|
||||
bitDepth = 10;
|
||||
@@ -20,7 +20,7 @@
|
||||
name = "HDMI-A-1";
|
||||
width = 1920;
|
||||
height = 1080;
|
||||
refreshRate = 60;
|
||||
refreshRate = "60";
|
||||
position = "2560x0";
|
||||
# transform = 3;
|
||||
workspace = "5";
|
||||
@@ -29,7 +29,7 @@
|
||||
name = "eDP-1";
|
||||
width = 1920;
|
||||
height = 1200;
|
||||
refreshRate = 60;
|
||||
refreshRate = "60";
|
||||
workspace = "1";
|
||||
}
|
||||
];
|
||||
|
||||
@@ -4,9 +4,11 @@
|
||||
homeImports,
|
||||
self,
|
||||
...
|
||||
}: {
|
||||
flake.nixosConfigurations = let
|
||||
cLib = import ../lib inputs.nixpkgs.lib;
|
||||
}:
|
||||
{
|
||||
flake.nixosConfigurations =
|
||||
let
|
||||
clib = import ../lib inputs.nixpkgs.lib;
|
||||
userConfig = "${self}/home";
|
||||
systemConfig = "${self}/system";
|
||||
hostConfig = "${self}/hosts";
|
||||
@@ -22,7 +24,6 @@
|
||||
|
||||
specialArgs = {
|
||||
inherit
|
||||
cLib
|
||||
inputs
|
||||
outputs
|
||||
self
|
||||
@@ -35,16 +36,20 @@
|
||||
smodPath
|
||||
;
|
||||
};
|
||||
in {
|
||||
specialArgsWithClib = specialArgs // {
|
||||
inherit clib;
|
||||
};
|
||||
in
|
||||
{
|
||||
kima = nixosSystem {
|
||||
inherit specialArgs;
|
||||
specialArgs = specialArgsWithClib;
|
||||
modules = [
|
||||
./kima
|
||||
"${self}/nix"
|
||||
{
|
||||
home-manager = {
|
||||
users.cnst.imports = homeImports."cnst@kima";
|
||||
extraSpecialArgs = specialArgs;
|
||||
extraSpecialArgs = specialArgsWithClib;
|
||||
};
|
||||
}
|
||||
self.nixosModules.nixos
|
||||
@@ -54,14 +59,14 @@
|
||||
];
|
||||
};
|
||||
bunk = nixosSystem {
|
||||
inherit specialArgs;
|
||||
specialArgs = specialArgsWithClib;
|
||||
modules = [
|
||||
./bunk
|
||||
"${self}/nix"
|
||||
{
|
||||
home-manager = {
|
||||
users.cnst.imports = homeImports."cnst@bunk";
|
||||
extraSpecialArgs = specialArgs;
|
||||
extraSpecialArgs = specialArgsWithClib;
|
||||
};
|
||||
}
|
||||
self.nixosModules.nixos
|
||||
@@ -94,14 +99,14 @@
|
||||
];
|
||||
};
|
||||
toothpc = nixosSystem {
|
||||
inherit specialArgs;
|
||||
specialArgs = specialArgsWithClib;
|
||||
modules = [
|
||||
./toothpc
|
||||
"${self}/nix"
|
||||
{
|
||||
home-manager = {
|
||||
users.toothpick.imports = homeImports."toothpick@toothpc";
|
||||
extraSpecialArgs = specialArgs;
|
||||
extraSpecialArgs = specialArgsWithClib;
|
||||
};
|
||||
}
|
||||
self.nixosModules.nixos
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
variant = "latest";
|
||||
hardware = [ "amd" ];
|
||||
extraKernelParams = [ ];
|
||||
amdOverdrive.enable = true;
|
||||
};
|
||||
loader = {
|
||||
default = {
|
||||
@@ -28,6 +29,13 @@
|
||||
};
|
||||
network = {
|
||||
enable = true;
|
||||
nameservers = [
|
||||
"192.168.88.1"
|
||||
"192.168.88.69"
|
||||
];
|
||||
search = [
|
||||
"taila7448a.ts.net"
|
||||
];
|
||||
interfaces = {
|
||||
"eno1" = {
|
||||
allowedTCPPorts = [
|
||||
@@ -65,7 +73,7 @@
|
||||
};
|
||||
};
|
||||
gamescope = {
|
||||
enable = true;
|
||||
enable = false;
|
||||
};
|
||||
gimp = {
|
||||
enable = true;
|
||||
@@ -74,8 +82,8 @@
|
||||
enable = false;
|
||||
};
|
||||
hyprland = {
|
||||
enable = false;
|
||||
withUWSM = false;
|
||||
enable = true;
|
||||
withUWSM = true;
|
||||
};
|
||||
inkscape = {
|
||||
enable = false;
|
||||
@@ -90,7 +98,7 @@
|
||||
enable = true;
|
||||
};
|
||||
niri = {
|
||||
enable = true;
|
||||
enable = false;
|
||||
};
|
||||
pkgs = {
|
||||
enable = true;
|
||||
@@ -214,6 +222,9 @@
|
||||
scheduler = "scx_lavd";
|
||||
flags = "--performance";
|
||||
};
|
||||
tailscale = {
|
||||
enable = true;
|
||||
};
|
||||
udisks = {
|
||||
enable = true;
|
||||
};
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
name = "DP-3";
|
||||
width = 2560;
|
||||
height = 1440;
|
||||
refreshRate = 240;
|
||||
refreshRate = "143.99";
|
||||
position = "0x0";
|
||||
transform = 0;
|
||||
bitDepth = 10;
|
||||
@@ -20,7 +20,7 @@
|
||||
name = "HDMI-A-1";
|
||||
width = 1920;
|
||||
height = 1080;
|
||||
refreshRate = 60;
|
||||
refreshRate = "60";
|
||||
position = "2560x0";
|
||||
transform = 3;
|
||||
workspace = "5";
|
||||
@@ -29,7 +29,7 @@
|
||||
name = "eDP-1";
|
||||
width = 1920;
|
||||
height = 1200;
|
||||
refreshRate = 60;
|
||||
refreshRate = "60";
|
||||
workspace = "1";
|
||||
}
|
||||
];
|
||||
|
||||
@@ -39,6 +39,7 @@ in {
|
||||
"share"
|
||||
"jellyfin"
|
||||
"render"
|
||||
"traefik"
|
||||
];
|
||||
};
|
||||
|
||||
@@ -67,7 +68,10 @@ in {
|
||||
|
||||
boot = {
|
||||
supportedFilesystems = ["zfs"];
|
||||
zfs.extraPools = ["data"];
|
||||
zfs = {
|
||||
package = pkgs.zfs_unstable;
|
||||
extraPools = ["data"];
|
||||
};
|
||||
};
|
||||
|
||||
services.zfs = {
|
||||
|
||||
@@ -109,7 +109,7 @@
|
||||
enable = true;
|
||||
};
|
||||
dev = {
|
||||
enable = false;
|
||||
enable = true;
|
||||
};
|
||||
};
|
||||
mysql-workbench = {
|
||||
@@ -213,6 +213,9 @@
|
||||
scheduler = "scx_lavd";
|
||||
flags = "--performance";
|
||||
};
|
||||
tailscale = {
|
||||
enable = false;
|
||||
};
|
||||
udisks = {
|
||||
enable = true;
|
||||
};
|
||||
|
||||
@@ -3,69 +3,31 @@
|
||||
enable = true;
|
||||
email = "adam@cnst.dev";
|
||||
domain = "cnix.dev";
|
||||
ip = "192.168.88.14";
|
||||
user = "share";
|
||||
group = "share";
|
||||
uid = 994;
|
||||
gid = 993;
|
||||
|
||||
infra = {
|
||||
authentik = {
|
||||
enable = true;
|
||||
url = "auth.cnst.dev";
|
||||
port = 9000;
|
||||
cloudflared = {
|
||||
tunnelId = "b66f9368-db9e-4302-8b48-527cda34a635";
|
||||
credentialsFile = config.age.secrets.authentikCloudflared.path;
|
||||
};
|
||||
};
|
||||
traefik = {
|
||||
enable = true;
|
||||
};
|
||||
www = {
|
||||
enable = true;
|
||||
url = "cnst.dev";
|
||||
};
|
||||
gitea = {
|
||||
tailscale = {
|
||||
enable = true;
|
||||
};
|
||||
unbound = {
|
||||
enable = true;
|
||||
};
|
||||
acme = {
|
||||
enable = false;
|
||||
};
|
||||
homepage-dashboard = {
|
||||
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;
|
||||
};
|
||||
};
|
||||
nextcloud = {
|
||||
enable = true;
|
||||
adminpassFile = config.age.secrets.nextcloudAdminPass.path;
|
||||
};
|
||||
fail2ban = {
|
||||
enable = true;
|
||||
apiKeyFile = config.age.secrets.cloudflareFirewallApiKey.path;
|
||||
@@ -75,19 +37,242 @@
|
||||
enable = true;
|
||||
interface = "enp6s0";
|
||||
};
|
||||
gluetun = {
|
||||
enable = true;
|
||||
};
|
||||
podman = {
|
||||
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 = {
|
||||
enable = true;
|
||||
subdomain = "qbt";
|
||||
exposure = "local";
|
||||
port = 8080;
|
||||
homepage = {
|
||||
name = "qBittorrent";
|
||||
description = "Torrent client";
|
||||
icon = "qbittorrent.svg";
|
||||
category = "Downloads";
|
||||
};
|
||||
};
|
||||
slskd = {
|
||||
enable = true;
|
||||
subdomain = "slskd";
|
||||
exposure = "local";
|
||||
port = 5030;
|
||||
homepage = {
|
||||
name = "Soulseek";
|
||||
description = "Web-based Soulseek client";
|
||||
icon = "slskd.svg";
|
||||
category = "Downloads";
|
||||
};
|
||||
};
|
||||
pihole = {
|
||||
enable = true;
|
||||
subdomain = "pihole";
|
||||
exposure = "local";
|
||||
port = 8053;
|
||||
homepage = {
|
||||
name = "PiHole";
|
||||
description = "Adblocking and DNS service";
|
||||
icon = "pi-hole.svg";
|
||||
category = "Services";
|
||||
path = "/admin";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -4,6 +4,10 @@
|
||||
username = "cnst";
|
||||
mail = "adam@cnst.dev";
|
||||
sshUser = "sobotka";
|
||||
domains = {
|
||||
local = "cnix.dev";
|
||||
public = "cnst.dev";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
name = "DVI-D-1";
|
||||
width = 1920;
|
||||
height = 1080;
|
||||
refreshRate = 144;
|
||||
refreshRate = "144";
|
||||
position = "0x0";
|
||||
transform = 0;
|
||||
workspace = "1";
|
||||
|
||||
@@ -11,9 +11,6 @@
|
||||
unbound = {
|
||||
enable = true;
|
||||
};
|
||||
acme = {
|
||||
enable = true;
|
||||
};
|
||||
homepage-dashboard = {
|
||||
enable = false;
|
||||
};
|
||||
|
||||
26
lib/server/default.nix
Normal file
26
lib/server/default.nix
Normal file
@@ -0,0 +1,26 @@
|
||||
{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;
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
lib: {
|
||||
bgs = rec {
|
||||
files = {
|
||||
wallpaper_1 = "~/media/images/bg_1.jpg";
|
||||
wallpaper_2 = "~/media/images/bg_2.jpg";
|
||||
wallpaper_3 = "~/media/images/bg_3.jpg";
|
||||
wallpaper_4 = "~/media/images/waterwindow.jpg";
|
||||
wallpaper_5 = "~/media/images/barngreet.png";
|
||||
wallpaper_1 = "~/media/images/bgs/bg_1.jpg";
|
||||
wallpaper_2 = "~/media/images/bgs/bg_2.jpg";
|
||||
wallpaper_3 = "~/media/images/bgs/bg_3.jpg";
|
||||
wallpaper_4 = "~/media/images/bgs/waterwindow.jpg";
|
||||
wallpaper_5 = "~/media/images/bgs/barngreet.png";
|
||||
};
|
||||
|
||||
list = builtins.attrNames files;
|
||||
|
||||
@@ -100,7 +100,6 @@
|
||||
./nixos/services/virtualisation
|
||||
./nixos/services/locate
|
||||
./nixos/services/mullvad
|
||||
./nixos/services/mullvad-netns
|
||||
./nixos/services/nfs
|
||||
./nixos/services/nix-ld
|
||||
./nixos/services/openssh
|
||||
@@ -114,6 +113,7 @@
|
||||
./nixos/services/udisks
|
||||
./nixos/services/xserver
|
||||
./nixos/services/zram
|
||||
./nixos/services/tailscale
|
||||
|
||||
./nixos/system/fonts
|
||||
./nixos/system/locale
|
||||
@@ -123,27 +123,6 @@
|
||||
server = {
|
||||
imports = [
|
||||
./server
|
||||
./server/acme
|
||||
./server/fail2ban
|
||||
./server/homepage-dashboard
|
||||
./server/nextcloud
|
||||
./server/vaultwarden
|
||||
./server/bazarr
|
||||
./server/prowlarr
|
||||
./server/lidarr
|
||||
./server/radarr
|
||||
./server/sonarr
|
||||
./server/jellyseerr
|
||||
./server/jellyfin
|
||||
./server/podman
|
||||
./server/unbound
|
||||
./server/uptime-kuma
|
||||
./server/keepalived
|
||||
./server/gitea
|
||||
./server/postgres
|
||||
./server/traefik
|
||||
./server/www
|
||||
./server/authentik
|
||||
];
|
||||
};
|
||||
settings = {
|
||||
|
||||
@@ -14,36 +14,37 @@ in
|
||||
config = mkIf cfg.enable {
|
||||
programs.alacritty = {
|
||||
enable = true;
|
||||
theme = "gruvbox_material_hard_dark";
|
||||
settings = {
|
||||
# Default colors
|
||||
colors.primary = {
|
||||
background = "#282828";
|
||||
foreground = "#d4be98";
|
||||
};
|
||||
colors = {
|
||||
# Normal colors
|
||||
normal = {
|
||||
black = "#3c3836";
|
||||
red = "#ea6962";
|
||||
green = "#a9b665";
|
||||
yellow = "#d8a657";
|
||||
blue = "#7daea3";
|
||||
magenta = "#d3869b";
|
||||
cyan = "#89b482";
|
||||
white = "#d4be98";
|
||||
};
|
||||
# Bright colors (same as normal colors)
|
||||
bright = {
|
||||
black = "#3c3836";
|
||||
red = "#ea6962";
|
||||
green = "#a9b665";
|
||||
yellow = "#d8a657";
|
||||
blue = "#7daea3";
|
||||
magenta = "#d3869b";
|
||||
cyan = "#89b482";
|
||||
white = "#d4be98";
|
||||
};
|
||||
};
|
||||
# colors = {
|
||||
# primary = {
|
||||
# background = "#282828";
|
||||
# foreground = "#d4be98";
|
||||
# };
|
||||
# # Normal colors
|
||||
# normal = {
|
||||
# black = "#3c3836";
|
||||
# red = "#ea6962";
|
||||
# green = "#a9b665";
|
||||
# yellow = "#d8a657";
|
||||
# blue = "#7daea3";
|
||||
# magenta = "#d3869b";
|
||||
# cyan = "#89b482";
|
||||
# white = "#d4be98";
|
||||
# };
|
||||
# # Bright colors (same as normal colors)
|
||||
# bright = {
|
||||
# black = "#3c3836";
|
||||
# red = "#ea6962";
|
||||
# green = "#a9b665";
|
||||
# yellow = "#d8a657";
|
||||
# blue = "#7daea3";
|
||||
# magenta = "#d3869b";
|
||||
# cyan = "#89b482";
|
||||
# white = "#d4be98";
|
||||
# };
|
||||
# };
|
||||
font = {
|
||||
size = 12;
|
||||
normal = {
|
||||
@@ -73,7 +74,7 @@ in
|
||||
];
|
||||
window = {
|
||||
dynamic_title = true;
|
||||
opacity = 0.9;
|
||||
opacity = 0.95;
|
||||
padding = {
|
||||
x = 5;
|
||||
y = 5;
|
||||
|
||||
@@ -1,26 +1,18 @@
|
||||
{
|
||||
inputs,
|
||||
pkgs,
|
||||
lib,
|
||||
osConfig,
|
||||
cLib,
|
||||
clib,
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (lib) mkIf mkEnableOption;
|
||||
}: let
|
||||
inherit (lib) mkIf;
|
||||
cfg = osConfig.nixos.programs.hyprland;
|
||||
|
||||
hyprlockFlake = inputs.hyprlock.packages.${pkgs.system}.hyprlock;
|
||||
# hyprlockPkg = pkgs.hyprlock;
|
||||
#
|
||||
bg = osConfig.settings.theme.background;
|
||||
inherit (cLib.theme.bgs) resolve;
|
||||
in
|
||||
{
|
||||
inherit (clib.theme.bgs) resolve;
|
||||
in {
|
||||
config = mkIf cfg.enable {
|
||||
programs.hyprlock = {
|
||||
enable = true;
|
||||
package = hyprlockFlake;
|
||||
settings = {
|
||||
general = {
|
||||
# disable_loading_bar = true;
|
||||
|
||||
@@ -7,6 +7,9 @@
|
||||
let
|
||||
inherit (lib) mkIf mkEnableOption;
|
||||
cfg = config.home.programs.mpv;
|
||||
inherit (config.xdg.userDirs) videos;
|
||||
inherit (config.home) homeDirectory;
|
||||
shaders_dir = "${pkgs.mpv-shim-default-shaders}/share/mpv-shim-default-shaders/shaders";
|
||||
in
|
||||
{
|
||||
options = {
|
||||
@@ -15,8 +18,71 @@ in
|
||||
config = mkIf cfg.enable {
|
||||
programs.mpv = {
|
||||
enable = true;
|
||||
defaultProfiles = [ "gpu-hq" ];
|
||||
scripts = [ pkgs.mpvScripts.mpris ];
|
||||
config = {
|
||||
profile = "gpu-hq";
|
||||
gpu-context = "wayland";
|
||||
vo = "gpu-next";
|
||||
video-sync = "display-resample";
|
||||
interpolation = true;
|
||||
tscale = "oversample";
|
||||
fullscreen = false;
|
||||
keep-open = true;
|
||||
sub-auto = "fuzzy";
|
||||
sub-font = "Noto Sans Medium";
|
||||
sub-blur = 10;
|
||||
|
||||
screenshot-format = "png";
|
||||
|
||||
title = "\${filename} - mpv";
|
||||
script-opts = "osc-title=\${filename},osc-boxalpha=150,osc-visibility=never,osc-boxvideo=yes";
|
||||
ytdl-format = "bestvideo[height<=?1440]+bestaudio/best";
|
||||
ao = "pipewire";
|
||||
alang = "eng,en";
|
||||
slang = "eng,en,enUS";
|
||||
|
||||
glsl-shader = "${homeDirectory}/.config/mpv/shaders/FSR.glsl";
|
||||
scale = "lanczos";
|
||||
cscale = "lanczos";
|
||||
dscale = "mitchell";
|
||||
deband = "yes";
|
||||
scale-antiring = 1;
|
||||
|
||||
osc = "no";
|
||||
osd-on-seek = "no";
|
||||
osd-bar = "no";
|
||||
osd-bar-w = 30;
|
||||
osd-bar-h = "0.2";
|
||||
osd-duration = 750;
|
||||
|
||||
really-quiet = "yes";
|
||||
autofit = "65%";
|
||||
};
|
||||
|
||||
bindings = {
|
||||
"ctrl+a" = "script-message osc-visibility cycle";
|
||||
};
|
||||
scripts = with pkgs.mpvScripts; [
|
||||
mpris
|
||||
uosc
|
||||
thumbfast
|
||||
sponsorblock
|
||||
autocrop
|
||||
];
|
||||
};
|
||||
programs.yt-dlp = {
|
||||
enable = true;
|
||||
extraConfig = ''
|
||||
-o ${videos}/youtube/%(title)s.%(ext)s
|
||||
'';
|
||||
};
|
||||
|
||||
home = {
|
||||
file = {
|
||||
".config/mpv/shaders/FSR.glsl".source = "${shaders_dir}/FSR.glsl";
|
||||
};
|
||||
packages = with pkgs; [
|
||||
jellyfin-mpv-shim
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -88,7 +88,7 @@ in
|
||||
hyprpicker
|
||||
libnotify
|
||||
pamixer
|
||||
oculante
|
||||
loupe
|
||||
adwaita-icon-theme
|
||||
qt5.qtwayland
|
||||
qt6.qtwayland
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"group/system"
|
||||
],
|
||||
"modules-center": [
|
||||
"niri/workspaces"
|
||||
"hyprland/workspaces"
|
||||
],
|
||||
"modules-right": [
|
||||
"custom/progress",
|
||||
@@ -126,9 +126,13 @@
|
||||
"all-outputs": false,
|
||||
"format": "{icon}",
|
||||
"format-icons": {
|
||||
"urgent": "",
|
||||
"visible": "",
|
||||
"empty": ""
|
||||
"1": "1",
|
||||
"2": "2",
|
||||
"3": "3",
|
||||
"4": "4",
|
||||
"5": "5",
|
||||
"active": "_",
|
||||
"default": "_"
|
||||
},
|
||||
"on-click": "activate",
|
||||
"show-special": false,
|
||||
|
||||
@@ -28,8 +28,8 @@ tooltip label {
|
||||
margin: 0 0px;
|
||||
background-color: transparent;
|
||||
color: #fbf1c7;
|
||||
border-top: 3px solid transparent;
|
||||
border-bottom: 3px solid transparent;
|
||||
border-top: 2px solid transparent;
|
||||
border-bottom: 2px solid transparent;
|
||||
}
|
||||
|
||||
#workspaces button:hover {
|
||||
@@ -45,7 +45,7 @@ tooltip label {
|
||||
background-image: url("assets/button.svg");
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: 18px 15px;
|
||||
background-size: 24px 20px;
|
||||
}
|
||||
|
||||
#custom-trayicon {
|
||||
|
||||
@@ -27,10 +27,10 @@ in
|
||||
};
|
||||
gtk = {
|
||||
enable = true;
|
||||
theme = {
|
||||
package = pkgs.orchis-theme;
|
||||
name = "Orchis-Grey-Dark-Compact";
|
||||
};
|
||||
# theme = {
|
||||
# package = pkgs.orchis-theme;
|
||||
# name = "Orchis-Grey-Dark-Compact";
|
||||
# };
|
||||
iconTheme = {
|
||||
# package = pkgs.adwaita-icon-theme;
|
||||
package = pkgs.papirus-icon-theme;
|
||||
|
||||
@@ -1,22 +1,14 @@
|
||||
{
|
||||
osConfig,
|
||||
lib,
|
||||
pkgs,
|
||||
inputs,
|
||||
...
|
||||
}:
|
||||
let
|
||||
}: let
|
||||
inherit (lib) mkIf;
|
||||
cfg = osConfig.nixos.programs.hyprland;
|
||||
|
||||
hypridleFlake = inputs.hypridle.packages.${pkgs.system}.hypridle;
|
||||
# hypridlePkg = pkgs.hypridle;
|
||||
in
|
||||
{
|
||||
in {
|
||||
config = mkIf cfg.enable {
|
||||
services.hypridle = {
|
||||
enable = true;
|
||||
package = hypridleFlake;
|
||||
settings = {
|
||||
general = {
|
||||
lock_cmd = "hyprlock";
|
||||
|
||||
@@ -1,18 +1,14 @@
|
||||
{
|
||||
lib,
|
||||
pkgs,
|
||||
inputs,
|
||||
osConfig,
|
||||
cLib,
|
||||
clib,
|
||||
...
|
||||
}:
|
||||
let
|
||||
}: let
|
||||
inherit (lib) mkIf;
|
||||
|
||||
cfg = osConfig.nixos.programs.hyprland;
|
||||
hyprpaperFlake = inputs.hyprpaper.packages.${pkgs.system}.default;
|
||||
bg = osConfig.settings.theme.background;
|
||||
bgs = cLib.theme.bgs;
|
||||
bgs = clib.theme.bgs;
|
||||
|
||||
monitorMappings = [
|
||||
{
|
||||
@@ -32,12 +28,10 @@ let
|
||||
bg = bg.primary;
|
||||
}
|
||||
];
|
||||
in
|
||||
{
|
||||
in {
|
||||
config = mkIf cfg.enable {
|
||||
services.hyprpaper = {
|
||||
enable = true;
|
||||
package = hyprpaperFlake;
|
||||
|
||||
settings = {
|
||||
ipc = "on";
|
||||
|
||||
@@ -84,15 +84,15 @@ in
|
||||
"application/pdf" = "org.pwmt.zathura-pdf-mupdf.desktop";
|
||||
"inode/directory" = "thunar.desktop";
|
||||
|
||||
"image/apng" = "oculante.desktop";
|
||||
"image/avif" = "oculante.desktop";
|
||||
"image/bmp" = "oculante.desktop";
|
||||
"image/gif" = "oculante.desktop";
|
||||
"image/jpeg" = "oculante.desktop";
|
||||
"image/png" = "oculante.desktop";
|
||||
"image/svg+xml" = "oculante.desktop";
|
||||
"image/tiff" = "oculante.desktop";
|
||||
"image/webp" = "oculante.desktop";
|
||||
"image/apng" = "feh.desktop";
|
||||
"image/avif" = "feh.desktop";
|
||||
"image/bmp" = "feh.desktop";
|
||||
"image/gif" = "feh.desktop";
|
||||
"image/jpeg" = "feh.desktop";
|
||||
"image/png" = "feh.desktop";
|
||||
"image/svg+xml" = "feh.desktop";
|
||||
"image/tiff" = "feh.desktop";
|
||||
"image/webp" = "feh.desktop";
|
||||
|
||||
"video/H264" = [
|
||||
"mpv.desktop"
|
||||
|
||||
@@ -5,7 +5,12 @@
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (lib) mkOption types;
|
||||
inherit (lib)
|
||||
mkOption
|
||||
types
|
||||
mkEnableOption
|
||||
mkIf
|
||||
;
|
||||
cfg = config.nixos.boot.kernel;
|
||||
|
||||
hasHardware = hw: builtins.elem hw cfg.hardware;
|
||||
@@ -37,8 +42,11 @@ in
|
||||
);
|
||||
default = [ ];
|
||||
description = "List of hardware types (e.g. GPU and CPU vendors) to configure kernel settings for.";
|
||||
|
||||
};
|
||||
|
||||
amdOverdrive.enable = mkEnableOption "Enable AMD pstate/overdrive";
|
||||
|
||||
extraKernelParams = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [ ];
|
||||
@@ -74,7 +82,7 @@ in
|
||||
"quiet"
|
||||
"splash"
|
||||
]
|
||||
++ (if hasHardware "amd" then [ "amd_pstate=active" ] else [ ])
|
||||
++ (if hasHardware "amd" then [ ] else [ ])
|
||||
++ (if hasHardware "intel" then [ ] else [ ])
|
||||
++ (if hasHardware "nvidia" then [ ] else [ ])
|
||||
++ cfg.extraKernelParams;
|
||||
@@ -85,5 +93,6 @@ in
|
||||
++ (if hasHardware "nvidia" then [ "nouveau" ] else [ ])
|
||||
++ cfg.extraBlacklistedModules;
|
||||
};
|
||||
hardware.amdgpu.overdrive.enable = mkIf cfg.amdOverdrive.enable true;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -89,7 +89,8 @@ in
|
||||
|
||||
config = mkIf cfg.enable (mkMerge [
|
||||
{
|
||||
hardware.graphics = {
|
||||
hardware = {
|
||||
graphics = {
|
||||
enable = true;
|
||||
enable32Bit = true;
|
||||
extraPackages = flatten (
|
||||
@@ -121,6 +122,7 @@ in
|
||||
|
||||
extraPackages32 = flatten (concatMap (_: commonPackages32) cfg.vendors);
|
||||
};
|
||||
};
|
||||
|
||||
environment.systemPackages = flatten (
|
||||
concatMap (
|
||||
@@ -145,10 +147,6 @@ in
|
||||
);
|
||||
}
|
||||
|
||||
(mkIf (hasVendor "amd") {
|
||||
hardware.amdgpu.overdrive.enable = true;
|
||||
})
|
||||
|
||||
(mkIf (hasVendor "nvidia") {
|
||||
hardware.nvidia = {
|
||||
package =
|
||||
|
||||
@@ -2,20 +2,29 @@
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (lib)
|
||||
}: let
|
||||
inherit
|
||||
(lib)
|
||||
mkIf
|
||||
mkEnableOption
|
||||
mkOption
|
||||
types
|
||||
;
|
||||
cfg = config.nixos.hardware.network;
|
||||
in
|
||||
{
|
||||
in {
|
||||
options = {
|
||||
nixos.hardware.network = {
|
||||
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 {
|
||||
type = types.attrsOf (
|
||||
types.submodule {
|
||||
@@ -55,6 +64,8 @@ in
|
||||
networking = {
|
||||
networkmanager.enable = true;
|
||||
nftables.enable = true;
|
||||
nameservers = cfg.nameservers;
|
||||
search = cfg.search;
|
||||
firewall = {
|
||||
enable = true;
|
||||
inherit (cfg) interfaces;
|
||||
|
||||
@@ -18,9 +18,7 @@ in
|
||||
gaps_in = 2;
|
||||
gaps_out = "4, 4, 4, 4";
|
||||
border_size = 3;
|
||||
#col.active_border = rgba(33ccffee) rgba(00ff99ee) 45deg
|
||||
#col.inactive_border = rgba(595959aa)
|
||||
"col.active_border" = "rgb(4c7a5d)"; # rgba(b16286ee) 45deg
|
||||
"col.active_border" = "rgb(4c7a5d)";
|
||||
"col.inactive_border" = "rgb(504945)";
|
||||
layout = "dwindle";
|
||||
resize_on_border = true;
|
||||
|
||||
@@ -37,9 +37,9 @@ in
|
||||
};
|
||||
|
||||
gestures = {
|
||||
workspace_swipe = true;
|
||||
# workspace_swipe = true;
|
||||
workspace_swipe_distance = 400;
|
||||
workspace_swipe_fingers = 3;
|
||||
# workspace_swipe_fingers = 3;
|
||||
workspace_swipe_cancel_ratio = 0.2;
|
||||
workspace_swipe_min_speed_to_force = 5;
|
||||
workspace_swipe_direction_lock = true;
|
||||
|
||||
@@ -99,7 +99,7 @@ in
|
||||
|
||||
(mkIf (host == "kima") {
|
||||
programs.hyprland.settings = {
|
||||
"$terminal" = "ghostty";
|
||||
"$terminal" = "alacritty";
|
||||
"$browser" = "zen";
|
||||
"$browserinc" = "zen --private-window";
|
||||
"$mod" = "SUPER";
|
||||
@@ -111,7 +111,7 @@ in
|
||||
|
||||
(mkIf (host == "bunk") {
|
||||
programs.hyprland.settings = {
|
||||
"$terminal" = "foot";
|
||||
"$terminal" = "alacritty";
|
||||
"$browser" = "zen";
|
||||
"$browserinc" = "zen --private-window";
|
||||
"$mod" = "ALT_L";
|
||||
|
||||
@@ -21,7 +21,7 @@ in
|
||||
let
|
||||
resolution =
|
||||
if m.width != null && m.height != null then
|
||||
"${toString m.width}x${toString m.height}@${toString m.refreshRate}"
|
||||
"${toString m.width}x${toString m.height}@${m.refreshRate}"
|
||||
else
|
||||
"preferred";
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
{
|
||||
config,
|
||||
inputs,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
@@ -14,22 +13,22 @@ in
|
||||
nixos.programs.niri.enable = mkEnableOption "Enables niri";
|
||||
};
|
||||
config = mkIf cfg.enable {
|
||||
nixpkgs.overlays = [ inputs.niri.overlays.niri ];
|
||||
environment = {
|
||||
variables = {
|
||||
DISPLAY = ":0";
|
||||
NIXOS_OZONE_WL = "1";
|
||||
QT_WAYLAND_DISABLE_WINDOWDECORATION = "1";
|
||||
};
|
||||
systemPackages = with pkgs; [
|
||||
xwayland-satellite-unstable
|
||||
xwayland-satellite
|
||||
wl-clipboard
|
||||
wayland-utils
|
||||
xdg-utils
|
||||
];
|
||||
};
|
||||
systemd.user.services.niri-flake-polkit.enable = false;
|
||||
programs.niri = {
|
||||
enable = true;
|
||||
package = pkgs.niri-unstable;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -78,6 +78,7 @@ in
|
||||
openssl
|
||||
xmrig
|
||||
ocl-icd
|
||||
dig
|
||||
]
|
||||
|
||||
(mkIf cfg.common.enable [
|
||||
@@ -96,9 +97,6 @@ in
|
||||
])
|
||||
|
||||
(mkIf cfg.desktop.enable [
|
||||
protonup
|
||||
winetricks
|
||||
wine
|
||||
geekbench
|
||||
unigine-heaven
|
||||
])
|
||||
@@ -109,15 +107,13 @@ in
|
||||
|
||||
(mkIf cfg.server.enable [
|
||||
nvtopPackages.intel
|
||||
nvtopPackages.amd
|
||||
dig
|
||||
helix
|
||||
zfs
|
||||
zfstools
|
||||
])
|
||||
|
||||
(mkIf cfg.dev.enable [
|
||||
# lldb_20 # some biuld error atm
|
||||
sqlite
|
||||
gemini-cli
|
||||
nfs-utils
|
||||
gcc
|
||||
@@ -144,7 +140,6 @@ in
|
||||
prettierd
|
||||
# php84Packages.php-cs-fixer
|
||||
shfmt
|
||||
luaformatter
|
||||
black
|
||||
])
|
||||
];
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
let
|
||||
@@ -17,6 +18,20 @@ in
|
||||
enable = true;
|
||||
gamescopeSession.enable = true;
|
||||
};
|
||||
gamescope = {
|
||||
enable = true;
|
||||
capSysNice = true;
|
||||
args = [
|
||||
"--rt"
|
||||
"--expose-wayland"
|
||||
];
|
||||
};
|
||||
};
|
||||
environment.systemPackages = with pkgs; [
|
||||
protonup
|
||||
wine
|
||||
winetricks
|
||||
wine-wayland
|
||||
];
|
||||
};
|
||||
}
|
||||
|
||||
@@ -74,19 +74,11 @@ in {
|
||||
wgCredentials.file = "${self}/secrets/wgCredentials.age";
|
||||
wgSobotkaPrivateKey.file = "${self}/secrets/wgSobotkaPrivateKey.age";
|
||||
gluetunEnvironment.file = "${self}/secrets/gluetunEnvironment.age";
|
||||
nextcloudAdminPass.file = "${self}/secrets/nextcloudAdminPass.age";
|
||||
nextcloudCloudflared.file = "${self}/secrets/nextcloudCloudflared.age";
|
||||
vaultwardenCloudflared.file = "${self}/secrets/vaultwardenCloudflared.age";
|
||||
vaultwardenEnvironment.file = "${self}/secrets/vaultwardenEnvironment.age";
|
||||
homepageEnvironment.file = "${self}/secrets/homepageEnvironment.age";
|
||||
pihole.file = "${self}/secrets/pihole.age";
|
||||
slskd.file = "${self}/secrets/slskd.age";
|
||||
};
|
||||
})
|
||||
(mkIf cfg.ziggy.enable {
|
||||
secrets = {
|
||||
cloudflareDnsCredentialsZiggy.file = "${self}/secrets/cloudflareDnsCredentialsZiggy.age";
|
||||
piholeZiggy.file = "${self}/secrets/piholeZiggy.age";
|
||||
};
|
||||
})
|
||||
(mkIf cfg.toothpc.enable {
|
||||
|
||||
@@ -63,7 +63,7 @@ in
|
||||
settings = rec {
|
||||
tuigreet_session =
|
||||
let
|
||||
session = "${pkgs.niri-unstable}/bin/niri-session";
|
||||
session = "${pkgs.niri}/bin/niri-session";
|
||||
tuigreet = "${lib.getExe pkgs.tuigreet}";
|
||||
in
|
||||
{
|
||||
|
||||
@@ -19,6 +19,9 @@ in
|
||||
keyboards.hhkbse = {
|
||||
extraDefCfg = ''
|
||||
process-unmapped-keys yes
|
||||
linux-dev-names-include (
|
||||
"HHKB-Hybrid_1 Keyboard"
|
||||
)
|
||||
'';
|
||||
devices = [
|
||||
"/dev/input/by-id/usb-PFU_Limited_HHKB-Hybrid-event-kbd"
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
{ self, pkgs, ... }:
|
||||
{
|
||||
age.secrets.wgCredentials = {
|
||||
file = "${self}/secrets/wgCredentials.age";
|
||||
mode = "0400";
|
||||
owner = "root";
|
||||
group = "root";
|
||||
path = "/etc/wireguard/mullvad.conf";
|
||||
};
|
||||
|
||||
systemd.services.mullvad-netns = {
|
||||
description = "WireGuard Mullvad netns for VMs";
|
||||
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
RemainAfterExit = true;
|
||||
|
||||
ExecStart = "${pkgs.writeShellScript "mullvad-netns-up" ''
|
||||
set -euo pipefail
|
||||
|
||||
ip netns add mullvad || true
|
||||
|
||||
ip link add veth0 type veth peer name veth1 || true
|
||||
ip link set veth1 netns mullvad
|
||||
ip addr add 10.250.0.1/24 dev veth0 || true
|
||||
ip link set veth0 up
|
||||
ip netns exec mullvad ip addr add 10.250.0.2/24 dev veth1 || true
|
||||
ip netns exec mullvad ip link set veth1 up
|
||||
|
||||
ip netns exec mullvad wg-quick up /etc/wireguard/mullvad.conf
|
||||
ip netns exec mullvad ip route add default dev wg0 || true
|
||||
|
||||
nft add table ip mullvad-nat || true
|
||||
nft add chain ip mullvad-nat postrouting { type nat hook postrouting priority 100 \; } || true
|
||||
nft add rule ip mullvad-nat postrouting ip saddr 10.250.0.0/24 oif "wg0" masquerade || true
|
||||
''}";
|
||||
|
||||
ExecStop = "${pkgs.writeShellScript "mullvad-netns-down" ''
|
||||
set -euo pipefail
|
||||
|
||||
ip netns exec mullvad wg-quick down /etc/wireguard/mullvad.conf || true
|
||||
ip link delete veth0 || true
|
||||
ip netns delete mullvad || true
|
||||
nft delete table ip mullvad-nat || true
|
||||
''}";
|
||||
};
|
||||
|
||||
# no wantedBy here -> won't start at boot
|
||||
};
|
||||
}
|
||||
16
modules/nixos/services/tailscale/default.nix
Normal file
16
modules/nixos/services/tailscale/default.nix
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
with lib; let
|
||||
cfg = config.nixos.services.tailscale;
|
||||
in {
|
||||
options.nixos.services.tailscale = {
|
||||
enable = mkEnableOption "Enable tailscale";
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
services.tailscale.enable = true;
|
||||
};
|
||||
}
|
||||
@@ -45,7 +45,6 @@ in
|
||||
# nodePackages_latest.sql-formatter
|
||||
prettierd
|
||||
shfmt
|
||||
luaformatter
|
||||
black
|
||||
];
|
||||
};
|
||||
|
||||
@@ -30,13 +30,19 @@ in
|
||||
enable = true;
|
||||
xdgOpenUsePortal = cfg.xdgOpenUsePortal;
|
||||
config = {
|
||||
common.default = [ "gtk" ];
|
||||
common.default = [
|
||||
"gtk"
|
||||
"gnome"
|
||||
];
|
||||
hyprland.default = [
|
||||
"gtk"
|
||||
"hyprland"
|
||||
];
|
||||
};
|
||||
extraPortals = [ pkgs.xdg-desktop-portal-gtk ];
|
||||
extraPortals = with pkgs; [
|
||||
xdg-desktop-portal-gtk
|
||||
xdg-desktop-portal-gnome
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
inherit (lib) mkIf mkEnableOption;
|
||||
cfg = config.server.acme;
|
||||
|
||||
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.acme.enable = mkEnableOption "Enables ACME";
|
||||
};
|
||||
config = mkIf cfg.enable {
|
||||
networking.firewall = let
|
||||
ports = [
|
||||
80
|
||||
443
|
||||
];
|
||||
in {
|
||||
allowedTCPPorts = ports;
|
||||
};
|
||||
|
||||
security.acme = {
|
||||
acceptTerms = true;
|
||||
defaults.email = config.server.email;
|
||||
certs.${config.server.domain} = {
|
||||
reloadServices = ["caddy.service"];
|
||||
domain = "${config.server.domain}";
|
||||
extraDomainNames = ["*.${config.server.domain}"];
|
||||
dnsProvider = "cloudflare";
|
||||
dnsResolver = "1.1.1.1:53";
|
||||
dnsPropagationCheck = true;
|
||||
group = config.services.caddy.group;
|
||||
environmentFile = getCloudflareCredentials config.networking.hostName;
|
||||
};
|
||||
certs.${config.server.www.url} = {
|
||||
reloadServices = ["caddy.service"];
|
||||
domain = "${config.server.www.url}";
|
||||
extraDomainNames = ["*.${config.server.www.url}"];
|
||||
dnsProvider = "cloudflare";
|
||||
dnsResolver = "1.1.1.1:53";
|
||||
dnsPropagationCheck = true;
|
||||
group = config.services.caddy.group;
|
||||
environmentFile = getCloudflareCredentials config.networking.hostName;
|
||||
};
|
||||
};
|
||||
|
||||
services.caddy = {
|
||||
enable = true;
|
||||
globalConfig = ''
|
||||
auto_https off
|
||||
'';
|
||||
virtualHosts = {
|
||||
"http://${config.server.domain}" = {
|
||||
extraConfig = ''
|
||||
redir https://{host}{uri}
|
||||
'';
|
||||
};
|
||||
"http://*.${config.server.domain}" = {
|
||||
extraConfig = ''
|
||||
redir https://{host}{uri}
|
||||
'';
|
||||
};
|
||||
|
||||
"http://${config.server.www.url}" = {
|
||||
extraConfig = ''
|
||||
redir https://{host}{uri}
|
||||
'';
|
||||
};
|
||||
"http://*.${config.server.www.url}" = {
|
||||
extraConfig = ''
|
||||
redir https://{host}{uri}
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
{
|
||||
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,101 +1,16 @@
|
||||
{
|
||||
self,
|
||||
lib,
|
||||
config,
|
||||
pkgs,
|
||||
...
|
||||
}: let
|
||||
hardDrives = [
|
||||
"/dev/disk/by-label/data"
|
||||
];
|
||||
inherit (lib) mkOption types;
|
||||
cfg = config.server;
|
||||
ifTheyExist = groups: builtins.filter (group: builtins.hasAttr group config.users.groups) groups;
|
||||
clib = import "${self}/lib/server" {inherit lib;};
|
||||
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"
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
imports = [
|
||||
{
|
||||
_module.args.clib = clib;
|
||||
}
|
||||
./options.nix
|
||||
./infra
|
||||
./services
|
||||
];
|
||||
}
|
||||
|
||||
@@ -1,111 +0,0 @@
|
||||
# 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
|
||||
'';
|
||||
}
|
||||
];
|
||||
};
|
||||
}
|
||||
@@ -1,125 +0,0 @@
|
||||
# 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";
|
||||
}
|
||||
];
|
||||
};
|
||||
}
|
||||
@@ -1,119 +0,0 @@
|
||||
# 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.routers."${unit}" = {
|
||||
rule = "Host(`" + cfg.url + "`)";
|
||||
service = "${unit}-service";
|
||||
entryPoints = ["websecure"];
|
||||
tls = {};
|
||||
};
|
||||
|
||||
services.traefik.dynamicConfigOptions.http.services."${unit}-service".loadBalancer.servers = [
|
||||
{url = "http://127.0.0.1:${toString cfg.port}";}
|
||||
];
|
||||
|
||||
server.postgresql.databases = [
|
||||
{
|
||||
database = "gitea";
|
||||
}
|
||||
];
|
||||
};
|
||||
}
|
||||
@@ -1,240 +0,0 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}: 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 {
|
||||
services = {
|
||||
glances.enable = true;
|
||||
${unit} = {
|
||||
enable = true;
|
||||
allowedHosts = srv.domain;
|
||||
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;
|
||||
};
|
||||
}
|
||||
{
|
||||
datetime = {
|
||||
text_size = "x1";
|
||||
format = {
|
||||
hour12 = false;
|
||||
timeStyle = "short";
|
||||
dateStyle = "long";
|
||||
};
|
||||
};
|
||||
}
|
||||
{
|
||||
resources = {
|
||||
label = "";
|
||||
memory = true;
|
||||
disk = ["/"];
|
||||
};
|
||||
}
|
||||
];
|
||||
|
||||
services = let
|
||||
homepageCategories = [
|
||||
"Arr"
|
||||
"Media"
|
||||
"Downloads"
|
||||
"Services"
|
||||
"Smart Home"
|
||||
];
|
||||
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,45 +1,68 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
self,
|
||||
...
|
||||
}: let
|
||||
unit = "authentik";
|
||||
cfg = config.server.${unit};
|
||||
srv = config.server;
|
||||
cfg = config.server.infra.${unit};
|
||||
srv = config.server.infra.www.domain;
|
||||
in {
|
||||
options.server.${unit} = {
|
||||
options.server.infra.${unit} = {
|
||||
enable = lib.mkEnableOption {
|
||||
description = "Enable ${unit}";
|
||||
};
|
||||
url = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "auth.${srv.domain}";
|
||||
default = "auth.${srv.www.domain}";
|
||||
};
|
||||
homepage.name = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "Authentik";
|
||||
port = lib.mkOption {
|
||||
type = lib.types.port;
|
||||
description = "The local port the service runs on";
|
||||
};
|
||||
homepage.description = lib.mkOption {
|
||||
cloudflared = {
|
||||
credentialsFile = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "Open Source Identity and Access Management";
|
||||
example = lib.literalExpression ''
|
||||
pkgs.writeText "cloudflare-credentials.json" '''
|
||||
{"AccountTag":"secret"."TunnelSecret":"secret","TunnelID":"secret"}
|
||||
'''
|
||||
'';
|
||||
};
|
||||
homepage.icon = lib.mkOption {
|
||||
tunnelId = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "authentik.svg";
|
||||
example = "00000000-0000-0000-0000-000000000000";
|
||||
};
|
||||
homepage.category = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "Services";
|
||||
};
|
||||
homepage = {
|
||||
name = "Authentik";
|
||||
description = "An open-source IdP for modern SSO";
|
||||
icon = "authentik.svg";
|
||||
category = "Services";
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
age.secrets.authentikEnv = {
|
||||
age.secrets = {
|
||||
authentikEnv = {
|
||||
file = "${self}/secrets/authentikEnv.age";
|
||||
owner = "authentik";
|
||||
};
|
||||
authentikCloudflared = {
|
||||
file = "${self}/secrets/authentikCloudflared.age";
|
||||
};
|
||||
};
|
||||
|
||||
server.infra = {
|
||||
fail2ban = {
|
||||
jails = {
|
||||
authentik = {
|
||||
serviceName = "authentik";
|
||||
failRegex = ''^.*Username or password is incorrect.*IP:\s*<HOST>'';
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
services = {
|
||||
authentik = {
|
||||
enable = true;
|
||||
@@ -52,13 +75,21 @@ in {
|
||||
};
|
||||
};
|
||||
|
||||
cloudflared = {
|
||||
enable = true;
|
||||
tunnels.${cfg.cloudflared.tunnelId} = {
|
||||
credentialsFile = cfg.cloudflared.credentialsFile;
|
||||
default = "http_status:404";
|
||||
ingress."${cfg.url}".service = "http://127.0.0.1:9000";
|
||||
};
|
||||
};
|
||||
|
||||
traefik = {
|
||||
dynamicConfigOptions = {
|
||||
http = {
|
||||
middlewares = {
|
||||
authentik = {
|
||||
forwardAuth = {
|
||||
tls.insecureSkipVerify = true;
|
||||
address = "https://localhost:9443/outpost.goauthentik.io/auth/traefik";
|
||||
trustForwardHeader = true;
|
||||
authResponseHeaders = [
|
||||
@@ -89,7 +120,7 @@ in {
|
||||
routers = {
|
||||
auth = {
|
||||
entryPoints = ["websecure"];
|
||||
rule = "Host(`${cfg.url}`) || HostRegexp(`{subdomain:[a-z0-9]+}.${srv.domain}`) && PathPrefix(`/outpost.goauthentik.io/`)";
|
||||
rule = "Host(`${cfg.url}`) && PathPrefix(`/outpost.goauthentik.io/`)";
|
||||
service = "auth";
|
||||
tls.certResolver = "letsencrypt";
|
||||
};
|
||||
13
modules/server/infra/default.nix
Normal file
13
modules/server/infra/default.nix
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
imports = [
|
||||
./authentik
|
||||
./fail2ban
|
||||
./keepalived
|
||||
./podman
|
||||
./postgres
|
||||
./tailscale
|
||||
./traefik
|
||||
./unbound
|
||||
./www
|
||||
];
|
||||
}
|
||||
131
modules/server/infra/fail2ban/default.nix
Normal file
131
modules/server/infra/fail2ban/default.nix
Normal file
@@ -0,0 +1,131 @@
|
||||
# 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
|
||||
'';
|
||||
}
|
||||
];
|
||||
};
|
||||
}
|
||||
@@ -3,27 +3,24 @@
|
||||
config,
|
||||
self,
|
||||
...
|
||||
}:
|
||||
let
|
||||
}: let
|
||||
unit = "keepalived";
|
||||
cfg = config.server.${unit};
|
||||
cfg = config.server.infra.${unit};
|
||||
|
||||
hostCfg =
|
||||
hostname:
|
||||
if hostname == "sobotka" then
|
||||
{
|
||||
hostCfg = hostname:
|
||||
if hostname == "sobotka"
|
||||
then {
|
||||
ip = "192.168.88.14";
|
||||
priority = 20;
|
||||
state = "MASTER";
|
||||
}
|
||||
else if hostname == "ziggy" then
|
||||
{
|
||||
else if hostname == "ziggy"
|
||||
then {
|
||||
ip = "192.168.88.12";
|
||||
priority = 10;
|
||||
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;
|
||||
|
||||
@@ -34,9 +31,8 @@ let
|
||||
|
||||
# Remove self from peers
|
||||
peers = builtins.filter (ip: ip != _self.ip) allPeers;
|
||||
in
|
||||
{
|
||||
options.server.${unit} = {
|
||||
in {
|
||||
options.server.infra.${unit} = {
|
||||
enable = lib.mkEnableOption {
|
||||
description = "Enable ${unit}";
|
||||
};
|
||||
6
modules/server/infra/podman/acquis.yaml
Normal file
6
modules/server/infra/podman/acquis.yaml
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
filenames:
|
||||
- /var/log/traefik/access.log
|
||||
poll_without_inotify: true
|
||||
labels:
|
||||
type: traefik
|
||||
194
modules/server/infra/podman/default.nix
Normal file
194
modules/server/infra/podman/default.nix
Normal file
@@ -0,0 +1,194 @@
|
||||
{
|
||||
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"
|
||||
];
|
||||
};
|
||||
})
|
||||
];
|
||||
};
|
||||
}
|
||||
@@ -7,10 +7,10 @@
|
||||
}: let
|
||||
inherit (lib) types mkOption;
|
||||
|
||||
cfg = config.server.postgresql;
|
||||
cfg = config.server.infra.postgresql;
|
||||
in {
|
||||
options = {
|
||||
server.postgresql = {
|
||||
server.infra.postgresql = {
|
||||
upgradeTargetPackage = mkOption {
|
||||
type = types.nullOr types.package;
|
||||
default = null;
|
||||
@@ -7,7 +7,7 @@
|
||||
}: let
|
||||
inherit (lib) types mkOption;
|
||||
|
||||
cfg = config.server.postgresql;
|
||||
cfg = config.server.infra.postgresql;
|
||||
|
||||
database = {name, ...}: {
|
||||
options = {
|
||||
@@ -31,7 +31,7 @@
|
||||
};
|
||||
in {
|
||||
options = {
|
||||
server.postgresql = {
|
||||
server.infra.postgresql = {
|
||||
databases = mkOption {
|
||||
type = types.listOf (types.submodule database);
|
||||
default = [];
|
||||
26
modules/server/infra/tailscale/default.nix
Normal file
26
modules/server/infra/tailscale/default.nix
Normal file
@@ -0,0 +1,26 @@
|
||||
{
|
||||
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"
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
||||
183
modules/server/infra/traefik/default.nix
Normal file
183
modules/server/infra/traefik/default.nix
Normal file
@@ -0,0 +1,183 @@
|
||||
{
|
||||
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";
|
||||
# };
|
||||
# };
|
||||
# };
|
||||
# };
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -5,7 +5,25 @@
|
||||
...
|
||||
}: let
|
||||
unit = "unbound";
|
||||
cfg = config.server.${unit};
|
||||
cfg = config.server.infra.${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);
|
||||
|
||||
revParts = lib.lists.reverseList (lib.splitString "." srv.ip);
|
||||
revName = lib.concatStringsSep "." revParts;
|
||||
|
||||
localPTRs = ["${revName}.in-addr.arpa. PTR traefik.${srv.domain}"];
|
||||
|
||||
hostIp = hostname:
|
||||
if hostname == "ziggy"
|
||||
@@ -14,11 +32,12 @@
|
||||
then "192.168.88.14"
|
||||
else throw "No IP defined for host ${hostname}";
|
||||
in {
|
||||
options.server.${unit} = {
|
||||
options.server.infra.${unit} = {
|
||||
enable = lib.mkEnableOption {
|
||||
description = "Enable ${unit}";
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
services = {
|
||||
# resolved.enable = lib.mkForce false;
|
||||
@@ -97,6 +116,10 @@ in {
|
||||
"255.255.255.255/32"
|
||||
"2001:db8::/32"
|
||||
];
|
||||
local-data = localARecords;
|
||||
|
||||
# Example PTR entry: "14.88.168.192.in-addr.arpa. PTR traefik.cnix.dev."
|
||||
# local-data-ptr = localPTRs;
|
||||
};
|
||||
};
|
||||
};
|
||||
135
modules/server/infra/www/default.nix
Normal file
135
modules/server/infra/www/default.nix
Normal file
@@ -0,0 +1,135 @@
|
||||
{
|
||||
lib,
|
||||
config,
|
||||
self,
|
||||
...
|
||||
}: let
|
||||
inherit (lib) mkIf mkEnableOption mkOption types;
|
||||
cfg = config.server.infra.www;
|
||||
in {
|
||||
options.server.infra.www = {
|
||||
enable = mkEnableOption {
|
||||
description = "Enable personal website";
|
||||
};
|
||||
url = mkOption {
|
||||
default = "";
|
||||
type = types.str;
|
||||
description = ''
|
||||
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 = {
|
||||
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 = {
|
||||
wwwCloudflared.file = "${self}/secrets/wwwCloudflared.age";
|
||||
};
|
||||
|
||||
server.infra = {
|
||||
fail2ban = {
|
||||
jails = {
|
||||
nginx-404 = {
|
||||
serviceName = "nginx";
|
||||
failRegex = ''^.*\[error\].*directory index of.* is forbidden.*client: <HOST>.*$'';
|
||||
ignoreRegex = '''';
|
||||
maxRetry = 5;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
services = {
|
||||
nginx = {
|
||||
enable = true;
|
||||
defaultListen = [
|
||||
{
|
||||
addr = "127.0.0.1";
|
||||
port = 8283;
|
||||
}
|
||||
];
|
||||
virtualHosts."webfinger" = {
|
||||
forceSSL = false;
|
||||
serverName = cfg.url;
|
||||
root = "/var/www/webfinger";
|
||||
|
||||
locations."= /.well-known/webfinger" = {
|
||||
root = "/var/www/webfinger";
|
||||
extraConfig = ''
|
||||
default_type application/jrd+json;
|
||||
try_files /.well-known/webfinger =404;
|
||||
'';
|
||||
};
|
||||
|
||||
locations."= /robots.txt" = {
|
||||
root = "/var/www/webfinger";
|
||||
extraConfig = ''
|
||||
default_type text/plain;
|
||||
try_files /robots.txt =404;
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
cloudflared = {
|
||||
enable = true;
|
||||
tunnels.${cfg.cloudflared.tunnelId} = {
|
||||
credentialsFile = cfg.cloudflared.credentialsFile;
|
||||
default = "http_status:404";
|
||||
ingress."${cfg.url}".service = "http://127.0.0.1:8283";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
environment.etc = {
|
||||
"webfinger/.well-known/webfinger".text = ''
|
||||
{
|
||||
"subject": "acct:adam@${cfg.url}",
|
||||
"links": [
|
||||
{
|
||||
"rel": "http://openid.net/specs/connect/1.0/issuer",
|
||||
"href": "https://auth.${cfg.url}/application/o/tailscale/"
|
||||
}
|
||||
]
|
||||
}
|
||||
'';
|
||||
|
||||
"webfinger/robots.txt".text = ''
|
||||
User-agent: *
|
||||
Disallow: /
|
||||
'';
|
||||
};
|
||||
|
||||
services.traefik.dynamicConfigOptions.http = {
|
||||
routers.webfinger = {
|
||||
entryPoints = ["websecure"];
|
||||
rule = "Host(`${cfg.url}`) && Path(`/.well-known/webfinger`)";
|
||||
service = "webfinger";
|
||||
tls.certResolver = "letsencrypt";
|
||||
};
|
||||
|
||||
services.webfinger.loadBalancer.servers = [
|
||||
{url = "http://127.0.0.1:8283";}
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
{
|
||||
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"];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
{
|
||||
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"];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
{
|
||||
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"];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
180
modules/server/options.nix
Normal file
180
modules/server/options.nix
Normal file
@@ -0,0 +1,180 @@
|
||||
{
|
||||
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"
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -1,315 +0,0 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}: 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 {
|
||||
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"
|
||||
];
|
||||
};
|
||||
})
|
||||
];
|
||||
};
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
{
|
||||
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"];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
{
|
||||
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"];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
17
modules/server/services/bazarr/default.nix
Normal file
17
modules/server/services/bazarr/default.nix
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
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;
|
||||
};
|
||||
};
|
||||
}
|
||||
19
modules/server/services/default.nix
Normal file
19
modules/server/services/default.nix
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
imports = [
|
||||
./bazarr
|
||||
./flaresolverr
|
||||
./gitea
|
||||
./homepage-dashboard
|
||||
./jellyfin
|
||||
./jellyseerr
|
||||
./lidarr
|
||||
./n8n
|
||||
./nextcloud
|
||||
./ollama
|
||||
./prowlarr
|
||||
./radarr
|
||||
./sonarr
|
||||
./uptime-kuma
|
||||
./vaultwarden
|
||||
];
|
||||
}
|
||||
16
modules/server/services/flaresolverr/default.nix
Normal file
16
modules/server/services/flaresolverr/default.nix
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
unit = "flaresolverr";
|
||||
cfg = config.server.services.${unit};
|
||||
in {
|
||||
config = lib.mkIf cfg.enable {
|
||||
services = {
|
||||
${unit} = {
|
||||
enable = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
94
modules/server/services/gitea/default.nix
Normal file
94
modules/server/services/gitea/default.nix
Normal file
@@ -0,0 +1,94 @@
|
||||
{
|
||||
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;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
227
modules/server/services/homepage-dashboard/default.nix
Normal file
227
modules/server/services/homepage-dashboard/default.nix
Normal file
@@ -0,0 +1,227 @@
|
||||
{
|
||||
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";
|
||||
};
|
||||
};
|
||||
}
|
||||
];
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
21
modules/server/services/jellyfin/default.nix
Normal file
21
modules/server/services/jellyfin/default.nix
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
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
|
||||
];
|
||||
};
|
||||
}
|
||||
15
modules/server/services/jellyseerr/default.nix
Normal file
15
modules/server/services/jellyseerr/default.nix
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
unit = "jellyseerr";
|
||||
cfg = config.server.services.${unit};
|
||||
in {
|
||||
config = lib.mkIf cfg.enable {
|
||||
services.${unit} = {
|
||||
enable = true;
|
||||
port = cfg.port;
|
||||
};
|
||||
};
|
||||
}
|
||||
17
modules/server/services/lidarr/default.nix
Normal file
17
modules/server/services/lidarr/default.nix
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
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;
|
||||
};
|
||||
};
|
||||
}
|
||||
17
modules/server/services/n8n/default.nix
Normal file
17
modules/server/services/n8n/default.nix
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
unit = "n8n";
|
||||
cfg = config.server.services.${unit};
|
||||
in {
|
||||
config = lib.mkIf cfg.enable {
|
||||
services = {
|
||||
n8n = {
|
||||
enable = true;
|
||||
openFirewall = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -2,62 +2,34 @@
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
self,
|
||||
...
|
||||
}: let
|
||||
unit = "nextcloud";
|
||||
cfg = config.server.${unit};
|
||||
cfg = config.server.services.${unit};
|
||||
srv = config.server;
|
||||
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 {
|
||||
server.fail2ban = lib.mkIf config.server.fail2ban.enable {
|
||||
jails = {
|
||||
nextcloud = {
|
||||
serviceName = "phpfpm-nextcloud";
|
||||
failRegex = "^.*Login failed:.*(Remote IP: <HOST>).*$";
|
||||
};
|
||||
age.secrets = {
|
||||
nextcloudAdminPass.file = "${self}/secrets/nextcloudAdminPass.age";
|
||||
nextcloudCloudflared.file = "${self}/secrets/nextcloudCloudflared.age";
|
||||
};
|
||||
|
||||
server.infra.fail2ban.jails.nextcloud = {
|
||||
serviceName = "${unit}";
|
||||
_groupsre = ''(?:(?:,?\s*"\w+":(?:"[^"]+"|\w+))*)'';
|
||||
failRegex = ''
|
||||
^\{%(_groupsre)s,?\s*"remoteAddr":"<HOST>"%(_groupsre)s,?\s*"message":"Login failed:
|
||||
^\{%(_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 = {
|
||||
${unit} = {
|
||||
enable = true;
|
||||
package = pkgs.nextcloud31;
|
||||
package = pkgs.nextcloud32;
|
||||
hostName = "nextcloud";
|
||||
configureRedis = true;
|
||||
caching = {
|
||||
@@ -95,7 +67,7 @@ in {
|
||||
dbhost = "/run/postgresql";
|
||||
dbname = "nextcloud";
|
||||
adminuser = "cnst";
|
||||
adminpassFile = cfg.adminpassFile;
|
||||
adminpassFile = config.age.secrets.nextcloudAdminPass.path;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -114,21 +86,9 @@ in {
|
||||
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.postgresql.databases = [
|
||||
server.infra.postgresql.databases = [
|
||||
{
|
||||
database = "nextcloud";
|
||||
}
|
||||
27
modules/server/services/ollama/default.nix
Normal file
27
modules/server/services/ollama/default.nix
Normal file
@@ -0,0 +1,27 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}: let
|
||||
unit = "ollama";
|
||||
cfg = config.server.services.${unit};
|
||||
in {
|
||||
config = lib.mkIf cfg.enable {
|
||||
environment.systemPackages = with pkgs; [
|
||||
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";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
16
modules/server/services/prowlarr/default.nix
Normal file
16
modules/server/services/prowlarr/default.nix
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
unit = "prowlarr";
|
||||
cfg = config.server.services.${unit};
|
||||
in {
|
||||
config = lib.mkIf cfg.enable {
|
||||
services = {
|
||||
${unit} = {
|
||||
enable = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
17
modules/server/services/radarr/default.nix
Normal file
17
modules/server/services/radarr/default.nix
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
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;
|
||||
};
|
||||
};
|
||||
}
|
||||
17
modules/server/services/sonarr/default.nix
Normal file
17
modules/server/services/sonarr/default.nix
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
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;
|
||||
};
|
||||
};
|
||||
}
|
||||
16
modules/server/services/uptime-kuma/default.nix
Normal file
16
modules/server/services/uptime-kuma/default.nix
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
unit = "uptime-kuma";
|
||||
cfg = config.server.services.${unit};
|
||||
in {
|
||||
config = lib.mkIf cfg.enable {
|
||||
services = {
|
||||
${unit} = {
|
||||
enable = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
59
modules/server/services/vaultwarden/default.nix
Normal file
59
modules/server/services/vaultwarden/default.nix
Normal file
@@ -0,0 +1,59 @@
|
||||
# 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";
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
{
|
||||
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"];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -1,100 +0,0 @@
|
||||
{
|
||||
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"];
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
{
|
||||
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"];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
# from @fufexan & @notthebee
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
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 {
|
||||
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,44 +0,0 @@
|
||||
{
|
||||
lib,
|
||||
config,
|
||||
pkgs,
|
||||
...
|
||||
}: let
|
||||
inherit (lib) mkOption mkEnableOption mkIf types;
|
||||
cfg = config.server.www;
|
||||
srv = config.server;
|
||||
in {
|
||||
options.server.www = {
|
||||
enable = mkEnableOption {
|
||||
description = "Enable personal website";
|
||||
};
|
||||
url = mkOption {
|
||||
default = "";
|
||||
type = types.str;
|
||||
description = ''
|
||||
Public domain name to be used to access the server services via Caddy reverse proxy
|
||||
'';
|
||||
};
|
||||
};
|
||||
config = mkIf cfg.enable {
|
||||
services.caddy.virtualHosts."${cfg.url}" = {
|
||||
useACMEHost = cfg.url;
|
||||
extraConfig = ''
|
||||
handle_path /.well-known/webfinger {
|
||||
header Content-Type application/jrd+json
|
||||
respond `{
|
||||
"subject": "acct:adam@${cfg.url}",
|
||||
"links": [
|
||||
{
|
||||
"rel": "http://openid.net/specs/connect/1.0/issuer",
|
||||
"href": "https://login.${cfg.url}/realms/cnix"
|
||||
}
|
||||
]
|
||||
}`
|
||||
}
|
||||
|
||||
reverse_proxy http://127.0.0.1:8283
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -2,8 +2,7 @@
|
||||
lib,
|
||||
config,
|
||||
...
|
||||
}:
|
||||
let
|
||||
}: let
|
||||
inherit (lib) mkOption types;
|
||||
|
||||
sshKeys = {
|
||||
@@ -16,14 +15,14 @@ let
|
||||
keyName = config.settings.accounts.sshUser or null;
|
||||
|
||||
selectedKey =
|
||||
if keyName != null then
|
||||
if keyName != null
|
||||
then
|
||||
lib.attrByPath [
|
||||
keyName
|
||||
] (builtins.abort "No SSH key defined for hostname/key '${toString keyName}'") sshKeys
|
||||
else
|
||||
builtins.abort "No accounts.sshUser provided, cannot select SSH key.";
|
||||
in
|
||||
{
|
||||
] (builtins.abort "No SSH key defined for hostname/key '${toString keyName}'")
|
||||
sshKeys
|
||||
else builtins.abort "No accounts.sshUser provided, cannot select SSH key.";
|
||||
in {
|
||||
options.settings.accounts = {
|
||||
username = mkOption {
|
||||
type = types.str;
|
||||
@@ -46,5 +45,21 @@ in
|
||||
default = null;
|
||||
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;
|
||||
};
|
||||
refreshRate = mkOption {
|
||||
type = types.int;
|
||||
default = 60;
|
||||
type = types.str;
|
||||
default = "60";
|
||||
};
|
||||
transform = mkOption {
|
||||
type = types.int;
|
||||
|
||||
@@ -5,9 +5,7 @@
|
||||
"aarch64-linux"
|
||||
];
|
||||
|
||||
perSystem =
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
perSystem = {pkgs, ...}: {
|
||||
packages = {
|
||||
# instant repl with automatic flake loading
|
||||
repl = pkgs.callPackage ./repl {};
|
||||
|
||||
5
scripts/bin/choosepaper.sh
Normal file
5
scripts/bin/choosepaper.sh
Normal file
@@ -0,0 +1,5 @@
|
||||
export bg_dir="$HOME/media/images/bgs/"
|
||||
find "$bg_dir" -type f | fzf --reverse --preview 'pistol {}' | while read -r img; do
|
||||
pkill swaybg || true
|
||||
swaybg -m fill -o '*' -i "$img" &
|
||||
done
|
||||
@@ -33,6 +33,20 @@ in
|
||||
);
|
||||
};
|
||||
|
||||
".local/bin/choosepaper.sh" = {
|
||||
source = getExe (
|
||||
pkgs.writeShellApplication {
|
||||
name = "spawn";
|
||||
runtimeInputs = with pkgs; [
|
||||
fzf
|
||||
swaybg
|
||||
pistol
|
||||
];
|
||||
text = readFile ./bin/choosepaper.sh;
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
".local/bin/pavucontrol-toggle.sh" = {
|
||||
source = getExe (
|
||||
pkgs.writeShellApplication {
|
||||
|
||||
14
secrets/authentikCloudflared.age
Normal file
14
secrets/authentikCloudflared.age
Normal file
@@ -0,0 +1,14 @@
|
||||
age-encryption.org/v1
|
||||
-> ssh-ed25519 t9iOEg 2oTh42u4hxJGAypwwLJwDCPMngauHB8BhKA83xAXr1M
|
||||
Sr6Hbfnd52F0dUk5RO3wxxJ7RGi3+NUCBq/MzDbKR7s
|
||||
-> ssh-ed25519 KUYMFA O2j6gYY1QR1ZlFiWw+7y6nKUeE658Wp3PdV6dsMqwTU
|
||||
NYwnTkZX5PHnNtL1vqJqIsYzIFUY43AVso8ecMAHvWs
|
||||
-> ssh-ed25519 76RhUQ VTzoQh0fHrG41Gr0YnPY7Jz7yFFugigm/DpUUE/Ny18
|
||||
SITvKJf5+ql4DhpJoPVvEXdLGIBeKnlLlm8u4QPr0RY
|
||||
-> ssh-ed25519 Jf8sqw oVI2y3zqpswvyZoNwklrKI1ZbxMJ5a1kzc43RErkbD8
|
||||
aHNuHMH2XNQ7+9sfsA8LMhBSgTDmvmI1wY26V2j+lsE
|
||||
--- 0UL0vxM2f5IeVhDO1Cg7SUmhuvpFh+GsEEW4g5JEORU
|
||||
<EFBFBD>)q<>$*<2A><><EFBFBD>b<10>X<EFBFBD><58><EFBFBD>`<60> %f
|
||||
_<EFBFBD>%%1ݗ<><DD97><EFBFBD>)<29><>fT<66>٧&<26>`+<2B>K<EFBFBD><4B>q<EFBFBD><71>I<><EEADBE><EFBFBD><EFBFBD><EFBFBD><19><><03>\=<3D>M<EFBFBD><4D><18>
|
||||
!<21><>7<EFBFBD>b<EFBFBD>]<5D>X<>_lri<72>_<EFBFBD><03><>;<3B>R
|
||||
<EFBFBD>)<29><>c<EFBFBD>H<><48>5.p<>:m<>_<EFBFBD>&Vj/<2F><01><>Ra|MU<4D><55>b<EFBFBD><62><02>y<EFBFBD><79><EFBFBD><EFBFBD>El<45>nS<6E>9"<11><>گ+<<3C>
|
||||
11
secrets/crowdsecApi.age
Normal file
11
secrets/crowdsecApi.age
Normal file
@@ -0,0 +1,11 @@
|
||||
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><>
|
||||
12
secrets/giteaCloudflared.age
Normal file
12
secrets/giteaCloudflared.age
Normal file
@@ -0,0 +1,12 @@
|
||||
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
|
||||
@@ -1,12 +1,11 @@
|
||||
age-encryption.org/v1
|
||||
-> ssh-ed25519 t9iOEg YHd2jugviPL+l0qu9sfKGQMhadhh8yV2CEXRhyRMo0Y
|
||||
TsTGSSKMni3aAGelZQZRm11l9Gy0K2EuXE0mWoR5ri0
|
||||
-> ssh-ed25519 KUYMFA Mw9YsgXeolm1FB6KPpibun4gm9RlBCbVoZHh6gwIiBs
|
||||
T7eSNqVr9TZQ2TwRjmjEluqRbCuv2rt7W/zGeXTHvq4
|
||||
-> ssh-ed25519 76RhUQ RpdKCq6ztmllb9zkJ13D1GkHNtU7asvMImtRF+hmXVg
|
||||
J7u+MAU/A6cGvKq9ljc62YDzOAZrDGCovNxkhfSRMPg
|
||||
-> ssh-ed25519 Jf8sqw DmmVZgw3QlOBSYbAq7U40u8tEByPfOZmmSxb54NSaTo
|
||||
CzmB5eZeGE9459QkPSku46ctDg+F39VeWZZl8l0A3n4
|
||||
--- w/ZxO5JNsOmJ8HMw1lkETG6yxTuuQH8crwiIuMsG3mY
|
||||
%ΒDR<><52>+'}<7D>,<2C>;<3B><>><EFBFBD><EFBFBD>><EFBFBD><EFBFBD>&
|
||||
_8<EFBFBD><17>+G<>%<25><>u<EFBFBD>q<EFBFBD><71><EFBFBD><EFBFBD>Wy(<28>Q<EFBFBD>B<EFBFBD><42>#,<2C>:<3A><><EFBFBD><EFBFBD>y
|
||||
-> ssh-ed25519 t9iOEg soUBuL30TIFNz0ssNsAgsXvBX8zHIegjTxXZWvofnUM
|
||||
L7QLYInnXK3NH9lPDv2cVavmDKEFbAA5ytXbYk9p+5I
|
||||
-> ssh-ed25519 KUYMFA Q+oMze/zGxtC9QzASd/2uVXuCEx+Pch21VN/A5CxTHA
|
||||
iu9+A2/trjm+qr89Z4wmdYQky9ieDBuuSNKa5LX7EwI
|
||||
-> ssh-ed25519 76RhUQ zuf44eu7FnCtuqTZEbjZb8MA27Fc9N0Pd640IoUVTn4
|
||||
rcGaL5osCcCFgw9tGnviz6DSD2/MlSJjJyBpJXPTmM4
|
||||
-> ssh-ed25519 Jf8sqw nj2HZZ60Ew758i2tr2aFZuQkUw2VvUYJioGVz9mpeUw
|
||||
Q4K8yAFZLa8juxmGNEFPgZLsIHEKFX7/PIG0dy2RWKQ
|
||||
--- mjB7Qenx4RAnECaEi/7rrRJVIq8dEJ4BSXpg+sUjezg
|
||||
J?<3F>M$<24><>O<>#<1A><0E>ҨZ<D2A8><5A>M<EFBFBD>D<EFBFBD>y<EFBFBD><79>/a<><04><><EFBFBD><EFBFBD>i!<21>(<28><><EFBFBD>\<5C><><EFBFBD><EFBFBD><EFBFBD>+<2B>I<>YV<59><56>k<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user