feat: z2m!
This commit is contained in:
parent
f923a0e25a
commit
3c067ad506
8 changed files with 338 additions and 208 deletions
|
@ -14,7 +14,6 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
mySystem.system.systemd.pushover-alerts.enable = false;
|
mySystem.system.systemd.pushover-alerts.enable = false;
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
redlib.enable = true;
|
redlib.enable = true;
|
||||||
|
|
||||||
mosquitto.enable = true;
|
mosquitto.enable = true;
|
||||||
|
zigbee2mqtt.enable = true;
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -70,12 +70,6 @@ in
|
||||||
};
|
};
|
||||||
environmentFiles = [ config.sops.secrets."services/${app}/env".path ];
|
environmentFiles = [ config.sops.secrets."services/${app}/env".path ];
|
||||||
ports = [ (builtins.toString port) ]; # expose port
|
ports = [ (builtins.toString port) ]; # expose port
|
||||||
labels = lib.myLib.mkTraefikLabels {
|
|
||||||
name = app;
|
|
||||||
domain = config.networking.domain;
|
|
||||||
|
|
||||||
inherit port;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
networking.firewall = mkIf cfg.openFirewall {
|
networking.firewall = mkIf cfg.openFirewall {
|
||||||
|
|
||||||
|
|
|
@ -16,5 +16,6 @@
|
||||||
./powerdns
|
./powerdns
|
||||||
./adguardhome
|
./adguardhome
|
||||||
./mosquitto
|
./mosquitto
|
||||||
|
./zigbee2mqtt
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,8 @@ in
|
||||||
|
|
||||||
sops.secrets."services/mosquitto/mq/hashedPassword" = {
|
sops.secrets."services/mosquitto/mq/hashedPassword" = {
|
||||||
sopsFile = ./secrets.sops.yaml;
|
sopsFile = ./secrets.sops.yaml;
|
||||||
owner = config.users.users.mosquitto.name;
|
owner = "mosquitto";
|
||||||
|
group = "mosquitto";
|
||||||
restartUnits = [ "${app}.service" ];
|
restartUnits = [ "${app}.service" ];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
services:
|
services:
|
||||||
mosquitto:
|
mosquitto:
|
||||||
mq:
|
mq:
|
||||||
hashedPassword: ENC[AES256_GCM,data:l6QVTtfZJhsMfKoN/pIuKevjq6avIroUMSJQpj/53Lhuw/Okw2E9o1QBECBYvNUoU/367rCR82TBmPF5jguunWLI15bxnKxBvcPda33SlYwPGuiXDaALfk0WAPs11mpwvpgNNiVPOD5gDCW7YSNG8w==,iv:VF9Cm8Yp7SZY/CH5V6aLTGWb0CA4N50Kl7RPJJ/aKBc=,tag:dq9HwYCakSSel3cv/t3BjQ==,type:str]
|
hashedPassword: ENC[AES256_GCM,data:FI2KLDYBW+HCXbOfmdyRYEwI8IeEX2iNWAiyGyn6FE2kkP1K1GETLbissBds+6DAPgbBULhxh8PZ9nkOCtR9QGKLkImxgMU1o8Zmwc6UxfkmFWvEDyt0/3g5gEVoO2rsLx4GMp4qO6Wbz0QCxJWJwQ==,iv:Pt9g/c3A1aChcgxQMSa76f1/c7uq8ctf9CDTFKNSvcs=,tag:zSS9heWyjvwFwKoEmYo+GA==,type:str]
|
||||||
|
plainPassword.yaml: ENC[AES256_GCM,data:z+/SQE+PfsIoDekjf5D6f6nkxsfiNmcym4YSVdIl,iv:heh5N8HazUUP251llJLVGdka+65Ofjm4by1kug5uKYI=,tag:NS5K47rZRLH6OzyQopB3+A==,type:str]
|
||||||
sops:
|
sops:
|
||||||
kms: []
|
kms: []
|
||||||
gcp_kms: []
|
gcp_kms: []
|
||||||
|
@ -11,68 +12,68 @@ sops:
|
||||||
- recipient: age1lj5vmr02qkudvv2xedfj5tq8x93gllgpr6tzylwdlt7lud4tfv5qfqsd5u
|
- recipient: age1lj5vmr02qkudvv2xedfj5tq8x93gllgpr6tzylwdlt7lud4tfv5qfqsd5u
|
||||||
enc: |
|
enc: |
|
||||||
-----BEGIN AGE ENCRYPTED FILE-----
|
-----BEGIN AGE ENCRYPTED FILE-----
|
||||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBFVlVjV3BBQjJHT1ZOVm9n
|
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBjNmJPbGFaRXkrYnh6RHR4
|
||||||
RGhhOGcxanhNWEIxTTBUMU9DcEd3Tjc1c25VCjZVOXhVajVhVzR4WWlEbTQ5amFD
|
dHBWNWs0RDB1UnFycXdoWmFFYkNGcHh4YUZjCm9LYnZIU1dvNzVTNHp0NjBEMTE2
|
||||||
WWN4bXJueVBrSHBocU93MDB5ZDdjT0EKLS0tIFhXY2xNZnVLYnIyYmxTSXU3Q3g4
|
MHpOdVh5aVR3c2o5V21LU1ZDWnpXdFEKLS0tIDB4emRQRGVVYzFYQ2JsakVIeFhn
|
||||||
dElVV3ZsNFZZM083Tm10dVJJeDlkTWMK3/QJ1Gni+zj7J7gc0x3xL35rfBr6UNVa
|
QlFEYjBSVjVKUFVEV3gwK2NZaW1XSGMKHBPiLSd7Ixs68xMcpOJzw2Vu4GbKAglY
|
||||||
4ii+q0pHpMBTMb0S1nGbazi3wb1I5KxnINzS6mFSWXkMFU63l3b2YA==
|
1yAcQgIRvFxCV/uz4BwAFvyCtYYsUD4GhEAFp/wwq6W1hTEAseV0RA==
|
||||||
-----END AGE ENCRYPTED FILE-----
|
-----END AGE ENCRYPTED FILE-----
|
||||||
- recipient: age17edew3aahg3t5nte5g0a505sn96vnj8g8gqse8q06ccrrn2n3uysyshu2c
|
- recipient: age17edew3aahg3t5nte5g0a505sn96vnj8g8gqse8q06ccrrn2n3uysyshu2c
|
||||||
enc: |
|
enc: |
|
||||||
-----BEGIN AGE ENCRYPTED FILE-----
|
-----BEGIN AGE ENCRYPTED FILE-----
|
||||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBPejZ3NVMrZnRtMkNQV3dp
|
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBGRGE0OWZaR0ZhY2piMkxY
|
||||||
ejJraDFpcG5mNEs5WE5YMGJKTEx5OGs4ZkJNCk05NDA4NTVxTFQ4UU5Mck9hYlZS
|
cG1HRFIrWjJFeG8vbzhPWW51cWVvN2FXV2hvCjhLNmVwRkRWQm54N3FPczFudGVB
|
||||||
Skx0L0xDVkxqU0ZROTBBTjQzaHdNSUkKLS0tIHpRQWtub3Bmc29aSjdBeHhKK1pq
|
N096dmFaUktqMDBIRWxlTnVaa2VOcVkKLS0tIEFZSmYweDRqVlpOdUhESXFjbnR0
|
||||||
L0dLRm4wRTZsS0thc3VUSit5cDgxL2MKXGdQz7a9oEoqxNnGCQODcpb4W1RUKcli
|
RXpBU2t0bFlJQW1RSXZ0dzZFT3RXT0UKraC9wurjhf+SiKPewE5L3auOI59kaj/h
|
||||||
josRkGYVeOfRY0+1BKwk5XIbAKMohz+YbTKUKkWDYEXiffSjd7Ae2Q==
|
7nUUnWUQfkebO5wxtmbbmenXK//oY1tRbC/Dp2JPUTQo2wwrXMF/JQ==
|
||||||
-----END AGE ENCRYPTED FILE-----
|
-----END AGE ENCRYPTED FILE-----
|
||||||
- recipient: age1u4tht685sqg6dkmjyer96r93pl425u6353md6fphpd84jh3jwcusvm7mgk
|
- recipient: age1u4tht685sqg6dkmjyer96r93pl425u6353md6fphpd84jh3jwcusvm7mgk
|
||||||
enc: |
|
enc: |
|
||||||
-----BEGIN AGE ENCRYPTED FILE-----
|
-----BEGIN AGE ENCRYPTED FILE-----
|
||||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBtNWhPRkt3M1NJajBlOCty
|
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBEVjdTRkdDMElXV0pLL3Fv
|
||||||
RlEwQ1ZCQXhNQnIxbzVwcHpJUE11U2ZvcmxnClYyZ3dqSC91K2I2TmhSMEVIUWJy
|
MFpxaStjaHNPSmY1RnFUbUhVS09hUEZYYVFVCk4yUEsxV2FvYm5ybVdGS0pmVW5m
|
||||||
N1dMbjdsNjVUdVM3Uk9BeElRaUhzRXcKLS0tIGxhS1pTUEt3aU9nckNHMnQ2Q0xw
|
b1FYb3RxYXFhVVhjNms1bjBtVEYyMm8KLS0tIDk2Uy9xT3VZdGdSY1Rjc3l5OGE4
|
||||||
WjdCRTRMdzVMekk1YXZBejdxdWF4UEkK7SPmOHbup24/IhITZzOnl7YSSYXl/ShW
|
ZzJvWTdDRlFNMmliUGZZbnRCc0UwRHcKdJllfqPlYBNf/nWkT5E1Is1moIFvN6lc
|
||||||
gOqyzkXxe079LHOadm/nqn+XVgnYdTeGf4budabp1TxUaMPsxgjG8g==
|
XVGQ9tzH1tpZC9PwmC1nL08fmuzwI5k9zqL2D+eG+vH7yjBLRFzxVg==
|
||||||
-----END AGE ENCRYPTED FILE-----
|
-----END AGE ENCRYPTED FILE-----
|
||||||
- recipient: age1cp6vegrmqfkuj8nmt2u3z0sur7n0f7e9x9zmdv4zygp8j2pnucpsdkgagc
|
- recipient: age1cp6vegrmqfkuj8nmt2u3z0sur7n0f7e9x9zmdv4zygp8j2pnucpsdkgagc
|
||||||
enc: |
|
enc: |
|
||||||
-----BEGIN AGE ENCRYPTED FILE-----
|
-----BEGIN AGE ENCRYPTED FILE-----
|
||||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBkcFpSOE16bVlKalc4eEJn
|
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAzOUJOTFJFSHp1QTdKVmZk
|
||||||
cVdwdWJwV3grR0dUUkZ2V1kvVyt5UVNmQVNrCnJLakF1aWhKaGYyYnR3Zlh0dUxI
|
UVZhVEpqQzVTOTZHOXBYbDJUVjBpL2ErV2tJCm1jOUVmVE8wc3ZLSDZJRVkxQkNU
|
||||||
WStFbmVjWEM3QkU0NmlodjY0OXJLOWsKLS0tIFRPOC96M3IxcXdsaDB5RnJJb1dZ
|
eEw2RVNpVzJFcTlPbnF1Q2g0RVo5OUEKLS0tIFpvcU11RGVNR0dNQWc1aGJFd1lm
|
||||||
a3hpczhWUDVQM3JiVU5ja3ZDMVRGb3MKowyjuHf0SO6zJ4+dnnuxWUn17uTDh0Iy
|
Ym1kellUNjRsTTdQZTViZnBkRllqbWsKWFwR8WeIxJunlgzT3GpYkIdFRLJZlhm4
|
||||||
4x0cAKbwuSLlna3miG0Vxvfy/EehDuiZFW3c3EM7ITdayodM4lQNwQ==
|
Vr4N5CMnNXJYWRiNJDrHDKvVw6EeUUhyJ+7aJ9UAfR0YfX47yIlW5A==
|
||||||
-----END AGE ENCRYPTED FILE-----
|
-----END AGE ENCRYPTED FILE-----
|
||||||
- recipient: age1ekt5xz7u2xgdzgsrffhd9x22n80cn4thxd8zxjy2ey5vq3ca7gnqz25g5r
|
- recipient: age1ekt5xz7u2xgdzgsrffhd9x22n80cn4thxd8zxjy2ey5vq3ca7gnqz25g5r
|
||||||
enc: |
|
enc: |
|
||||||
-----BEGIN AGE ENCRYPTED FILE-----
|
-----BEGIN AGE ENCRYPTED FILE-----
|
||||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBXMy9XTFEvMExXQUJqbnlL
|
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBnWUpaOUVnRS9Va211UXl0
|
||||||
YTdLd0c4bnVkOENtVGlocnRVQmhocHRiTlNnCm5Cc08yK3lLTkU0ZkNzQUViOC9q
|
dUFmOVlmR2d1REVNRXJKMFV1OTVsSDZGRldvCk5CcGpWZHFBYmtsbVRjWW1QejNJ
|
||||||
a1JGRFlaVnJyMVRod2NKWHJ6VVlSMzQKLS0tIFI4Z01hKzN5Y1VZKzIwb1VvVnZz
|
Y0FPSVJ1UlhhcVhRaTVXMERyRURIRjAKLS0tIDloZ2J0anNqSEZmUXg4eDFyTVZ0
|
||||||
bXFlZ1hCV3ZGOXJBMDY3M1RzOVZzbWMKlCRZZ+cKYyxd5VusNklUqJkVGp4/A7/U
|
WXAvTmRpUjRKMnJlZmV0SEEwZndtNkEK99oVyOIlfKP6zHnuS1LKGORuOLfX3vAU
|
||||||
TBmsn2lHgLi+mnoCN6YLNcLz0gxG27VFMAQSaDECMW6HP0Yy2soAKA==
|
Gw7IHXRUSpZhElOSK0jc9F2O6IEGYpfu5PYC4m8uojhRXsG6W/XTXA==
|
||||||
-----END AGE ENCRYPTED FILE-----
|
-----END AGE ENCRYPTED FILE-----
|
||||||
- recipient: age1jpeh4s553taxkyxhzlshzqjfrtvmmp5lw0hmpgn3mdnmgzku332qe082dl
|
- recipient: age1jpeh4s553taxkyxhzlshzqjfrtvmmp5lw0hmpgn3mdnmgzku332qe082dl
|
||||||
enc: |
|
enc: |
|
||||||
-----BEGIN AGE ENCRYPTED FILE-----
|
-----BEGIN AGE ENCRYPTED FILE-----
|
||||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBZSnZKNjRGamJGZ2gxbnBR
|
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSArUVZScTVpWjZvUzlFeDVQ
|
||||||
S2t5TkpTcll6QVpmclhrWEtGODQrUkVyVVRjCmgwcWpBTWZhMFc4NC9MVDV4UVox
|
RjRreTBPTEF3bXZ1Sk5sWmgzUURxcU5talFzClFRSjFFUEtQMis4dkNLRFFaaHlq
|
||||||
WVY1WjMxajVsNG9YRTJOYktrSTVZRUkKLS0tIE01dkZXRTFmM3lWN0RqLzJWQVF0
|
QXdhQWxEMXdHSGgzSXlqZm4xbEFVaGMKLS0tIG9OOHUwZWI3SXJ2SWZvdS9EVzV5
|
||||||
aSt3SUE2N3BJeFJUVnR6K2UzUDl0a28K2WcNLOYihCBoL5KMTQWvtbgqtTosA3Y6
|
aVpWNmk5b1owbjJHSWtnOHRJWmhEbGMKT4VdLG/8qX+KWO6vQ2TsrT1+w4XgDani
|
||||||
s+2XzBnz/RonDVe2Wh+trkwfKfiwyEvhcyBHQIjU6g4eWovVDMq7Vw==
|
KOAS/DimV22EjmHljs9ByWdqkVw0KIBfp2oXo9m0Jqn0H1M2yEMozg==
|
||||||
-----END AGE ENCRYPTED FILE-----
|
-----END AGE ENCRYPTED FILE-----
|
||||||
- recipient: age1j2r8mypw44uvqhfs53424h6fu2rkr5m7asl7rl3zn3xzva9m3dcqpa97gw
|
- recipient: age1j2r8mypw44uvqhfs53424h6fu2rkr5m7asl7rl3zn3xzva9m3dcqpa97gw
|
||||||
enc: |
|
enc: |
|
||||||
-----BEGIN AGE ENCRYPTED FILE-----
|
-----BEGIN AGE ENCRYPTED FILE-----
|
||||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBkaEVuZWRaeExoaStDQW14
|
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBWNzZiS1pVTXMxQW9UUldr
|
||||||
SFdwM1VxTFQ4dGdNRUdQOUF1djVnOUQ5M3hFCmc4NWxtTDNRcjlmVGxLSW45c0lm
|
dFNHUDhxV1lnOFNaK2J6SEY3WUtId0FLSTNjCkJhUm1sVnlJMFk5Wm9lNGdMYnZv
|
||||||
ZzRURjZmTTFibk43Q0RiZkk1NmdOL2sKLS0tIDZ0L3U2M2JlamJwTVUwRFVHR1FM
|
eVR6MGNVYjBSNENqU1BJWituMnJJeFUKLS0tIEk0ZUVETHRmSmJjT2NDMGNrajlZ
|
||||||
aUsvNG95K0lxdUFjRUpXdHhDZjIyV0EKEYU4IkFdNXqWHD6+ukmcOkiB7UW5Fn1w
|
NUMxdEhvQnRES2hwck5jeEw3bnprZ00KUnkLNK+hmCihLwPiWt3NHjASuQwgBOlf
|
||||||
M009nesLsOp1j1sVEStgPzPJLnw/j2OZQgkiMSzeLE1CrGLaOLdpCw==
|
AsW8BkUjjQY/ABR3X6sNSI8uXQt+8BHP14U4cO8jwggcyE2W1Pq03A==
|
||||||
-----END AGE ENCRYPTED FILE-----
|
-----END AGE ENCRYPTED FILE-----
|
||||||
lastmodified: "2024-04-25T03:13:36Z"
|
lastmodified: "2024-04-25T05:21:30Z"
|
||||||
mac: ENC[AES256_GCM,data:YC1lPTCSUZPgZte0WHGbqh1k3vAfcvVNyxR7+daPH5xwrXyZa/jTIY5U/UuD+nVCr2YFB89QKGko6c76sqoDxhMRf/FDZt0YSa+RaOJO0LNinRBokV2sm0oYxeWoKEUB1B5cuXVfBqqsgw6qQqvIuysXGk0A8vjXUT/btZSd2/A=,iv:Gu3X3xxZ5dmb2Y6Ve/7xznmS0/x5uU9iIDRiOE/DR9Y=,tag:1l7GtZTxBFLvV4JzRVt4Ow==,type:str]
|
mac: ENC[AES256_GCM,data:aN2YsPhDMl8vvLgi98iRCl5f7llJ8VTt7y1vh7liBAwG6hW1vZeetqSxvWiVDugozjsbK6n44AUDjhnfwo8EXp8iWQmJDXuS1PoEph4C18oo4Eu8n9ZpLQFGSKRMYXuetwrzOkn42tMYadYbwLPIandKqaTGUD4FcoqZtGxaH3c=,iv:Wfb1r8JNO74KjBWTIGwW2bXTVv3AIpj5KW9FXYrDm7c=,tag:FEnXv1S0J3XaxZ6TQz0bhQ==,type:str]
|
||||||
pgp: []
|
pgp: []
|
||||||
unencrypted_suffix: _unencrypted
|
unencrypted_suffix: _unencrypted
|
||||||
version: 3.8.1
|
version: 3.8.1
|
||||||
|
|
|
@ -7,103 +7,10 @@
|
||||||
with lib;
|
with lib;
|
||||||
let
|
let
|
||||||
cfg = config.mySystem.services.traefik;
|
cfg = config.mySystem.services.traefik;
|
||||||
routersFile = builtins.toFile "routers.yaml" (builtins.toJSON cfg.routers);
|
|
||||||
|
|
||||||
in
|
# core dynamic options to define middleware
|
||||||
{
|
# sso etc
|
||||||
options.mySystem.services.traefik = {
|
dynamicOptions = [{
|
||||||
enable = mkEnableOption "Traefik reverse proxy";
|
|
||||||
routers = lib.mkOption {
|
|
||||||
type = lib.types.listOf lib.types.attrs;
|
|
||||||
description = "Routers to add to traefik";
|
|
||||||
default = [ ];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
config = mkIf cfg.enable {
|
|
||||||
|
|
||||||
networking.firewall.allowedTCPPorts = [ 80 443 ];
|
|
||||||
|
|
||||||
sops.secrets."system/services/traefik/apiTokenFile".sopsFile = ./secrets.sops.yaml;
|
|
||||||
|
|
||||||
# Restart when secret changes
|
|
||||||
sops.secrets."system/services/traefik/apiTokenFile".restartUnits = [ "traefik.service" ];
|
|
||||||
|
|
||||||
systemd.services.traefik = {
|
|
||||||
serviceConfig.EnvironmentFile = [
|
|
||||||
config.sops.secrets."system/services/traefik/apiTokenFile".path
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
# add user to group to view files/storage
|
|
||||||
users.users.truxnell.extraGroups = [ "traefik" ];
|
|
||||||
|
|
||||||
services.traefik = {
|
|
||||||
# TODO refactor into subfiles
|
|
||||||
enable = true;
|
|
||||||
group = "podman"; # podman backend, required to access socket
|
|
||||||
|
|
||||||
dataDir = "${config.mySystem.persistentFolder}/traefik";
|
|
||||||
# Required so traefik is permitted to watch docker events
|
|
||||||
# group = "docker";
|
|
||||||
|
|
||||||
staticConfigOptions = {
|
|
||||||
|
|
||||||
global = {
|
|
||||||
checkNewVersion = false;
|
|
||||||
sendAnonymousUsage = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
api.dashboard = true;
|
|
||||||
log.level = "DEBUG";
|
|
||||||
|
|
||||||
# Allow backend services to have self-signed certs
|
|
||||||
serversTransport.insecureSkipVerify = true;
|
|
||||||
|
|
||||||
providers = {
|
|
||||||
docker = {
|
|
||||||
endpoint = "unix:///var/run/podman/podman.sock";
|
|
||||||
exposedByDefault = false;
|
|
||||||
defaultRule = "Host(`{{ normalize .Name }}.${config.mySystem.domain}`)";
|
|
||||||
# network = "proxy";
|
|
||||||
};
|
|
||||||
file = {
|
|
||||||
filename = routersFile;
|
|
||||||
watch = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
# Listen on port 80 and redirect to port 443
|
|
||||||
entryPoints.web = {
|
|
||||||
address = ":80";
|
|
||||||
http.redirections.entrypoint.to = "websecure";
|
|
||||||
};
|
|
||||||
|
|
||||||
# Run everything SSL
|
|
||||||
entryPoints.websecure = {
|
|
||||||
address = ":443";
|
|
||||||
http = {
|
|
||||||
tls = {
|
|
||||||
certresolver = "letsencrypt";
|
|
||||||
domains.main = "${config.mySystem.domain}";
|
|
||||||
domains.sans = "*.${config.mySystem.domain}";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
http3 = { };
|
|
||||||
};
|
|
||||||
|
|
||||||
certificatesResolvers.letsencrypt.acme = {
|
|
||||||
dnsChallenge.provider = "cloudflare";
|
|
||||||
dnsChallenge.resolvers = [ "1.1.1.1:53" ];
|
|
||||||
keyType = "EC256";
|
|
||||||
storage = "${config.services.traefik.dataDir}/acme.json";
|
|
||||||
};
|
|
||||||
# };
|
|
||||||
};
|
|
||||||
# Dynamic configuration
|
|
||||||
dynamicConfigOptions = {
|
|
||||||
|
|
||||||
http.middlewares = {
|
http.middlewares = {
|
||||||
# Whitelist local network and VPN addresses
|
# Whitelist local network and VPN addresses
|
||||||
|
@ -174,9 +81,122 @@ in
|
||||||
service = "api@internal";
|
service = "api@internal";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
}];
|
||||||
|
|
||||||
|
# Combine the above 'core 'options with the (dynamicOptions)
|
||||||
|
# list of ingress routers for each serfie defined in various
|
||||||
|
# modules (cfg.routers)
|
||||||
|
# this folds the list and iterates each element to add them together
|
||||||
|
dynamicOptionsAttrset = lib.foldl' (acc: elem: lib.recursiveUpdate acc elem) { } (dynamicOptions ++ cfg.routers);
|
||||||
|
routersFile = builtins.toFile "routers.yaml" (builtins.toJSON dynamicOptionsAttrset);
|
||||||
|
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.mySystem.services.traefik = {
|
||||||
|
enable = mkEnableOption "Traefik reverse proxy";
|
||||||
|
routers = lib.mkOption {
|
||||||
|
type = lib.types.listOf lib.types.attrs;
|
||||||
|
description = "Routers to add to traefik";
|
||||||
|
default = [ ];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
config = mkIf cfg.enable
|
||||||
|
{
|
||||||
|
|
||||||
|
# put the dynamic configs in a file
|
||||||
|
# i put this in a file instead of piping directly into
|
||||||
|
# the traefik module, so that if i update the file
|
||||||
|
# with a new router nix doesnt restart traefik, it just updates
|
||||||
|
# the etc file and traefik picks up the changes.
|
||||||
|
environment.etc."traefik/config.yaml".source = routersFile;
|
||||||
|
|
||||||
|
networking.firewall.allowedTCPPorts = [ 80 443 ];
|
||||||
|
|
||||||
|
sops.secrets."system/services/traefik/apiTokenFile".sopsFile = ./secrets.sops.yaml;
|
||||||
|
|
||||||
|
# Restart when secret changes
|
||||||
|
sops.secrets."system/services/traefik/apiTokenFile".restartUnits = [ "traefik.service" ];
|
||||||
|
|
||||||
|
systemd.services.traefik = {
|
||||||
|
serviceConfig.EnvironmentFile = [
|
||||||
|
config.sops.secrets."system/services/traefik/apiTokenFile".path
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
# add user to group to view files/storage
|
||||||
|
users.users.truxnell.extraGroups = [ "traefik" ];
|
||||||
|
|
||||||
|
services.traefik = {
|
||||||
|
# TODO refactor into subfiles
|
||||||
|
enable = true;
|
||||||
|
group = "podman"; # podman backend, required to access socket
|
||||||
|
|
||||||
|
dataDir = "${config.mySystem.persistentFolder}/traefik";
|
||||||
|
# Required so traefik is permitted to watch docker events
|
||||||
|
# group = "docker";
|
||||||
|
|
||||||
|
staticConfigOptions = {
|
||||||
|
|
||||||
|
global = {
|
||||||
|
checkNewVersion = false;
|
||||||
|
sendAnonymousUsage = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
api.dashboard = true;
|
||||||
|
log.level = "DEBUG";
|
||||||
|
|
||||||
|
# Allow backend services to have self-signed certs
|
||||||
|
serversTransport.insecureSkipVerify = true;
|
||||||
|
|
||||||
|
providers = {
|
||||||
|
docker = {
|
||||||
|
endpoint = "unix:///var/run/podman/podman.sock";
|
||||||
|
exposedByDefault = false;
|
||||||
|
defaultRule = "Host(`{{ normalize .Name }}.${config.mySystem.domain}`)";
|
||||||
|
# network = "proxy";
|
||||||
|
};
|
||||||
|
file = {
|
||||||
|
filename = "/etc/traefik/config.yaml";
|
||||||
|
watch = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
# Listen on port 80 and redirect to port 443
|
||||||
|
entryPoints.web = {
|
||||||
|
address = ":80";
|
||||||
|
http.redirections.entrypoint.to = "websecure";
|
||||||
|
};
|
||||||
|
|
||||||
|
# Run everything SSL
|
||||||
|
entryPoints.websecure = {
|
||||||
|
address = ":443";
|
||||||
|
http = {
|
||||||
|
tls = {
|
||||||
|
certresolver = "letsencrypt";
|
||||||
|
domains.main = "${config.mySystem.domain}";
|
||||||
|
domains.sans = "*.${config.mySystem.domain}";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
http3 = { };
|
||||||
|
};
|
||||||
|
|
||||||
|
certificatesResolvers.letsencrypt.acme = {
|
||||||
|
dnsChallenge.provider = "cloudflare";
|
||||||
|
dnsChallenge.resolvers = [ "1.1.1.1:53" ];
|
||||||
|
keyType = "EC256";
|
||||||
|
storage = "${config.services.traefik.dataDir}/acme.json";
|
||||||
|
};
|
||||||
|
# };
|
||||||
|
};
|
||||||
|
# Dynamic configuration
|
||||||
|
# refer the etc file defined above with the build
|
||||||
|
# dynamic options
|
||||||
|
dynamicConfigFile = "/etc/traefik/config.yaml";
|
||||||
|
};
|
||||||
|
|
||||||
mySystem.services.homepage.infrastructure = [
|
mySystem.services.homepage.infrastructure = [
|
||||||
{
|
{
|
||||||
"Traefik ${config.networking.hostName}" = {
|
"Traefik ${config.networking.hostName}" = {
|
||||||
|
|
113
nixos/modules/nixos/services/zigbee2mqtt/default.nix
Normal file
113
nixos/modules/nixos/services/zigbee2mqtt/default.nix
Normal file
|
@ -0,0 +1,113 @@
|
||||||
|
{ lib
|
||||||
|
, config
|
||||||
|
, pkgs
|
||||||
|
, ...
|
||||||
|
}:
|
||||||
|
with lib;
|
||||||
|
let
|
||||||
|
cfg = config.mySystem.services.zigbee2mqtt;
|
||||||
|
persistentFolder = "${config.mySystem.persistentFolder}/nixos/services/${app}/";
|
||||||
|
app = "zigbee2mqtt";
|
||||||
|
user = app;
|
||||||
|
group = app;
|
||||||
|
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.mySystem.services.zigbee2mqtt = {
|
||||||
|
enable = mkEnableOption "zigbee2mqtt";
|
||||||
|
addToHomepage = mkEnableOption "Add ${app} to homepage" // { default = true; };
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
config = mkIf cfg.enable {
|
||||||
|
|
||||||
|
# ensure folder exist and has correct owner/group
|
||||||
|
systemd.tmpfiles.rules = [
|
||||||
|
"d ${persistentFolder} 0750 ${user} ${group} -" #The - disables automatic cleanup, so the file wont be removed after a period
|
||||||
|
];
|
||||||
|
|
||||||
|
sops.secrets."services/mosquitto/mq/plainPassword.yaml" = {
|
||||||
|
sopsFile = ../mosquitto/secrets.sops.yaml;
|
||||||
|
owner = config.users.users.zigbee2mqtt.name;
|
||||||
|
group = config.users.users.zigbee2mqtt.group;
|
||||||
|
restartUnits = [ "${app}.service" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
services.zigbee2mqtt = {
|
||||||
|
enable = true;
|
||||||
|
dataDir = persistentFolder;
|
||||||
|
settings = {
|
||||||
|
advanced.log_level = "warn";
|
||||||
|
homeassistant = true;
|
||||||
|
permit_join = false;
|
||||||
|
include_device_information = true;
|
||||||
|
frontend =
|
||||||
|
{
|
||||||
|
port = 8080;
|
||||||
|
url = "https://${app}.${config.networking.domain}";
|
||||||
|
};
|
||||||
|
client_id = "z2m";
|
||||||
|
serial = {
|
||||||
|
port = "tcp://10.8.30.110:6638";
|
||||||
|
};
|
||||||
|
mqtt = {
|
||||||
|
server = "mqtt://mqtt.trux.dev:1883";
|
||||||
|
user = "mq";
|
||||||
|
password = "!${config.sops.secrets."services/mosquitto/mq/plainPassword.yaml".path} password";
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
users.users.truxnell.extraGroups = [ app ];
|
||||||
|
|
||||||
|
mySystem.services.traefik.routers = [{
|
||||||
|
http.routers.${app} = {
|
||||||
|
rule = "Host(`${app}.${config.mySystem.domain}`)";
|
||||||
|
entrypoints = "websecure";
|
||||||
|
middlewares = "local-ip-only@file";
|
||||||
|
service = "${app}";
|
||||||
|
};
|
||||||
|
http.services.${app} = {
|
||||||
|
loadBalancer = {
|
||||||
|
servers = [{
|
||||||
|
url = "http://localhost:8080";
|
||||||
|
}];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
}];
|
||||||
|
|
||||||
|
|
||||||
|
mySystem.services.homepage.media = mkIf cfg.addToHomepage [
|
||||||
|
{
|
||||||
|
${app} = {
|
||||||
|
icon = "${app}.svg";
|
||||||
|
href = "https://${app}.${config.mySystem.domain}";
|
||||||
|
description = "Zigbee bridge to MQTT";
|
||||||
|
container = "${app}";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
mySystem.services.gatus.monitors = [{
|
||||||
|
|
||||||
|
name = app;
|
||||||
|
group = "services";
|
||||||
|
url = "https://${app}.${config.mySystem.domain}";
|
||||||
|
interval = "1m";
|
||||||
|
conditions = [ "[CONNECTED] == true" "[STATUS] == 200" "[RESPONSE_TIME] < 50" ];
|
||||||
|
}];
|
||||||
|
|
||||||
|
services.restic.backups = config.lib.mySystem.mkRestic
|
||||||
|
{
|
||||||
|
inherit app;
|
||||||
|
user = builtins.toString user;
|
||||||
|
paths = [ persistentFolder ];
|
||||||
|
appFolder = app;
|
||||||
|
inherit persistentFolder;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
Reference in a new issue