navidrome
This commit is contained in:
parent
1408470a53
commit
28dc0896b9
16 changed files with 969 additions and 171 deletions
42
flake.lock
generated
42
flake.lock
generated
|
|
@ -391,11 +391,11 @@
|
|||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1764194569,
|
||||
"narHash": "sha256-iUM9ktarEzThkayyZrzQ7oycPshAY2XRQqVKz0xX/L0=",
|
||||
"lastModified": 1764304195,
|
||||
"narHash": "sha256-bO7FN/bF6gG7TlZpKAZjO3VvfsLaPFkefeUfJJ7F/7w=",
|
||||
"owner": "nix-community",
|
||||
"repo": "home-manager",
|
||||
"rev": "9651819d75f6c7ffaf8a9227490ac704f29659f0",
|
||||
"rev": "86ff0ef506c209bb397849706e85cc3a913cb577",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
@ -704,11 +704,11 @@
|
|||
"rust-overlay": "rust-overlay_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1764160906,
|
||||
"narHash": "sha256-6Dud/oe0UnkgCe+JAGF+GjXl6S6ynpcAUYWCdbXjJL4=",
|
||||
"lastModified": 1764306526,
|
||||
"narHash": "sha256-Lwz8CwV4ryaqbKNZ4ftnNrhwZI29aoHQ5MRJponTDTY=",
|
||||
"owner": "YaLTeR",
|
||||
"repo": "niri",
|
||||
"rev": "8370c539fb584f78924b826d0ac0ad8fa068cf95",
|
||||
"rev": "0652342df8fffa93abcc5e567be1afb3eab002f6",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
@ -782,11 +782,11 @@
|
|||
},
|
||||
"nixos-hardware": {
|
||||
"locked": {
|
||||
"lastModified": 1764080039,
|
||||
"narHash": "sha256-b1MtLQsQc4Ji1u08f+C6g5XrmLPkJQ1fhNkCt+0AERQ=",
|
||||
"lastModified": 1764328224,
|
||||
"narHash": "sha256-hFyF1XQd+XrRx7WZCrGJp544dykexD8Q5SrJJZpEQYg=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixos-hardware",
|
||||
"rev": "da17006633ca9cda369be82893ae36824a2ddf1a",
|
||||
"rev": "d62603a997438e19182af69d3ce7be07565ecad4",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
@ -814,11 +814,11 @@
|
|||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1763966396,
|
||||
"narHash": "sha256-6eeL1YPcY1MV3DDStIDIdy/zZCDKgHdkCmsrLJFiZf0=",
|
||||
"lastModified": 1764242076,
|
||||
"narHash": "sha256-sKoIWfnijJ0+9e4wRvIgm/HgE27bzwQxcEmo2J/gNpI=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "5ae3b07d8d6527c42f17c876e404993199144b6a",
|
||||
"rev": "2fad6eac6077f03fe109c4d4eb171cf96791faa4",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
@ -858,11 +858,11 @@
|
|||
},
|
||||
"nixpkgs-master": {
|
||||
"locked": {
|
||||
"lastModified": 1764245472,
|
||||
"narHash": "sha256-udCSZoKawLiNJKFQgikkN96tvVJggs61ihRq8sRt8tM=",
|
||||
"lastModified": 1764330598,
|
||||
"narHash": "sha256-tIMoFVAMzjGq3iLiA0hQ+C6CtLkmJEBXuEm0XtwlgtU=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "6c16b7ce10e5ef1fee3aecfb327be61888818a7a",
|
||||
"rev": "b8ee623e26961c7f34e78248d553fa35e1f8032b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
@ -1177,11 +1177,11 @@
|
|||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1764211126,
|
||||
"narHash": "sha256-p5y13PnMZYd5WdHk+XCzyUaLGBUCwnz2n4KYKEZM0Pw=",
|
||||
"lastModified": 1764297505,
|
||||
"narHash": "sha256-qrLpVu2/hA9Cu6IovMEsgh9YRyvmmWS+bSx7C1JGChA=",
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"rev": "895935bff08cfcfb663fb9c8263c43596e7cd1ed",
|
||||
"rev": "9623580f8ce09ec444b9aca107566ec5db110e62",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
@ -1411,11 +1411,11 @@
|
|||
"rust-overlay": "rust-overlay_6"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1763704521,
|
||||
"narHash": "sha256-ceYEV6PnvUN8Zixao4gpPuN+VT3B0SlAXKuPNHZhqUY=",
|
||||
"lastModified": 1764304415,
|
||||
"narHash": "sha256-KBSPRgS7SC/U2t0GSuEojwAIEgl4HTK2I0M4558PQwo=",
|
||||
"owner": "Supreeeme",
|
||||
"repo": "xwayland-satellite",
|
||||
"rev": "f379ff5722a821212eb59ada9cf8e51cb3654aad",
|
||||
"rev": "5d23452874f6d0b8fabfcd69b84098ea6ef31352",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@
|
|||
nixpkgs.system = "x86_64-linux";
|
||||
imports = [
|
||||
./hardware-configuration.nix
|
||||
./services/traccar.nix
|
||||
./services/navidrome.nix
|
||||
# ./services/attic.nix
|
||||
# ./services/immich.nix
|
||||
# ./services/jellyfin.nix
|
||||
|
|
@ -63,6 +65,7 @@
|
|||
networking.nat.internalInterfaces = [ "ve-+" ];
|
||||
networking.nat.externalInterface = "enp1s0f1"; # TODO: changeme
|
||||
|
||||
services.traefik.staticConfigOptions.entryPoints.websecure.proxyProtocol.trustedIPs = ["10.0.0.1"];
|
||||
services.traefik.dynamicConfigOptions.http.routers.simpleproxy-oldds9-router.rule =
|
||||
lib.mkForce "HostRegexp(`^.+\.hailsatan\.eu$`)";
|
||||
# services.traefik.dynamicConfigOptions.http.routers.simpleproxy-oldds9-router.tls.options = "old";
|
||||
|
|
@ -94,6 +97,13 @@
|
|||
sopsFile = ./secrets/dyndns.yaml;
|
||||
};
|
||||
|
||||
xyno.services.kanidm = {
|
||||
enable = true;
|
||||
setupTraefik = true;
|
||||
};
|
||||
xyno.services.oauth2Proxy.enable = true;
|
||||
xyno.services.postgres.enable = true;
|
||||
|
||||
xyno.presets.cli.enable = true;
|
||||
xyno.presets.server.enable = true;
|
||||
xyno.impermanence.enable = true;
|
||||
|
|
|
|||
|
|
@ -6,6 +6,6 @@
|
|||
};
|
||||
# xyno.services.wireguard.pubKey = "aZvSeAhKG3B5I2My5IqQoSlntMzbCHM6OU92WEScohc=";
|
||||
deployment = {
|
||||
targetHost = "10.0.0.2";
|
||||
targetHost = "nemesis.xyno.systems";
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@
|
|||
zramSwap.enable = true;
|
||||
zramSwap.writebackDevice = "/dev/zvol/spool/nemesis/zswap";
|
||||
|
||||
fileSystems."/persistent/var/lib/postgres" = {
|
||||
fileSystems."/persistent/var/lib/postgresql" = {
|
||||
# has things of https://wiki.archlinux.org/title/ZFS#Databases set
|
||||
device = "spool/nemesis/postgres";
|
||||
fsType = "zfs";
|
||||
|
|
|
|||
|
|
@ -1,38 +1,56 @@
|
|||
dyndns: ENC[AES256_GCM,data:yDDTTBimaFcd/MG+eSbYmOHq/Ij0fAoz0zDY+C4bv7ZNn1yAA6C8DE3fXnvAvWhatLLSbRGDxHRRm7JuAHOfGGisN9cXwL+fkB7rZMVZemaL2wrOAQxyzHDEeZnZHRwsVGYhAmTsbUCVLi4CyzjRHGbCLZtZ8b+DzT0644uTi9IQovcLrWun62KMt7yjFS+Wb85XItMrIk4gJRCOhllrAXKY/z0idgv8GCNRDsDsmKL8arfcWzo2+bU/Uqhqt1Md6++jySPNPxwwcORYUudqQM63N0g47jSnmbXJ11XRRq6ZBQJaHhx25YOj2WiDH1382Kn71hnnObWS8HcXI3pwAg51mQ7Wlu+Mlt/3iZjOS1ble4IrQGItLVQUqWjyKSLvTbPfe6P/AuQ9VFGLZ7VGhVUAuyum727bx7jg1oQmqETrkL9BwaW/2FsBCVfKobgBOM6s/XMO07dOrzkO14BxOgM7zcILkz0J3IClXDOnK+Qtqe9d0E4JiSItk1hlL+PI256dGt3J2oHHAZTNOhCn1f3/t1nwkDaPM379LhVHVGhGNFtPkwp1itAQPe/zY6apHCOrcd4sti7QjVssW+ekWjMGqIC0D41aw5oRUhE0pGSwVzVTwrxqc/IiLag8UxjFpBEWO9826I5qD3LQhH+sAfsrcBp9SeRrrt5icNbqLhKDxeB2,iv:Bj9aQZ8X1j5tV+iRPwFQ9NvNaxtlaRn6u60qqzHmWmw=,tag:gDKAPd8FEomSwyiT3yy2iw==,type:str]
|
||||
dyndns: ENC[AES256_GCM,data:E+yFHhfpyB3kFb59Nokjr4kIBpgRVZPLZzpHjwp9Ixd9b4rr8Fky0yz4b+/5MlXsSKsR4zfhUi/4yudeYVrSwMWeLibKHeAtoWYTlnEjhBn30wvlEA08M3zmvfMRvGB0Ur2bmax5OzCQbh2v0NKB+4mrIN9SVhBIR89Y5DLm7sd7KIJJxTruo2d+ODphAzFFNtuuyg4s3iq2+Y5H/zwrpgT4Td39h1ys+hfk4ght/OAseTZfda4qCdHhT0S4+aoCkhiyPUxr80KtuHhmt6UvpsazSDJmZyKyVJ3PpYcfS1VfBqAIdNc2enxxquNBRwppd3V8pXjIZKzPRTySFnLpgPIJBhnFkozJm44jaOttoSFrbrF1+7/iL/ssNWpHQvtr0Ke5jS1EPb6k0MZZnJxhGKUiZWzDL/Xb7FJex8pE5gTTK+24VD13mvIW2qCrtXybTydnid/76SzYpdz407mHgBsQUorA,iv:WGbR31NhtayYfdn89diNlOwWkUOulYmBVs9qqZSNieo=,tag:yvqJ6Ok2i0GC5ZSFYWySsg==,type:str]
|
||||
sops:
|
||||
lastmodified: "2025-11-24T15:13:32Z"
|
||||
mac: ENC[AES256_GCM,data:f+3n2Xc7jU+qW+vHk98BTgwLwVHTXzWHMjLwNr3Y3Pp8VIQf8d8iF8QwhDFPWN1uqsxsb/XD48CXbd5AwxuVcgcSM7FIHkjfIn0pHRk0jTAkXTxjWIwg9pqnGAZ5B/fA8XAvcyPpE299gMYzU2soAL11DZtrEVVXJWN2sD5IlL8=,iv:Uykx2R6xO/KW1XP0Nm8GyaoepmdU96AfGQQhLz6BlNQ=,tag:bqe0gZF6WhQg55NhWyNC5A==,type:str]
|
||||
lastmodified: "2025-12-01T18:59:41Z"
|
||||
mac: ENC[AES256_GCM,data:DGjRJWTAl2q58KDAcCxk30gvsin8C7/yBvw5qt+gGcHgJr4ggdVU1afW2Hn+qkexuSK0vLZP6tPJo6reiwyEAZNREPXnU21DUm83lMybu/zRdLFenA03ffPgJ4V+a6m9Ya/CmJzz/vaUxxtyeqCgynUI24otI/+ta0Hh1LQCbC4=,iv:t7NbX7mMMh2r2b0FLrmssxlFJSd9TTGAb7kjoYeKnzc=,tag:MKvgoxYoOj5TT/EzD8hKzw==,type:str]
|
||||
pgp:
|
||||
- created_at: "2025-11-24T13:05:23Z"
|
||||
enc: |-
|
||||
-----BEGIN PGP MESSAGE-----
|
||||
|
||||
hL4DAAAAAAAAAAASBAMEDMeIdplYrk7VppUFRCTcB7Pv+xnVKSLhhSoN6kqbHXqA
|
||||
YYv8o4AbT9bf1+L9wywA+Eg55tj8aocse/tdRQWTymy4+8grb/sm0oZQT22T51JP
|
||||
mWxhWIX+sliCqHnS/W2tuVLyDzAiJ/Tg19kOc576OH1z6f2HMIM7yvADoKupfqIw
|
||||
rbwo0G8CdZCW1hzutCnC2mD4Op2BxK1b26oZdNA06y+BMHHefyDTl/wXwiNQKWiq
|
||||
0l4BoaYNx2ma5ZTSBk7YNeIXikwM3XtZnUZU+V17EgClNbxhmTRc0h7fmeprjYcW
|
||||
zETvhSIm+JFTR0mdQsrDvTs7kt+PnaYptoM0CHaYCHTq48pyYKL3Gm0NtCAHuFc3
|
||||
=UlnU
|
||||
hL4DAAAAAAAAAAASBAMEIEXAYYvAspPhhSKpflgdFds2UrMJYMBl1TyKwMsTxQd/
|
||||
Chj1aQqRRdrQ0tF3Mkd13EEDJwU3kgJWrrh8uB5ukU+yYuig5kS5Gl51eW5H+FlD
|
||||
YFYJFsvJBIqbpNzpI7zitD4OvBZ6UCmwul+X9ibYVZRJjrZ6e4zSPmOk9D4Srecw
|
||||
Pz9nn6NnUA5PXd627Kt4JFBQ1OiLon/ZMBTKhk/vHuUKdYYJNQleJFnpWCU3lNN2
|
||||
0l4BTf26neMgV1qi34Nb86n3Jk8zqC/pMOgtoN2IrY45kR5lUDqGHTemKHw3JdmO
|
||||
9oiuqPnlGJktOxdAk+8jHxDrVwRsth+2f+U0cLkMNGTBcY8g1OPWk65ObwIpZ1rZ
|
||||
=NWw0
|
||||
-----END PGP MESSAGE-----
|
||||
fp: 0D98D5964AC8BB1CA034CE4EC456133700066642
|
||||
- created_at: "2025-11-24T15:13:16Z"
|
||||
enc: |-
|
||||
-----BEGIN PGP MESSAGE-----
|
||||
|
||||
hQGMAwAAAAAAAAAAAQv/SQPw9p1r4Sg9zYTyX1n3n6xJzhr+hEGLwwGhcmJh8mup
|
||||
D9n+aaZU4WK2Huha8Jd1bNqNo3J9UpqQMIaexfd64HoVdDHCxBzfThiMvgwpQ30a
|
||||
kTQqC0DGkLaFM5W8IVOremwjhLzrTBesu8ny8CasQYJ0tZ+QFU51OvxD4q0r9OLT
|
||||
BcCGqDsKZ3HDr7OIi4FsqdZRfxinJ+zteK93uxA+fB8Hkxok2g7Z2A5Nv2cOo54X
|
||||
NJxwsCN4l2Hs8MaVMTC+KGASn87m+Q1xwcVD7ujPmGGjMYb84j2sBn0DP3mNQh7y
|
||||
89jz6HPbq9goF++Sp172bwswmJwZLVCWkgvzQo+szfCqGnq6LTlG9JaVswkkSz7N
|
||||
z9kvF6L2dg7N2XlkLLP9UnxMkNxUrA615LvSn/z9AA7Dp6ay7TCsOeSWrz5m7+PF
|
||||
VVfTp4PN3y7hsZXvWWk1eqsOaThI5GY7N7W6aQlNmvhibjw7FJEF4Iv4FBJsOD23
|
||||
vYv+38yn377hnimtzoVt0lgBFtO8QhedShEvVjROUNjjEE2WB2jpP5/wZVIsrefs
|
||||
tl87MAyLedE/Zs5MByubb0buC2jifQnkxsA1QSvbZB2/NTi/SLSPeCMdFrVkYdcG
|
||||
hP8cp1HkI81F
|
||||
=iDKg
|
||||
hQGMAwAAAAAAAAAAAQv9EPOBFyrp+Zysk3SaNiYaQl928f0pe84uSO9Fm4VPqKtC
|
||||
xjov8740j38gvQIXpI2zADMlemLGzftbJPfBarSFVlukYoQkjs0SXQD0ukXsiCw2
|
||||
eLpEyOx57BFQMRwiNeh6gSkS6WeHAJNiQj1rY11MvyAsDIup8su5XPEw5DWjr3R0
|
||||
JdY029HuF6wqpmtgZnaFn6vmPYWYdtnYsxjqOJSPx+rXbWagiDgYy3DAOc7ltyIs
|
||||
bZoAsjVwQW/tl3hjWhKFeOSfsd9vdUX1TacKqqNZy4mLeEHZOYANeeLkOb+T1T4r
|
||||
Cexau6H3xZqc87T4S1ZBpEyWawIJHmIalFDoj466mUMOTJth7LxW7vfAdMpwbl1K
|
||||
HHbTK7vyYxLeo/e5rw646eVmbyPeFf3gF/IXRWB8qoL4g/atGbbQ+WJ86mLgMDg9
|
||||
9AqgVhSbVLoaWooqjh40tJ53raNm5HsO8ozfrJ9hx7Dq3QmCivpA14Q7UD6Yu1nT
|
||||
RxY6Ng7ykHGGIx3LacV70lgBoinGEzvbxe2Se7B+FOlEL+zFywRt8yFwqc0SXY6o
|
||||
qLriyhU2p05gvV45oR3pm9336VtwKu1lsN+Z9guKDZmKSgfIxZ22NulsA7E2zV8Z
|
||||
MacEdQskbB7J
|
||||
=zk6P
|
||||
-----END PGP MESSAGE-----
|
||||
fp: b730b2bf54eb792a14bfd3e68c14c08894376c5f
|
||||
- created_at: "2025-11-29T08:16:39Z"
|
||||
enc: |-
|
||||
-----BEGIN PGP MESSAGE-----
|
||||
|
||||
hQGMAwAAAAAAAAAAAQv+OaIQywQwV7AS4gi4GjVHFVyhk7Wd3/5fLlMt9UeB56gt
|
||||
l5+4VVkIzslwiuu9NF5KfvuXr4OQG3cOnb7KRgU5UEUEQtaDrMLFO/TwbBzVTC40
|
||||
YNHOya0Ow3MRcEegnM3ox5vL4nHLQwevL0jY8TUxa1xfcTvSj8qOQ9zzzkxzR3L6
|
||||
XvD6+dL9pHh1gtU6vlmPIm1PLsWalp0LJAOij3FQdzaxWpDRc0U+Wwr4lt5LiYS2
|
||||
jOFc5OZFeIOqMfzul5GCy933eu+V+Ch8PXa5/6PtWxFHx5bvF2pclubguRLziux1
|
||||
koeCxBpK3coHT1NX5AEmbtCEieFY9bMy6JTiih4I8eM2nkPjWyqByGh2mFuzjf4V
|
||||
OBGyHUZHK+KpDkRkwSS/6GqX3n89KMsf6aZwM35CkBvdG3PamyO8eVmE36OTGe4g
|
||||
1oj12rIjIj4dKtQ68vRgexvlH1Qq3GBHfsJRF5lRi4dKtPPLjU2P1fJWFcjszIEe
|
||||
q2QEcpDbCPYelI7mhwzT0lgBND6Yxso3tpW/Il/uRKao/9H+DgIYaIIRBml/cqaq
|
||||
VqDnFIYodxuW73R8n5GlfctY+gya9ZiGlK5uJwlghRE8gCVUjFrDnFS+uiVC6QI6
|
||||
SepzVJKOMUB8
|
||||
=7yY4
|
||||
-----END PGP MESSAGE-----
|
||||
fp: fada7e7be28e186e463ad745a38d17f36849d8a7
|
||||
unencrypted_suffix: _unencrypted
|
||||
version: 3.11.0
|
||||
|
|
|
|||
80
instances/nemesis/secrets/kanidm.yaml
Normal file
80
instances/nemesis/secrets/kanidm.yaml
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
oauth2Proxy:
|
||||
cookieSecret: ENC[AES256_GCM,data:CA6VBdPT3tuit4eWfBi1ycau4kErwAMfLwJ0maYr+/8Th8q51ZFHaWOcCA8=,iv:HSWCUEgVTkB9tKfzZWXUzH/sCoVZztzwbr1ZUwZBLBs=,tag:qOdClvQl2Cgn3lHXXA/o1Q==,type:str]
|
||||
kanidm:
|
||||
adminPassword: ENC[AES256_GCM,data:JQHTQHwXKMgbc0SRdkhMjKjZBznuIbHdcR4TXsmikKWX+5T4VOSqo4CwlXj0XQSV,iv:ruCMDfPlwcAUXdRypB0lNSH1UuV9ryS4vLSleVHnWwc=,tag:V4phitbR0tk6jUrdyFlZWQ==,type:str]
|
||||
idmAdminPassword: ENC[AES256_GCM,data:D128I5u5pTP6xgSiP+EIZWJmbkXDfHHLh7Bw8wAiMxYPpjGG3EDsdG+8CwOUP8jZ,iv:5h/UZ7BHviKYIY0zpTo/seFHvMcGucDLeey9bc+GDlo=,tag:DSelYBlzIN94K7tOI3QtDA==,type:str]
|
||||
sops:
|
||||
lastmodified: "2025-12-03T21:25:56Z"
|
||||
mac: ENC[AES256_GCM,data:R3cxPrzR5tT0CMNvrtBWDCE8RTvPj9tPslkGhubfOREQBR+qIw7e84uSrswo2+KJkc+AL7CPzVSgsdcSjalNxIqLlL2Gg1y/BKgE6UDB5GDT49+cfCL68hFYkZ+4Cl6bKdLpOuuhsR92NwQk171bx+KCgjE2KUBRFDjOllo+V7M=,iv:LdeRN1jnLNKL3pXVVEQ3BzI3csJSRil5gkQOnxyLi+U=,tag:Ti9Ryuc4kyeuKDwRelQI2A==,type:str]
|
||||
pgp:
|
||||
- created_at: "2025-11-29T10:45:57Z"
|
||||
enc: |-
|
||||
-----BEGIN PGP MESSAGE-----
|
||||
|
||||
hL4DAAAAAAAAAAASBAMEYHWKHKXoJ9J5HDHfY9FhItdcvUdWz57Wl79xKzH94s42
|
||||
B7k57At1H6mW3BOrbnDNgNyBs6dHIG1jTA+4yITgIAcn/bl9JRbMOjmDZZzzevJi
|
||||
4yQdnm8C6mxQhbUNDpWJ4He6+m7vMZx8uq0S6dq0a5aAE/7ph7Z4gvIbBjZIA6gw
|
||||
z/GwpL9SyZjSyTW8Z9XPLebonCp1lhD0tsVHk9GKoL46UWlYzq87XSyJOo4AHGAO
|
||||
0l4BWq3e7iDmzdxwtCoIC7PKHPmigUielz1qDdCGAIMQsAhaJqOa24gCUW7cklgk
|
||||
A18EVlSyfeqGaqr//cuGqm8TnrG9cfLtMgnjUv3UQfBWVOh5P8ccKTbl4SUY2BfQ
|
||||
=JRop
|
||||
-----END PGP MESSAGE-----
|
||||
fp: 0D98D5964AC8BB1CA034CE4EC456133700066642
|
||||
- created_at: "2025-11-29T10:45:57Z"
|
||||
enc: |-
|
||||
-----BEGIN PGP MESSAGE-----
|
||||
|
||||
hQGMAwAAAAAAAAAAAQv9GuE7hANGXNsAGi3e1oB4c2y9jpvi3RkEifcxBg19yf9n
|
||||
L9t3Av1Ym2H/Bc5Sw5++qrF7Jy3Aujt1T8ytayxzVsuLesgkuDzjtot0JgUsRSWK
|
||||
r2dXDoo9gaftX434fGViamHTX2wHBo9VEwqe/c2NjwLeIx/O6u4FwJmUAgzGy1pp
|
||||
I5TSpYMky4coLbFpDX7AuUuPymI6lGNad6JoeOoTP2gb5Kt2Ycr7ZqzOp2kaPxua
|
||||
yw5HuoiXLkzxywuWh+IIbqanyN8qxbjvEOS4ZJHegECZhDS27kocwiXhUlcT1NC1
|
||||
1pFW7EJaVMzikSBy06LiPWsYjNmQIR9o8uoeP//XMcq34N0036IxVaOWs8Qnls97
|
||||
TJM6lCov4c0XcNrfop15hWNK2gxSzNwxWkmG5PUHwfRi9JGvL6Ng/EHbJS+6F3Nx
|
||||
z7H2jAIdzc9StMd411SJrZSpDk1wpnecroUWYdO5OIKJu70J5FvNSaKripEECy1x
|
||||
wBrqY5RLmi/qYsfyCupg0lgBPGUyJbV2XLt1Qcf4eStzy5ZYi8gnn02T0EWvCspf
|
||||
0tKMs7hbLm6FwK7vG7Cmc1LQCm73oW09cZCrLurd9JtiRftfww9pBEc85MfPUBIt
|
||||
PYAWvU26TshG
|
||||
=vU9m
|
||||
-----END PGP MESSAGE-----
|
||||
fp: fada7e7be28e186e463ad745a38d17f36849d8a7
|
||||
- created_at: "2025-11-29T10:45:57Z"
|
||||
enc: |-
|
||||
-----BEGIN PGP MESSAGE-----
|
||||
|
||||
hQGMAwAAAAAAAAAAAQwAnX5FoTN8ft2sFXRotgVGt2he9RJMiq0orduWeTXZPLK8
|
||||
mvyYOcrQ71fOIm9sIg6hJfabeR2GjBsm09XIXJ71zLl0lWgb8SvcYmbgaJJ+svfY
|
||||
pPrW+ZninOUZgwkJ8L1gM3ZWOJlx+92NKtdxifIY98SMKacT+aVe7vNTrQVwmRn9
|
||||
cZZQd8B75zN7IV99bJCG2BYvSt+p8gZ1vm3GxhowctbSgCl6knHDHJlpXE7SyLHv
|
||||
ReHjfCFetJQd/XqLL4vZifrlpGKyGPP5pYnEQT5bbsJr9exBeZQ7PsAB0OG+KpOB
|
||||
r4IvB78XGJlbHTnqlP6GKAKek6NSldlEq5tCsKo5wl3Jg2/SgxSbOhbb5YmOqwcq
|
||||
S+JJhbfjRGSJMMXLOP9QtLQU5qktwip5g+ZxgKDrcgQvUPUsbV3PEW9l/0WoCf1Q
|
||||
7e+mBJ+TRJVOjS9hC1mr/C6kkJJurdpH3PvUSncSk4s0+bkw66nLwmc3QLpI6DV7
|
||||
BLJVkOUQzUWaB6k6NVkE0lgBbVYeyaOS3JcoFHrYex6bDHjliD/SH+xjc8wyJR8s
|
||||
wz5CwfFPqudE9ZYvilJ3lN2AtJrRBaxtR5dgrG2fUx9OB6FSOoRVOpmnFC3YUt6a
|
||||
FNZYBn5X10t/
|
||||
=Mj7y
|
||||
-----END PGP MESSAGE-----
|
||||
fp: b730b2bf54eb792a14bfd3e68c14c08894376c5f
|
||||
- created_at: "2025-11-29T10:45:57Z"
|
||||
enc: |-
|
||||
-----BEGIN PGP MESSAGE-----
|
||||
|
||||
hQIMAwAAAAAAAAAAAQ//a9QFgxhKeW4xcFeERaCiO5nb07wS8BxENBw57RDTp52F
|
||||
0kzEdp+HnkVujYMC5cjKlz3x6ZT+CFcVT8HZTwTjlrtCdO/R1OGeO0NcC/tRQNvV
|
||||
LUgaV9mCzYAbfJG1skdz9EMZZ3W9qPBgKXbX7vGhPirwXyAUUEfQsWon8eOymrd6
|
||||
FoapcdLo9ymTnar14WH0kM7B0i4Kqv6+NKquc0OiL8eSufL4wubJrXZZkOdtnXCD
|
||||
omwFtYmF+IgQAzaCBWLGY3sOW9nD27Y9F1vToOpKQvxE+IT3VGTZN02Xy2J4lhnJ
|
||||
IE2SmaeY29g2QWIRePCrehpaRNCjlmTS7j7SRT2K9bOVcbiwljUidwkC58323EmC
|
||||
UlacFRSY5Cfeav2VL188ywh4vihnUpWJoncHKvcUEEeLykbQcdpy2Zwl6u6UB+2g
|
||||
oDmhk1pFV4ejJlRe1BpLHiBcnA5/OFsWxMGQp57mZ2vyGWYQgtsQZ71JVENq7nSt
|
||||
TKi6OPhRTZX2Wk8lcZMjm+5XeNrGMSUEYwCPRza+5C0f3LzSfjmmGDLxwaQmCaYI
|
||||
ZjKSuj14N9VQNJJ8Yxn9uni1acKs+q1XM1b3gJUT2gpFbOjh1BjtAGrat1f4mKk9
|
||||
0PwxBA7cZkdmgJ0t/oNja8ElpOMLMTbI7yYOLY3hD64CtFKWWwpxbD7bK65neRTS
|
||||
WAE9cEyjhq3TOKNdKaIP5N6a6Sq+98N9xE7/3/lVYncFZ1zV4+9l8Gyjr4rsSSV+
|
||||
68gg9t6FUPIHyNHdrvmqLLQP+paA9RMb7yOMkULB8zBKJrZMXnu+wsI=
|
||||
=Du56
|
||||
-----END PGP MESSAGE-----
|
||||
fp: 4019fd893bba15618c2f93a38ef418ce360bc418
|
||||
unencrypted_suffix: _unencrypted
|
||||
version: 3.11.0
|
||||
48
instances/nemesis/services/navidrome.nix
Normal file
48
instances/nemesis/services/navidrome.nix
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
{
|
||||
config,
|
||||
...
|
||||
}:
|
||||
let
|
||||
host = "music.xyno.systems";
|
||||
internalIp = "127.0.0.5";
|
||||
in
|
||||
{
|
||||
services.kanidm.provision = {
|
||||
groups = {
|
||||
navidrome_users.members = [ "application_admins" ];
|
||||
};
|
||||
};
|
||||
xyno.services.oauth2Proxy.hosts."${host}" = {
|
||||
allowedGroups = [ "navidrome_users" ];
|
||||
};
|
||||
xyno.services.traefik.simpleProxy = {
|
||||
navidrome = {
|
||||
inherit host;
|
||||
inherit (config.xyno.services.oauth2Proxy.hosts.${host}) middlewares;
|
||||
internal = "http://${internalIp}:4533";
|
||||
};
|
||||
navidrome-subsonic = {
|
||||
inherit host;
|
||||
rule = "Host(`${host}`) && PathPrefix(`/rest/`) && !Query(`c`, `NavidromeUI`)";
|
||||
internal = "http://${internalIp}:4533";
|
||||
};
|
||||
};
|
||||
|
||||
services.navidrome = {
|
||||
enable = true;
|
||||
settings = {
|
||||
Address = internalIp;
|
||||
MusicFolder = "/data/media/beets/music";
|
||||
ReverseProxyWhitelist = "127.0.0.1/32";
|
||||
BaseUrl = "https://${host}";
|
||||
Prometheus = {
|
||||
Enabled = false; # TODO
|
||||
};
|
||||
ReverseProxyUserHeader = "X-Auth-Request-Preferred-Username";
|
||||
Scanner = {
|
||||
Schedule = "45 0 * * *"; # daily at 0:45
|
||||
};
|
||||
};
|
||||
};
|
||||
xyno.impermanence.directories = [ "/var/lib/navidrome" ];
|
||||
}
|
||||
93
instances/nemesis/services/traccar.nix
Normal file
93
instances/nemesis/services/traccar.nix
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
{
|
||||
pkgs,
|
||||
lib,
|
||||
config,
|
||||
...
|
||||
}:
|
||||
{
|
||||
xyno.services.traefik.simpleProxy.traccar = {
|
||||
host = "track.66642.bot";
|
||||
internal = "http://127.0.0.4:8082";
|
||||
};
|
||||
services.kanidm.provision = {
|
||||
groups = {
|
||||
traccar_users.members = [ "traccar_admins" ];
|
||||
traccar_admins.members = [ "application_admins" ];
|
||||
};
|
||||
systems.oauth2.traccar = {
|
||||
displayName = "Traccar";
|
||||
originUrl = "https://track.66642.bot/api/session/openid/callback";
|
||||
originLanding = "https://track.66642.bot/login";
|
||||
imageFile = "${pkgs.traccar}/web/logo.svg";
|
||||
# public = true;
|
||||
scopeMaps."traccar_users" = [
|
||||
"openid"
|
||||
"profile"
|
||||
"email"
|
||||
"groups"
|
||||
];
|
||||
allowInsecureClientDisablePkce = true;
|
||||
};
|
||||
};
|
||||
xyno.services.kanidm.templates."traccar" = {
|
||||
text = p: ''
|
||||
OPENID_CLIENT_ID=${p.clientId}
|
||||
OPENID_CLIENT_SECRET=${p.basicSecret}
|
||||
DATABASE_URL='jdbc:postgresql://localhost/traccar?socketFactory=org.newsclub.net.unix.AFUNIXSocketFactory$FactoryArg&socketFactoryArg=/run/postgresql/.s.PGSQL.5432'
|
||||
'';
|
||||
wantedBy = [ "traccar.service" ];
|
||||
};
|
||||
systemd.services.traccar.serviceConfig.ExecStart =
|
||||
lib.mkForce "${pkgs.openjdk}/bin/java -cp './tracker-server.jar:./lib/*:${pkgs.junixsocket-common}/share/java/junixsocket-common-${pkgs.junixsocket-common.version}.jar:${pkgs.junixsocket-native-common}/share/java/junixsocket-native-common-${pkgs.junixsocket-common.version}.jar' org.traccar.Main /var/lib/traccar/config.xml"; # forgive it for what it has done
|
||||
services.traccar = {
|
||||
enable = true;
|
||||
environmentFile = config.xyno.services.kanidm.templates.traccar.path;
|
||||
settings = {
|
||||
database.driver = "org.postgresql.Driver";
|
||||
database.url = "$DATABASE_URL";
|
||||
database.user = "traccar";
|
||||
mail.debug = "true"; # log mail content instead of sending email
|
||||
openid.adminGroup = "traccar_admins@idm.xyno.systems";
|
||||
openid.allowGroup = "traccar_users@idm.xyno.systems";
|
||||
openid.clientId = "$OPENID_CLIENT_ID";
|
||||
openid.clientSecret = "$OPENID_CLIENT_SECRET";
|
||||
openid.force = "true";
|
||||
openid.issuerUrl = "https://idm.xyno.systems/oauth2/openid/traccar";
|
||||
web.address = "127.0.0.4";
|
||||
web.url = "https://track.66642.bot";
|
||||
};
|
||||
};
|
||||
systemd.services.postgresql-install-timescale-in-traccar = {
|
||||
after = [
|
||||
"postgresql.service"
|
||||
"postgresql-setup.service"
|
||||
];
|
||||
requires = [
|
||||
"postgresql.service"
|
||||
"postgresql-setup.service"
|
||||
];
|
||||
requiredBy = [ "traccar.service" ];
|
||||
|
||||
serviceConfig = {
|
||||
User = "postgres";
|
||||
Group = "postgres";
|
||||
Type = "oneshot";
|
||||
RemainAfterExit = true;
|
||||
};
|
||||
|
||||
path = [ config.services.postgresql.finalPackage ];
|
||||
environment.PGPORT = builtins.toString config.services.postgresql.settings.port;
|
||||
script = ''
|
||||
psql -d traccar -tAc "CREATE EXTENSION IF NOT EXISTS timescaledb;"
|
||||
'';
|
||||
|
||||
};
|
||||
services.postgresql.settings.shared_preload_libraries = [ "timescaledb" ];
|
||||
services.postgresql.ensureDatabases = [ "traccar" ];
|
||||
services.postgresql.ensureUsers = [
|
||||
{
|
||||
name = "traccar";
|
||||
ensureDBOwnership = true;
|
||||
}
|
||||
];
|
||||
}
|
||||
|
|
@ -88,6 +88,7 @@ in
|
|||
ptouch-print
|
||||
hledger
|
||||
|
||||
super-productivity
|
||||
];
|
||||
environment.variables."LEDGER_FILE" = "~/docs/hledger/main.journal";
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,11 @@
|
|||
./presets/server.nix
|
||||
# ./services/authentik
|
||||
# ./services/caddy
|
||||
./services/kanidm.nix
|
||||
./services/traefik.nix
|
||||
./services/postgres.nix
|
||||
./services/oauth2Proxy/default.nix
|
||||
./services/oauth2Proxy/integration.nix
|
||||
./services/monitoring.nix
|
||||
./services/wireguard.nix
|
||||
./system/impermanence.nix
|
||||
|
|
|
|||
|
|
@ -84,6 +84,8 @@ in
|
|||
# https://github.com/NixOS/nixpkgs/issues/361592 needed for run0
|
||||
security.pam.services.systemd-run0 = { };
|
||||
|
||||
# services.ssh.knownHosts = lib.mapAttrs' (n: v: lib.nameValuePair v.deployment.targetHost { publicKey = v.})
|
||||
|
||||
programs.yazi = {
|
||||
enable = true;
|
||||
initLua = pkgs.writeText "yazi-init.lua" ''
|
||||
|
|
|
|||
|
|
@ -5,13 +5,59 @@
|
|||
...
|
||||
}:
|
||||
let
|
||||
inherit (lib) mkEnableOption mkIf mkOption;
|
||||
inherit (lib.types) str nullOr pathWith;
|
||||
inherit (lib)
|
||||
mkEnableOption
|
||||
mkIf
|
||||
mkOption
|
||||
converge
|
||||
mkMerge
|
||||
filterAttrsRecursive
|
||||
literalExpression
|
||||
mapAttrsToList
|
||||
concatStringsSep
|
||||
attrNames
|
||||
;
|
||||
inherit (lib.types)
|
||||
str
|
||||
nullOr
|
||||
pathWith
|
||||
submodule
|
||||
listOf
|
||||
functionTo
|
||||
attrsOf
|
||||
lines
|
||||
;
|
||||
absPath = pathWith {
|
||||
inStore = false;
|
||||
absolute = true;
|
||||
};
|
||||
cfg = config.xyno.services.kanidm;
|
||||
tlsDir = "/run/generated/kanidm-tls";
|
||||
package = pkgs.kanidmWithSecretProvisioning_1_8.overrideAttrs (old: {
|
||||
doCheck = false;
|
||||
patches = old.patches ++ [
|
||||
(pkgs.writeText "patch-kanidm-name" ''
|
||||
diff --git a/server/lib/src/value.rs b/server/lib/src/value.rs
|
||||
index 86b5a74c1..c83b2f93d 100644
|
||||
--- a/server/lib/src/value.rs
|
||||
+++ b/server/lib/src/value.rs
|
||||
@@ -64,7 +64,7 @@ lazy_static! {
|
||||
/// Only lowercase+numbers, with limited chars.
|
||||
pub static ref INAME_RE: Regex = {
|
||||
#[allow(clippy::expect_used)]
|
||||
- Regex::new("^[a-z][a-z0-9-_\\.]{0,63}$").expect("Invalid Iname regex found")
|
||||
+ Regex::new("^[a-z0-9-_\\.]{0,64}$").expect("Invalid Iname regex found")
|
||||
};
|
||||
|
||||
/// Only alpha-numeric with limited special chars and space
|
||||
'')
|
||||
];
|
||||
});
|
||||
templatePlaceholders = {
|
||||
clientId = ''\($get.attrs.name[0])'';
|
||||
basicSecret = ''\($secret.secret)'';
|
||||
env = v: ''\(env.${v})'';
|
||||
};
|
||||
in
|
||||
{
|
||||
options.xyno.services.kanidm.enable = mkEnableOption "enables kanidm";
|
||||
|
|
@ -19,8 +65,75 @@ in
|
|||
default = "idm.xyno.systems";
|
||||
type = str;
|
||||
};
|
||||
options.xyno.services.kanidm.isReplica = mkEnableOption "replica";
|
||||
options.xyno.services.kanidm.isReplica = mkEnableOption "replica"; # TODO
|
||||
options.xyno.services.kanidm.setupTraefik = mkEnableOption "traefik";
|
||||
options.xyno.services.kanidm.templates = mkOption {
|
||||
type = attrsOf (
|
||||
submodule (
|
||||
{ name, ... }:
|
||||
{
|
||||
options = {
|
||||
path = mkOption {
|
||||
type = absPath;
|
||||
default = "/run/generated/kanidmTemplates/${name}";
|
||||
};
|
||||
user = mkOption {
|
||||
type = str;
|
||||
default = "root";
|
||||
};
|
||||
group = mkOption {
|
||||
type = str;
|
||||
default = "kanidm";
|
||||
};
|
||||
chmod = mkOption {
|
||||
type = str;
|
||||
default = "440";
|
||||
};
|
||||
wantedBy = mkOption {
|
||||
type = listOf str;
|
||||
default = [ ];
|
||||
example = [ "traccar.service" ];
|
||||
};
|
||||
text = mkOption {
|
||||
type = functionTo lines;
|
||||
description = ''
|
||||
jq templated string
|
||||
|
||||
current placeholders: ${concatStringsSep ", " (attrNames templatePlaceholders)}
|
||||
'';
|
||||
example = literalExpression ''
|
||||
p: ${"''"}
|
||||
OAUTH2_PROXY_CLIENT_ID=''${p.clientId}
|
||||
OAUTH2_PROXY_CLIENT_SECRET=''${p.clientSecret}
|
||||
${"''"}
|
||||
'';
|
||||
};
|
||||
environmentFiles = mkOption {
|
||||
type = listOf absPath;
|
||||
default = [ ];
|
||||
description = ''
|
||||
add environment variables to the template file.
|
||||
the environment variable BANANA would be accessible as
|
||||
```
|
||||
COOKIE_SECRET=''${p.env "BANANA"}
|
||||
```
|
||||
in the template
|
||||
'';
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
example = {
|
||||
traccar.text = p: ''
|
||||
OPENID_CLIENTID=${p.clientId}
|
||||
OPENID_SECRET=${p.basicSecret}
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
options.xyno.services.kanidm.tls = {
|
||||
keyPem = mkOption {
|
||||
|
|
@ -29,60 +142,144 @@ in
|
|||
description = "autogenerated if unset";
|
||||
};
|
||||
certPem = mkOption {
|
||||
default = "/run/generated/kanidm-tls/cert.pem";
|
||||
default = "${tlsDir}/cert.pem";
|
||||
type = absPath;
|
||||
};
|
||||
};
|
||||
config = mkIf cfg.enable {
|
||||
services.kanidm = {
|
||||
enableServer = true;
|
||||
enableClient = true;
|
||||
adminPasswordFile = config.sops.secrets."kanidm.password".path;
|
||||
provision = {
|
||||
adminPasswordFile = config.sops.secrets."kanidm.password".path;
|
||||
};
|
||||
serverSettings = {
|
||||
tls_key = if cfg.tls.keyPem != null then cfg.tls.keyPem else "/run/generated/key.pem";
|
||||
tls_chain = cfg.tls.certPem;
|
||||
bindaddress = "127.0.0.3:8443";
|
||||
};
|
||||
};
|
||||
xyno.services.traefik.simpleProxy = mkIf cfg.setupTraefik {
|
||||
host = cfg.domain;
|
||||
internal = "https://127.0.0.3:8443";
|
||||
transport = "kanidm-https";
|
||||
};
|
||||
services.traefik.dynamicConfigOptions.http = mkIf cfg.setupTraefik {
|
||||
serversTransports."kanidm-https" = {
|
||||
serverName = cfg.domain;
|
||||
certificates = [
|
||||
cfg.certPem
|
||||
];
|
||||
};
|
||||
};
|
||||
config = mkMerge [
|
||||
(mkIf cfg.enable {
|
||||
services.kanidm = {
|
||||
enableServer = true;
|
||||
enableClient = true;
|
||||
inherit package;
|
||||
clientSettings.uri = "https://${cfg.domain}";
|
||||
|
||||
systemd.services.generate-kanidm-tls = mkIf (cfg.tls.keyPem == null) {
|
||||
serviceConfig = {
|
||||
User = "root";
|
||||
Group = "kanidm";
|
||||
provision = {
|
||||
enable = true;
|
||||
adminPasswordFile = config.sops.secrets."kanidm/adminPassword".path;
|
||||
idmAdminPasswordFile = config.sops.secrets."kanidm/idmAdminPassword".path;
|
||||
instanceUrl = "https://127.0.0.3:8443";
|
||||
acceptInvalidCerts = true;
|
||||
autoRemove = true;
|
||||
groups.application_admins = {};
|
||||
};
|
||||
serverSettings = {
|
||||
trust_x_forward_for = true;
|
||||
tls_key = if cfg.tls.keyPem != null then cfg.tls.keyPem else "${tlsDir}/key.pem";
|
||||
tls_chain = cfg.tls.certPem;
|
||||
bindaddress = "127.0.0.3:8443";
|
||||
origin = "https://${cfg.domain}";
|
||||
domain = cfg.domain;
|
||||
};
|
||||
};
|
||||
wantedBy = [
|
||||
"kanidm.service"
|
||||
"traefik.service"
|
||||
];
|
||||
script = ''
|
||||
mkdir -p /run/generated/kanidm-tls
|
||||
${pkgs.openssl}/bin/openssl req -x509 -newkey ed25519 -noenc -subj "/CN=generated.${cfg.domain}" -addext "subjectAltName=DNS:${cfg.domain}" -keyout /run/generated/key.pem -out /run/generated/cert.pem
|
||||
'';
|
||||
};
|
||||
sops.secrets."kanidm.password" = {
|
||||
sopsFile = ../../instances/${config.networking.hostName}/secrets/kanidm.yaml;
|
||||
};
|
||||
# sops.templates."kanidm.env".content = ''
|
||||
# DESEC_TOKEN=${config.sops.placeholder.desec_token}
|
||||
# DESEC_PROPAGATION_TIMEOUT=1200
|
||||
# '';
|
||||
# sops.templates."kanidm.env".reloadUnits = [ "kanidm.service" ];
|
||||
systemd.tmpfiles.rules = [ "d /run/generated/kanidmTemplates 1755 root kanidm -" ];
|
||||
systemd.services = mkMerge (
|
||||
(mapAttrsToList (n: v: {
|
||||
"generate-kanidm-template-${n}" = {
|
||||
serviceConfig = {
|
||||
User = "root";
|
||||
Group = "kanidm";
|
||||
Type = "oneshot";
|
||||
PrivateTmp = true;
|
||||
EnvironmentFile = v.environmentFiles;
|
||||
};
|
||||
requires = [ "kanidm.service" ] ++ (lib.optional cfg.setupTraefik "traefik.service");
|
||||
after = [
|
||||
"kanidm.service"
|
||||
"systemd-tmpfiles-setup.service"
|
||||
]
|
||||
++ (lib.optional cfg.setupTraefik "traefik.service");
|
||||
before = v.wantedBy;
|
||||
partOf = v.wantedBy;
|
||||
wantedBy = if (builtins.length v.wantedBy) == 0 then [ "multi-user.target" ] else v.wantedBy;
|
||||
enableStrictShellChecks = true;
|
||||
path = [
|
||||
package
|
||||
pkgs.jq
|
||||
];
|
||||
environment.KANIDM_TOKEN_CACHE_PATH = "/tmp/kanidm-token-cache";
|
||||
script =
|
||||
let
|
||||
templateText = v.text templatePlaceholders;
|
||||
in
|
||||
''
|
||||
KANIDM_PASSWORD=$(cat "${
|
||||
config.sops.secrets."kanidm/idmAdminPassword".path
|
||||
}") kanidm login -D idm_admin
|
||||
jq -r -s \
|
||||
-f "${pkgs.writeText "kanidm-template-${n}" ''"${templateText}"''}" \
|
||||
--argjson get "$(kanidm system oauth2 get --output json "${n}")" \
|
||||
--argjson secret "$(kanidm system oauth2 show-basic-secret --output json "${n}")" \
|
||||
> "${v.path}"
|
||||
chown "${v.user}:${v.group}" "${v.path}"
|
||||
chmod "${v.chmod}" "${v.path}"
|
||||
'';
|
||||
};
|
||||
}) cfg.templates)
|
||||
++ [
|
||||
(mkIf (cfg.tls.keyPem == null) {
|
||||
|
||||
generate-kanidm-tls =
|
||||
let
|
||||
units = [
|
||||
"kanidm.service"
|
||||
]
|
||||
++ (lib.optional cfg.setupTraefik "traefik.service");
|
||||
in
|
||||
{
|
||||
serviceConfig = {
|
||||
User = "root";
|
||||
Group = "kanidm";
|
||||
Type = "oneshot";
|
||||
};
|
||||
wantedBy = units;
|
||||
before = units;
|
||||
script = ''
|
||||
mkdir -p ${tlsDir}
|
||||
cd ${tlsDir}
|
||||
${config.services.kanidm.package}/bin/kanidmd cert-generate -c ${
|
||||
let
|
||||
toml = pkgs.formats.toml { };
|
||||
filterConfig = converge (filterAttrsRecursive (_: v: v != null));
|
||||
in
|
||||
toml.generate "kanidm-tls.conf" (filterConfig (config.services.kanidm.serverSettings))
|
||||
}
|
||||
chmod +g ${tlsDir}/*
|
||||
'';
|
||||
};
|
||||
})
|
||||
]
|
||||
);
|
||||
sops.secrets."kanidm/adminPassword" = {
|
||||
sopsFile = ../../instances/${config.networking.hostName}/secrets/kanidm.yaml;
|
||||
reloadUnits = [ "kanidm.service" ];
|
||||
owner = "kanidm";
|
||||
};
|
||||
sops.secrets."kanidm/idmAdminPassword" = {
|
||||
sopsFile = ../../instances/${config.networking.hostName}/secrets/kanidm.yaml;
|
||||
reloadUnits = [ "kanidm.service" ];
|
||||
owner = "kanidm";
|
||||
};
|
||||
|
||||
xyno.impermanence.directories = [ "/var/lib/kanidm" ];
|
||||
})
|
||||
(mkIf (cfg.enable && cfg.setupTraefik) {
|
||||
|
||||
xyno.services.traefik.simpleProxy.kanidm = {
|
||||
host = cfg.domain;
|
||||
internal = "https://127.0.0.3:8443";
|
||||
transport = "kanidm-https";
|
||||
};
|
||||
services.traefik.dynamicConfigOptions.http = mkIf (cfg.tls.keyPem == null) {
|
||||
serversTransports."kanidm-https" = {
|
||||
serverName = cfg.domain;
|
||||
rootcas = [
|
||||
"${tlsDir}/ca.pem"
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
})
|
||||
];
|
||||
|
||||
};
|
||||
}
|
||||
|
|
|
|||
85
modules/services/oauth2Proxy/default.nix
Normal file
85
modules/services/oauth2Proxy/default.nix
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
{
|
||||
pkgs,
|
||||
lib,
|
||||
config,
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (lib)
|
||||
mkEnableOption
|
||||
mkIf
|
||||
mkOption
|
||||
getExe
|
||||
;
|
||||
inherit (lib.types)
|
||||
pathWith
|
||||
listOf
|
||||
;
|
||||
cfg = config.xyno.services.oauth2Proxy;
|
||||
settingsFormat = pkgs.formats.toml { };
|
||||
configFile = settingsFormat.generate "oauth2-proxy.conf" cfg.settings;
|
||||
absPath = pathWith {
|
||||
inStore = false;
|
||||
absolute = true;
|
||||
};
|
||||
in
|
||||
{
|
||||
options.xyno.services.oauth2Proxy = {
|
||||
enable = mkEnableOption "oauth2-proxy";
|
||||
package = lib.mkPackageOption pkgs "oauth2-proxy" { };
|
||||
settings = mkOption {
|
||||
type = settingsFormat.type;
|
||||
description = "what to add to the config toml file";
|
||||
};
|
||||
environmentFiles = mkOption {
|
||||
type = listOf absPath;
|
||||
default = [ ];
|
||||
example = [ "/run/secrets/oauth2Proxy" ];
|
||||
};
|
||||
};
|
||||
config = mkIf cfg.enable {
|
||||
systemd.services.oauth2-proxy = {
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
description = "OAuth2 Proxy (66642's less weird version)";
|
||||
confinement.enable = true;
|
||||
after = [ "network.target" ];
|
||||
serviceConfig = {
|
||||
BindReadOnlyPaths = [
|
||||
"-/etc/resolv.conf"
|
||||
"-/run/systemd"
|
||||
"/etc/hosts"
|
||||
"${config.security.pki.caBundle}:/etc/ssl/certs/ca-certificates.crt"
|
||||
];
|
||||
ExecStart = "${getExe cfg.package} --config=${configFile}";
|
||||
EnvironmentFile = cfg.environmentFiles;
|
||||
DynamicUser = true;
|
||||
CapabilityBoundingSet = [ "" ];
|
||||
RestrictAddressFamilies = [
|
||||
"AF_INET"
|
||||
"AF_INET6"
|
||||
];
|
||||
|
||||
PrivateDevices = true;
|
||||
UMask = "0022";
|
||||
SystemCallFilter = [ "@system-service" ];
|
||||
SystemCallErrorNumber = "EPERM";
|
||||
LockPersonality = true;
|
||||
PrivateTmp = true;
|
||||
ProcSubset = "pid";
|
||||
ProtectClock = true;
|
||||
ProtectControlGroups = true;
|
||||
ProtectHome = true;
|
||||
ProtectHostname = true;
|
||||
ProtectKernelLogs = true;
|
||||
ProtectKernelModules = true;
|
||||
ProtectKernelTunables = true;
|
||||
ProtectProc = "invisible";
|
||||
ProtectSystem = "strict";
|
||||
RestrictNamespaces = true;
|
||||
RestrictRealtime = true;
|
||||
RestrictSUIDSGID = true;
|
||||
SystemCallArchitectures = "native";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
208
modules/services/oauth2Proxy/integration.nix
Normal file
208
modules/services/oauth2Proxy/integration.nix
Normal file
|
|
@ -0,0 +1,208 @@
|
|||
{
|
||||
lib,
|
||||
config,
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (lib)
|
||||
mkIf
|
||||
mkOption
|
||||
mkMerge
|
||||
attrNames
|
||||
mapAttrsToList
|
||||
;
|
||||
inherit (lib.types)
|
||||
str
|
||||
nullOr
|
||||
submodule
|
||||
listOf
|
||||
attrsOf
|
||||
;
|
||||
cfg = config.xyno.services.oauth2Proxy;
|
||||
kanidmCfg = config.xyno.services.kanidm;
|
||||
oauth2ProxyInternalHostPort = "127.0.0.4:4180";
|
||||
oauth2ProxyInternalHostPortMetrics = "127.0.0.4:4181";
|
||||
in
|
||||
{
|
||||
options.xyno.services.oauth2Proxy = {
|
||||
domain = mkOption {
|
||||
default = "oauth.xyno.systems";
|
||||
type = str;
|
||||
};
|
||||
hosts = mkOption {
|
||||
type = attrsOf (
|
||||
submodule (
|
||||
{ name, ... }:
|
||||
{
|
||||
options.allowedGroups = mkOption {
|
||||
type = nullOr (listOf str);
|
||||
default = null;
|
||||
};
|
||||
options.allowed_email_domains = mkOption {
|
||||
type = nullOr (listOf str);
|
||||
default = null;
|
||||
};
|
||||
options.allowed_emails = mkOption {
|
||||
type = nullOr (listOf str);
|
||||
default = null;
|
||||
};
|
||||
options.middlewares = mkOption {
|
||||
type = listOf str;
|
||||
description = "add to your service";
|
||||
default = [
|
||||
"oauth-errors"
|
||||
"oauth-host-${name}"
|
||||
];
|
||||
};
|
||||
}
|
||||
)
|
||||
);
|
||||
example = {
|
||||
"navidrome.xyno.systems" = {
|
||||
allowedGroups = [ "navidrome_access@idm.xyno.systems" ];
|
||||
};
|
||||
};
|
||||
default = { };
|
||||
};
|
||||
};
|
||||
config = mkIf (cfg.enable && config.xyno.services.kanidm.enable) {
|
||||
services.kanidm.provision = {
|
||||
groups = {
|
||||
proxy_users.members = [ "application_admins" ];
|
||||
};
|
||||
systems.oauth2.oauth2_proxy = {
|
||||
displayName = "oauth2 proxy";
|
||||
originUrl = [
|
||||
"https://${cfg.domain}/oauth2/callback"
|
||||
]
|
||||
++ (mapAttrsToList (n: v: "https://${n}/oauth2/callback") cfg.hosts);
|
||||
originLanding = "https://${cfg.domain}/oauth2/sign_in";
|
||||
preferShortUsername = true;
|
||||
claimMaps = {
|
||||
"proxy_group" = {
|
||||
joinType = "array";
|
||||
valuesByGroup = {
|
||||
"proxy_users" = [
|
||||
"proxy_users"
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
scopeMaps."proxy_users" = [
|
||||
"email"
|
||||
"openid"
|
||||
];
|
||||
};
|
||||
};
|
||||
xyno.services.kanidm.templates.oauth2_proxy = {
|
||||
wantedBy = [
|
||||
"oauth2-proxy.service"
|
||||
];
|
||||
text = p: ''
|
||||
OAUTH2_PROXY_CLIENT_ID=${p.clientId}
|
||||
OAUTH2_PROXY_CLIENT_SECRET=${p.basicSecret}
|
||||
OAUTH2_PROXY_COOKIE_SECRET=${p.env "COOKIE_SECRET"}
|
||||
OAUTH2_PROXY_OIDC_ISSUER_URL=https://${kanidmCfg.domain}/oauth2/openid/${p.clientId}
|
||||
'';
|
||||
environmentFiles = [ config.sops.templates.oauth2ProxyEnv.path ];
|
||||
};
|
||||
sops.secrets."oauth2Proxy/cookieSecret" = {
|
||||
sopsFile = ../../../instances/${config.networking.hostName}/secrets/kanidm.yaml;
|
||||
};
|
||||
sops.templates."oauth2ProxyEnv" = {
|
||||
restartUnits = [ "generate-kanidm-template-oauth2_proxy.service" ];
|
||||
content = ''
|
||||
COOKIE_SECRET=${config.sops.placeholder."oauth2Proxy/cookieSecret"}
|
||||
'';
|
||||
};
|
||||
|
||||
xyno.services.monitoring.exporters.oauth2Proxy = "http://${oauth2ProxyInternalHostPortMetrics}";
|
||||
|
||||
systemd.services.oauth2Proxy.after = [ "traefik.service" ];
|
||||
xyno.services.oauth2Proxy = {
|
||||
environmentFiles = [ kanidmCfg.templates.oauth2_proxy.path ];
|
||||
settings = mkMerge [
|
||||
{
|
||||
provider = "oidc";
|
||||
scope = "openid email";
|
||||
oidc_groups_claim = "proxy_group";
|
||||
allowed_groups = [ "proxy_users" ];
|
||||
|
||||
http_address = "${oauth2ProxyInternalHostPort}";
|
||||
https_address = "";
|
||||
whitelist_domains = attrNames cfg.hosts;
|
||||
email_domains = "*";
|
||||
skip_provider_button = true;
|
||||
code_challenge_method = "S256";
|
||||
set_xauthrequest = true;
|
||||
}
|
||||
(mkIf config.xyno.services.monitoring.enable {
|
||||
metrics_address = "http://${oauth2ProxyInternalHostPortMetrics}";
|
||||
|
||||
})
|
||||
];
|
||||
};
|
||||
|
||||
xyno.services.traefik.simpleProxy = mkMerge (
|
||||
[
|
||||
{
|
||||
oauth = {
|
||||
rule = "Host(`${cfg.domain}`) && PathPrefix(`/oauth2`)";
|
||||
internal = "http://${oauth2ProxyInternalHostPort}";
|
||||
middlewares = [ "auth-headers" ];
|
||||
host = cfg.domain;
|
||||
};
|
||||
}
|
||||
]
|
||||
++ (mapAttrsToList (n: v: {
|
||||
"oauth-host-${n}" = {
|
||||
rule = "Host(`${n}`) && PathPrefix(`/oauth2`)";
|
||||
internal = "http://${oauth2ProxyInternalHostPort}";
|
||||
middlewares = [ "auth-headers" ];
|
||||
host = n;
|
||||
};
|
||||
}) cfg.hosts)
|
||||
);
|
||||
services.traefik.dynamicConfigOptions.http.middlewares = mkMerge (
|
||||
(mapAttrsToList (n: v: {
|
||||
"oauth-host-${n}" =
|
||||
let
|
||||
maybeQueryArg =
|
||||
name: value:
|
||||
if name == "middlewares" || value == null then
|
||||
null
|
||||
else
|
||||
"${name}=${lib.concatStringsSep "," (builtins.map lib.escapeURL value)}";
|
||||
allArgs = lib.mapAttrsToList maybeQueryArg v;
|
||||
cleanArgs = builtins.filter (x: x != null) allArgs;
|
||||
cleanArgsStr = lib.concatStringsSep "&" cleanArgs;
|
||||
in
|
||||
{
|
||||
forwardAuth = {
|
||||
address = "https://${cfg.domain}/oauth2/auth?${cleanArgsStr}";
|
||||
authResponseHeaders = [
|
||||
"X-Auth-Request-User"
|
||||
"X-Auth-Request-Groups"
|
||||
"X-Auth-Request-Email"
|
||||
"X-Auth-Request-Preferred-Username"
|
||||
];
|
||||
trustForwardHeader = true;
|
||||
};
|
||||
};
|
||||
}) cfg.hosts)
|
||||
++ [
|
||||
{
|
||||
auth-headers.headers = {
|
||||
frameDeny = true;
|
||||
contentTypeNosniff = true;
|
||||
};
|
||||
oauth-errors.errors = {
|
||||
status = [ "401-403" ];
|
||||
service = config.xyno.services.traefik.simpleProxy.oauth.serviceName;
|
||||
query = "/oauth2/sign_in?rd={url}";
|
||||
};
|
||||
}
|
||||
]
|
||||
);
|
||||
};
|
||||
}
|
||||
|
|
@ -12,7 +12,9 @@ in
|
|||
config = lib.mkIf cfg.enable {
|
||||
services.postgresql = {
|
||||
enable = true;
|
||||
package = pkgs.postgresql_17_jit;
|
||||
package = pkgs.postgresql_18;
|
||||
enableJIT = true;
|
||||
extensions = ps: with ps; [ timescaledb-apache ];
|
||||
identMap = ''
|
||||
# ArbitraryMapName systemUser DBUser
|
||||
superuser_map root postgres
|
||||
|
|
@ -26,7 +28,7 @@ in
|
|||
};
|
||||
xyno.services.monitoring.exporters.postgres = config.services.prometheus.exporters.postgres.port;
|
||||
|
||||
xyno.impermanence.extraDirectories = [ "/var/lib/postgresql" ];
|
||||
xyno.impermanence.directories = [ "/var/lib/postgresql" ];
|
||||
|
||||
services.borgmatic.settings.postgresql_databases = [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -5,61 +5,82 @@
|
|||
...
|
||||
}:
|
||||
let
|
||||
inherit (lib)
|
||||
mapAttrsToList
|
||||
mkMerge
|
||||
splitString
|
||||
concatStringsSep
|
||||
mkIf
|
||||
mkOption
|
||||
mkEnableOption
|
||||
;
|
||||
inherit (lib.types)
|
||||
str
|
||||
bool
|
||||
nullOr
|
||||
anything
|
||||
attrsOf
|
||||
submodule
|
||||
listOf
|
||||
;
|
||||
cfg = config.xyno.services.traefik;
|
||||
simpleProxyOpts = lib.mapAttrsToList (
|
||||
simpleProxyOpts = mapAttrsToList (
|
||||
n: v:
|
||||
let
|
||||
router = "simpleproxy-${n}-router";
|
||||
service = "simpleproxy-${n}-service";
|
||||
spl = lib.splitString "." v.host;
|
||||
certDomain =
|
||||
if (builtins.length spl) > 2 then lib.concatStringsSep "." (builtins.tail spl) else spl;
|
||||
router = v.routerName;
|
||||
service = v.serviceName;
|
||||
spl = splitString "." v.host;
|
||||
certDomain = if (builtins.length spl) > 2 then concatStringsSep "." (builtins.tail spl) else spl;
|
||||
in
|
||||
{
|
||||
routers."${router}-robotstxt" = {
|
||||
service = "robotstxt";
|
||||
rule = "Host(`${v.host}`) && Path(`/robots.txt`)";
|
||||
tls.certResolver = "letsencrypt";
|
||||
tls.domains = [
|
||||
{
|
||||
main = certDomain;
|
||||
sans = [ "*.${certDomain}" ];
|
||||
}
|
||||
];
|
||||
|
||||
};
|
||||
routers.${router} = {
|
||||
inherit service;
|
||||
rule = "Host(`${v.host}`)";
|
||||
tls.certResolver = "letsencrypt";
|
||||
tls.domains = [
|
||||
{
|
||||
main = certDomain;
|
||||
sans = [ "*.${certDomain}" ];
|
||||
}
|
||||
];
|
||||
};
|
||||
services.${service} = {
|
||||
loadBalancer.servers = [
|
||||
{ url = v.internal; }
|
||||
];
|
||||
loadBalancer.serverTransport = lib.mkIf (v.transport != null) v.transport;
|
||||
};
|
||||
services.robotstxt = {
|
||||
loadBalancer.servers = [
|
||||
{ url = "http://127.0.0.2:8080"; }
|
||||
];
|
||||
};
|
||||
}
|
||||
mkMerge [
|
||||
(mkIf v.robotProtection {
|
||||
routers."${router}-robotstxt" = {
|
||||
service = "robotstxt";
|
||||
rule = "Host(`${v.host}`) && Path(`/robots.txt`)";
|
||||
tls.certResolver = "letsencrypt";
|
||||
tls.domains = [
|
||||
{
|
||||
main = certDomain;
|
||||
sans = [ "*.${certDomain}" ];
|
||||
}
|
||||
];
|
||||
};
|
||||
services.robotstxt = {
|
||||
loadBalancer.servers = [
|
||||
{ url = "http://127.0.0.2:8080"; }
|
||||
];
|
||||
};
|
||||
})
|
||||
{
|
||||
routers.${router} = {
|
||||
inherit service;
|
||||
inherit (v) middlewares;
|
||||
rule = if v.rule != null then v.rule else "Host(`${v.host}`)";
|
||||
tls.certResolver = "letsencrypt";
|
||||
tls.domains = [
|
||||
{
|
||||
main = certDomain;
|
||||
sans = [ "*.${certDomain}" ];
|
||||
}
|
||||
];
|
||||
};
|
||||
services.${service} = {
|
||||
loadBalancer.servers = [
|
||||
{ url = v.internal; }
|
||||
];
|
||||
loadBalancer.serversTransport = mkIf (v.transport != null) v.transport;
|
||||
};
|
||||
}
|
||||
]
|
||||
) cfg.simpleProxy;
|
||||
in
|
||||
{
|
||||
options.xyno.services.traefik.enable = lib.mkEnableOption "enables traefik";
|
||||
options.xyno.services.traefik.noBots = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
options.xyno.services.traefik.enable = mkEnableOption "enables traefik";
|
||||
options.xyno.services.traefik.noBots = mkOption {
|
||||
type = bool;
|
||||
default = true;
|
||||
};
|
||||
options.xyno.services.traefik.simpleProxy = lib.mkOption {
|
||||
options.xyno.services.traefik.simpleProxy = mkOption {
|
||||
example = {
|
||||
"example" = {
|
||||
host = "example.org";
|
||||
|
|
@ -68,38 +89,63 @@ in
|
|||
};
|
||||
};
|
||||
default = { };
|
||||
type = lib.types.attrsOf (
|
||||
lib.types.submodule {
|
||||
options = {
|
||||
middlewares = lib.mkOption {
|
||||
type = lib.types.nullOr (lib.types.listOf lib.types.str);
|
||||
};
|
||||
internal = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
};
|
||||
host = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
};
|
||||
transport = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.anything;
|
||||
default = null;
|
||||
};
|
||||
type = attrsOf (
|
||||
submodule (
|
||||
{ config, name,... }:
|
||||
{
|
||||
options = {
|
||||
middlewares = mkOption {
|
||||
type = listOf str;
|
||||
default = [];
|
||||
|
||||
};
|
||||
}
|
||||
};
|
||||
internal = mkOption {
|
||||
type = str;
|
||||
description = "where to proxy to";
|
||||
};
|
||||
host = mkOption {
|
||||
type = str;
|
||||
description = "used for the route and tls";
|
||||
};
|
||||
routerName = mkOption {
|
||||
type = str;
|
||||
default = "simpleproxy-${name}-router";
|
||||
};
|
||||
serviceName = mkOption {
|
||||
type = str;
|
||||
default = "simpleproxy-${name}-service";
|
||||
};
|
||||
robotProtection = mkOption {
|
||||
type = bool;
|
||||
default = true;
|
||||
description = "robots.txt and (soon) iocane";
|
||||
};
|
||||
rule = mkOption {
|
||||
type = str;
|
||||
default = "Host(`${config.host}`)";
|
||||
description = "overrides the Host(`\${host}`) rule with something custom if set";
|
||||
};
|
||||
transport = mkOption {
|
||||
type = nullOr anything;
|
||||
default = null;
|
||||
};
|
||||
|
||||
};
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
};
|
||||
config = lib.mkIf cfg.enable {
|
||||
config = mkIf cfg.enable {
|
||||
services.nginx = {
|
||||
enable = lib.mkIf cfg.noBots true;
|
||||
defaultListen = lib.mkIf cfg.noBots [
|
||||
enable = mkIf cfg.noBots true;
|
||||
defaultListen = mkIf cfg.noBots [
|
||||
{
|
||||
addr = "127.0.0.2";
|
||||
port = 8080;
|
||||
}
|
||||
];
|
||||
virtualHosts._.default = true;
|
||||
virtualHosts._.default = true;
|
||||
virtualHosts._.locations."/".root = pkgs.writeTextFile {
|
||||
name = "robots.txt";
|
||||
destination = "/robots.txt";
|
||||
|
|
@ -115,7 +161,8 @@ in
|
|||
config.sops.templates."traefik.env".path
|
||||
];
|
||||
staticConfigOptions = {
|
||||
metrics = lib.mkIf config.xyno.services.monitoring.enable {
|
||||
accessLog = {};
|
||||
metrics = mkIf config.xyno.services.monitoring.enable {
|
||||
otlp.http.endpoint = "http://localhost:8429/v1/metrics";
|
||||
};
|
||||
entryponits.web = {
|
||||
|
|
@ -137,13 +184,16 @@ in
|
|||
email = "ssl@xyno.systems";
|
||||
caServer = "https://acme-v02.api.letsencrypt.org/directory";
|
||||
dnsChallenge = {
|
||||
resolvers = [ "8.8.8.8" "1.1.1.1" ];
|
||||
resolvers = [
|
||||
"8.8.8.8"
|
||||
"1.1.1.1"
|
||||
];
|
||||
provider = "desec";
|
||||
};
|
||||
};
|
||||
};
|
||||
dynamicConfigOptions = {
|
||||
http = lib.mkMerge simpleProxyOpts;
|
||||
http = mkMerge simpleProxyOpts;
|
||||
# tls.options.default = {
|
||||
# # mozilla modern
|
||||
# minVersion = "VersionTLS13";
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue