Compare commits

...

200 Commits

Author SHA1 Message Date
384b18b575 313 current 2025-10-11 18:01:55 25.05.20251006.20c4598 6.12.50 * 2025-10-11 18:08:36 -05:00
21ecf083d2 312 current 2025-10-11 17:54:46 25.05.20251006.20c4598 6.12.50 * 2025-10-11 18:02:03 -05:00
cb340e679c 311 current 2025-10-11 17:44:24 25.05.20251006.20c4598 6.12.50 * 2025-10-11 17:54:48 -05:00
476a2106e1 310 current 2025-10-11 17:42:26 25.05.20251006.20c4598 6.12.50 * 2025-10-11 17:44:27 -05:00
03cff3b3e0 309 current 2025-10-11 17:35:20 25.05.20251006.20c4598 6.12.50 * 2025-10-11 17:42:29 -05:00
d759a3e747 308 current 2025-10-11 17:30:56 25.05.20251006.20c4598 6.12.50 * 2025-10-11 17:35:22 -05:00
9fca78ed4c 307 current 2025-10-11 17:27:31 25.05.20251006.20c4598 6.12.50 * 2025-10-11 17:30:59 -05:00
634e450ba1 306 current 2025-10-11 17:04:37 25.05.20251006.20c4598 6.12.50 * 2025-10-11 17:27:34 -05:00
bcfdcad1b2 306 current 2025-10-11 17:04:37 25.05.20251006.20c4598 6.12.50 * 2025-10-11 17:26:32 -05:00
cbaa2b9eb9 306 current 2025-10-11 17:04:37 25.05.20251006.20c4598 6.12.50 * 2025-10-11 17:25:08 -05:00
3f0900ed10 306 current 2025-10-11 17:04:37 25.05.20251006.20c4598 6.12.50 * 2025-10-11 17:24:32 -05:00
7326275c09 305 current 2025-10-11 16:58:36 25.05.20251006.20c4598 6.12.50 * 2025-10-11 17:04:40 -05:00
0ede6674dd 304 current 2025-10-11 16:50:34 25.05.20251006.20c4598 6.12.50 * 2025-10-11 16:58:38 -05:00
5c53a81353 303 current 2025-10-11 16:41:52 25.05.20251006.20c4598 6.12.50 * 2025-10-11 16:50:36 -05:00
e4bdf3af43 302 current 2025-10-11 16:40:25 25.05.20251006.20c4598 6.12.50 * 2025-10-11 16:41:54 -05:00
82dbb34bd0 301 current 2025-10-11 16:34:19 25.05.20251006.20c4598 6.12.50 * 2025-10-11 16:40:28 -05:00
ada2bf81db 301 current 2025-10-11 16:34:19 25.05.20251006.20c4598 6.12.50 * 2025-10-11 16:37:13 -05:00
a17626a9cb 300 current 2025-10-11 15:30:33 25.05.20251006.20c4598 6.12.50 * 2025-10-11 16:34:22 -05:00
dbca751466 300 current 2025-10-11 15:30:33 25.05.20251006.20c4598 6.12.50 * 2025-10-11 16:31:50 -05:00
91f82d7dc3 300 current 2025-10-11 15:30:33 25.05.20251006.20c4598 6.12.50 * 2025-10-11 16:31:12 -05:00
c637b6802b 300 current 2025-10-11 15:30:33 25.05.20251006.20c4598 6.12.50 * 2025-10-11 16:29:03 -05:00
f0ec85cc03 300 current 2025-10-11 15:30:33 25.05.20251006.20c4598 6.12.50 * 2025-10-11 16:28:13 -05:00
47ab6fa142 299 current 2025-10-11 14:41:20 25.05.20251006.20c4598 6.12.50 * 2025-10-11 15:30:35 -05:00
11028080bb 299 current 2025-10-11 14:41:20 25.05.20251006.20c4598 6.12.50 * 2025-10-11 15:27:52 -05:00
49528805a5 299 current 2025-10-11 14:41:20 25.05.20251006.20c4598 6.12.50 * 2025-10-11 15:24:56 -05:00
bbda7104ba 299 current 2025-10-11 14:41:20 25.05.20251006.20c4598 6.12.50 * 2025-10-11 15:23:15 -05:00
32904bd35e 299 current 2025-10-11 14:41:20 25.05.20251006.20c4598 6.12.50 * 2025-10-11 15:21:49 -05:00
b5bbb6fd8e 299 current 2025-10-11 14:41:20 25.05.20251006.20c4598 6.12.50 * 2025-10-11 15:07:17 -05:00
6819b00e6b 298 current 2025-10-11 14:26:58 25.05.20251006.20c4598 6.12.50 * 2025-10-11 14:41:22 -05:00
1911315178 298 current 2025-10-11 14:26:58 25.05.20251006.20c4598 6.12.50 * 2025-10-11 14:36:37 -05:00
79b903403b 298 current 2025-10-11 14:26:58 25.05.20251006.20c4598 6.12.50 * 2025-10-11 14:33:49 -05:00
634b09fc42 298 current 2025-10-11 14:26:58 25.05.20251006.20c4598 6.12.50 * 2025-10-11 14:31:03 -05:00
01fe78bffe 298 current 2025-10-11 14:26:58 25.05.20251006.20c4598 6.12.50 * 2025-10-11 14:30:28 -05:00
790e358869 297 current 2025-10-11 13:48:37 25.05.20251006.20c4598 6.12.50 * 2025-10-11 14:27:01 -05:00
895b5d1add 297 current 2025-10-11 13:48:37 25.05.20251006.20c4598 6.12.50 * 2025-10-11 14:25:45 -05:00
de6b452d78 297 current 2025-10-11 13:48:37 25.05.20251006.20c4598 6.12.50 * 2025-10-11 14:23:01 -05:00
09603e8e30 297 current 2025-10-11 13:48:37 25.05.20251006.20c4598 6.12.50 * 2025-10-11 14:20:33 -05:00
eec5b89396 296 current 2025-10-11 13:35:39 25.05.20251006.20c4598 6.12.50 * 2025-10-11 13:48:39 -05:00
4ba44f7248 296 current 2025-10-11 13:35:39 25.05.20251006.20c4598 6.12.50 * 2025-10-11 13:45:50 -05:00
c749475fa9 296 current 2025-10-11 13:35:39 25.05.20251006.20c4598 6.12.50 * 2025-10-11 13:43:17 -05:00
6347aeab13 296 current 2025-10-11 13:35:39 25.05.20251006.20c4598 6.12.50 * 2025-10-11 13:41:27 -05:00
f9f598827a 295 current 2025-10-11 13:20:27 25.05.20251006.20c4598 6.12.50 * 2025-10-11 13:35:42 -05:00
0335d89b2f 295 current 2025-10-11 13:20:27 25.05.20251006.20c4598 6.12.50 * 2025-10-11 13:33:54 -05:00
b69c92e6db 295 current 2025-10-11 13:20:27 25.05.20251006.20c4598 6.12.50 * 2025-10-11 13:33:06 -05:00
0077c9028a 295 current 2025-10-11 13:20:27 25.05.20251006.20c4598 6.12.50 * 2025-10-11 13:32:29 -05:00
c0e581ff08 295 current 2025-10-11 13:20:27 25.05.20251006.20c4598 6.12.50 * 2025-10-11 13:27:48 -05:00
5ecb7775ae 295 current 2025-10-11 13:20:27 25.05.20251006.20c4598 6.12.50 * 2025-10-11 13:27:04 -05:00
3d7cad4fea 295 current 2025-10-11 13:20:27 25.05.20251006.20c4598 6.12.50 * 2025-10-11 13:25:06 -05:00
952b0cc69a 294 current 2025-10-11 12:58:57 25.05.20251006.20c4598 6.12.50 * 2025-10-11 13:20:30 -05:00
2f86551967 294 current 2025-10-11 12:58:57 25.05.20251006.20c4598 6.12.50 * 2025-10-11 13:18:56 -05:00
43e489ff52 294 current 2025-10-11 12:58:57 25.05.20251006.20c4598 6.12.50 * 2025-10-11 13:01:06 -05:00
3470cb1bbc 293 current 2025-10-11 12:20:27 25.05.20251006.20c4598 6.12.50 * 2025-10-11 13:00:29 -05:00
d46d270ad0 292 current 2025-10-11 12:17:54 25.05.20251006.20c4598 6.12.50 * 2025-10-11 12:20:29 -05:00
7205a6b00e 291 current 2025-10-11 12:01:16 25.05.20251006.20c4598 6.12.50 * 2025-10-11 12:17:56 -05:00
d49ed2acc3 291 current 2025-10-11 12:01:16 25.05.20251006.20c4598 6.12.50 * 2025-10-11 12:16:04 -05:00
89c1be5186 290 current 2025-10-11 11:39:41 25.05.20251006.20c4598 6.12.50 * 2025-10-11 12:01:18 -05:00
7d02cf9b19 290 current 2025-10-11 11:39:41 25.05.20251006.20c4598 6.12.50 * 2025-10-11 12:00:03 -05:00
d7aabfaa4b 290 current 2025-10-11 11:39:41 25.05.20251006.20c4598 6.12.50 * 2025-10-11 11:53:51 -05:00
2eafe082ba 290 current 2025-10-11 11:39:41 25.05.20251006.20c4598 6.12.50 * 2025-10-11 11:52:48 -05:00
efda5e5598 290 current 2025-10-11 11:39:41 25.05.20251006.20c4598 6.12.50 * 2025-10-11 11:51:18 -05:00
1eb60294cb 290 current 2025-10-11 11:39:41 25.05.20251006.20c4598 6.12.50 * 2025-10-11 11:48:30 -05:00
2031aa443f 290 current 2025-10-11 11:39:41 25.05.20251006.20c4598 6.12.50 * 2025-10-11 11:47:35 -05:00
7f56e043e7 290 current 2025-10-11 11:39:41 25.05.20251006.20c4598 6.12.50 * 2025-10-11 11:43:34 -05:00
0d78ee24a0 289 current 2025-10-11 11:25:44 25.05.20251006.20c4598 6.12.50 * 2025-10-11 11:39:44 -05:00
fec6c6c146 288 current 2025-10-11 10:03:00 25.05.20251006.20c4598 6.12.50 * 2025-10-11 11:25:47 -05:00
7bd47ff538 288 current 2025-10-11 10:03:00 25.05.20251006.20c4598 6.12.50 * 2025-10-11 11:24:45 -05:00
0f0f838c1b 288 current 2025-10-11 10:03:00 25.05.20251006.20c4598 6.12.50 * 2025-10-11 11:24:08 -05:00
247ab094d5 288 current 2025-10-11 10:03:00 25.05.20251006.20c4598 6.12.50 * 2025-10-11 11:20:39 -05:00
6508ed6159 288 current 2025-10-11 10:03:00 25.05.20251006.20c4598 6.12.50 * 2025-10-11 11:15:58 -05:00
d924c98656 288 current 2025-10-11 10:03:00 25.05.20251006.20c4598 6.12.50 * 2025-10-11 11:14:03 -05:00
8c33edf4dd 288 current 2025-10-11 10:03:00 25.05.20251006.20c4598 6.12.50 * 2025-10-11 11:11:48 -05:00
d4200497a7 288 current 2025-10-11 10:03:00 25.05.20251006.20c4598 6.12.50 * 2025-10-11 11:11:18 -05:00
d4b38ba1e7 288 current 2025-10-11 10:03:00 25.05.20251006.20c4598 6.12.50 * 2025-10-11 11:10:21 -05:00
fa62f88352 288 current 2025-10-11 10:03:00 25.05.20251006.20c4598 6.12.50 * 2025-10-11 11:05:20 -05:00
c818ac0e34 288 current 2025-10-11 10:03:00 25.05.20251006.20c4598 6.12.50 * 2025-10-11 11:00:36 -05:00
a96471232e 288 current 2025-10-11 10:03:00 25.05.20251006.20c4598 6.12.50 * 2025-10-11 10:58:20 -05:00
fe35a1ef86 288 current 2025-10-11 10:03:00 25.05.20251006.20c4598 6.12.50 * 2025-10-11 10:54:55 -05:00
e211775905 288 current 2025-10-11 10:03:00 25.05.20251006.20c4598 6.12.50 * 2025-10-11 10:53:34 -05:00
1055e10921 288 current 2025-10-11 10:03:00 25.05.20251006.20c4598 6.12.50 * 2025-10-11 10:51:05 -05:00
ee7745f83f 288 current 2025-10-11 10:03:00 25.05.20251006.20c4598 6.12.50 * 2025-10-11 10:49:01 -05:00
3e2ada161a 288 current 2025-10-11 10:03:00 25.05.20251006.20c4598 6.12.50 * 2025-10-11 10:48:10 -05:00
51934f6577 288 current 2025-10-11 10:03:00 25.05.20251006.20c4598 6.12.50 * 2025-10-11 10:46:10 -05:00
a27f922c5b 288 current 2025-10-11 10:03:00 25.05.20251006.20c4598 6.12.50 * 2025-10-11 10:45:04 -05:00
7c5d2df922 288 current 2025-10-11 10:03:00 25.05.20251006.20c4598 6.12.50 * 2025-10-11 10:44:26 -05:00
a3b3441b64 288 current 2025-10-11 10:03:00 25.05.20251006.20c4598 6.12.50 * 2025-10-11 10:42:59 -05:00
ea5501723a 288 current 2025-10-11 10:03:00 25.05.20251006.20c4598 6.12.50 * 2025-10-11 10:36:40 -05:00
347b4e9f74 288 current 2025-10-11 10:03:00 25.05.20251006.20c4598 6.12.50 * 2025-10-11 10:36:01 -05:00
fd553ec4ca 288 current 2025-10-11 10:03:00 25.05.20251006.20c4598 6.12.50 * 2025-10-11 10:29:08 -05:00
65af57f6d9 288 current 2025-10-11 10:03:00 25.05.20251006.20c4598 6.12.50 * 2025-10-11 10:28:37 -05:00
53a3bd0261 288 current 2025-10-11 10:03:00 25.05.20251006.20c4598 6.12.50 * 2025-10-11 10:28:01 -05:00
4206dbbb35 288 current 2025-10-11 10:03:00 25.05.20251006.20c4598 6.12.50 * 2025-10-11 10:27:16 -05:00
4f62d2746d 288 current 2025-10-11 10:03:00 25.05.20251006.20c4598 6.12.50 * 2025-10-11 10:26:40 -05:00
6b01510afb 288 current 2025-10-11 10:03:00 25.05.20251006.20c4598 6.12.50 * 2025-10-11 10:25:39 -05:00
3b4d0e3152 288 current 2025-10-11 10:03:00 25.05.20251006.20c4598 6.12.50 * 2025-10-11 10:24:01 -05:00
f51570624b 288 current 2025-10-11 10:03:00 25.05.20251006.20c4598 6.12.50 * 2025-10-11 10:22:54 -05:00
0cb49c0c42 287 current 2025-10-11 09:51:39 25.05.20251006.20c4598 6.12.50 * 2025-10-11 10:03:02 -05:00
f3127697ca 287 current 2025-10-11 09:51:39 25.05.20251006.20c4598 6.12.50 * 2025-10-11 10:02:20 -05:00
846d531ad3 287 current 2025-10-11 09:51:39 25.05.20251006.20c4598 6.12.50 * 2025-10-11 09:55:24 -05:00
58007d7743 287 current 2025-10-11 09:51:39 25.05.20251006.20c4598 6.12.50 * 2025-10-11 09:54:14 -05:00
d258d95057 286 current 2025-10-11 09:36:17 25.05.20251006.20c4598 6.12.50 * 2025-10-11 09:51:41 -05:00
8d5743c0bc 286 current 2025-10-11 09:36:17 25.05.20251006.20c4598 6.12.50 * 2025-10-11 09:49:52 -05:00
f4b71070ce 286 current 2025-10-11 09:36:17 25.05.20251006.20c4598 6.12.50 * 2025-10-11 09:48:26 -05:00
badcab048c 286 current 2025-10-11 09:36:17 25.05.20251006.20c4598 6.12.50 * 2025-10-11 09:45:38 -05:00
730bf26b93 285 current 2025-10-11 08:57:30 25.05.20251006.20c4598 6.12.50 * 2025-10-11 09:36:19 -05:00
d333b3186b 285 current 2025-10-11 08:57:30 25.05.20251006.20c4598 6.12.50 * 2025-10-11 09:32:15 -05:00
12936f35e2 285 current 2025-10-11 08:57:30 25.05.20251006.20c4598 6.12.50 * 2025-10-11 09:31:40 -05:00
f50139dfca 285 current 2025-10-11 08:57:30 25.05.20251006.20c4598 6.12.50 * 2025-10-11 09:28:20 -05:00
f5625cc963 285 current 2025-10-11 08:57:30 25.05.20251006.20c4598 6.12.50 * 2025-10-11 09:26:10 -05:00
2854340455 285 current 2025-10-11 08:57:30 25.05.20251006.20c4598 6.12.50 * 2025-10-11 09:23:57 -05:00
1533db75f4 285 current 2025-10-11 08:57:30 25.05.20251006.20c4598 6.12.50 * 2025-10-11 09:22:42 -05:00
6fe75b1221 285 current 2025-10-11 08:57:30 25.05.20251006.20c4598 6.12.50 * 2025-10-11 09:21:40 -05:00
50e70d1cd1 285 current 2025-10-11 08:57:30 25.05.20251006.20c4598 6.12.50 * 2025-10-11 09:20:52 -05:00
83e60189b6 285 current 2025-10-11 08:57:30 25.05.20251006.20c4598 6.12.50 * 2025-10-11 09:19:43 -05:00
6a92cae6f7 285 current 2025-10-11 08:57:30 25.05.20251006.20c4598 6.12.50 * 2025-10-11 09:19:16 -05:00
9e30589699 285 current 2025-10-11 08:57:30 25.05.20251006.20c4598 6.12.50 * 2025-10-11 09:15:18 -05:00
e6039316db 284 current 2025-10-11 08:13:32 25.05.20251006.20c4598 6.12.50 * 2025-10-11 08:57:32 -05:00
0f5b1d83b5 283 current 2025-10-11 06:19:49 25.05.20251006.20c4598 6.12.50 * 2025-10-11 08:13:35 -05:00
0fb8657c2e 282 current 2025-10-11 06:07:58 25.05.20251006.20c4598 6.12.50 * 2025-10-11 06:19:51 -05:00
59dd4bbe70 281 current 2025-10-11 05:45:24 25.05.20251006.20c4598 6.12.50 * 2025-10-11 06:08:01 -05:00
9e00aeca04 280 current 2025-10-11 05:36:52 25.05.20251006.20c4598 6.12.50 * 2025-10-11 05:45:31 -05:00
0c6c2562f3 280 current 2025-10-11 05:36:52 25.05.20251006.20c4598 6.12.50 * 2025-10-11 05:42:30 -05:00
4bac164d92 280 current 2025-10-11 05:36:52 25.05.20251006.20c4598 6.12.50 * 2025-10-11 05:41:34 -05:00
afccaa5886 280 current 2025-10-11 05:36:52 25.05.20251006.20c4598 6.12.50 * 2025-10-11 05:40:29 -05:00
6a60ce6b85 279 current 2025-10-11 05:35:16 25.05.20251006.20c4598 6.12.50 * 2025-10-11 05:36:55 -05:00
bf908ac917 278 current 2025-10-11 05:22:07 25.05.20251006.20c4598 6.12.50 * 2025-10-11 05:35:19 -05:00
7ceb225b06 278 current 2025-10-11 05:22:07 25.05.20251006.20c4598 6.12.50 * 2025-10-11 05:30:57 -05:00
6b291ecd40 278 current 2025-10-11 05:22:07 25.05.20251006.20c4598 6.12.50 * 2025-10-11 05:29:41 -05:00
64d7b799be 278 current 2025-10-11 05:22:07 25.05.20251006.20c4598 6.12.50 * 2025-10-11 05:28:00 -05:00
33bfd2ed4f 277 current 2025-10-11 05:18:00 25.05.20251006.20c4598 6.12.50 * 2025-10-11 05:22:10 -05:00
5ad52957fa 276 current 2025-10-11 05:12:51 25.05.20251006.20c4598 6.12.50 * 2025-10-11 05:18:02 -05:00
b3aa8fe80a 275 current 2025-10-11 05:11:39 25.05.20251006.20c4598 6.12.50 * 2025-10-11 05:12:54 -05:00
d43f12cdd2 274 current 2025-10-11 05:02:07 25.05.20251006.20c4598 6.12.50 * 2025-10-11 05:11:42 -05:00
ff90df08d0 274 current 2025-10-11 05:02:07 25.05.20251006.20c4598 6.12.50 * 2025-10-11 05:10:43 -05:00
3fd4bb375e 274 current 2025-10-11 05:02:07 25.05.20251006.20c4598 6.12.50 * 2025-10-11 05:09:57 -05:00
a2ebf1dd31 274 current 2025-10-11 05:02:07 25.05.20251006.20c4598 6.12.50 * 2025-10-11 05:08:59 -05:00
1bab984f02 274 current 2025-10-11 05:02:07 25.05.20251006.20c4598 6.12.50 * 2025-10-11 05:08:32 -05:00
9fc91817fd 273 current 2025-10-11 04:43:13 25.05.20251006.20c4598 6.12.50 * 2025-10-11 05:02:10 -05:00
4be5721730 272 current 2025-10-11 04:36:05 25.05.20251006.20c4598 6.12.50 * 2025-10-11 04:43:15 -05:00
d45e598a2f 271 current 2025-10-11 04:20:39 25.05.20251006.20c4598 6.12.50 * 2025-10-11 04:36:08 -05:00
b2e4ee7e6b 270 current 2025-10-11 03:40:05 25.05.20251006.20c4598 6.12.50 * 2025-10-11 04:20:42 -05:00
1f2d75d848 270 current 2025-10-11 03:40:05 25.05.20251006.20c4598 6.12.50 * 2025-10-11 04:04:15 -05:00
b51aca18c7 270 current 2025-10-11 03:40:05 25.05.20251006.20c4598 6.12.50 * 2025-10-11 03:40:50 -05:00
d7e1708f65 269 current 2025-10-11 03:39:33 25.05.20251006.20c4598 6.12.50 * 2025-10-11 03:40:08 -05:00
a04fa13800 268 current 2025-10-11 03:24:47 25.05.20251006.20c4598 6.12.50 * 2025-10-11 03:39:36 -05:00
48c6d04db3 268 current 2025-10-11 03:24:47 25.05.20251006.20c4598 6.12.50 * 2025-10-11 03:25:27 -05:00
ff4f6904fd 267 current 2025-10-11 03:22:34 25.05.20251006.20c4598 6.12.50 * 2025-10-11 03:24:55 -05:00
d377cda9a9 267 current 2025-10-11 03:22:34 25.05.20251006.20c4598 6.12.50 * 2025-10-11 03:23:06 -05:00
88bdb0b48c 266 current 2025-10-11 03:12:18 25.05.20251006.20c4598 6.12.50 * 2025-10-11 03:22:46 -05:00
e9b193afc2 266 current 2025-10-11 03:12:18 25.05.20251006.20c4598 6.12.50 * 2025-10-11 03:16:37 -05:00
463250c092 265 current 2025-10-11 03:09:55 25.05.20251006.20c4598 6.12.50 * 2025-10-11 03:12:24 -05:00
0485e78610 264 current 2025-10-11 03:06:37 25.05.20251006.20c4598 6.12.50 * 2025-10-11 03:10:02 -05:00
ce6847fd36 263 current 2025-10-11 02:55:17 25.05.20251006.20c4598 6.12.50 * 2025-10-11 03:06:43 -05:00
502e53377f 262 current 2025-10-11 02:49:09 25.05.20251006.20c4598 6.12.50 * 2025-10-11 02:55:24 -05:00
f54922caf7 262 current 2025-10-11 02:49:09 25.05.20251006.20c4598 6.12.50 * 2025-10-11 02:50:10 -05:00
fc6b0e9390 261 current 2025-10-11 02:26:00 25.05.20251006.20c4598 6.12.50 * 2025-10-11 02:49:16 -05:00
dc4948063e 261 current 2025-10-11 02:26:00 25.05.20251006.20c4598 6.12.50 * 2025-10-11 02:40:43 -05:00
4abe7423c8 261 current 2025-10-11 02:26:00 25.05.20251006.20c4598 6.12.50 * 2025-10-11 02:39:30 -05:00
1d7ac94c5d 261 current 2025-10-11 02:26:00 25.05.20251006.20c4598 6.12.50 * 2025-10-11 02:39:09 -05:00
7d5c027da6 260 current 2025-10-11 02:24:48 25.05.20251006.20c4598 6.12.50 * 2025-10-11 02:26:07 -05:00
180d78430b 259 current 2025-10-11 02:18:02 25.05.20251006.20c4598 6.12.50 * 2025-10-11 02:24:55 -05:00
26eac1e2a7 259 current 2025-10-11 02:18:02 25.05.20251006.20c4598 6.12.50 * 2025-10-11 02:19:17 -05:00
793ffda17a 258 current 2025-10-11 01:50:08 25.05.20251006.20c4598 6.12.50 * 2025-10-11 02:18:05 -05:00
3e37b91846 258 current 2025-10-11 01:50:08 25.05.20251006.20c4598 6.12.50 * 2025-10-11 02:12:52 -05:00
5258bd62d8 257 current 2025-10-11 01:15:03 25.05.20251006.20c4598 6.12.50 * 2025-10-11 01:50:30 -05:00
39e44c0ade 257 current 2025-10-11 01:15:03 25.05.20251006.20c4598 6.12.50 * 2025-10-11 01:48:51 -05:00
cc673dde8e 257 current 2025-10-11 01:15:03 25.05.20251006.20c4598 6.12.50 * 2025-10-11 01:41:47 -05:00
e3c9bd23ee 257 current 2025-10-11 01:15:03 25.05.20251006.20c4598 6.12.50 * 2025-10-11 01:40:17 -05:00
2fccc66805 257 current 2025-10-11 01:15:03 25.05.20251006.20c4598 6.12.50 * 2025-10-11 01:39:34 -05:00
b78ba63ab5 256 current 2025-10-11 00:38:56 25.05.20251006.20c4598 6.12.50 * 2025-10-11 01:15:07 -05:00
d6260546ca 255 current 2025-10-11 00:13:49 25.05.20251006.20c4598 6.12.50 * 2025-10-11 00:38:58 -05:00
477d0bea34 255 current 2025-10-11 00:13:49 25.05.20251006.20c4598 6.12.50 * 2025-10-11 00:37:49 -05:00
aed29a27de 255 current 2025-10-11 00:13:49 25.05.20251006.20c4598 6.12.50 * 2025-10-11 00:33:02 -05:00
d0c59fa764 255 current 2025-10-11 00:13:49 25.05.20251006.20c4598 6.12.50 * 2025-10-11 00:20:09 -05:00
42f5eb9c1a 254 current 2025-10-10 23:53:30 25.05.20251006.20c4598 6.12.50 * 2025-10-11 00:13:51 -05:00
b677b2f547 253 current 2025-10-10 23:51:29 25.05.20251006.20c4598 6.12.50 * 2025-10-10 23:53:34 -05:00
0632c3735e 252 current 2025-10-10 23:46:52 25.05.20251006.20c4598 6.12.50 * 2025-10-10 23:51:33 -05:00
6b919051d9 252 current 2025-10-10 23:46:52 25.05.20251006.20c4598 6.12.50 * 2025-10-10 23:49:44 -05:00
b6a56848b0 251 current 2025-10-10 23:44:52 25.05.20251006.20c4598 6.12.50 * 2025-10-10 23:46:55 -05:00
848a8ec406 251 current 2025-10-10 23:44:52 25.05.20251006.20c4598 6.12.50 * 2025-10-10 23:46:01 -05:00
00992dd0a2 250 current 2025-10-10 23:43:41 25.05.20251006.20c4598 6.12.50 * 2025-10-10 23:44:55 -05:00
a4b0c2b91c 249 current 2025-10-10 23:12:14 25.05.20251006.20c4598 6.12.50 * 2025-10-10 23:43:44 -05:00
7eda531e01 249 current 2025-10-10 23:12:14 25.05.20251006.20c4598 6.12.50 * 2025-10-10 23:42:39 -05:00
a8fecf2c26 249 current 2025-10-10 23:12:14 25.05.20251006.20c4598 6.12.50 * 2025-10-10 23:41:04 -05:00
f2f1b9cba5 249 current 2025-10-10 23:12:14 25.05.20251006.20c4598 6.12.50 * 2025-10-10 23:37:32 -05:00
b5fc9b38e4 249 current 2025-10-10 23:12:14 25.05.20251006.20c4598 6.12.50 * 2025-10-10 23:36:22 -05:00
4332cbf69b 249 current 2025-10-10 23:12:14 25.05.20251006.20c4598 6.12.50 * 2025-10-10 23:24:00 -05:00
4bc74cf035 249 current 2025-10-10 23:12:14 25.05.20251006.20c4598 6.12.50 * 2025-10-10 23:14:49 -05:00
622974ad88 248 current 2025-10-10 23:08:55 25.05.20251006.20c4598 6.12.50 * 2025-10-10 23:12:17 -05:00
fa229e997d 248 current 2025-10-10 23:08:55 25.05.20251006.20c4598 6.12.50 * 2025-10-10 23:09:27 -05:00
0e4786a464 247 current 2025-10-10 23:01:56 25.05.20251006.20c4598 6.12.50 * 2025-10-10 23:08:58 -05:00
83612a7f87 247 current 2025-10-10 23:01:56 25.05.20251006.20c4598 6.12.50 * 2025-10-10 23:08:05 -05:00
4cf4edff26 247 current 2025-10-10 23:01:56 25.05.20251006.20c4598 6.12.50 * 2025-10-10 23:05:09 -05:00
9a589ab24a 246 current 2025-10-10 22:49:32 25.05.20251006.20c4598 6.12.50 * 2025-10-10 23:02:00 -05:00
53bf7fd64e 246 current 2025-10-10 22:49:32 25.05.20251006.20c4598 6.12.50 * 2025-10-10 22:55:53 -05:00
d61beb3f7b 245 current 2025-10-10 22:45:03 25.05.20251006.20c4598 6.12.50 * 2025-10-10 22:49:34 -05:00
09991aa67d 244 current 2025-10-10 22:38:41 25.05.20251006.20c4598 6.12.50 * 2025-10-10 22:45:06 -05:00
a8f2cd7331 243 current 2025-10-10 22:37:51 25.05.20251006.20c4598 6.12.50 * 2025-10-10 22:38:44 -05:00
b9a8012a48 242 current 2025-10-10 22:36:02 25.05.20251006.20c4598 6.12.50 * 2025-10-10 22:37:53 -05:00
bc76eb71c3 241 current 2025-10-10 22:34:34 25.05.20251006.20c4598 6.12.50 * 2025-10-10 22:36:04 -05:00
7ff5c40f32 240 current 2025-10-10 21:55:37 25.05.20251006.20c4598 6.12.50 * 2025-10-10 22:34:48 -05:00
29 changed files with 1268 additions and 164 deletions

View File

@@ -1,6 +1,6 @@
# flake for blakes nixos config # flake for blakes nixos config
# define new devices in outputs # define new devices in outputs
# generation: 240 current 2025-10-10 21:55:37 25.05.20251006.20c4598 6.12.50 * # generation: 313 current 2025-10-11 18:01:55 25.05.20251006.20c4598 6.12.50 *
{ {
description = "blakes nix config"; description = "blakes nix config";
inputs = { inputs = {

View File

@@ -20,12 +20,9 @@ in
backups.enable = true; backups.enable = true;
backups.repo = "/holocron/backups"; backups.repo = "/holocron/backups";
sops.enable = true; sops.enable = true;
docker.enable = true; podman.enable = true;
syncthing.enable = true; syncthing.enable = true;
tailscale.enable = true; tailscale.enable = true;
vpns.enable = false;
vpns.wg_mex = false;
vpn-confinement.enable = false;
nvidia.enable = true; nvidia.enable = true;
}; };
homelab = { homelab = {
@@ -39,9 +36,10 @@ in
jellyfin.enable = true; jellyfin.enable = true;
vaultwarden.enable = true; vaultwarden.enable = true;
gitea.enable = true; gitea.enable = true;
glance.enable = true;
qbittorrent.enable = true; qbittorrent.enable = true;
immich.enable = true; immich.enable = true;
home-assistant.enable = true; hass.enable = true;
zigbee2mqtt.enable = true; zigbee2mqtt.enable = true;
mosquitto.enable = true; mosquitto.enable = true;
prowlarr.enable = true; prowlarr.enable = true;

View File

@@ -27,6 +27,16 @@ in
type = lib.types.str; type = lib.types.str;
description = "base domain used for reverse proxy"; description = "base domain used for reverse proxy";
}; };
public_domain = lib.mkOption {
default = "blakedheld.xyz";
type = lib.types.str;
description = "base domain used for reverse proxy";
};
host_ip = lib.mkOption {
default = "10.10.0.10";
type = lib.types.str;
description = "base domain used for reverse proxy";
};
}; };
imports = [ imports = [

View File

@@ -62,18 +62,19 @@ in
wants = [ "network.target" ]; wants = [ "network.target" ];
serviceConfig = { serviceConfig = {
User = "minecraft"; User = "minecraft";
Group = "minecraft";
WorkingDirectory = srv.data_dir; WorkingDirectory = srv.data_dir;
UMask = "0007"; UMask = "0007";
ExecStart = "${pkgs.openjdk21}/bin/java -Xmx${srv.ram} -jar ${srv.data_dir}/server.jar nogui"; ExecStart = "${pkgs.openjdk21}/bin/java -Xmx${srv.ram} -jar server.jar nogui";
# ExecStart = "${pkgs.tmux}/bin/tmux new-session -d -s mcrp-${name} '${pkgs.openjdk21}/bin/java -Xmx${srv.ram} -jar ${srv.data_dir}/server.jar nogui'"; # ExecStart = "${pkgs.tmux}/bin/tmux new-session -d -s mc-${name} '${pkgs.openjdk21}/bin/java -Xmx${srv.ram} -jar server.jar nogui'";
# ExecStop = "${pkgs.tmux}/bin/tmux send-keys -t mcrp-${name} C-c"; # stop server by sending Ctrl+C to tmux session # ExecStop = "${pkgs.tmux}/bin/tmux send-keys -t mc-${name} C-c";
Restart = "on-failure"; Restart = "on-failure";
KillMode = "process"; KillMode = "process";
}; };
wantedBy = [ "multi-user.target" ]; wantedBy = [ "multi-user.target" ];
}) servers; }) servers;
environment.systemPackages = with pkgs; [ openjdk21 mcrcon ]; environment.systemPackages = with pkgs; [ openjdk21 mcrcon tmux ];
services.mysql = { services.mysql = {
enable = true; enable = true;
@@ -128,9 +129,14 @@ in
}; };
# add to backups # add to backups
modules.system.backups.paths = lib.mkIf cfg.backup [ cfg.data_dir ]; modules.system.backups.baks = lib.listToAttrs (
lib.mapAttrsToList (srv_name: cfg:
{
name = srv_name; # attribute key
value = { paths = [ cfg.data_dir ]; }; # attribute value
}
) servers
);
}; };
} }

View File

@@ -81,7 +81,17 @@ in
}; };
}; };
# add to glance
modules.services.glance.links.mediastack = [{
title = service;
url = "https://${cfg.url}";
error-url = "http://${homelab.host_ip}:${toString cfg.port}";
check-url = "http://${homelab.host_ip}:${toString cfg.port}";
icon = "di:${service}"; }];
# add to backups # add to backups
modules.system.backups.paths = lib.mkIf cfg.backup [ cfg.data_dir ]; modules.system.backups.baks = {
${service} = { paths = [ cfg.data_dir ]; };
};
}; };
} }

View File

@@ -83,7 +83,17 @@ in
}; };
}; };
# add to glance
modules.services.glance.links.mediastack = [{
title = service;
url = "https://${cfg.url}";
error-url = "http://${homelab.host_ip}:${toString cfg.port}";
check-url = "http://${homelab.host_ip}:${toString cfg.port}";
icon = "di:${service}"; }];
# add to backups # add to backups
modules.system.backups.paths = lib.mkIf cfg.backup [ cfg.data_dir ]; modules.system.backups.baks = {
${service} = { paths = [ cfg.data_dir ]; };
};
}; };
} }

View File

@@ -86,7 +86,17 @@ in
}; };
}; };
# add to glance
modules.services.glance.links.mediastack = [{
title = service;
url = "https://${cfg.url}";
error-url = "http://${homelab.host_ip}:${toString cfg.port}";
check-url = "http://${homelab.host_ip}:${toString cfg.port}";
icon = "di:${service}"; }];
# add to backups # add to backups
modules.system.backups.paths = lib.mkIf cfg.backup [ cfg.data_dir ]; modules.system.backups.baks = {
${service} = { paths = [ cfg.data_dir ]; };
};
}; };
} }

View File

@@ -84,7 +84,17 @@ in
}; };
}; };
# add to glance
modules.services.glance.links.mediastack = [{
title = service;
url = "https://${cfg.url}";
error-url = "http://${homelab.host_ip}:${toString cfg.port}";
check-url = "http://${homelab.host_ip}:${toString cfg.port}";
icon = "di:${service}"; }];
# add to backups # add to backups
modules.system.backups.paths = lib.mkIf cfg.backup [ cfg.data_dir ]; modules.system.backups.baks = {
${service} = { paths = [ cfg.data_dir ]; };
};
}; };
} }

View File

@@ -3,22 +3,24 @@
{ {
# services show up in glance in reverse import order lmao
imports = [ imports = [
./jellyfin ./smarthome/zigbee2mqtt
./vaultwarden ./vaultwarden
./gitea ./gitea
./qbittorrent
./immich
./uptime-kuma
./nginx-proxy
./smarthome/homeassistant ./smarthome/homeassistant
./smarthome/zigbee2mqtt ./immich
./smarthome/mosquitto
./arr/prowlarr
./arr/flaresolverr
./arr/bazarr ./arr/bazarr
./arr/sonarr ./arr/prowlarr
./qbittorrent
./arr/radarr ./arr/radarr
./arr/sonarr
./jellyfin
./nginx-proxy
./arr/flaresolverr
./smarthome/mosquitto
./uptime-kuma
./glance
]; ];
} }

View File

@@ -85,6 +85,9 @@ in
proxyPass = "http://127.0.0.1:${toString cfg.port}"; proxyPass = "http://127.0.0.1:${toString cfg.port}";
}; };
}; };
# uncomment for service hosted publicly
#---------------------------------------------------------------------------
# # external reverse proxy entry # # external reverse proxy entry
# services.nginx.virtualHosts."${service}.blakedheld.xyz" = { # services.nginx.virtualHosts."${service}.blakedheld.xyz" = {
# forceSSL = true; # forceSSL = true;
@@ -95,6 +98,22 @@ in
# }; # };
# }; # };
# #
# # add to glance public service
# modules.services.glance.links.<category> = [{
# title = service;
# url = "https://pass.${homelab.public_domain}";
# error-url = "http://${homelab.host_ip}:${toString cfg.port}";
# check-url = "http://${homelab.host_ip}:${toString cfg.port}";
# icon = "di:${service}"; }];
#---------------------------------------------------------------------------
# # add to glance local service
# modules.services.glance.links.<category> = [{
# title = service;
# url = "https://${cfg.url}";
# error-url = "http://${homelab.host_ip}:${toString cfg.port}";
# check-url = "http://${homelab.host_ip}:${toString cfg.port}";
# icon = "di:${service}"; }];
#
# sops.secrets = { # sops.secrets = {
# "${service}_" = { # "${service}_" = {
# owner = "${service}"; # owner = "${service}";
@@ -103,6 +122,8 @@ in
# }; # };
# add to backups # add to backups
modules.system.backups.paths = lib.mkIf cfg.backup [ cfg.data_dir ]; modules.system.backups.baks = {
${service} = { paths = [ cfg.data_dir ]; };
};
}; };
} }

View File

@@ -108,6 +108,14 @@ in
}; };
}; };
# add to glance
modules.services.glance.links.services = [{
title = service;
url = "https://git.${homelab.public_domain}";
error-url = "http://${homelab.host_ip}:${toString cfg.port}";
check-url = "http://${homelab.host_ip}:${toString cfg.port}";
icon = "di:${service}"; }];
sops.secrets = { sops.secrets = {
"${service}_database_password" = { "${service}_database_password" = {
owner = "${service}"; owner = "${service}";
@@ -116,6 +124,8 @@ in
}; };
# add to backups # add to backups
modules.system.backups.paths = lib.mkIf cfg.backup [ cfg.data_dir ]; modules.system.backups.baks = {
${service} = { paths = [ cfg.data_dir ]; };
};
}; };
} }

View File

@@ -0,0 +1,256 @@
{ pkgs, config, lib, ... }:
/*
this is a wrapper module for glance that allows you to
to pass monitor entries in with nix, all declaratively!
| <8yy> |
V V
# add to glance
modules.services.glance.links.mediastack = [{
title = service;
url = "https://${cfg.url}";
error-url = "http://${homelab.host_ip}:${toString cfg.port}";
check-url = "http://${homelab.host_ip}:${toString cfg.port}";
icon = "di:${service}";
allow-insecure = true; }];
*/
let
service = "glance";
cfg = config.modules.services.${service};
sec = config.sops.secrets;
homelab = config.modules.homelab;
in
{
options.modules.services.${service} = {
enable = lib.mkEnableOption "enables ${service}";
# set port options
port = lib.mkOption {
type = lib.types.int;
default = 7700;
description = "set port for ${service} (default: ${toString cfg.port}";
};
url = lib.mkOption {
type = lib.types.str;
default = "${homelab.base_domain}";
description = "set domain for ${service}";
};
data_dir = lib.mkOption {
type = lib.types.str;
default = "/var/lib/${service}";
description = "set data directory for ${service}";
};
ids = lib.mkOption {
type = lib.types.int;
default = cfg.port;
description = "set uid and pid of ${service} user (matches port by default)";
};
backup = lib.mkOption {
type = lib.types.bool;
default = true;
description = "enable backups for ${service}";
};
links = {
services = lib.mkOption {
type = lib.types.listOf lib.types.attrs;
default = [];
description = "list of links for ${service}";
};
mediastack = lib.mkOption {
type = lib.types.listOf lib.types.attrs;
default = [];
description = "list of links for ${service}";
};
system = lib.mkOption {
type = lib.types.listOf lib.types.attrs;
default = [];
description = "list of links for ${service}";
};
};
};
config = lib.mkIf cfg.enable {
# declare ${service} group
users.groups.${service} = { gid = lib.mkForce cfg.ids; };
# declare ${service} user
users.users.${service} = {
description = "${service} server user";
uid = lib.mkForce cfg.ids;
isSystemUser = true;
home = cfg.data_dir;
createHome = true;
group = "${service}";
extraGroups = [];
};
services.${service} = {
enable = true;
openFirewall = true;
settings = {
server = {
host = "0.0.0.0";
port = cfg.port;
};
pages = [
{
name = "violet";
hide-desktop-navigation = true;
columns = [
{
size = "small";
widgets = [
{ type = "calendar"; first-day-of-week = "monday"; }
{ type = "server-stats"; servers = [ { type = "local"; name = "violet"; } ]; }
{
type = "clock";
hour-format = "24h";
timezones = [
{ timezone = "America/Chicago"; label = "HTX"; }
{ timezone = "America/Denver"; label = "AF"; }
];
}
{ type = "twitch-channels"; channels = [ "mang0" "SaltSSBM" "thewaffle77" "ironmouse" "linustech" ]; }
];
}
{
size = "full";
widgets = [
{
type = "search";
autofocus = true;
search-engine = "https://www.ecosia.org/search?q={QUERY}";
new-tab = true;
bangs = [
{ title = "YouTube"; shortcut = "!y"; url = "https://www.youtube.com/results?search_query={QUERY}"; }
{ title = "Google"; shortcut = "!g"; url = "https://www.google.com/search?q={QUERY}"; }
{ title = "Github"; shortcut = "!gh"; url = "https://github.com/search?q={QUERY}&type=repositories"; }
];
}
{
type = "monitor";
cache = "1m";
title = "services";
sites = cfg.links.services;
# sites = [
# { title = "jellyfin"; url = "https://media.blakedheld.xyz"; icon = "di:jellyfin"; }
# { title = "audiobookshelf"; url = "https://audiobooks.blakedheld.xyz"; icon = "di:audiobookshelf"; }
# { title = "yacreader"; url = "http://10.10.0.30:3434"; icon = "/assets/icons/yacreader.png"; }
# { title = "sonarr"; url = "http://10.10.0.30:3636"; icon = "di:sonarr"; }
# { title = "qbittorrent"; url = "http://10.10.0.40:3333"; icon = "di:qbittorrent"; }
# { title = "radarr"; url = "http://10.10.0.30:3737"; icon = "di:radarr"; }
# { title = "kiwix"; url = "http://10.10.0.30:5050"; icon = "di:kiwix"; }
# { title = "prowlarr"; url = "http://10.10.0.30:3535"; icon = "di:prowlarr"; }
# { title = "bazarr"; url = "http://10.10.0.30:3838"; icon = "di:bazarr"; }
# ];
}
{
type = "monitor";
cache = "1m";
title = "mediastack";
sites = cfg.links.mediastack;
# [
# { title = "immich"; url = "https://pics.blakedheld.xyz"; icon = "di:immich"; }
# { title = "vaultwarden"; url = "https://pass.blakedheld.xyz"; icon = "di:vaultwarden"; }
# { title = "gitea"; url = "https://git.blakedheld.xyz"; icon = "di:gitea"; }
# { title = "home assistant"; url = "https://home.blakedheld.xyz"; icon = "di:home-assistant"; }
# { title = "zigbee2mqtt"; url = "http://10.10.0.30:4142"; icon = "di:zigbee2mqtt"; }
# { title = "syncthing"; url = "http://10.10.0.20:2222"; icon = "di:syncthing"; }
# { title = "archivebox"; url = "http://10.10.0.30:5656"; icon = "sh:archivebox"; }
# { title = "copyparty"; url = "http://10.10.0.20:3923"; icon = "sh:copyparty"; }
# ];
}
{
type = "monitor";
cache = "1m";
title = "system";
sites = cfg.links.system;
# [
# { title = "proxmox"; url = "http://10.10.0.10:8006"; icon = "di:proxmox"; allow-insecure = true; }
# { title = "nginx"; url = "http://10.10.0.30:8080"; icon = "di:nginx"; }
# { title = "uptime kuma"; url = "http://10.10.0.30:8181"; icon = "di:uptime-kuma"; }
# { title = "tn holocron"; url = "https://10.10.0.20"; icon = "di:truenas"; allow-insecure = true; }
# { title = "bebe"; url = "https://10.10.0.1"; icon = "di:unifi"; allow-insecure = true; }
# ];
}
];
}
{
size = "small";
widgets = [
{ type = "weather"; location = "Pearland, Texas, United States"; units = "imperial"; hour-format = "24h"; }
{
type = "markets";
markets = [
{ symbol = "SPY"; name = "S&P 500"; }
{ symbol = "XMR-USD"; name = "Monero"; }
{ symbol = "NVDA"; name = "NVIDIA"; }
{ symbol = "AAPL"; name = "Apple"; }
{ symbol = "MSFT"; name = "Microsoft"; }
];
}
{
type = "releases";
cache = "1d";
repositories = [
"glanceapp/glance"
"go-gitea/gitea"
"immich-app/immich"
"syncthing/syncthing"
];
}
];
}
];
}
];
};
};
# override umask to make permissions work out
systemd.services.${service}.serviceConfig = {
UMask = lib.mkForce "0007";
# User = "${service}";
# Group = "${service}";
};
# # open firewall
# networking.firewall.allowedTCPPorts = [ cfg.port ];
# internal reverse proxy entry
services.nginx.virtualHosts."${cfg.url}" = {
forceSSL = true;
sslCertificate = sec."ssl_blakedheld_crt".path;
sslCertificateKey = sec."ssl_blakedheld_key".path;
locations."/" = {
proxyPass = "http://127.0.0.1:${toString cfg.port}";
};
};
# # external reverse proxy entry
# services.nginx.virtualHosts."${service}.blakedheld.xyz" = {
# forceSSL = true;
# sslCertificate = sec."ssl_blakedheld_crt".path;
# sslCertificateKey = sec."ssl_blakedheld_key".path;
# locations."/" = {
# proxyPass = "http://127.0.0.1:${toString cfg.port}";
# };
# };
#
# sops.secrets = {
# "${service}_" = {
# owner = "${service}";
# group = "${service}";
# };
# };
# add to backups
modules.system.backups.baks = {
${service} = { paths = [ cfg.data_dir ]; };
};
};
}

View File

@@ -0,0 +1,230 @@
{ pkgs, config, lib, ... }:
let
service = "glance";
cfg = config.modules.services.${service};
sec = config.sops.secrets;
homelab = config.modules.homelab;
in
{
options.modules.services.${service} = {
enable = lib.mkEnableOption "enables ${service}";
# set port options
port = lib.mkOption {
type = lib.types.int;
default = 7700;
description = "set port for ${service} (default: ${toString cfg.port}";
};
url = lib.mkOption {
type = lib.types.str;
default = "${homelab.base_domain}";
description = "set domain for ${service}";
};
data_dir = lib.mkOption {
type = lib.types.str;
default = "/var/lib/${service}";
description = "set data directory for ${service}";
};
ids = lib.mkOption {
type = lib.types.int;
default = cfg.port;
description = "set uid and pid of ${service} user (matches port by default)";
};
backup = lib.mkOption {
type = lib.types.bool;
default = true;
description = "enable backups for ${service}";
};
pages = lib.mkOption {
type = lib.types.attrsOf (lib.types.submodule {
options.description = lib.mkOption { type = lib.types.str; };
options.url = lib.mkOption { type = lib.types.str; };
options.icon = lib.mkOption { type = lib.types.str; };
options.category = lib.mkOption { type = lib.types.str; };
});
default = {};
description = "configure the service for use in ${service}";
};
};
config = lib.mkIf cfg.enable {
# declare ${service} group
users.groups.${service} = { gid = lib.mkForce cfg.ids; };
# declare ${service} user
users.users.${service} = {
description = "${service} server user";
uid = lib.mkForce cfg.ids;
isSystemUser = true;
home = cfg.data_dir;
createHome = true;
group = "${service}";
extraGroups = [];
};
services.${service} = {
enable = true;
openFirewall = true;
settings = {
server = {
host = "0.0.0.0";
port = cfg.port;
};
pages = [
{
name = "violet";
hide-desktop-navigation = true;
columns = [
{
size = "small";
widgets = [
{ type = "calendar"; first-day-of-week = "monday"; }
{ type = "server-stats"; servers = [ { type = "local"; name = "violet"; } ]; }
{
type = "clock";
hour-format = "24h";
timezones = [
{ timezone = "America/Chicago"; label = "HTX"; }
{ timezone = "America/Denver"; label = "AF"; }
];
}
{ type = "twitch-channels"; channels = [ "mang0" "SaltSSBM" "thewaffle77" "ironmouse" "linustech" ]; }
];
}
{
size = "full";
widgets = [
{
type = "search";
autofocus = true;
search-engine = "https://www.ecosia.org/search?q={QUERY}";
new-tab = true;
bangs = [
{ title = "YouTube"; shortcut = "!y"; url = "https://www.youtube.com/results?search_query={QUERY}"; }
{ title = "Google"; shortcut = "!g"; url = "https://www.google.com/search?q={QUERY}"; }
{ title = "Github"; shortcut = "!gh"; url = "https://github.com/search?q={QUERY}&type=repositories"; }
];
}
{
type = "monitor";
cache = "1m";
title = "mediastack";
sites = [
{ title = "jellyfin"; url = "https://media.blakedheld.xyz"; icon = "di:jellyfin"; }
{ title = "audiobookshelf"; url = "https://audiobooks.blakedheld.xyz"; icon = "di:audiobookshelf"; }
{ title = "yacreader"; url = "http://10.10.0.30:3434"; icon = "/assets/icons/yacreader.png"; }
{ title = "sonarr"; url = "http://10.10.0.30:3636"; icon = "di:sonarr"; }
{ title = "qbittorrent"; url = "http://10.10.0.40:3333"; icon = "di:qbittorrent"; }
{ title = "radarr"; url = "http://10.10.0.30:3737"; icon = "di:radarr"; }
{ title = "kiwix"; url = "http://10.10.0.30:5050"; icon = "di:kiwix"; }
{ title = "prowlarr"; url = "http://10.10.0.30:3535"; icon = "di:prowlarr"; }
{ title = "bazarr"; url = "http://10.10.0.30:3838"; icon = "di:bazarr"; }
];
}
{
type = "monitor";
cache = "1m";
title = "services";
sites = [
{ title = "immich"; url = "https://pics.blakedheld.xyz"; icon = "di:immich"; }
{ title = "vaultwarden"; url = "https://pass.blakedheld.xyz"; icon = "di:vaultwarden"; }
{ title = "gitea"; url = "https://git.blakedheld.xyz"; icon = "di:gitea"; }
{ title = "home assistant"; url = "https://home.blakedheld.xyz"; icon = "di:home-assistant"; }
{ title = "zigbee2mqtt"; url = "http://10.10.0.30:4142"; icon = "di:zigbee2mqtt"; }
{ title = "syncthing"; url = "http://10.10.0.20:2222"; icon = "di:syncthing"; }
{ title = "archivebox"; url = "http://10.10.0.30:5656"; icon = "sh:archivebox"; }
{ title = "copyparty"; url = "http://10.10.0.20:3923"; icon = "sh:copyparty"; }
];
}
{
type = "monitor";
cache = "1m";
title = "system";
sites = [
{ title = "proxmox"; url = "http://10.10.0.10:8006"; icon = "di:proxmox"; allow-insecure = true; }
{ title = "nginx"; url = "http://10.10.0.30:8080"; icon = "di:nginx"; }
{ title = "uptime kuma"; url = "http://10.10.0.30:8181"; icon = "di:uptime-kuma"; }
{ title = "tn holocron"; url = "https://10.10.0.20"; icon = "di:truenas"; allow-insecure = true; }
{ title = "bebe"; url = "https://10.10.0.1"; icon = "di:unifi"; allow-insecure = true; }
];
}
];
}
{
size = "small";
widgets = [
{ type = "weather"; location = "Pearland, Texas, United States"; units = "imperial"; hour-format = "24h"; }
{
type = "markets";
markets = [
{ symbol = "SPY"; name = "S&P 500"; }
{ symbol = "XMR-USD"; name = "Monero"; }
{ symbol = "NVDA"; name = "NVIDIA"; }
{ symbol = "AAPL"; name = "Apple"; }
{ symbol = "MSFT"; name = "Microsoft"; }
];
}
{
type = "releases";
cache = "1d";
repositories = [
"glanceapp/glance"
"go-gitea/gitea"
"immich-app/immich"
"syncthing/syncthing"
];
}
];
}
];
}
];
};
};
# override umask to make permissions work out
systemd.services.${service}.serviceConfig = {
UMask = lib.mkForce "0007";
# User = "${service}";
# Group = "${service}";
};
# # open firewall
# networking.firewall.allowedTCPPorts = [ cfg.port ];
# internal reverse proxy entry
services.nginx.virtualHosts."${cfg.url}" = {
forceSSL = true;
sslCertificate = sec."ssl_blakedheld_crt".path;
sslCertificateKey = sec."ssl_blakedheld_key".path;
locations."/" = {
proxyPass = "http://127.0.0.1:${toString cfg.port}";
};
};
# # external reverse proxy entry
# services.nginx.virtualHosts."${service}.blakedheld.xyz" = {
# forceSSL = true;
# sslCertificate = sec."ssl_blakedheld_crt".path;
# sslCertificateKey = sec."ssl_blakedheld_key".path;
# locations."/" = {
# proxyPass = "http://127.0.0.1:${toString cfg.port}";
# };
# };
#
# sops.secrets = {
# "${service}_" = {
# owner = "${service}";
# group = "${service}";
# };
# };
# add to backups
modules.system.backups.baks = {
${service} = { paths = [ cfg.data_dir ]; };
};
};
}

View File

@@ -0,0 +1,230 @@
{ pkgs, config, lib, ... }:
let
service = "glance";
cfg = config.modules.services.${service};
sec = config.sops.secrets;
homelab = config.modules.homelab;
in
{
options.modules.services.${service} = {
enable = lib.mkEnableOption "enables ${service}";
# set port options
port = lib.mkOption {
type = lib.types.int;
default = 7700;
description = "set port for ${service} (default: ${toString cfg.port}";
};
url = lib.mkOption {
type = lib.types.str;
default = "${homelab.base_domain}";
description = "set domain for ${service}";
};
data_dir = lib.mkOption {
type = lib.types.str;
default = "/var/lib/${service}";
description = "set data directory for ${service}";
};
ids = lib.mkOption {
type = lib.types.int;
default = cfg.port;
description = "set uid and pid of ${service} user (matches port by default)";
};
backup = lib.mkOption {
type = lib.types.bool;
default = true;
description = "enable backups for ${service}";
};
pages = lib.mkOption {
type = lib.types.attrsOf (lib.types.submodule {
options.description = lib.mkOption { type = lib.types.str; };
options.url = lib.mkOption { type = lib.types.str; };
options.icon = lib.mkOption { type = lib.types.str; };
options.category = lib.mkOption { type = lib.types.str; };
});
default = {};
description = "configure the service for use in ${service}";
};
};
config = lib.mkIf cfg.enable {
# declare ${service} group
users.groups.${service} = { gid = lib.mkForce cfg.ids; };
# declare ${service} user
users.users.${service} = {
description = "${service} server user";
uid = lib.mkForce cfg.ids;
isSystemUser = true;
home = cfg.data_dir;
createHome = true;
group = "${service}";
extraGroups = [];
};
services.${service} = {
enable = true;
openFirewall = true;
settings = {
server = {
host = "0.0.0.0";
port = cfg.port;
};
pages = [
{
name = "violet";
hide-desktop-navigation = true;
columns = [
{
size = "small";
widgets = [
{ type = "calendar"; first-day-of-week = "monday"; }
{ type = "server-stats"; servers = [ { type = "local"; name = "violet"; } ]; }
{
type = "clock";
hour-format = "24h";
timezones = [
{ timezone = "America/Chicago"; label = "HTX"; }
{ timezone = "America/Denver"; label = "AF"; }
];
}
{ type = "twitch-channels"; channels = [ "mang0" "SaltSSBM" "thewaffle77" "ironmouse" "linustech" ]; }
];
}
{
size = "full";
widgets = [
{
type = "search";
autofocus = true;
search-engine = "https://www.ecosia.org/search?q={QUERY}";
new-tab = true;
bangs = [
{ title = "YouTube"; shortcut = "!y"; url = "https://www.youtube.com/results?search_query={QUERY}"; }
{ title = "Google"; shortcut = "!g"; url = "https://www.google.com/search?q={QUERY}"; }
{ title = "Github"; shortcut = "!gh"; url = "https://github.com/search?q={QUERY}&type=repositories"; }
];
}
{
type = "monitor";
cache = "1m";
title = "mediastack";
sites = [
{ title = "jellyfin"; url = "https://media.blakedheld.xyz"; icon = "di:jellyfin"; }
{ title = "audiobookshelf"; url = "https://audiobooks.blakedheld.xyz"; icon = "di:audiobookshelf"; }
{ title = "yacreader"; url = "http://10.10.0.30:3434"; icon = "/assets/icons/yacreader.png"; }
{ title = "sonarr"; url = "http://10.10.0.30:3636"; icon = "di:sonarr"; }
{ title = "qbittorrent"; url = "http://10.10.0.40:3333"; icon = "di:qbittorrent"; }
{ title = "radarr"; url = "http://10.10.0.30:3737"; icon = "di:radarr"; }
{ title = "kiwix"; url = "http://10.10.0.30:5050"; icon = "di:kiwix"; }
{ title = "prowlarr"; url = "http://10.10.0.30:3535"; icon = "di:prowlarr"; }
{ title = "bazarr"; url = "http://10.10.0.30:3838"; icon = "di:bazarr"; }
];
}
{
type = "monitor";
cache = "1m";
title = "services";
sites = [
{ title = "immich"; url = "https://pics.blakedheld.xyz"; icon = "di:immich"; }
{ title = "vaultwarden"; url = "https://pass.blakedheld.xyz"; icon = "di:vaultwarden"; }
{ title = "gitea"; url = "https://git.blakedheld.xyz"; icon = "di:gitea"; }
{ title = "home assistant"; url = "https://home.blakedheld.xyz"; icon = "di:home-assistant"; }
{ title = "zigbee2mqtt"; url = "http://10.10.0.30:4142"; icon = "di:zigbee2mqtt"; }
{ title = "syncthing"; url = "http://10.10.0.20:2222"; icon = "di:syncthing"; }
{ title = "archivebox"; url = "http://10.10.0.30:5656"; icon = "sh:archivebox"; }
{ title = "copyparty"; url = "http://10.10.0.20:3923"; icon = "sh:copyparty"; }
];
}
{
type = "monitor";
cache = "1m";
title = "system";
sites = [
{ title = "proxmox"; url = "http://10.10.0.10:8006"; icon = "di:proxmox"; allow-insecure = true; }
{ title = "nginx"; url = "http://10.10.0.30:8080"; icon = "di:nginx"; }
{ title = "uptime kuma"; url = "http://10.10.0.30:8181"; icon = "di:uptime-kuma"; }
{ title = "tn holocron"; url = "https://10.10.0.20"; icon = "di:truenas"; allow-insecure = true; }
{ title = "bebe"; url = "https://10.10.0.1"; icon = "di:unifi"; allow-insecure = true; }
];
}
];
}
{
size = "small";
widgets = [
{ type = "weather"; location = "Pearland, Texas, United States"; units = "imperial"; hour-format = "24h"; }
{
type = "markets";
markets = [
{ symbol = "SPY"; name = "S&P 500"; }
{ symbol = "XMR-USD"; name = "Monero"; }
{ symbol = "NVDA"; name = "NVIDIA"; }
{ symbol = "AAPL"; name = "Apple"; }
{ symbol = "MSFT"; name = "Microsoft"; }
];
}
{
type = "releases";
cache = "1d";
repositories = [
"glanceapp/glance"
"go-gitea/gitea"
"immich-app/immich"
"syncthing/syncthing"
];
}
];
}
];
}
];
};
};
# override umask to make permissions work out
systemd.services.${service}.serviceConfig = {
UMask = lib.mkForce "0007";
# User = "${service}";
# Group = "${service}";
};
# # open firewall
# networking.firewall.allowedTCPPorts = [ cfg.port ];
# internal reverse proxy entry
services.nginx.virtualHosts."${cfg.url}" = {
forceSSL = true;
sslCertificate = sec."ssl_blakedheld_crt".path;
sslCertificateKey = sec."ssl_blakedheld_key".path;
locations."/" = {
proxyPass = "http://127.0.0.1:${toString cfg.port}";
};
};
# # external reverse proxy entry
# services.nginx.virtualHosts."${service}.blakedheld.xyz" = {
# forceSSL = true;
# sslCertificate = sec."ssl_blakedheld_crt".path;
# sslCertificateKey = sec."ssl_blakedheld_key".path;
# locations."/" = {
# proxyPass = "http://127.0.0.1:${toString cfg.port}";
# };
# };
#
# sops.secrets = {
# "${service}_" = {
# owner = "${service}";
# group = "${service}";
# };
# };
# add to backups
modules.system.backups.baks = {
${service} = { paths = [ cfg.data_dir ]; };
};
};
}

View File

@@ -96,7 +96,17 @@ in
}; };
}; };
# add to glance
modules.services.glance.links.services = [{
title = service;
url = "https://photos.${homelab.public_domain}";
error-url = "http://${homelab.host_ip}:${toString cfg.port}";
check-url = "http://${homelab.host_ip}:${toString cfg.port}";
icon = "di:${service}"; }];
# add to backups # add to backups
modules.system.backups.paths = lib.mkIf cfg.backup [ cfg.data_dir "/var/lib/redis-immich" ]; modules.system.backups.baks = {
${service} = { paths = [ cfg.data_dir "/var/lib/redis-immich" ]; };
};
}; };
} }

View File

@@ -90,14 +90,17 @@ in
}; };
}; };
# sops.secrets = { # add to glance
# "${service}_" = { modules.services.glance.links.mediastack = [{
# owner = "${service}"; title = service;
# group = "${service}"; url = "https://media.${homelab.public_domain}";
# }; error-url = "http://${homelab.host_ip}:${toString cfg.port}";
# }; check-url = "http://${homelab.host_ip}:${toString cfg.port}";
icon = "di:${service}"; }];
# add to backups # add to backups
modules.system.backups.paths = lib.mkIf cfg.backup [ cfg.data_dir ]; modules.system.backups.baks = {
${service} = { paths = [ cfg.data_dir ]; };
};
}; };
} }

View File

@@ -119,7 +119,17 @@ in
}; };
}; };
# add to glance
modules.services.glance.links.mediastack = [{
title = service;
url = "https://${cfg.url}";
error-url = "http://${homelab.host_ip}:${toString cfg.port}";
check-url = "http://${homelab.host_ip}:${toString cfg.port}";
icon = "di:${service}"; }];
# add to backups # add to backups
modules.system.backups.paths = lib.mkIf cfg.backup [ cfg.data_dir ]; modules.system.backups.baks = {
${service} = { paths = [ cfg.data_dir ]; };
};
}; };
} }

View File

@@ -1,7 +1,8 @@
{ pkgs, config, lib, inputs, ... }: { pkgs, config, lib, inputs, ... }:
let let
service = "home-assistant"; nixservice = "home-assistant";
service = "hass";
cfg = config.modules.services.${service}; cfg = config.modules.services.${service};
sec = config.sops.secrets; sec = config.sops.secrets;
homelab = config.modules.homelab; homelab = config.modules.homelab;
@@ -18,12 +19,12 @@ in
}; };
url = lib.mkOption { url = lib.mkOption {
type = lib.types.str; type = lib.types.str;
default = "hass.${homelab.base_domain}"; default = "${service}.${homelab.base_domain}";
description = "set domain for ${service}"; description = "set domain for ${service}";
}; };
data_dir = lib.mkOption { data_dir = lib.mkOption {
type = lib.types.str; type = lib.types.str;
default = "/var/lib/hass"; default = "/var/lib/${service}";
description = "set data directory for ${service}"; description = "set data directory for ${service}";
}; };
ids = lib.mkOption { ids = lib.mkOption {
@@ -41,53 +42,49 @@ in
config = lib.mkIf cfg.enable { config = lib.mkIf cfg.enable {
# declare ${service} group # declare ${service} group
users.groups.hass = { gid = lib.mkForce cfg.ids; }; users.groups.${service} = { gid = lib.mkForce cfg.ids; };
# declare ${service} user # declare ${service} user
users.users.hass = { users.users.${service} = {
description = "${service} server user"; description = "${service} server user";
uid = lib.mkForce cfg.ids; uid = lib.mkForce cfg.ids;
isSystemUser = true; isSystemUser = true;
#home = cfg.data_dir; home = cfg.data_dir;
#createHome = true; createHome = true;
group = "hass"; group = service;
extraGroups = [ "bluetooth" ]; extraGroups = [];
}; };
# enable the ${service} service # still suss as fuck bro man fuck
services.${service} = { virtualisation.oci-containers.containers = {
enable = true; hass = {
package = inputs.nixpkgs-unstable.legacyPackages.${pkgs.system}.home-assistant; image = "homeassistant/home-assistant:stable";
extraComponents = [ autoStart = true;
# required for onboarding extraOptions = [
"analytics" "--pull=newer"
"google_translate" "--network=host"
"met"
"radio_browser"
"shopping_list"
# zlib
"isal"
]; ];
# imperative config volumes = [
# config = null; "${cfg.data_dir}:/config"
# lovelaceConfig = null; ];
# configDir = cfg.data_dir; # ports = [
# declartive poggers! # "0.0.0.0:7704:8123"
config = { # "0.0.0.0:4141:4141"
# Includes dependencies for a basic setup # ];
default_config = {}; environment = {
TZ = homelab.tz;
PUID = toString config.users.users.${service}.uid;
PGID = toString config.users.groups.${service}.gid;
};
}; };
}; };
# override umask to make permissions work out # override umask to make permissions work out
systemd.services.${service}.serviceConfig = { systemd.services.${service}.serviceConfig = {
UMask = lib.mkForce "0007"; UMask = lib.mkForce "0007";
User = lib.mkForce "hass";
Group = lib.mkForce "hass";
}; };
# # open firewall # open firewall
networking.firewall.allowedTCPPorts = [ cfg.port 8123 ]; networking.firewall.allowedTCPPorts = [ cfg.port 8123 ];
# internal reverse proxy entry # internal reverse proxy entry
@@ -95,28 +92,93 @@ in
forceSSL = true; forceSSL = true;
sslCertificate = sec."ssl_blakedheld_crt".path; sslCertificate = sec."ssl_blakedheld_crt".path;
sslCertificateKey = sec."ssl_blakedheld_key".path; sslCertificateKey = sec."ssl_blakedheld_key".path;
extraConfig = ''
proxy_buffering off;
'';
locations."/" = { locations."/" = {
proxyPass = "http://127.0.0.1:${toString cfg.port}"; proxyPass = "http://127.0.0.1:${toString cfg.port}";
extraConfig =
"proxy_set_header Upgrade $http_upgrade;" +
"proxy_set_header Connection upgrade;"
;
}; };
}; };
# external reverse proxy entry # external reverse proxy entry
services.nginx.virtualHosts."hass.blakedheld.xyz" = { services.nginx.virtualHosts."${service}.blakedheld.xyz" = {
forceSSL = true; forceSSL = true;
sslCertificate = sec."ssl_blakedheld_crt".path; sslCertificate = sec."ssl_blakedheld_crt".path;
sslCertificateKey = sec."ssl_blakedheld_key".path; sslCertificateKey = sec."ssl_blakedheld_key".path;
extraConfig = ''
proxy_buffering off;
'';
locations."/" = { locations."/" = {
proxyPass = "http://127.0.0.1:${toString cfg.port}"; proxyPass = "http://127.0.0.1:${toString cfg.port}";
extraConfig =
"proxy_set_header Upgrade $http_upgrade;" +
"proxy_set_header Connection upgrade;"
;
}; };
}; };
# sops.secrets = { # add to glance
# "${service}_" = { modules.services.glance.links.services = [{
# owner = "${service}"; title = "home assistant";
# group = "${service}"; url = "https://hass.${homelab.public_domain}";
# }; error-url = "http://${homelab.host_ip}:${toString cfg.port}";
# }; check-url = "http://${homelab.host_ip}:${toString cfg.port}";
icon = "di:${nixservice}"; }];
# add to backups # add to backups
modules.system.backups.paths = lib.mkIf cfg.backup [ cfg.data_dir ]; modules.system.backups.baks = {
${service} = { paths = [ cfg.data_dir ]; };
};
}; };
} }
# here lies my tough, and I mean fucking tough, swing at
# getting this to work bare metal, ggs ill see you again
# - didnt take long
# --------------------------------------------------------------------------------
# # enable the ${service} service
# services.${nixservice} = {
# enable = true;
# package = inputs.nixpkgs-unstable.legacyPackages.${pkgs.system}.home-assistant;
# extraComponents = [
# # required for onboarding
# "analytics"
# "google_translate"
# "met"
# "radio_browser"
# "shopping_list"
# "isal"
# "default_config"
# "mqtt"
# ];
# extraPackages = python3Packages: with python3Packages; [
# psycopg2
# universal-silabs-flasher
# getmac
# zha
# ha-silabs-firmware-client
# paho-mqtt
# aiomqtt
# aiounifi
# ibeacon-ble
# ];
# # imperative config
# config = null;
# lovelaceConfig = null;
# configDir = cfg.data_dir;
# # declartive poggers!
## config = {
## # Includes dependencies for a basic setup
## default_config = {};
## };
# };

View File

@@ -60,8 +60,14 @@ in
{ {
port = 1883; port = 1883;
address = "0.0.0.0"; address = "0.0.0.0";
settings.allow_anonymous = true; users.zigbee = {
#passwordFile = sec."mosquitto_password_file".path; # optional acl = [ "readwrite #" ];
hashedPassword = "$7$101$140powz2MtsRawFT$ydndjal9wCAywIWtUEAh/IusdfDFvnHMupTFjdS7Ad/EjsEIbJgHrLY9waCe4Z3142XieuxMrXUDjMTp2qwyiw==";
};
# use with no auth
# settings.allow_anonymous = true;
# acl = [ "pattern readwrite #" ];
# omitPasswordAuth = true;
} }
]; ];
# override umask to make permissions work out # override umask to make permissions work out
@@ -71,27 +77,19 @@ in
Group = "${service}"; Group = "${service}";
}; };
# # open firewall # open firewall
networking.firewall.allowedTCPPorts = [ cfg.port ]; networking.firewall.allowedTCPPorts = [ cfg.port ];
# # internal reverse proxy entry
# services.nginx.virtualHosts."${cfg.url}" = {
# forceSSL = true;
# sslCertificate = sec."ssl_blakedheld_crt".path;
# sslCertificateKey = sec."ssl_blakedheld_key".path;
# locations."/" = {
# proxyPass = "http://127.0.0.1:${toString cfg.port}";
# };
# };
sops.secrets = { sops.secrets = {
"${service}_password_file" = { "${service}_hashed_passwd" = {
owner = "${service}"; owner = "${service}";
group = "${service}"; group = "${service}";
}; };
}; };
# add to backups # add to backups
modules.system.backups.paths = lib.mkIf cfg.backup [ cfg.data_dir ]; modules.system.backups.baks = {
${service} = { paths = [ cfg.data_dir ]; };
};
}; };
} }

View File

@@ -18,7 +18,7 @@ in
}; };
url = lib.mkOption { url = lib.mkOption {
type = lib.types.str; type = lib.types.str;
default = "${service}.${homelab.base_domain}"; default = "z2m.${homelab.base_domain}";
description = "set domain for ${service}"; description = "set domain for ${service}";
}; };
data_dir = lib.mkOption { data_dir = lib.mkOption {
@@ -61,7 +61,11 @@ in
settings = { settings = {
mqtt = { mqtt = {
base_topic = "zigbee2mqtt"; base_topic = "zigbee2mqtt";
client_id = "zigbee2mqtt";
server = "mqtt://localhost:1883"; server = "mqtt://localhost:1883";
user = "!/run/secrets/mosquitto_passwd.yaml user";
password = "!/run/secrets/mosquitto_passwd.yaml password";
keepalive = 20;
}; };
serial = { serial = {
port = "/dev/serial/by-id/usb-Itead_Sonoff_Zigbee_3.0_USB_Dongle_Plus_V2_4a4e75d63653ef1198d728e0174bec31-if00-port0"; port = "/dev/serial/by-id/usb-Itead_Sonoff_Zigbee_3.0_USB_Dongle_Plus_V2_4a4e75d63653ef1198d728e0174bec31-if00-port0";
@@ -99,15 +103,25 @@ in
proxyPass = "http://127.0.0.1:${toString cfg.port}"; proxyPass = "http://127.0.0.1:${toString cfg.port}";
}; };
}; };
#
# sops.secrets = { # add to glance
# "${service}_" = { modules.services.glance.links.services = [{
# owner = "${service}"; title = service;
# group = "${service}"; url = "https://${cfg.url}";
# }; error-url = "http://${homelab.host_ip}:${toString cfg.port}";
# }; check-url = "http://${homelab.host_ip}:${toString cfg.port}";
icon = "di:${service}"; }];
sops.secrets = {
"mosquitto_passwd.yaml" = {
owner = "${service}";
group = "${service}";
};
};
# add to backups # add to backups
modules.system.backups.paths = lib.mkIf cfg.backup [ cfg.data_dir ]; modules.system.backups.baks = {
${service} = { paths = [ cfg.data_dir ]; };
};
}; };
} }

View File

@@ -60,6 +60,7 @@ in
settings = settings =
{ {
PORT = toString cfg.port; PORT = toString cfg.port;
HOST = "0.0.0.0";
}; };
}; };
@@ -83,7 +84,7 @@ in
}; };
}; };
# # external reverse proxy entry # # external reverse proxy entry
# services.nginx.virtualHosts."uptime.blakedheld.xyz" = { # services.nginx.virtualHosts."up.blakedheld.xyz" = {
# forceSSL = true; # forceSSL = true;
# sslCertificate = sec."ssl_blakedheld_crt".path; # sslCertificate = sec."ssl_blakedheld_crt".path;
# sslCertificateKey = sec."ssl_blakedheld_key".path; # sslCertificateKey = sec."ssl_blakedheld_key".path;
@@ -92,6 +93,14 @@ in
# }; # };
# }; # };
# add to glance
modules.services.glance.links.system = [{
title = service;
url = "https://${cfg.url}";
error-url = "http://${homelab.host_ip}:${toString cfg.port}";
check-url = "http://${homelab.host_ip}:${toString cfg.port}";
icon = "di:${service}"; }];
# sops.secrets = { # sops.secrets = {
# "${service}_" = { # "${service}_" = {
# owner = "${service}"; # owner = "${service}";

View File

@@ -103,6 +103,14 @@ in
}; };
}; };
# add to glance
modules.services.glance.links.services = [{
title = service;
url = "https://pass.${homelab.public_domain}";
error-url = "http://${homelab.host_ip}:${toString cfg.port}";
check-url = "http://${homelab.host_ip}:${toString cfg.port}";
icon = "di:${service}"; }];
sops.secrets = { sops.secrets = {
"${service}_admin_token" = { "${service}_admin_token" = {
owner = "${service}"; owner = "${service}";
@@ -111,6 +119,8 @@ in
}; };
# add to backups # add to backups
modules.system.backups.paths = lib.mkIf cfg.backup [ cfg.data_dir ]; modules.system.backups.baks = {
${service} = { paths = [ cfg.data_dir ]; };
};
}; };
} }

View File

@@ -1,76 +1,123 @@
{ config, lib, pkgs, ... }: { config, lib, pkgs, ... }:
/*
this module enables a backup script made with borg!
to use import & set the options below
to declare a backup add the following code
to a module and it will backup all listed paths
in a borg archive to the specified repo
| <3yy> |
V V
modules.system.backups.baks = {
${service} = { paths = [ cfg.data_dir ]; };
};
*/
let let
cfg = config.modules.system.backups; cfg = config.modules.system.backups;
sec = config.sops.secrets;
borg = "${pkgs.borgbackup}/bin/borg"; borg = "${pkgs.borgbackup}/bin/borg";
backup_paths = lib.unique config.modules.system.backups.paths;
passwd_file = config.sops.secrets."borg_passwd".path;
in in
{ {
options.modules.system.backups = { options.modules.system.backups = {
enable = lib.mkEnableOption "enables backups with borg"; enable = lib.mkEnableOption "enables backups with borg";
baks = lib.mkOption {
type = lib.types.attrsOf (lib.types.attrsOf (lib.types.listOf lib.types.path));
default = {};
description = "backup jobs, nested attribute sets should be <bak_name> = paths [<list_of_paths>]";
};
paths = lib.mkOption { paths = lib.mkOption {
type = lib.types.listOf lib.types.path; type = lib.types.list;
default = [];
description = "list of directories to back up";
}; };
repo = lib.mkOption { repo = lib.mkOption {
type = lib.types.path; type = lib.types.path;
default = "/holocron/borg"; default = "/holocron/borg";
description = "borg repository path"; description = "borg repository path";
}; };
passphraseFile = lib.mkOption { passwd_file = lib.mkOption {
type = lib.types.path; type = lib.types.path;
default = passwd_file; default = sec."borg_passwd".path;
description = "borg repository passphrase file"; description = "borg repository passphrase file";
}; };
}; };
config = lib.mkIf (cfg.enable && backup_paths != []) { config = lib.mkIf (cfg.enable && cfg.baks != {}) {
# systemd.tmpfiles.rules = [
# "d ${cfg.repo} 0755 root root"
# ];
systemd.services.backups = { systemd.services.backups = {
description = "backup service with borg!"; description = "backup service with borg!";
path = [ pkgs.borgbackup ]; path = [ pkgs.borgbackup ];
serviceConfig = { serviceConfig = {
Type = "oneshot"; Type = "oneshot";
EnvironmentFile = config.modules.system.backups.passphraseFile; # EnvironmentFile = config.modules.system.backups.passphraseFile;
# the actual script borg is using # the actual script borg is using
ExecStart = pkgs.writeShellScript "borg-backup" '' ExecStart = pkgs.writeShellScript "borg-backup" ''
set -euo pipefail set -euo pipefail
export BORG_PASSPHRASE="$(cat ${passwd_file})" export BORG_PASSPHRASE="$(cat ${cfg.passwd_file})"
export BORG_REPO="${cfg.repo}" export BORG_REPO="${cfg.repo}"
timestamp="$(date +'%Y-%m-%dT%H:%M:%S')" timestamp="$(date +'%Y-%m-%d_%H:%M:%S')"
mode=all
# Initialize repo if it doesn't exist # init repo in needed
if ! borg info "$BORG_REPO" >/dev/null 2>&1; then if ! borg info "$BORG_REPO" >/dev/null 2>&1; then
echo "init borg repo at $BORG_REPO" echo "Initializing Borg repo at $BORG_REPO"
borg init --encryption=repokey "$BORG_REPO" borg init --encryption=repokey "$BORG_REPO"
fi fi
# Create backup borg break-lock "$BORG_REPO" || true
echo "starting backup..."
echo "starting backup at $timestamp"
if [ "$mode" = "sep" ]; then
# loop for each backup
${lib.concatStringsSep "\n\n" (lib.mapAttrsToList (bak_name: bak_paths:
''
echo "------------ Backing up ${bak_name} ------------"
archive="$timestamp-${bak_name}"
echo "backing up: ${lib.concatStringsSep " " bak_paths.paths} $archive"
borg create \ borg create \
--verbose \ --verbose \
--filter AME \ --filter AME \
--list \ --list \
--stats \ --stats \
--show-rc \ --show-rc \
--compression lz4 \ --compression lzma,9 \
"$BORG_REPO::${toString config.networking.hostName}-$timestamp" \ "$BORG_REPO::$archive" \
${lib.concatStringsSep " " cfg.paths} ${lib.concatStringsSep " " bak_paths.paths}
echo "pruning old backups for ${bak_name}..."
# Prune old backups according to retention policy
echo "Pruning old backups..."
borg prune -v --list "$BORG_REPO" \ borg prune -v --list "$BORG_REPO" \
--prefix "${bak_name}-" \
--keep-daily=7 \ --keep-daily=7 \
--keep-weekly=52 \ --keep-weekly=52 \
--keep-monthly=-1 --keep-monthly=-1
echo "backup run complete at \"$BORG_REPO::$archive\""
''
) cfg.baks)}
else
# flatten all paths from cfg.baks into one big list
all_paths="${
lib.concatStringsSep " "
(lib.flatten
(lib.mapAttrsToList (_: bak: bak.paths) cfg.baks))
}"
borg create \
--verbose \
--filter AME \
--list \
--stats \
--show-rc \
--compression lzma,9 \
"$BORG_REPO::$timestamp-${toString config.networking.hostName}" \
$all_paths
echo "$timestamp - backup completed successfully." echo "pruning old backups for ${toString config.networking.hostName}..."
borg prune -v --list "$BORG_REPO" \
--prefix "${toString config.networking.hostName}" \
--keep-daily=7 \
--keep-weekly=52 \
--keep-monthly=-1
echo "backup run complete at \"$BORG_REPO::${toString config.networking.hostName}\""
fi
''; '';
}; };
}; };
@@ -97,6 +144,3 @@ in
}; };
}; };
} }
# add to modules
# modules.system.backups.paths = lib.mkIf cfg.backups [ <path> ];

View File

@@ -0,0 +1,102 @@
{ config, lib, pkgs, ... }:
let
cfg = config.modules.system.backups;
borg = "${pkgs.borgbackup}/bin/borg";
backup_paths = lib.unique config.modules.system.backups.paths;
passwd_file = config.sops.secrets."borg_passwd".path;
in
{
options.modules.system.backups = {
enable = lib.mkEnableOption "enables backups with borg";
paths = lib.mkOption {
type = lib.types.listOf lib.types.path;
default = [];
description = "list of directories to back up";
};
repo = lib.mkOption {
type = lib.types.path;
default = "/holocron/borg";
description = "borg repository path";
};
passphraseFile = lib.mkOption {
type = lib.types.path;
default = passwd_file;
description = "borg repository passphrase file";
};
};
config = lib.mkIf (cfg.enable && backup_paths != []) {
# systemd.tmpfiles.rules = [
# "d ${cfg.repo} 0755 root root"
# ];
systemd.services.backups = {
description = "backup service with borg!";
path = [ pkgs.borgbackup ];
serviceConfig = {
Type = "oneshot";
EnvironmentFile = config.modules.system.backups.passphraseFile;
# the actual script borg is using
ExecStart = pkgs.writeShellScript "borg-backup" ''
set -euo pipefail
export BORG_PASSPHRASE="$(cat ${passwd_file})"
export BORG_REPO="${cfg.repo}"
timestamp="$(date +'%Y-%m-%dT%H:%M:%S')"
# Initialize repo if it doesn't exist
if ! borg info "$BORG_REPO" >/dev/null 2>&1; then
echo "init borg repo at $BORG_REPO"
borg init --encryption=repokey "$BORG_REPO"
fi
# Create backup
echo "starting backup..."
borg create \
--verbose \
--filter AME \
--list \
--stats \
--show-rc \
--compression lzma,9 \
"$BORG_REPO::${toString config.networking.hostName}-$timestamp" \
${lib.concatStringsSep " " cfg.paths}
# Prune old backups according to retention policy
echo "Pruning old backups..."
borg prune -v --list "$BORG_REPO" \
--keep-daily=7 \
--keep-weekly=52 \
--keep-monthly=-1
echo "$timestamp - backup completed successfully."
'';
};
};
# create timer to run backups daily
systemd.timers.backups = {
description = "daily borg backup timer";
wantedBy = [ "timers.target" ];
timerConfig = {
OnCalendar = "daily";
Persistent = true;
};
};
# install borg binary
environment.systemPackages = [ pkgs.borgbackup ];
# declare secret for repo password
sops.secrets = {
"borg_passwd" = {
owner = "root";
group = "root";
};
};
};
}
# add to modules
# modules.system.backups.paths = lib.mkIf cfg.backups [ <path> ];

View File

@@ -6,6 +6,7 @@
./backups.nix ./backups.nix
./sops.nix ./sops.nix
./docker.nix ./docker.nix
./podman.nix
./tailscale.nix ./tailscale.nix
./vpns.nix ./vpns.nix
./vpn-confinement.nix ./vpn-confinement.nix
@@ -23,4 +24,9 @@
modules.system.syncthing.enable = lib.mkDefault false; modules.system.syncthing.enable = lib.mkDefault false;
modules.system.nvidia.enable = lib.mkDefault false; modules.system.nvidia.enable = lib.mkDefault false;
# modules.system.backups.baks = {
# ${service} = { paths = [ cfg.data_dir ]; };
# };
} }

24
modules/system/podman.nix Normal file
View File

@@ -0,0 +1,24 @@
{ pkgs, config, lib, ... }:
let
cfg = config.modules.system.podman;
in
{
options.modules.system.podman = {
enable = lib.mkEnableOption "enables podman";
};
config = lib.mkIf cfg.enable {
virtualisation = {
oci-containers.backend = "podman";
podman = {
enable = true;
dockerCompat = true;
autoPrune.enable = true;
defaultNetwork.settings = {
dns_enabled = true;
};
};
};
};
}

View File

@@ -20,11 +20,12 @@ vpncon_mex_config: ENC[AES256_GCM,data:4i356X97sBoRliskmh5ewcEwZHkpo37IhPcemKVdW
vaultwarden_admin_token: ENC[AES256_GCM,data:G1v3N064ci0Fw5EtTzaryailWpsv6f4w6eoHp2vjXIBtIlScdQk1Q0W+eDNRk8Wr2C3ysTXQNbyYismNsls+jeS3W+YqkKL4fnh3a5UTzQrMqvaH11n3ak0X9R9vmt+ZJXBrUrAOKJ6RPHJJSWenhjDB77kwEdQ=,iv:f8X+x/AdmZ3b3dtcSFrxGgA2tCgDRpgddjlVu3mdCmM=,tag:c0MXljVvhwOdvrb/8hWlsQ==,type:str] vaultwarden_admin_token: ENC[AES256_GCM,data:G1v3N064ci0Fw5EtTzaryailWpsv6f4w6eoHp2vjXIBtIlScdQk1Q0W+eDNRk8Wr2C3ysTXQNbyYismNsls+jeS3W+YqkKL4fnh3a5UTzQrMqvaH11n3ak0X9R9vmt+ZJXBrUrAOKJ6RPHJJSWenhjDB77kwEdQ=,iv:f8X+x/AdmZ3b3dtcSFrxGgA2tCgDRpgddjlVu3mdCmM=,tag:c0MXljVvhwOdvrb/8hWlsQ==,type:str]
#ENC[AES256_GCM,data:2ESzSsQZqKdjD7OXN8ZPThj6g9acJREe,iv:aDFPB0vs8NNo8ExLcJw7qtQvWbCb1XK6TJrHSK86qss=,tag:z+dypHAGUjEXP7Y9MHYWwg==,type:comment] #ENC[AES256_GCM,data:2ESzSsQZqKdjD7OXN8ZPThj6g9acJREe,iv:aDFPB0vs8NNo8ExLcJw7qtQvWbCb1XK6TJrHSK86qss=,tag:z+dypHAGUjEXP7Y9MHYWwg==,type:comment]
gitea_database_password: ENC[AES256_GCM,data:nhFn0/G7gW5rk996OZzlcTt7T9KMbP8MNM+ReFC8w1H9ZqBSJUbs3K+n68uQVrkOVSXE0cKpOR1VbQ+i+46z3g==,iv:bT4GRZZ83v47/EmeV2KaUFo+4qTT4T2AktFUpPiZdF4=,tag:OC9TInkAr1egM+xnBDizxw==,type:str] gitea_database_password: ENC[AES256_GCM,data:nhFn0/G7gW5rk996OZzlcTt7T9KMbP8MNM+ReFC8w1H9ZqBSJUbs3K+n68uQVrkOVSXE0cKpOR1VbQ+i+46z3g==,iv:bT4GRZZ83v47/EmeV2KaUFo+4qTT4T2AktFUpPiZdF4=,tag:OC9TInkAr1egM+xnBDizxw==,type:str]
#ENC[AES256_GCM,data:nbB5Cd7i/KTMCjCzcX8o1sxREZQ/gLAG,iv:iyuO2erxdJM08WHJBjKuNIXYxVhH7rfyOLTcGCcGqNQ=,tag:UeDszimXv8kQUmDetLeFqg==,type:comment]
mosquitto_password_file: ENC[AES256_GCM,data:7ifs2hGnFQSgJOAKpN0usfiaqLjj7Rjb7zn1/qBDbqEi5hV0JfUncZGorBivR/+kjXHQO6nxaHcKqYvPedNdJ7Qy4/uil/xwgwSmzcbisdVYkhd2pf/N34EQFxmqohud0aTH9V47QbgTdrUPfvsiL+ljLvLu4w==,iv:z7YPIfJHHaLOJrDVnMQhgcMzYAPordFR11kHRAzZqYU=,tag:LRddczdvy01YTm2DFDgSJQ==,type:str]
#ENC[AES256_GCM,data:HJ81OxRD2xtNZKv+8oDqiT8mYpv45JMvjxU5pdmEKzl64SK3lQ==,iv:wStoC6XaZlvRPfbqti2CUbPrOOTt4KktaUp2ecVrggU=,tag:isOwKfNdQZAM+E8YQXBSFA==,type:comment] #ENC[AES256_GCM,data:HJ81OxRD2xtNZKv+8oDqiT8mYpv45JMvjxU5pdmEKzl64SK3lQ==,iv:wStoC6XaZlvRPfbqti2CUbPrOOTt4KktaUp2ecVrggU=,tag:isOwKfNdQZAM+E8YQXBSFA==,type:comment]
velocity_forwarding: ENC[AES256_GCM,data:MUNhW3q0/klK51k3,iv:dGT5N+IrZfBxMIwa0mUrIKF2HJvx/uZ5o/ps6bgDNOE=,tag:KNY2LKwmmnCdWqRnxSKctw==,type:str] velocity_forwarding: ENC[AES256_GCM,data:MUNhW3q0/klK51k3,iv:dGT5N+IrZfBxMIwa0mUrIKF2HJvx/uZ5o/ps6bgDNOE=,tag:KNY2LKwmmnCdWqRnxSKctw==,type:str]
minecraft_recpro_db_passwd: ENC[AES256_GCM,data:dPAkdEX0hBigo/lND2r3ShxnS4Jc5wTI2ShcKnvjig==,iv:WjPugYspUvhy6TAh5UF3etvxTZjAPe3bkgFxIkh6FDw=,tag:h9LGoxp2x8PHxcP8fEkSlA==,type:str] minecraft_recpro_db_passwd: ENC[AES256_GCM,data:dPAkdEX0hBigo/lND2r3ShxnS4Jc5wTI2ShcKnvjig==,iv:WjPugYspUvhy6TAh5UF3etvxTZjAPe3bkgFxIkh6FDw=,tag:h9LGoxp2x8PHxcP8fEkSlA==,type:str]
#ENC[AES256_GCM,data:nbB5Cd7i/KTMCjCzcX8o1sxREZQ/gLAG,iv:iyuO2erxdJM08WHJBjKuNIXYxVhH7rfyOLTcGCcGqNQ=,tag:UeDszimXv8kQUmDetLeFqg==,type:comment]
mosquitto_hashed_passwd: ENC[AES256_GCM,data:k1Lnr8ZTDpzXMoRmRH61X41boX/D8Rm1KPh7x3/IHFo+XKIOUQns53iA+7e7Ohp8uWSthDlOk4SlRvTXdUNiEz7Zmw9LYwy7BHbwpNo2pFApAye1ORPrMrhMUkUfgBgc8oqPPyRXmmrOAFp6GBbRhg==,iv:D8wQL9iF0rqOte5X24kDTVjYUJXbZSLz0Ykbp0HqmYo=,tag:RUCgO1uKPIdumSo563cg1Q==,type:str]
mosquitto_passwd.yaml: ENC[AES256_GCM,data:9xwHiUaQ6zG/4rkRemXtbRJ/KEV4yajqyYlcXRR1eAQ2XijYOzitPjt53h3FPqp5rxl6dJerXNH5CiZZK3t1l339NxNseJFGVmIHitWJxNmGJMlG3M8r8Q==,iv:C6WWZuVkYaasB2pol3uf4Mc3d/lDEgt2pKX+dHl/Cr4=,tag:jYTC6RKF2TzDSwSUh6D8zQ==,type:str]
sops: sops:
age: age:
- recipient: age14gfh682a7m7jfp3qrulql03x5rs7yedwmxwksxrrmgjsunstyuksqx93pz - recipient: age14gfh682a7m7jfp3qrulql03x5rs7yedwmxwksxrrmgjsunstyuksqx93pz
@@ -36,7 +37,7 @@ sops:
U0tmdFBuZnJES3piOTZNV0VKQmQ0eVUKCWRQ/flLzmpC64WyLoipklZBmrkpYiUg U0tmdFBuZnJES3piOTZNV0VKQmQ0eVUKCWRQ/flLzmpC64WyLoipklZBmrkpYiUg
PRu+itNolpPTHm96pe+P93g2iP0wgekG0cX21wkiU2xaLF3dY2FEIA== PRu+itNolpPTHm96pe+P93g2iP0wgekG0cX21wkiU2xaLF3dY2FEIA==
-----END AGE ENCRYPTED FILE----- -----END AGE ENCRYPTED FILE-----
lastmodified: "2025-10-10T08:43:27Z" lastmodified: "2025-10-11T10:14:22Z"
mac: ENC[AES256_GCM,data:3mH0+EY8MFLe78x38CFyWY7CzgkRftAAy25y6lWcqeY8U6XT9CCenaL6vsbZO5j1ypXMtYMlJOO2VFgM5SmbdEKY1rzZldNOoyeMpfV/hHRI6Gm1dD9IyXFFISb12MhO3kt/stWRs84ufGkKe/BpjcurnFlbCAy064cQd9Knu1Y=,iv:KZOlNj/WkbhwgY/OvuY+emTtYftaFZWi+CFIZwFfXiw=,tag:adndDqlpqiVx6VYqKLVETQ==,type:str] mac: ENC[AES256_GCM,data:80GGFasWeFt8D6clEJ8xO2xLQG+xRrekNeu2M7VMvFyPaigYPWz1oMTN4zmbWSX+MCpc/EZuP3rRm7o33embAY3z4qxKuXexTwn4a36xHr1aNCSE5JYXnc3d+e48MnOD284QTWJD1+SEQ2pt2OraDa73HGYckUXz0g9yduLx4tc=,iv:mFLSg+C6BbNu5cneSJZE6tdZGmxHDfHCeVscWZtHB8k=,tag:GP8wpdwstFtIFxuoUPi/3g==,type:str]
unencrypted_suffix: _unencrypted unencrypted_suffix: _unencrypted
version: 3.11.0 version: 3.11.0

View File

@@ -28,13 +28,14 @@ map ] half-down
# files & archives # files & archives
map ad mkdir map ad mkdir
map af mkfile map af mkfile
map ab mkbak
map ae extract map ae extract
map aa archive map aa archive
# trash # trash
map gt cd ~/.local/share/Trash/files map gt cd ~/.local/share/Trash/files
map <delete> trash map <delete> trash
map <s-delete> $trash-restore map <s-delete> $trash restore
# --- functions --- # --- functions ---
@@ -78,7 +79,7 @@ cmd archive %{{
}} }}
# move files to trash # move files to trash
cmd trash %IFS="$(printf '\n\t')"; trash-put $fx cmd trash %IFS="$(printf '\n\t')"; trash put $fx
# make a directory # make a directory
cmd mkdir %{{ cmd mkdir %{{
@@ -100,4 +101,10 @@ cmd mkfile %{{
fi fi
}} }}
# make backup
cmd mkbak %{{
for x in $fx; do
cp $x $x.bak
done
}}

View File

@@ -14,6 +14,7 @@
imagemagick imagemagick
sops sops
usbutils usbutils
trashy
]; ];