Compare commits

..

6 commits

22 changed files with 128 additions and 155 deletions

View file

@ -26,7 +26,6 @@
services = {
gc.enable = true;
sound.enable = true;
tailscale.enable = true;
nebula.node = {
enable = true;
address = "10.254.250.1";

View file

@ -1,8 +1,5 @@
{
"seb-password": "ENC[AES256_GCM,data:dFdYolLTXrxAT8ybVAq3+8eKxO5x2qB810o9FSpUAtfjgYr9DFFVvi06Ut+14ukGcfulXLOixyf0pM/3n9/jeNghnsD14hoGxw==,iv:vORmRgBgZvdafRa8vFF4LL3fw44yZV3yNq3L8eOcQRI=,tag:kr7ZUJpJUhzPJwCCezWCRA==,type:str]",
"tailscale": {
"auth-key": "ENC[AES256_GCM,data:nbc5TURKW/d81lJ5LjJmEykGe6Cz7hnl42BgJdma4S0O92t9EtHCapjujlSSivqO9vjUWUtkJ9JMn5SQOw==,iv:SeVyuQpObjTG/FvBaUn5yv6ktVIXCXWoHv1eLlymnrI=,tag:gKOSviNCzCoRx6zsJ/MzqA==,type:str]"
},
"syncthing": {
"cert": "ENC[AES256_GCM,data:Rf6Pgni4jkcFC0pYC+CBJnCRfsNqSBR2yStaFngefb2/rQd3za2h7o7fp2IPVLs9fYmUG5r8/mP9K0m46xA/2wVLp+ddyNA2wndSwk7ZqNEs2BA/GAdelX8gtcPV74CkB/NJa4E42qH7aTVcgrBZVIM27RxO6e/8r8JSXb/HOczYpLAVdW2DHXjGrzi43cjEcn8UK+dNeNsp0AlEZqN9eRRbqh3JQr7+WOYKkk0R0VP3SLH4O9ROLzSJ4Pw4BoLArR3lvp7pOLOrmXvazToKkMInnLZsH0oV7Zvpu1kTz2KrvhIZdNoUZOV2L/laoS7nc/MFixEwpMy4gqszhiADXlNEbslZyZPcq9KxLgIH0W3xKuQDwrC/RWfjMAwnpucByKy9dR4+9C7maVYp5rvBdRbhNM/Yp6U465d8qJVG5YmURG5NBudAsXkfkp8/AqGSK8RQk/F2b28SfqVCfd/Kga1SINcbdEY7P9nNxx3sbVhncQ3pZXY2tZhYJiSuZ/hGMuPa3yMJPgDPJV8tPIUASCNxbeLOKp7HVghb9IIHSDhhiZmFTFB9xT8X9w05w0afLgQQCybG81YGXvXTiA/xLriA2AzQqg4KzdjUgs+lv7rPL9fsP5V7LAoBZamTirsOCoApMrP7L+QP0OTFyHBakf+GBEREwn5dygos+/vBXne4RtDmji/+zh9U1CqwwCIbx/rdVODzYusYV0lvDjYPyVnTWjEGQN5uGCgEBozQWUkaR1KlmamzcXS9ihPsIa1VNu/aLRrb66hS99wuALFdHJPg5XgHNKEA+Re/lXqUwups/A1RQ9bymqXUj8lIK1hDWsC3DCqDsL54x2BIodyvBBB8hyHFnBC3xg+W8yC0SQLivkFLdNMTRdAgyREFEZp3Nvi19B9+njnciFjcbRj+sG1L9X2OSvDZ2e7273DYtXAVsI9977VBtQYHmjXeyDVBnK53sri/8P2ofniPmBM/ZQ9X1UtMI+vrKIj/o4jcTaEcAmqA9bI2YbG5p84rIH6mBA4SvPCHGz6s48XhaYLzCJbOIR+eqwjbvBA=,iv:72+0+hlBxKtuhjhrLD1EMlx8LcJtskxO+MCpYj7rpes=,tag:qnQlahuimpMoVY1hbTGI6g==,type:str]",
"key": "ENC[AES256_GCM,data:A/Am53gADkKNOn1kAgNoJmirRhIDtysyX8+ubtpyKTQKhTzEJfEKFrVw5BjJ8rYRS31DgMYV20FQs7HOfoRsR3MFdSGDFUgePnbIcNGpHD6EY8GJ9TblT+NyPsYsKG4WgFZElOjQYT3X9Rr0IWoNnDJoOaaI5sCpOumfLKWrekWvYfTUT+SiFfkCebeEQs7ZF7G6ZQJF73upaeKdbd8/uBdcfVc/c6PdjGvY1xnCOAqW39S9K2fK0RibqHs8BiuzPBTCYjBg6euYXi+XGrZjmHLFnj/ZflroiPJr/qFhMDVnmiaW7M3sWYDQYYPd6rk6Adam+ylEAU8BXwIjmdHNkR48WbdIDYWCHHdv4iZ8MLTj6MaX/ksIZvev2M19Eiyi,iv:lkGS4uR0Xd7FnahXLjVc8g0PiRPxyUS6YQY3EM3B5G0=,tag:NZYybe/MgP+LNlJ09AiV6g==,type:str]"
@ -21,8 +18,8 @@
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA2Qmh4TnU2U0toYXZlaUpU\nZWdBVFMwRVpxelBTb3FvMHVDQkFMMkVlOEVjCjNaTEJDaGlkcUJtem43aDZ6Yk9j\nZGhmWFFvbm1HN0N1VkUyN1lQLzM2c0UKLS0tIHhEeFNyaXI0UDB0ZDBydW80djRX\nSmpyNDlLSFMvaXRsZGdWcS9nVTRzbk0KNryo5P1+bu9vntBafSgAAHxSsYXG2ELj\nQQM6kP+eaSoEFXfWxp7dhxHcjoTjQ9DmCgzVaDUD8nLzFsiJsgbjIg==\n-----END AGE ENCRYPTED FILE-----\n"
}
],
"lastmodified": "2025-12-21T01:21:48Z",
"mac": "ENC[AES256_GCM,data:tn8lgEn8Sp2YYFUVRUa+yOND7oISGld22+otWBB9U1she28JZ+g+vvdpCPRPevkqWHA+BawKUKkaD8Iaoe732HQukpbIBrVgK+g6YpaSnakhSZPGV2oE3z7KdSDeYdBF/La0ml1OKs67hldFfN9D2Sl5RdTROwBWaVaJesNTFS4=,iv:BCbSXBAUqb/LoDfLXLi6UB+CRuJOKEXuHFjITAdaH+E=,tag:f570BuZv30rL45m4y1IwJg==,type:str]",
"lastmodified": "2026-01-10T23:13:24Z",
"mac": "ENC[AES256_GCM,data:5JwqpNoFY0lW59TKMu9v//HQPfsrf37CRZAPZpJarHAAcxvAQhm25i8wwlrjZesEWmiqv3lzEi/82XX86h0kqSaB/7dbX+LVISNLeHJhYvOK4/MW87AjBAI9X9FjEhF1UMlE6ku6m7iJr3Jw11ePK6nxy3X+CPodd0q6DvuQKB0=,iv:UT32qwh51s0qaqDk47ytuCj9m2EehzkQpgeCKdTxtc0=,tag:6uxCkvCJGc8kPvGyX4TkFQ==,type:str]",
"unencrypted_suffix": "_unencrypted",
"version": "3.11.0"
}

View file

@ -29,7 +29,6 @@
wlan.enable = true;
bluetooth.enable = true;
sound.enable = true;
tailscale.enable = true;
nebula.node = {
enable = true;
address = "10.254.250.3";

View file

@ -1,8 +1,5 @@
{
"seb-password": "ENC[AES256_GCM,data:RoDF5G7xX1SEabK9/mzbM1nu7KWN9tZJh5GZuiwAOBcQPXLcFkPh+U/I/PlwpSqDT7aWULW+FFG5DzQkdWIKLojWatZrkIrYvw==,iv:oWQj47oxjxR3DBHhFwUD/Emj5ziZHwcbXzD69ChRmHU=,tag:EiPidd+ISk7e2ZMxgeLHNQ==,type:str]",
"tailscale": {
"auth-key": "ENC[AES256_GCM,data:bQtlPQiNwM1xP+6a1jRGeJFdsxxL87RK0jazIj0uoe/U7wwUSZsxpFHyi9AJzfZSLYiST3LkUBtd5EPVnpw=,iv:qzcRpnOqEQF7iWWA8FSXHSlbNIcNk88xgMOk55nY33c=,tag:ZLXi7FZAlrH+z7Q9EvAxdg==,type:str]"
},
"iwd": {
"EW90N.psk": "ENC[AES256_GCM,data:n2sY4SrmLG+nfIRQC2KXXHlS/1pRyWYsObg5K8MhX83jJp8MYZfa4BEwBm77ae62,iv:RIh/45UhkyEtjh5Q0FOS63p1RRgLlrRF+QTiFozm4eU=,tag:rVnKVlp8qu3eUSdyZW0hmA==,type:str]",
"Fairphone4.psk": "ENC[AES256_GCM,data:GGxrhfXB0vb+R87G4GgsAxqjh89g0gVJu3gTPXsBDDlUUz5xv9iS5UlHPaJD,iv:p80LlUGQkBdeEK63dBDWgWe0n6GtEC2rcn8fToOvD5I=,tag:XSh+FAxBzKs/LQyYM2mUUQ==,type:str]",
@ -28,8 +25,8 @@
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBPM1k5U2pCM0JkKytwSE16\nek1zdVVuQjdKS1MyZ29xSUZkK1FId2JVZ0dFCng5bjV3SGlGRHdvaHkvWnNQcWpk\ndGlMbWl6STdERmtHeXVMYTJ6NjQzSU0KLS0tIFBza3d4eVlsVHB3YS9ySUNFMjUx\neUkwQlExdGNwWU1hbHlzS0RkS3NLbFkKLiP/N/5jOnsQhRCOkZ/BieX3OLJOq82e\ngp57skqFeG0k22sPpbgOS0Uz7jckv7/C3kFpuwXQGpEHdzp3QZ+Owg==\n-----END AGE ENCRYPTED FILE-----\n"
}
],
"lastmodified": "2025-12-23T23:35:27Z",
"mac": "ENC[AES256_GCM,data:+4U7yeb/0mDHuVz/DcGzg3whECVm3HJChE/T1NNJKCkbc1lkdIfLvI7p68IBe5QtkTsGtm2pGqJn8ztbOCAJJ1feoZyHMdcDqGbJG+IpDSrPRdmwqvey5CGtrGgIdgW0vZUMCCywmbASzEmsVoFvOzBp5GAxeJsJZRuPU8ditRc=,iv:dkqg3210wXfVAjXPmXYkerLJX14muxeKPMKU65PrKMc=,tag:TPbzWHamgoVBbAyshiRahg==,type:str]",
"lastmodified": "2026-01-10T23:13:41Z",
"mac": "ENC[AES256_GCM,data:HOucc0/UhQ46sbupGkOoID7vuiA99ObG9ZKZ2AD7dcb7wMN35d/Y//xCJFo3XPRw4nGT/tb87RIh6rOwmN37rYgP0eU/43Eyj66/bCAGfFyY/U3kATwII+GhfLCbHR7Fm4jcYS9UmfhCTydqLlunxsqhqqoZHGLpPm9B4KsVdoU=,iv:ns/HFeeF9TsmcINEOMUSW92lDLe3QCp+lwFYEJRZIdE=,tag:DQA790sM42Jbm0uXs9GQ3w==,type:str]",
"unencrypted_suffix": "_unencrypted",
"version": "3.11.0"
}

View file

@ -26,8 +26,6 @@
onlyCleanRoots = true;
};
tailscale.enable = true;
nebula.node = {
enable = true;
address = "10.254.250.5";
@ -40,12 +38,12 @@
web-services =
let
tailscaleDomain = config.custom.services.tailscale.domain;
privateDomain = config.custom.services.nebula.network.domain;
in
{
gatus = {
enable = true;
domain = "status.${tailscaleDomain}";
domain = "status.${privateDomain}";
generateDefaultEndpoints = true;
endpoints."alerts" = {
path = "/v1/health";
@ -55,12 +53,12 @@
ntfy = {
enable = true;
domain = "alerts.${tailscaleDomain}";
domain = "alerts.${privateDomain}";
};
grafana = {
enable = true;
domain = "grafana.${tailscaleDomain}";
domain = "grafana.${privateDomain}";
datasources = {
prometheus.enable = true;
victoriametrics.enable = true;
@ -76,17 +74,17 @@
victoriametrics = {
enable = true;
domain = "metrics.${tailscaleDomain}";
domain = "metrics.${privateDomain}";
};
victorialogs = {
enable = true;
domain = "logs.${tailscaleDomain}";
domain = "logs.${privateDomain}";
};
alloy = {
enable = true;
domain = "alloy-${config.networking.hostName}.${tailscaleDomain}";
domain = "alloy.${config.networking.hostName}.${privateDomain}";
};
};
};

View file

@ -1,9 +1,5 @@
{
"seb-password": "ENC[AES256_GCM,data:BsVFQMY7q+RhByY3RTWwrwbdC4Pgb2kNVG8HXn+kmI2evAo8XmGbDHbr7mXnI2LA6E+iXm5bewfwwTnJWZjaup06/kr1bd8JDg==,iv:GpBQNm1jspU8PCN+SzfAUKSps3YySg6JJVYOLOFetOI=,tag:ydQaXcLVYllSZYWNCtH7+A==,type:str]",
"tailscale": {
"auth-key": "ENC[AES256_GCM,data:b+m+4KGLeS7hYLSqYXxX5VhiA946b4SEp+OAQUkK6e6ShYe0RnC0VfnypHjqwrdOiGYAIxB4ggIjZ9F5lfw=,iv:o36k4vtsnSThDQNIMIPBQHJ92WodbIyVC42L1t8Fvzg=,tag:/9oYSFO3asAGmWiedNo+Bw==,type:str]",
"service-auth-key": "ENC[AES256_GCM,data:Z/u3GJr1J7rhn1k+Ul0SyHhWKIxpIKqqinGphdZ/BNFvBGCsU8xKKHz7c4B6O94Oe3tuUNGp+X285lSnpZg=,iv:ch6Mg8ki82pxlWFGlOGoJB7Mhn3tYPEcL6Z8/6bXzCQ=,tag:9sHLrQ8F/DzYvdtvUM7dYg==,type:str]"
},
"healthchecks": {
"ping-key": "ENC[AES256_GCM,data:Zq71AU3oym7fC364YZNyRtx4N2G35Q==,iv:ibMBpcrSocLBhtumsSV00+KVN6Pi4SzE7soCkZcU4fY=,tag:Wv/Wr0wRZGXucMHZHgoNtg==,type:str]"
},
@ -13,6 +9,10 @@
"nebula": {
"host-key": "ENC[AES256_GCM,data:usSLqYOvDAAs7z1xo+gccDqgUE78upK+k522ldKcPoFKKBH87Us7gi6+XAOMDQ79U6i8j4l1lAE8kRdqDuvasodESHVSW9gSnnv5E73MVr0d1Snh7tAewVzneac+2R2R8tUzKzwzWM5SyyvJSoKGBg8WmGzdGT8UqC623utlYQ==,iv:NoZ2u8IK4g1Kwb6uZZ1jXJH4eFO9Jj5Phi5hPM4K72o=,tag:9mOv6oSESH+8r2ZC4yUE+w==,type:str]"
},
"porkbun": {
"api-key": "ENC[AES256_GCM,data:oqnAPVfLU8CG64+TsRijZ/2Wzy11bt3PvoEqbpWZbcXIE2aM0oZtUUtCxt0DiWp8Uyta6AO40V8+EGkzeqL4O6VLxU4=,iv:KaEwSmoG5zYxsWjUxwqbfe77Iiv03IAnFaIjQ5YoYkc=,tag:ilzXSYElARjnWkOcBKZBdA==,type:str]",
"secret-api-key": "ENC[AES256_GCM,data:dGOAsu3kPJmDwhddZGgrY8KrDJeS7PiEPjEVh/h8BgSygRKLInow/7PIaHcy8gIlsGFvU2CYORY7Vmf3QCxYbRTkdIQ=,iv:otDnIv0B1h1H6usJqSNVqv9UUcmx9r5Cn18Q6DFwBME=,tag:O2O3V33TmalVuL6y4V9ufw==,type:str]"
},
"sops": {
"age": [
{
@ -24,8 +24,8 @@
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBTVmV4dkZEaWVDNHMxUFdr\nYnhuVWpReXBNSEhhZkltQTE4bEpzSlBzL0VJCk15UFlwa0haWTZNaE1DVzVZVFBI\nd0QzcUptYmQ3dmhhdjhFV0xDSWdmMGMKLS0tIFhWamx6SXJleFFSVUFkRmw2VFZy\nOVVhNm9NSE0yRGFMQjNrM1B6cDVxSXMKrhAkDcWqutgSmQI5O+5i8fcwuTh2/XKr\nljK/Vn8EvGr8qEUeHzOBI1b5VtgngJkVJyfM9G/Q0lZvQF7ZZ5YCgQ==\n-----END AGE ENCRYPTED FILE-----\n"
}
],
"lastmodified": "2026-01-03T15:47:25Z",
"mac": "ENC[AES256_GCM,data:fEtJdI0I7Tiv21n30ZcxMdOsf4emevkouRmMW+100GEY19rL/VtAIXkvaaygdz/sGXXzLeANReLjo5Ryp93x8854eravT4nQ8IXpNlCgdBXmq7QgUD/nc5kaOj0//3neAxE+ht5MPWm+AbfO4kYDKTmF9GFoLRZMfyvrWXTVv4M=,iv:h4RUkWkr6PABpj0yp+YRhgJ/0X6kwpMyB30qVMbO2to=,tag:8a+w96TwPXk15GZdryWneQ==,type:str]",
"lastmodified": "2026-01-10T23:14:34Z",
"mac": "ENC[AES256_GCM,data:RpG1S1iuaHmBc9wT9Tau6dZHcFX9DwQA0kHcAuTZxbjopLfYJnVosvU9S9N+4tAZqwGLpKqVxX3UiUWLEIFwrcB3xM3/SdpKWD4CE/cyMbvwWCIN4RcHveFJ6py7ItXtipzLC0lZeRWDXP+IyREuKggAID50zXuSIPr6BDlnkYA=,iv:gWykL+vhNB3tLHtHlhbNd5iUPKjB5vDpx0nAf5j+F8Y=,tag:MAI8aaSR+g33IIYM4opqCw==,type:str]",
"unencrypted_suffix": "_unencrypted",
"version": "3.11.0"
}

View file

@ -15,7 +15,7 @@
custom =
let
tailscaleDomain = config.custom.services.tailscale.domain;
privateDomain = config.custom.services.nebula.network.domain;
in
{
persistence.enable = true;
@ -30,11 +30,6 @@
onlyCleanRoots = true;
};
tailscale = {
enable = true;
exitNode.enable = true;
};
nebula.node = {
enable = true;
address = "10.254.250.2";
@ -49,44 +44,44 @@
isServer = true;
doBackups = true;
deviceId = "5R2MH7T-Q2ZZS2P-ZMSQ2UJ-B6VBHES-XYLNMZ6-7FYC27L-4P7MGJ2-FY4ITQD";
gui.domain = "syncthing.${tailscaleDomain}";
gui.domain = "syncthing.${privateDomain}";
};
};
web-services = {
filebrowser = {
enable = true;
domain = "files.${tailscaleDomain}";
domain = "files.${privateDomain}";
doBackups = true;
};
radicale = {
enable = true;
domain = "calendar.${tailscaleDomain}";
domain = "calendar.${privateDomain}";
doBackups = true;
};
memos = {
enable = true;
domain = "memos.${tailscaleDomain}";
domain = "memos.${privateDomain}";
doBackups = true;
};
actualbudget = {
enable = true;
domain = "budget.${tailscaleDomain}";
domain = "budget.${privateDomain}";
doBackups = true;
};
freshrss = {
enable = true;
domain = "rss.${tailscaleDomain}";
domain = "rss.${privateDomain}";
doBackups = true;
};
alloy = {
enable = true;
domain = "alloy-${config.networking.hostName}.${tailscaleDomain}";
domain = "alloy.${config.networking.hostName}.${privateDomain}";
};
};
};

View file

@ -1,9 +1,5 @@
{
"seb-password": "ENC[AES256_GCM,data:Q+yRIOJCUzHmCZ5n0OAGyCkePVh0VJfeFYmgG2fh8Wwy6IKyG9c3/3qcMEIRSvG6Qm9KFGahuIR2md5bz7//pTRfPcu1GdIsMA==,iv:GpBQNm1jspU8PCN+SzfAUKSps3YySg6JJVYOLOFetOI=,tag:pOLRjWZKL2+GkMgV435FMw==,type:str]",
"tailscale": {
"auth-key": "ENC[AES256_GCM,data:qqJnjWR309LAuW49/7t2uZqWlAgPUvz8niLZuM2g8kJxaQmF0TEAWcBDpYridy9NLHnJ+xgA9g088t9dSg==,iv:imh6BrNPf2jVQ6eVaB9Mt+gX9zGq6mHX1+9yhY/KzrI=,tag:HPjhNE+vecDWwCAMC+nGfw==,type:str]",
"service-auth-key": "ENC[AES256_GCM,data:x69Z9Ac533qpKb9y/CQXJYvkw3G6OGyvoih9wABwlYO969+PvQssuNvciFGq8ZmqUXaGRcFsL45edegiKs0=,iv:0yO9RGbrBVfnQ7GR+3rdLBCk+UY9DQJk7NVGlUEBdNs=,tag:ISv0GFT9yinM2BAvvI3mvw==,type:str]"
},
"restic": {
"password": "ENC[AES256_GCM,data:AERasH4M/uP3aUELnggUmH6NzAx6v4Uqjg+ymF5X,iv:q5qJkB3+feZyEm778hKI8ikNz9/9dj+Z1hda6M4eHfQ=,tag:adI4AwzXp63SRSA8uAjRZw==,type:str]"
},
@ -24,6 +20,10 @@
"nebula": {
"host-key": "ENC[AES256_GCM,data:dS3tXWUK+POzTZ98wLETaWz4ief/yFULCfI5Y3EbK26KQpwxzw6cpLXUNOSZeUwz9brN/4JcwUgewJR08Uq3HZhKZKoMPZfPRtZMDe51I4RYg4hZd1mMWXQn82KmSytZCiDIL/9qCwYvObVRiNCpAOKRj6JBpgpoQ1u5hgn1EA==,iv:G25EpAnvoLfYXAdPyJVqS3ocUPg5LQlUoi7fA+XFOZ8=,tag:/BNhuxJCunM85H9DnPF5Kg==,type:str]"
},
"porkbun": {
"api-key": "ENC[AES256_GCM,data:RV/+aEQRcfQ9LMjZjxGNvCeiso51VqvqrOBRRrR/dXhmBvyoGuh2LaAjyoDoWEjWy5kIStStR+jXZEFWZ8KXvnmEnoU=,iv:j3sYW85Vf88EfeOfezlspDxEms6YqZYnzy5JAiES3+U=,tag:0M9vDvsirc6ze3Ut+yMSoA==,type:str]",
"secret-api-key": "ENC[AES256_GCM,data:SUngZ65fBmC9WlPkmJMjyBb6sHREKhqyRj9fsBGkj5IyjtGDfQ1b7Iv0VNeSY//bWv0VZruwT48a320BUlg1xiNCKU8=,iv:glUaArlHJsxCP5z3y7JnWvmtsdRzszXhYydpd1YaX5U=,tag:185iAkQ/J9CfKkTsgPP6lA==,type:str]"
},
"sops": {
"age": [
{
@ -35,8 +35,8 @@
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBqU01heng3NHdrYnZFZmZn\nZlJtUUIyd1ExTmhzeU5iZFZadFcwR25GOEVZCmxHOXNWQVh1ZlJSRHJtaDVHNVUv\nbTY0TlNmZ2hESDkzS2M3WHdlamxwclkKLS0tIEEvOFd3TDFkQmQwbjBodHhpb1BD\nZ2NvTnNqQmtrLy9aVDdGRGxZbVgrZG8KdnnjJWcjZFu3R8fVKToj6THHHRCFou9k\njQoedCZAML2A2FZIhHugH9wnDUPQQjG86WbcCBuFWcOTGiTF2gN+Qg==\n-----END AGE ENCRYPTED FILE-----\n"
}
],
"lastmodified": "2025-12-21T22:05:56Z",
"mac": "ENC[AES256_GCM,data:i6N/BeTtqkiYz5igk7mHxa69Z8MEe2cRF9541P93utNBddrTGev4VQ5VoqEQEkcOpKWvH5DbQcfsa8k60/zaGXJZ9tWbmbBiBTrbjdslpPJTbVkIwMXWYVhbS87WhfAsyQbRzXu73/jArGKVfDPzcdl2FuRmzXZKQkVjRc7x+Rc=,iv:HxjT6ppxY6jkrSPrcP9m84dd2gy2rGCGKV8MdjGy7FA=,tag:KPWQ2nhsGFuhX8ddFhEZow==,type:str]",
"lastmodified": "2026-01-10T23:14:08Z",
"mac": "ENC[AES256_GCM,data:ppj3M84MdH8awN6/r8b0DubMaQbqHpKpMfBJEb3TlbUJczE6kPmhuuX3Cx3FOsD+TJr0m8WRjCqb0Z844Z2oylaz7hmijYHLbByb+BY+dsSPU21zkvCli+KpzHkDY4+NcjhTN4MsopYSwVDegZoCb+qZ0nAqDKqLezUlNIKCUuI=,iv:xA1LzdkoEkiq2i5klIvojMIqvpIsuZeJTiKKOEBbR7k=,tag:o6eOKWKu216X+DnXRy6ARw==,type:str]",
"unencrypted_suffix": "_unencrypted",
"version": "3.11.0"
}

View file

@ -26,8 +26,6 @@
onlyCleanRoots = true;
};
tailscale.enable = true;
nebula.node = {
enable = true;
address = "10.254.250.4";
@ -78,7 +76,7 @@
alloy = {
enable = true;
domain = "alloy-${config.networking.hostName}.${config.custom.services.tailscale.domain}";
domain = "alloy.${config.networking.hostName}.${config.custom.services.nebula.network.domain}";
};
};
};

View file

@ -1,9 +1,5 @@
{
"seb-password": "ENC[AES256_GCM,data:znyHz9AhZipp2VNkXifU27IvEbPoKqLf4ibSkqfvkGGoX/jHnoJRYruWmwLnAaqTk6moHtew6HZq3xjvNgUf+qVgaleWQntrLg==,iv:GpBQNm1jspU8PCN+SzfAUKSps3YySg6JJVYOLOFetOI=,tag:CKgqMm/mVae1i9He/ioMAg==,type:str]",
"tailscale": {
"auth-key": "ENC[AES256_GCM,data:tnmR93k4iPsojBZgwVmnSPJkNDOYiJt9lJ/IpoDR/TWCIbpBmbFq7xKSnyoCXBRKiEZ6hK0z3jezuQc9IgQ=,iv:/b3+yxEOuPaRrrmD3LSUeSiNv/1u4bMxrg4B+1SKb0o=,tag:9f6ZSgFjP4HAExWiaStr2g==,type:str]",
"service-auth-key": "ENC[AES256_GCM,data:xlXV01WcdLVm/vRw8Elb3iCId8LstKP0UWSXDXeOG10goKLoIMV4JmJ8a8OalE3s3pO3FSLYQFxjQNxQmhk=,iv:ikHW6XVow1NJZB0hUhKl5JsC9gEZtvXc4F9SlUycQlI=,tag:GgqQPIxOXkYhhqPcv2/k0A==,type:str]"
},
"restic": {
"password": "ENC[AES256_GCM,data:IGV07og9eSoleJnZ2+/FFLph7TLNd80q+u6WNn+V,iv:E2hBYbvpCMDul81lgUBNVr5Fm7x0u1f9cEkma9jKwYE=,tag:eA7CAtfQtodTCyOuEn4+ug==,type:str]"
},
@ -23,6 +19,10 @@
"nebula": {
"host-key": "ENC[AES256_GCM,data:oi5uWtflxt+LB9ft6DuH+h3owTF8bj9lNKVAVyyZH4Ww5F4tN+GhQDNXHSt4SK4M/9K/M7/VfRjcL0uDJq0SJmI1oy0g/pTF+JcBAV/Z6PAhPWBXxMBkIdL+xYLR5lXmBKnTTkHoIqvBZH7wDHq2kOKrBFU96yFfrMLK1TVv5Q==,iv:eau9vYEVwUjGTgESR2d2QNiBlTZIq5Do97/xZqmrz2c=,tag:aTdQ2vRxI/BByG02VvpPMw==,type:str]"
},
"porkbun": {
"api-key": "ENC[AES256_GCM,data:KT1vUUnm0d2T9H1YI5SE6xgTVVdmbLFJeL/+otlw0mheH+9svnC19YP9szB/kBLAPLes+2qunpqM02B9tJxGgD30SNc=,iv:wVIkhrCQ7t7lkR0q0OO/XWZbgZYuja53XgUjfy1fTNA=,tag:MJ5tjbIofqcKXDuzD0b1aQ==,type:str]",
"secret-api-key": "ENC[AES256_GCM,data:lmU41AkCVb15sFuMqTZ7qZ978D5BLEYYidsb0yPPjiPPUmnfqBNM5lMVo4k4gt/PcMLcRVv5I6DDqE44zOK7YPf6Fck=,iv:sS7PfE2/CjUekIXGlvEA/N6R5JE7BvgfeXJO5dzv6/8=,tag:rp8FY3hEOyoafmwTdROJ7Q==,type:str]"
},
"sops": {
"age": [
{
@ -34,8 +34,8 @@
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBvVnphWlNaTUU0QytIdnEv\nQnNzelN4MUMreXZrME5KZStFMDg2V1VFd21rCkk2Uy9ITEF3SjlRVEdMMXlPdHhG\nam1PNnp3emtnMnczeFFSSStJaHF6TkkKLS0tIEJKbFRzbmNqMjk5NXVHZnhlWWZ3\nYng5L1F5YUJGOTg3TTJCK281SG9Id3MKsmH2yj19ig2g+KzBGLD9dWkdvr6TLdSd\nuuDC+frhj7wWrEomOOjIoYtWHXkUtTSAnCEZhrhfyupYhEvlFfWRlw==\n-----END AGE ENCRYPTED FILE-----\n"
}
],
"lastmodified": "2026-01-03T15:48:23Z",
"mac": "ENC[AES256_GCM,data:p+WJViYWL4HFi7Us7RXJHVDFk8Q0HQ7I+dtV8XrIgBHELp19QTu6BmJ/7G/36Fe1H6h78SmwU3gOdSThDa77CmPlKlGG8aS6edLChJnCWeM0FBl61bvrCgZQwjVq/LZNMwJJIHiktDIPiIgNOwVvTzRCErrH6/UYjH0aGeyRI4g=,iv:6JE/7GAfIrLhRXUMVvFu4roON5zNgmQZY4vJJdgwcS8=,tag:xlDMg/vtqO5VFkbdbSBKxQ==,type:str]",
"lastmodified": "2026-01-10T23:14:22Z",
"mac": "ENC[AES256_GCM,data:oQ8weypJMM2sm5XzRzn80IE6VQ7zKiJdkujLTfZbiUHXhPSpmNJqsXnAMREtKGAxxm6p9aTeZMbkX1xN1FGf38909/W0Bk/I0trpo1Q6bxLwlo/8eLvA5CAqrgQIgJz3jpIEDpXGsvTDVDxNQeFPH4HZHInwmF4Z6snVBuv8UZI=,iv:D3qt1rhAdMRRnBzlaKf8hGU+f7isjIKPyGM1MCnhoBs=,tag:6ihR9KXKsr8SVPceVlB1Cg==,type:str]",
"unencrypted_suffix": "_unencrypted",
"version": "3.11.0"
}

View file

@ -3,7 +3,7 @@
self,
}:
{
isTailscaleDomain = domain: domain |> lib.hasSuffix ".ts.net";
isPrivateDomain = domain: domain |> lib.hasSuffix ".splitleaf.de";
subdomainOf = domain: domain |> lib.splitString "." |> lib.head;

View file

@ -1,16 +0,0 @@
{ config, lib, ... }@moduleArgs:
{
options.custom.services.tailscale.enable = lib.mkEnableOption "" // {
default = moduleArgs.osConfig.custom.services.tailscale.enable or false;
};
config = lib.mkIf config.custom.services.tailscale.enable {
programs.ssh = {
enable = true;
matchBlocks.installer.extraOptions = {
UserKnownHostsFile = "/dev/null";
StrictHostKeyChecking = "no";
};
};
};
}

View file

@ -1,18 +1,16 @@
{
config,
pkgs,
lib,
lib',
...
}:
let
cfg = config.custom.services.caddy;
inherit (config.services.caddy) user;
virtualHosts = cfg.virtualHosts |> lib.attrValues |> lib.filter (value: value.enable);
publicHostsExist = virtualHosts |> lib.any (value: !lib'.isTailscaleDomain value.domain);
tailscaleHostsExist = virtualHosts |> lib.any (value: lib'.isTailscaleDomain value.domain);
publicHostsExist = virtualHosts |> lib.any (value: (!lib'.isPrivateDomain value.domain));
privateHostsExist = virtualHosts |> lib.any (value: lib'.isPrivateDomain value.domain);
webPorts = [
80
@ -29,7 +27,15 @@ let
lib.nameValuePair domain {
logFormat = "output file ${config.services.caddy.logDir}/${domain}.log { mode 640 }";
extraConfig = lib.concatLines [
(lib.optionalString (lib'.isTailscaleDomain domain) "bind tailscale/${lib'.subdomainOf domain}")
(lib.optionalString (lib'.isPrivateDomain domain) (
let
certDir = config.security.acme.certs.${domain}.directory;
in
''
tls ${certDir}/fullchain.pem ${certDir}/key.pem
bind ${config.custom.services.nebula.node.address}
''
))
(lib.optionalString (port != null) "reverse_proxy localhost:${toString port}")
(lib.optionalString (files != null) ''
root * ${files}
@ -103,23 +109,49 @@ in
networking.firewall.allowedTCPPorts = webPorts;
})
(lib.mkIf tailscaleHostsExist {
sops.secrets."tailscale/service-auth-key" = {
owner = user;
restartUnits = [ "caddy.service" ];
(lib.mkIf privateHostsExist {
sops.secrets = {
"porkbun/api-key".owner = config.users.users.acme.name;
"porkbun/secret-api-key".owner = config.users.users.acme.name;
};
services.caddy = {
package = pkgs.caddy.withPlugins {
plugins = [ "github.com/tailscale/caddy-tailscale@v0.0.0-20251117033914-662ef34c64b1" ];
hash = "sha256-3lc2oSLFIco5Pgz1QNH2hT5tDTPZ4wcbc+NKH9wLEfY=";
security.acme = {
acceptTerms = true;
defaults = {
email = "acme@sstork.dev";
dnsProvider = "porkbun";
dnsResolver = "1.1.1.1:53";
group = config.users.users.caddy.name;
credentialFiles = {
PORKBUN_API_KEY_FILE = config.sops.secrets."porkbun/api-key".path;
PORKBUN_SECRET_API_KEY_FILE = config.sops.secrets."porkbun/secret-api-key".path;
};
reloadServices = [ "caddy.service" ];
};
globalConfig = ''
tailscale {
auth_key {file.${config.sops.secrets."tailscale/service-auth-key".path}}
ephemeral true
}
'';
certs =
virtualHosts
|> lib.filter (host: lib'.isPrivateDomain host.domain)
|> lib.map (host: lib.nameValuePair host.domain { })
|> lib.listToAttrs;
};
services.nebula.networks.mesh.firewall.inbound = [
{
port = "80";
proto = "tcp";
host = "any";
}
{
port = "443";
proto = "tcp";
host = "any";
}
];
systemd.services.caddy = {
requires = [ "nebula@mesh.service" ];
after = [ "nebula@mesh.service" ];
};
})
]

View file

@ -135,7 +135,6 @@ in
settings = {
pki.disconnect_invalid = true;
cipher = "aes";
lighthouse.local_allow_list.interfaces.${config.services.tailscale.interfaceName} = false;
};
};

View file

@ -1,4 +1,10 @@
{ config, lib, ... }:
{
config,
self,
lib,
lib',
...
}:
let
nebulaCfg = config.custom.services.nebula;
cfg = nebulaCfg.node;
@ -25,22 +31,30 @@ in
local-zone = "\"${nebulaCfg.network.domain}.\" static";
local-data =
nebulaCfg.nodes
|> lib.map (node: "\"${node.name}.${nebulaCfg.network.domain}. A ${node.address}\"");
let
nodeRecords =
nebulaCfg.nodes
|> lib.map (node: "\"${node.name}.${nebulaCfg.network.domain}. A ${node.address}\"");
serviceRecords =
self.nixosConfigurations
|> lib.attrValues
|> lib.concatMap (
host:
host.config.meta.domains.local
|> lib.filter (domain: lib'.isPrivateDomain domain)
|> lib.map (domain: "\"${domain}. A ${host.config.custom.services.nebula.node.address}\"")
);
in
nodeRecords ++ serviceRecords;
};
forward-zone =
(lib.singleton {
name = ".";
forward-addr = [
"1.1.1.1"
"8.8.8.8"
];
})
++ lib.optional config.custom.services.tailscale.enable {
name = "${config.custom.services.tailscale.domain}";
forward-addr = [ "100.100.100.100" ];
};
forward-zone = lib.singleton {
name = ".";
forward-addr = [
"1.1.1.1"
"8.8.8.8"
];
};
};
};

View file

@ -59,7 +59,7 @@ in
message = "Running syncthing on a server requires `gui.domain` to be set";
}
{
assertion = (cfg.gui.domain != null) -> (lib'.isTailscaleDomain cfg.gui.domain);
assertion = (cfg.gui.domain != null) -> (lib'.isPrivateDomain cfg.gui.domain);
message = lib'.mkUnprotectedMessage "Syncthing-GUI";
}
];

View file

@ -1,39 +0,0 @@
{ config, lib, ... }:
let
cfg = config.custom.services.tailscale;
in
{
options.custom.services.tailscale = {
enable = lib.mkEnableOption "";
domain = lib.mkOption {
type = lib.types.nonEmptyStr;
default = "stork-atlas.ts.net";
};
ssh.enable = lib.mkEnableOption "";
exitNode.enable = lib.mkEnableOption "";
};
config = lib.mkIf cfg.enable {
meta.ports.udp = lib.mkIf config.services.tailscale.openFirewall [
config.services.tailscale.port
];
sops.secrets."tailscale/auth-key".restartUnits = [ "tailscaled-autoconnect.service" ];
services.tailscale = {
enable = true;
authKeyFile = config.sops.secrets."tailscale/auth-key".path;
openFirewall = true;
useRoutingFeatures = if cfg.exitNode.enable then "server" else "client";
extraUpFlags = [ "--reset=true" ];
extraSetFlags = [
"--ssh=${lib.boolToString cfg.ssh.enable}"
"--advertise-exit-node=${lib.boolToString cfg.exitNode.enable}"
];
};
systemd.services.tailscaled-set.after = [ "tailscaled-autoconnect.service" ];
custom.persistence.directories = [ "/var/lib/tailscale" ];
};
}

View file

@ -15,11 +15,11 @@ in
};
metricsEndpoint = lib.mkOption {
type = lib.types.nonEmptyStr;
default = "https://metrics.${config.custom.services.tailscale.domain}/prometheus/api/v1/write";
default = "https://metrics.${config.custom.services.nebula.network.domain}/prometheus/api/v1/write";
};
logsEndpoint = lib.mkOption {
type = lib.types.nonEmptyStr;
default = "https://logs.${config.custom.services.tailscale.domain}/insert/loki/api/v1/push";
default = "https://logs.${config.custom.services.nebula.network.domain}/insert/loki/api/v1/push";
};
collect = {
metrics = {

View file

@ -27,7 +27,7 @@ in
config = lib.mkIf cfg.enable {
assertions = lib.singleton {
assertion = lib'.isTailscaleDomain cfg.domain;
assertion = lib'.isPrivateDomain cfg.domain;
message = lib'.mkUnprotectedMessage "Filebrowser";
};

View file

@ -25,7 +25,7 @@ in
config = lib.mkIf cfg.enable {
assertions = lib.singleton {
assertion = lib'.isTailscaleDomain cfg.domain;
assertion = lib'.isPrivateDomain cfg.domain;
message = lib'.mkUnprotectedMessage "FreshRSS";
};

View file

@ -113,7 +113,7 @@ in
connectivity.checker.target = "1.1.1.1:53"; # Cloudflare DNS
alerting.ntfy = {
topic = "uptime";
url = "https://alerts.${config.custom.services.tailscale.domain}";
url = "https://alerts.${config.custom.services.nebula.network.domain}";
click = "https://${cfg.domain}";
default-alert = {
enable = true;

View file

@ -23,21 +23,21 @@ in
enable = lib.mkEnableOption "";
url = lib.mkOption {
type = lib.types.nonEmptyStr;
default = "https://metrics.${config.custom.services.tailscale.domain}";
default = "https://metrics.${config.custom.services.nebula.network.domain}";
};
};
victoriametrics = {
enable = lib.mkEnableOption "";
url = lib.mkOption {
type = lib.types.nonEmptyStr;
default = "https://metrics.${config.custom.services.tailscale.domain}";
default = "https://metrics.${config.custom.services.nebula.network.domain}";
};
};
victorialogs = {
enable = lib.mkEnableOption "";
url = lib.mkOption {
type = lib.types.nonEmptyStr;
default = "https://logs.${config.custom.services.tailscale.domain}";
default = "https://logs.${config.custom.services.nebula.network.domain}";
};
};
};