tangled
alpha
login
or
join now
wiro.world
/
dotfiles
2
fork
atom
yep, more dotfiles
2
fork
atom
overview
issues
1
pulls
1
pipelines
chore: bump to 25.11
wiro.world
3 months ago
27a6ff3e
6f79a1c8
verified
This commit was signed with the committer's
known signature
.
wiro.world
SSH Key Fingerprint:
SHA256:SmMcWpNAnL+VAgItSawvXgdPVn7f1rsyAuB/5VNclKY=
+236
-1338
30 changed files
expand all
collapse all
unified
split
flake.lock
flake.nix
home-manager
fragments
firefox.nix
git.nix
helix.nix
jujutsu.nix
stylix.nix
sway.nix
tools.nix
profiles
desktop.nix
lib
flake
default.nix
user.nix
modules
home-manager
default.nix
wl-clip-persist.nix
nixos
default.nix
geoclue2.nix
headscale.nix
logiops.nix
nixos
fragments
logiops.nix
security.nix
profiles
laptop.nix
server.nix
pkgs
default.nix
secrets
keys.nix
lldap-user-pass.age
secrets.nix
templates
blank
flake.nix
c
flake.nix
rust
flake.nix
rust-pkg
flake.nix
+90
-96
flake.lock
···
24
24
],
25
25
"nixpkgs": [
26
26
"nixpkgs"
27
27
-
]
27
27
+
],
28
28
+
"systems": "systems"
28
29
},
29
30
"locked": {
30
30
-
"lastModified": 1703089996,
31
31
-
"narHash": "sha256-ipqShkBmHKC9ft1ZAsA6aeKps32k7+XZSPwfxeHLsAU=",
32
32
-
"owner": "ryantm",
31
31
+
"lastModified": 1762618334,
32
32
+
"narHash": "sha256-wyT7Pl6tMFbFrs8Lk/TlEs81N6L+VSybPfiIgzU8lbQ=",
33
33
+
"owner": "mrnossiom",
33
34
"repo": "agenix",
34
34
-
"rev": "564595d0ad4be7277e07fa63b5a991b3c645655d",
35
35
+
"rev": "fcdea223397448d35d9b31f798479227e80183f6",
35
36
"type": "github"
36
37
},
37
38
"original": {
38
38
-
"owner": "ryantm",
39
39
-
"ref": "0.15.0",
39
39
+
"owner": "mrnossiom",
40
40
"repo": "agenix",
41
41
"type": "github"
42
42
}
···
46
46
"fromYaml": "fromYaml"
47
47
},
48
48
"locked": {
49
49
-
"lastModified": 1746562888,
50
50
-
"narHash": "sha256-YgNJQyB5dQiwavdDFBMNKk1wyS77AtdgDk/VtU6wEaI=",
49
49
+
"lastModified": 1755819240,
50
50
+
"narHash": "sha256-qcMhnL7aGAuFuutH4rq9fvAhCpJWVHLcHVZLtPctPlo=",
51
51
"owner": "SenchoPens",
52
52
"repo": "base16.nix",
53
53
-
"rev": "806a1777a5db2a1ef9d5d6f493ef2381047f2b89",
53
53
+
"rev": "75ed5e5e3fce37df22e49125181fa37899c3ccd6",
54
54
"type": "github"
55
55
},
56
56
"original": {
···
79
79
"base16-helix": {
80
80
"flake": false,
81
81
"locked": {
82
82
-
"lastModified": 1748408240,
83
83
-
"narHash": "sha256-9M2b1rMyMzJK0eusea0x3lyh3mu5nMeEDSc4RZkGm+g=",
82
82
+
"lastModified": 1752979451,
83
83
+
"narHash": "sha256-0CQM+FkYy0fOO/sMGhOoNL80ftsAzYCg9VhIrodqusM=",
84
84
"owner": "tinted-theming",
85
85
"repo": "base16-helix",
86
86
-
"rev": "6c711ab1a9db6f51e2f6887cc3345530b33e152e",
86
86
+
"rev": "27cf1e66e50abc622fb76a3019012dc07c678fac",
87
87
"type": "github"
88
88
},
89
89
"original": {
···
132
132
]
133
133
},
134
134
"locked": {
135
135
-
"lastModified": 1673295039,
136
136
-
"narHash": "sha256-AsdYgE8/GPwcelGgrntlijMg4t3hLFJFCRF3tL5WVjA=",
135
135
+
"lastModified": 1744478979,
136
136
+
"narHash": "sha256-dyN+teG9G82G+m+PX/aSAagkC+vUv0SgUw3XkPhQodQ=",
137
137
"owner": "lnl7",
138
138
"repo": "nix-darwin",
139
139
-
"rev": "87b9d090ad39b25b2400029c64825fc2a8868943",
139
139
+
"rev": "43975d782b418ebf4969e9ccba82466728c2851b",
140
140
"type": "github"
141
141
},
142
142
"original": {
···
170
170
"firefox-gnome-theme": {
171
171
"flake": false,
172
172
"locked": {
173
173
-
"lastModified": 1748383148,
174
174
-
"narHash": "sha256-pGvD/RGuuPf/4oogsfeRaeMm6ipUIznI2QSILKjKzeA=",
173
173
+
"lastModified": 1758112371,
174
174
+
"narHash": "sha256-lizRM2pj6PHrR25yimjyFn04OS4wcdbc38DCdBVa2rk=",
175
175
"owner": "rafaelmardojai",
176
176
"repo": "firefox-gnome-theme",
177
177
-
"rev": "4eb2714fbed2b80e234312611a947d6cb7d70caf",
177
177
+
"rev": "0909cfe4a2af8d358ad13b20246a350e14c2473d",
178
178
"type": "github"
179
179
},
180
180
"original": {
···
242
242
]
243
243
},
244
244
"locked": {
245
245
-
"lastModified": 1749398372,
246
246
-
"narHash": "sha256-tYBdgS56eXYaWVW3fsnPQ/nFlgWi/Z2Ymhyu21zVM98=",
245
245
+
"lastModified": 1756770412,
246
246
+
"narHash": "sha256-+uWLQZccFHwqpGqr2Yt5VsW/PbeJVTn9Dk6SHWhNRPw=",
247
247
"owner": "hercules-ci",
248
248
"repo": "flake-parts",
249
249
-
"rev": "9305fe4e5c2a6fcf5ba6a3ff155720fbe4076569",
249
249
+
"rev": "4524271976b625a4a605beefd893f270620fd751",
250
250
"type": "github"
251
251
},
252
252
"original": {
···
257
257
},
258
258
"flake-utils": {
259
259
"inputs": {
260
260
-
"systems": "systems_2"
260
260
+
"systems": "systems_3"
261
261
},
262
262
"locked": {
263
263
"lastModified": 1694529238,
···
399
399
"gnome-shell": {
400
400
"flake": false,
401
401
"locked": {
402
402
-
"lastModified": 1744584021,
403
403
-
"narHash": "sha256-0RJ4mJzf+klKF4Fuoc8VN8dpQQtZnKksFmR2jhWE1Ew=",
402
402
+
"host": "gitlab.gnome.org",
403
403
+
"lastModified": 1762869044,
404
404
+
"narHash": "sha256-nwm/GJ2Syigf7VccLAZ66mFC8mZJFqpJmIxSGKl7+Ds=",
404
405
"owner": "GNOME",
405
406
"repo": "gnome-shell",
406
406
-
"rev": "52c517c8f6c199a1d6f5118fae500ef69ea845ae",
407
407
-
"type": "github"
407
407
+
"rev": "680e3d195a92203f28d4bf8c6e8bb537cc3ed4ad",
408
408
+
"type": "gitlab"
408
409
},
409
410
"original": {
411
411
+
"host": "gitlab.gnome.org",
410
412
"owner": "GNOME",
411
411
-
"ref": "48.1",
413
413
+
"ref": "gnome-49",
412
414
"repo": "gnome-shell",
413
413
-
"type": "github"
415
415
+
"type": "gitlab"
414
416
}
415
417
},
416
418
"gomod2nix": {
···
442
444
]
443
445
},
444
446
"locked": {
445
445
-
"lastModified": 1758463745,
446
446
-
"narHash": "sha256-uhzsV0Q0I9j2y/rfweWeGif5AWe0MGrgZ/3TjpDYdGA=",
447
447
+
"lastModified": 1764398914,
448
448
+
"narHash": "sha256-YPrpwlVQidzQlMh0OnquaJR+58rKe9YNnuRis293Ilo=",
447
449
"owner": "nix-community",
448
450
"repo": "home-manager",
449
449
-
"rev": "3b955f5f0a942f9f60cdc9cacb7844335d0f21c3",
451
451
+
"rev": "d0c5fdc48db6f19471b8adc954eca09194e68036",
450
452
"type": "github"
451
453
},
452
454
"original": {
453
455
"owner": "nix-community",
454
454
-
"ref": "release-25.05",
456
456
+
"ref": "release-25.11",
455
457
"repo": "home-manager",
456
458
"type": "github"
457
459
}
···
592
594
"locked": {
593
595
"lastModified": 1762912391,
594
596
"narHash": "sha256-4hpBE7bGd24SfD28rzMdUGXsLsNEYxCCrTipFdoqoNM=",
595
595
-
"owner": "LnL7",
597
597
+
"owner": "nix-darwin",
596
598
"repo": "nix-darwin",
597
599
"rev": "d76299b2cd01837c4c271a7b5186e3d5d8ebd126",
598
600
"type": "github"
599
601
},
600
602
"original": {
601
601
-
"owner": "LnL7",
603
603
+
"owner": "nix-darwin",
602
604
"ref": "nix-darwin-25.05",
603
605
"repo": "nix-darwin",
604
606
"type": "github"
···
606
608
},
607
609
"nixos-hardware": {
608
610
"locked": {
609
609
-
"lastModified": 1762847253,
610
610
-
"narHash": "sha256-BWWnUUT01lPwCWUvS0p6Px5UOBFeXJ8jR+ZdLX8IbrU=",
611
611
+
"lastModified": 1764440730,
612
612
+
"narHash": "sha256-ZlJTNLUKQRANlLDomuRWLBCH5792x+6XUJ4YdFRjtO4=",
611
613
"owner": "nixos",
612
614
"repo": "nixos-hardware",
613
613
-
"rev": "899dc449bc6428b9ee6b3b8f771ca2b0ef945ab9",
615
615
+
"rev": "9154f4569b6cdfd3c595851a6ba51bfaa472d9f3",
614
616
"type": "github"
615
617
},
616
618
"original": {
···
621
623
},
622
624
"nixpkgs": {
623
625
"locked": {
624
624
-
"lastModified": 1763049705,
625
625
-
"narHash": "sha256-A5LS0AJZ1yDPTa2fHxufZN++n8MCmtgrJDtxFxrH4S8=",
626
626
+
"lastModified": 1764406085,
627
627
+
"narHash": "sha256-CYbMp8hwuOf4umokSNp+t1s4Hjd4vxXq4S5CD+xvgNs=",
626
628
"owner": "nixos",
627
629
"repo": "nixpkgs",
628
628
-
"rev": "3acb677ea67d4c6218f33de0db0955f116b7588c",
630
630
+
"rev": "9561691c9f450fad7c3526916e1c4f44be0d1192",
629
631
"type": "github"
630
632
},
631
633
"original": {
632
634
"owner": "nixos",
633
633
-
"ref": "nixos-25.05",
635
635
+
"ref": "nixos-25.11",
634
636
"repo": "nixpkgs",
635
637
"type": "github"
636
638
}
···
644
646
"nixpkgs": [
645
647
"stylix",
646
648
"nixpkgs"
647
647
-
],
648
648
-
"treefmt-nix": "treefmt-nix"
649
649
+
]
649
650
},
650
651
"locked": {
651
651
-
"lastModified": 1751320053,
652
652
-
"narHash": "sha256-3m6RMw0FbbaUUa01PNaMLoO7D99aBClmY5ed9V3vz+0=",
652
652
+
"lastModified": 1758998580,
653
653
+
"narHash": "sha256-VLx0z396gDCGSiowLMFz5XRO/XuNV+4EnDYjdJhHvUk=",
653
654
"owner": "nix-community",
654
655
"repo": "NUR",
655
655
-
"rev": "cbde1735782f9c2bb2c63d5e05fba171a14a4670",
656
656
+
"rev": "ba8d9c98f5f4630bcb0e815ab456afd90c930728",
656
657
"type": "github"
657
658
},
658
659
"original": {
···
810
811
]
811
812
},
812
813
"locked": {
813
813
-
"lastModified": 1762737305,
814
814
-
"narHash": "sha256-5zN6jJ6KKBGiJeK3Q4+afZfJU7VyyUgehOAA3zYegTc=",
814
814
+
"lastModified": 1764205213,
815
815
+
"narHash": "sha256-VWKPkM4m5kGgJ0HY1WKfvlPkKka6tYwUR8snetAFTu8=",
815
816
"owner": "nix-community",
816
817
"repo": "srvos",
817
817
-
"rev": "c04379f95fca70b38cdd45a1a7affe6d4226912b",
818
818
+
"rev": "8b90cbaadae462563297a2d08870cccfd986ca28",
818
819
"type": "github"
819
820
},
820
821
"original": {
···
836
837
"nixpkgs"
837
838
],
838
839
"nur": "nur",
839
839
-
"systems": "systems",
840
840
+
"systems": "systems_2",
840
841
"tinted-foot": "tinted-foot",
841
842
"tinted-kitty": "tinted-kitty",
842
843
"tinted-schemes": "tinted-schemes",
···
844
845
"tinted-zed": "tinted-zed"
845
846
},
846
847
"locked": {
847
847
-
"lastModified": 1762295027,
848
848
-
"narHash": "sha256-5z5cGrp9F8g8iyQrM8WkB6pAwP4AaicljKZ15gx+X9Y=",
848
848
+
"lastModified": 1764193603,
849
849
+
"narHash": "sha256-guX30TWe8HRG2qPFiM9893F2uTw4B8D/xkE6Mq7MiYg=",
849
850
"owner": "nix-community",
850
851
"repo": "stylix",
851
851
-
"rev": "91b9a270523361268ba6a8772152fde31103869f",
852
852
+
"rev": "9bf8725a3d65b3ff0ba68ce13779657f5095e36b",
852
853
"type": "github"
853
854
},
854
855
"original": {
855
856
"owner": "nix-community",
856
856
-
"ref": "release-25.05",
857
857
+
"ref": "release-25.11",
857
858
"repo": "stylix",
858
859
"type": "github"
859
860
}
···
888
889
"type": "github"
889
890
}
890
891
},
892
892
+
"systems_3": {
893
893
+
"locked": {
894
894
+
"lastModified": 1681028828,
895
895
+
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
896
896
+
"owner": "nix-systems",
897
897
+
"repo": "default",
898
898
+
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
899
899
+
"type": "github"
900
900
+
},
901
901
+
"original": {
902
902
+
"owner": "nix-systems",
903
903
+
"repo": "default",
904
904
+
"type": "github"
905
905
+
}
906
906
+
},
891
907
"tangled": {
892
908
"inputs": {
893
909
"actor-typeahead-src": "actor-typeahead-src",
···
905
921
"sqlite-lib-src": "sqlite-lib-src"
906
922
},
907
923
"locked": {
908
908
-
"lastModified": 1763089726,
909
909
-
"narHash": "sha256-lRTZLRcqWpVf6CzJmvg+ggp/YWWasT4u2lFKIiIopoM=",
924
924
+
"lastModified": 1764005195,
925
925
+
"narHash": "sha256-PzuWiW/nMxwQTX0i1bHwGazQF4ptLNI9OGwpmhDb9i0=",
910
926
"ref": "refs/heads/master",
911
911
-
"rev": "3eb9cefd98d13ab9864abb2e394fc41f89ffd923",
912
912
-
"revCount": 1660,
927
927
+
"rev": "7358ec6edfa4d17b8b8f543d99e83a4705901148",
928
928
+
"revCount": 1687,
913
929
"type": "git",
914
930
"url": "https://tangled.org/@tangled.org/core"
915
931
},
···
954
970
"tinted-schemes": {
955
971
"flake": false,
956
972
"locked": {
957
957
-
"lastModified": 1750770351,
958
958
-
"narHash": "sha256-LI+BnRoFNRa2ffbe3dcuIRYAUcGklBx0+EcFxlHj0SY=",
973
973
+
"lastModified": 1757716333,
974
974
+
"narHash": "sha256-d4km8W7w2zCUEmPAPUoLk1NlYrGODuVa3P7St+UrqkM=",
959
975
"owner": "tinted-theming",
960
976
"repo": "schemes",
961
961
-
"rev": "5a775c6ffd6e6125947b393872cde95867d85a2a",
977
977
+
"rev": "317a5e10c35825a6c905d912e480dfe8e71c7559",
962
978
"type": "github"
963
979
},
964
980
"original": {
···
970
986
"tinted-tmux": {
971
987
"flake": false,
972
988
"locked": {
973
973
-
"lastModified": 1751159871,
974
974
-
"narHash": "sha256-UOHBN1fgHIEzvPmdNMHaDvdRMgLmEJh2hNmDrp3d3LE=",
989
989
+
"lastModified": 1757811970,
990
990
+
"narHash": "sha256-n5ZJgmzGZXOD9pZdAl1OnBu3PIqD+X3vEBUGbTi4JiI=",
975
991
"owner": "tinted-theming",
976
992
"repo": "tinted-tmux",
977
977
-
"rev": "bded5e24407cec9d01bd47a317d15b9223a1546c",
993
993
+
"rev": "d217ba31c846006e9e0ae70775b0ee0f00aa6b1e",
978
994
"type": "github"
979
995
},
980
996
"original": {
···
986
1002
"tinted-zed": {
987
1003
"flake": false,
988
1004
"locked": {
989
989
-
"lastModified": 1751158968,
990
990
-
"narHash": "sha256-ksOyv7D3SRRtebpXxgpG4TK8gZSKFc4TIZpR+C98jX8=",
1005
1005
+
"lastModified": 1757811247,
1006
1006
+
"narHash": "sha256-4EFOUyLj85NRL3OacHoLGEo0wjiRJzfsXtR4CZWAn6w=",
991
1007
"owner": "tinted-theming",
992
1008
"repo": "base16-zed",
993
993
-
"rev": "86a470d94204f7652b906ab0d378e4231a5b3384",
1009
1009
+
"rev": "824fe0aacf82b3c26690d14e8d2cedd56e18404e",
994
1010
"type": "github"
995
1011
},
996
1012
"original": {
···
999
1015
"type": "github"
1000
1016
}
1001
1017
},
1002
1002
-
"treefmt-nix": {
1003
1003
-
"inputs": {
1004
1004
-
"nixpkgs": [
1005
1005
-
"stylix",
1006
1006
-
"nur",
1007
1007
-
"nixpkgs"
1008
1008
-
]
1009
1009
-
},
1010
1010
-
"locked": {
1011
1011
-
"lastModified": 1733222881,
1012
1012
-
"narHash": "sha256-JIPcz1PrpXUCbaccEnrcUS8jjEb/1vJbZz5KkobyFdM=",
1013
1013
-
"owner": "numtide",
1014
1014
-
"repo": "treefmt-nix",
1015
1015
-
"rev": "49717b5af6f80172275d47a418c9719a31a78b53",
1016
1016
-
"type": "github"
1017
1017
-
},
1018
1018
-
"original": {
1019
1019
-
"owner": "numtide",
1020
1020
-
"repo": "treefmt-nix",
1021
1021
-
"type": "github"
1022
1022
-
}
1023
1023
-
},
1024
1018
"unixpkgs": {
1025
1019
"locked": {
1026
1026
-
"lastModified": 1762977756,
1027
1027
-
"narHash": "sha256-4PqRErxfe+2toFJFgcRKZ0UI9NSIOJa+7RXVtBhy4KE=",
1020
1020
+
"lastModified": 1764242076,
1021
1021
+
"narHash": "sha256-sKoIWfnijJ0+9e4wRvIgm/HgE27bzwQxcEmo2J/gNpI=",
1028
1022
"owner": "nixos",
1029
1023
"repo": "nixpkgs",
1030
1030
-
"rev": "c5ae371f1a6a7fd27823bc500d9390b38c05fa55",
1024
1024
+
"rev": "2fad6eac6077f03fe109c4d4eb171cf96791faa4",
1031
1025
"type": "github"
1032
1026
},
1033
1027
"original": {
···
1069
1063
]
1070
1064
},
1071
1065
"locked": {
1072
1072
-
"lastModified": 1763097615,
1073
1073
-
"narHash": "sha256-qxpsf2FVzXrN0WDWRgeBz7RJ5vjHNFDy8oLqbC6gU3Y=",
1066
1066
+
"lastModified": 1764414951,
1067
1067
+
"narHash": "sha256-pZ2m2JmTTMyqiKB8WSigsSvAeoShI6OSRhzBuRO9SVY=",
1074
1068
"owner": "0xc000022070",
1075
1069
"repo": "zen-browser-flake",
1076
1076
-
"rev": "479ca480bf531285e88006aa1c70fd3bb5529f3d",
1070
1070
+
"rev": "10d2aa53ada9b14f6df2f9877d6a057f0a2b262f",
1077
1071
"type": "github"
1078
1072
},
1079
1073
"original": {
+11
-9
flake.nix
···
2
2
description = "NixOS and Home Manager configuration for Milo's laptops";
3
3
4
4
inputs = {
5
5
-
nixpkgs.url = "github:nixos/nixpkgs/nixos-25.05";
5
5
+
nixpkgs.url = "github:nixos/nixpkgs/nixos-25.11";
6
6
unixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
7
7
8
8
-
home-manager.url = "github:nix-community/home-manager/release-25.05";
8
8
+
home-manager.url = "github:nix-community/home-manager/release-25.11";
9
9
home-manager.inputs.nixpkgs.follows = "nixpkgs";
10
10
11
11
-
nix-darwin.url = "github:LnL7/nix-darwin/nix-darwin-25.05";
11
11
+
# nix-darwin.url = "github:nix-darwin/nix-darwin/nix-darwin-25.11";
12
12
+
nix-darwin.url = "github:nix-darwin/nix-darwin/nix-darwin-25.05";
12
13
nix-darwin.inputs.nixpkgs.follows = "nixpkgs";
13
14
14
14
-
stylix.url = "github:nix-community/stylix/release-25.05";
15
15
+
stylix.url = "github:nix-community/stylix/release-25.11";
15
16
stylix.inputs.nixpkgs.follows = "nixpkgs";
16
17
17
18
## Miscellaneous
18
19
19
19
-
agenix.url = "github:ryantm/agenix/0.15.0";
20
20
+
# agenix.url = "github:ryantm/agenix/0.15.0";
21
21
+
agenix.url = "github:mrnossiom/agenix";
20
22
agenix.inputs.nixpkgs.follows = "nixpkgs";
21
23
agenix.inputs.home-manager.follows = "home-manager";
22
24
···
57
59
58
60
flake-lib = import ./lib/flake (nixpkgs // { inherit self; });
59
61
60
60
-
forAllPkgs = func: forAllSystems (system: func pkgs.${system});
61
61
-
62
62
# This should be the only constructed nixpkgs instances in this flake
63
63
-
pkgs = forAllSystems (system: (import nixpkgs {
63
63
+
allPkgs = forAllSystems (system: (import nixpkgs {
64
64
inherit system;
65
65
config.allowUnfreePredicate = import ./lib/unfree.nix { lib = nixpkgs.lib; };
66
66
overlays = [ outputs.overlays.all ];
67
67
}));
68
68
+
69
69
+
forAllPkgs = func: forAllSystems (system: func allPkgs.${system});
68
70
in
69
71
{
70
72
formatter = forAllPkgs (pkgs: pkgs.nixpkgs-fmt);
···
73
75
lib = forAllPkgs (import ./lib);
74
76
templates = import ./templates;
75
77
76
76
-
apps = forAllPkgs (import ./apps { pkgs-per-system = pkgs; });
78
78
+
apps = forAllPkgs (import ./apps { pkgs-per-system = allPkgs; });
77
79
devShells = forAllPkgs (import ./shells.nix);
78
80
overlays = import ./overlays (nixpkgs // { inherit self; });
79
81
packages = forAllPkgs (import ./pkgs);
+4
home-manager/fragments/firefox.nix
···
84
84
enable = false;
85
85
profileNames = [ "default" ];
86
86
};
87
87
+
stylix.targets.zen-browser = {
88
88
+
enable = false;
89
89
+
profileNames = [ "default" ];
90
90
+
};
87
91
88
92
programs.zen-browser = {
89
93
enable = true;
+51
-48
home-manager/fragments/git.nix
···
28
28
enable = true;
29
29
lfs.enable = true;
30
30
31
31
-
userName = "Milo Moisson";
32
32
-
# TODO: this email should be behind a secret or at least a config
33
33
-
userEmail = "milo@wiro.world";
34
34
-
35
31
signing.signByDefault = true;
36
32
signing.key = "~/.ssh/id_ed25519.pub";
37
33
···
43
39
"result"
44
40
];
45
41
46
46
-
aliases = {
47
47
-
b = "branch --all";
48
48
-
brm = "branch --delete";
42
42
+
settings = {
43
43
+
user = {
44
44
+
name = "Milo Moisson";
45
45
+
# TODO: this email should be behind a secret or at least a config
46
46
+
email = "milo@wiro.world";
47
47
+
};
49
48
50
50
-
ll = "log --graph --oneline --pretty=custom";
51
51
-
lla = "log --graph --oneline --pretty=custom --all";
52
52
-
last = "log -1 HEAD --stat";
49
49
+
alias = {
50
50
+
b = "branch --all";
51
51
+
brm = "branch --delete";
53
52
54
54
-
st = "status --short --branch";
53
53
+
ll = "log --graph --oneline --pretty=custom";
54
54
+
lla = "log --graph --oneline --pretty=custom --all";
55
55
+
last = "log -1 HEAD --stat";
55
56
56
56
-
cm = "commit --message";
57
57
-
oups = "commit --amend";
57
57
+
st = "status --short --branch";
58
58
+
59
59
+
cm = "commit --message";
60
60
+
oups = "commit --amend";
58
61
59
59
-
ui = "!lazygit";
62
62
+
ui = "!lazygit";
60
63
61
61
-
rv = "remote --verbose";
64
64
+
rv = "remote --verbose";
62
65
63
63
-
ri = "rebase --interactive";
64
64
-
ris = "!git ri $(git slc)";
65
65
-
rc = "rebase --continue";
66
66
-
rs = "rebase --skip";
67
67
-
ra = "rebase --abort";
66
66
+
ri = "rebase --interactive";
67
67
+
ris = "!git ri $(git slc)";
68
68
+
rc = "rebase --continue";
69
69
+
rs = "rebase --skip";
70
70
+
ra = "rebase --abort";
68
71
69
69
-
# Select commit
70
70
-
slc = "!git log --oneline --pretty=custom | fzf | awk '{printf $1}'";
72
72
+
# Select commit
73
73
+
slc = "!git log --oneline --pretty=custom | fzf | awk '{printf $1}'";
71
74
72
72
-
a = "add";
73
73
-
al = "add --all";
74
74
-
ac = "add .";
75
75
-
ap = "add --patch";
75
75
+
a = "add";
76
76
+
al = "add --all";
77
77
+
ac = "add .";
78
78
+
ap = "add --patch";
76
79
77
77
-
pu = "push";
78
78
-
put = "push --follow-tags";
79
79
-
puf = "push --force-with-lease";
80
80
-
pl = "pull";
80
80
+
pu = "push";
81
81
+
put = "push --follow-tags";
82
82
+
puf = "push --force-with-lease";
83
83
+
pl = "pull";
81
84
82
82
-
f = "fetch";
85
85
+
f = "fetch";
83
86
84
84
-
s = "switch";
85
85
-
sc = "switch --create";
87
87
+
s = "switch";
88
88
+
sc = "switch --create";
86
89
87
87
-
ck = "checkout";
90
90
+
ck = "checkout";
88
91
89
89
-
cp = "cherry-pick";
92
92
+
cp = "cherry-pick";
90
93
91
91
-
df = "diff";
92
92
-
dfs = "diff --staged";
93
93
-
dfc = "diff --cached";
94
94
+
df = "diff";
95
95
+
dfs = "diff --staged";
96
96
+
dfc = "diff --cached";
94
97
95
95
-
m = "merge";
98
98
+
m = "merge";
96
99
97
97
-
rms = "restore --staged";
98
98
-
res = "restore";
100
100
+
rms = "restore --staged";
101
101
+
res = "restore";
99
102
100
100
-
sh = "stash";
101
101
-
shl = "stash list";
102
102
-
sha = "stash apply";
103
103
-
shp = "stash pop";
104
104
-
};
103
103
+
sh = "stash";
104
104
+
shl = "stash list";
105
105
+
sha = "stash apply";
106
106
+
shp = "stash pop";
107
107
+
};
105
108
106
106
-
extraConfig = {
107
109
fetch.prune = true;
108
110
color.ui = true;
109
111
init.defaultBranch = "main";
···
158
160
showCommandLog = false;
159
161
border = "single";
160
162
};
163
163
+
161
164
git = {
162
162
-
paging.externalDiffCommand = "difft --color=always";
165
165
+
pagers.externalDiffCommand = "difft --color=always";
163
166
};
164
167
165
168
# to be declarative or not to be declarative?
-1
home-manager/fragments/helix.nix
···
93
93
};
94
94
95
95
extraPackages = with pkgs; [
96
96
-
ansible-language-server
97
96
clang-tools
98
97
gopls
99
98
kotlin-language-server
+1
-2
home-manager/fragments/jujutsu.nix
···
29
29
signing = {
30
30
behavior = "own";
31
31
backend = "ssh";
32
32
-
key = keys.milomoisson;
33
33
-
32
32
+
key = keys.milo-ed25519;
34
33
git.sign-on-push = true;
35
34
};
36
35
+3
home-manager/fragments/stylix.nix
···
27
27
enable = true;
28
28
base16Scheme = lib.mkDefault "${pkgs.base16-schemes}/share/themes/onedark-dark.yaml";
29
29
30
30
+
# issues a warning because we use `useGlobalPkgs`
31
31
+
overlays.enable = false;
32
32
+
30
33
image = ../../assets/wallpaper-binary-cloud.png;
31
34
32
35
fonts = {
+1
-8
home-manager/fragments/sway.nix
···
1
1
-
{ self
2
2
-
, config
1
1
+
{ config
3
2
, lib
4
3
, pkgs
5
4
···
8
7
}:
9
8
10
9
let
11
11
-
inherit (self.outputs) homeManagerModules;
12
12
-
13
10
cfg = config.local.fragment.sway;
14
11
cfg-sway = config.wayland.windowManager.sway.config;
15
12
16
13
workspacesRange = lib.zipListsWith (key-idx: workspace-idx: { inherit key-idx workspace-idx; }) [ 1 2 3 4 5 6 7 8 9 0 ] (lib.range 1 10);
17
14
in
18
15
{
19
19
-
imports = [
20
20
-
homeManagerModules.wl-clip-persist
21
21
-
];
22
22
-
23
16
options.local.fragment.sway.enable = lib.mkEnableOption ''
24
17
Sway related
25
18
'';
+2
-2
home-manager/fragments/tools.nix
···
29
29
csvlens
30
30
delta
31
31
dogdns
32
32
-
du-dust
32
32
+
dust
33
33
encfs
34
34
fastfetch
35
35
fd
···
47
47
otree
48
48
ouch
49
49
parallel
50
50
+
perf
50
51
pv
51
52
restic
52
53
ripgrep
···
60
61
uni
61
62
unzip
62
63
vlock
63
63
-
wcurl
64
64
wormhole-rs
65
65
]) ++ lib.optionals (!flags.onlyCached) [ ];
66
66
+3
-1
home-manager/profiles/desktop.nix
···
125
125
126
126
programs.go = {
127
127
enable = true;
128
128
-
goPath = ".local/share/go";
128
128
+
env.GOPATH = ".local/share/go";
129
129
};
130
130
131
131
programs.gpg = {
···
139
139
enableFishIntegration = false;
140
140
enableZshIntegration = false;
141
141
};
142
142
+
143
143
+
programs.ssh.enableDefaultConfig = false;
142
144
};
143
145
}
+4
-1
lib/flake/default.nix
···
20
20
# local packages set
21
21
lpkgs = import ../../pkgs pkgs;
22
22
# unstable nixpkgs set
23
23
-
upkgs = import unixpkgs { inherit (pkgs) system config; };
23
23
+
upkgs = import unixpkgs {
24
24
+
config = pkgs.config;
25
25
+
system = pkgs.stdenv.hostPlatform.system;
26
26
+
};
24
27
# indicates if system is darwin
25
28
isDarwin = pkgs.stdenv.isDarwin;
26
29
};
+1
lib/flake/user.nix
···
36
36
} else {
37
37
home = "/home/${name}";
38
38
extraGroups = [
39
39
+
# TODO: remove or put under an condition
39
40
"wheel" # sudo access
40
41
"networkmanager" # needed for nm
41
42
];
+2
-3
modules/home-manager/default.nix
···
1
1
{
2
2
-
wakatime = import ./wakatime.nix;
3
3
-
wl-clip-persist = import ./wl-clip-persist.nix;
4
4
-
xcompose = import ./xcompose.nix;
2
2
+
wakatime = ./wakatime.nix;
3
3
+
xcompose = ./xcompose.nix;
5
4
}
-99
modules/home-manager/wl-clip-persist.nix
···
1
1
-
{ config
2
2
-
, lib
3
3
-
, pkgs
4
4
-
, ...
5
5
-
}:
6
6
-
7
7
-
let
8
8
-
cfg = config.services.wl-clip-persist;
9
9
-
in
10
10
-
{
11
11
-
options.services.wl-clip-persist = with lib; {
12
12
-
enable = mkEnableOption "";
13
13
-
14
14
-
package = mkPackageOption pkgs "wl-clip-persist" { };
15
15
-
16
16
-
clipboard = mkOption {
17
17
-
description = "The clipboard type to operate on";
18
18
-
default = "regular";
19
19
-
type = types.enum [ "regular" "primary" "both" ];
20
20
-
};
21
21
-
22
22
-
display = mkOption {
23
23
-
description = "The wayland display to operate on";
24
24
-
default = null;
25
25
-
type = types.nullOr types.str;
26
26
-
};
27
27
-
28
28
-
ignoreEventOnError = mkOption {
29
29
-
description = "Only handle selection events where no error occurred";
30
30
-
default = null;
31
31
-
type = types.nullOr types.bool;
32
32
-
};
33
33
-
34
34
-
allMimeTypeRegex = mkOption {
35
35
-
description = "Only handle selection events where all offered MIME types have a match for the regex";
36
36
-
default = null;
37
37
-
type = types.nullOr types.str;
38
38
-
};
39
39
-
40
40
-
interruptOldClipboardRequests = mkOption {
41
41
-
description = "Interrupt trying to send the old clipboard to other programs when the clipboard has been updated";
42
42
-
default = null;
43
43
-
type = types.nullOr types.bool;
44
44
-
};
45
45
-
46
46
-
selectionSizeLimit = mkOption {
47
47
-
description = "Only handle selection events whose total data size does not exceed the size limit";
48
48
-
default = null;
49
49
-
type = types.nullOr types.int;
50
50
-
};
51
51
-
52
52
-
readTimeout = mkOption {
53
53
-
description = "Timeout for trying to get the current clipboard";
54
54
-
default = 500;
55
55
-
type = types.int;
56
56
-
};
57
57
-
58
58
-
ignoreEventOnTimeout = mkOption {
59
59
-
description = "Only handle selection events where no timeout occurred";
60
60
-
default = null;
61
61
-
type = types.nullOr types.bool;
62
62
-
};
63
63
-
64
64
-
writeTimeout = mkOption {
65
65
-
description = "Timeout for trying to send the current clipboard to other programs";
66
66
-
default = 3000;
67
67
-
type = types.int;
68
68
-
};
69
69
-
};
70
70
-
71
71
-
config = lib.mkIf cfg.enable {
72
72
-
systemd.user.services.wl-clip-persist = {
73
73
-
Unit = {
74
74
-
Description = "wl-clip-persist system service";
75
75
-
PartOf = [ "graphical-session.target" ];
76
76
-
BindsTo = [ "graphical-session.target" ];
77
77
-
};
78
78
-
79
79
-
Service = {
80
80
-
Type = "simple";
81
81
-
ExecStart = "${lib.getExe cfg.package} ${lib.cli.toGNUCommandLineShell {} {
82
82
-
clipboard = cfg.clipboard;
83
83
-
display = cfg.display;
84
84
-
ignore-event-on-error = cfg.ignoreEventOnError;
85
85
-
all-mime-type-regex = cfg.allMimeTypeRegex;
86
86
-
interrupt-old-clipboard-requests = cfg.interruptOldClipboardRequests;
87
87
-
selection-size-limit = cfg.selectionSizeLimit;
88
88
-
read-timeout = cfg.readTimeout;
89
89
-
ignore-event-on-timeout = cfg.ignoreEventOnTimeout;
90
90
-
write-timeout = cfg.writeTimeout;
91
91
-
}}";
92
92
-
Restart = "on-failure";
93
93
-
TimeoutStopSec = 15;
94
94
-
};
95
95
-
96
96
-
Install.WantedBy = lib.mkDefault [ "graphical-session.target" ];
97
97
-
};
98
98
-
};
99
99
-
}
-2
modules/nixos/default.nix
···
1
1
{
2
2
-
geoclue2 = ./geoclue2.nix;
3
3
-
headscale = ./headscale.nix;
4
2
logiops = ./logiops.nix;
5
3
}
-324
modules/nixos/geoclue2.nix
···
1
1
-
# Adapted from the original nixpkgs repo
2
2
-
#
3
3
-
# It supports static location fallback. This is a workaround waiting for an
4
4
-
# alternative to MLS (Mozilla Location Services).
5
5
-
6
6
-
# Target interface to manage the static file would be:
7
7
-
# static = {
8
8
-
# latitude = 48.8;
9
9
-
# longitude = 2.3;
10
10
-
# };
11
11
-
#
12
12
-
# I spent way too much time getting this to work with a submodule.
13
13
-
14
14
-
{ config
15
15
-
, lib
16
16
-
, pkgs
17
17
-
, ...
18
18
-
}:
19
19
-
20
20
-
let
21
21
-
package = pkgs.geoclue2.override { withDemoAgent = config.services.geoclue2.enableDemoAgent; };
22
22
-
23
23
-
cfg = config.services.geoclue2;
24
24
-
25
25
-
defaultWhitelist = [ "gnome-shell" "io.elementary.desktop.agent-geoclue2" ];
26
26
-
27
27
-
appConfigModule = lib.types.submodule ({ name, ... }: with lib; {
28
28
-
options = {
29
29
-
desktopID = mkOption {
30
30
-
type = types.str;
31
31
-
description = "Desktop ID of the application.";
32
32
-
};
33
33
-
34
34
-
isAllowed = mkOption {
35
35
-
type = types.bool;
36
36
-
description = ''
37
37
-
Whether the application will be allowed access to location information.
38
38
-
'';
39
39
-
};
40
40
-
41
41
-
isSystem = mkOption {
42
42
-
type = types.bool;
43
43
-
description = ''
44
44
-
Whether the application is a system component or not.
45
45
-
'';
46
46
-
};
47
47
-
48
48
-
users = mkOption {
49
49
-
type = types.listOf types.str;
50
50
-
default = [ ];
51
51
-
description = ''
52
52
-
List of UIDs of all users for which this application is allowed location
53
53
-
info access, Defaults to an empty string to allow it for all users.
54
54
-
'';
55
55
-
};
56
56
-
};
57
57
-
58
58
-
config.desktopID = mkDefault name;
59
59
-
});
60
60
-
61
61
-
# staticModule = types.submodule ({ name, ... }: {
62
62
-
# options = {
63
63
-
# latitude = mkOption {
64
64
-
# type = types.float;
65
65
-
# example = 40.6893129;
66
66
-
# };
67
67
-
68
68
-
# longitude = mkOption {
69
69
-
# type = types.float;
70
70
-
# example = -74.0445531;
71
71
-
# };
72
72
-
73
73
-
# altitude = mkOption {
74
74
-
# type = types.float;
75
75
-
# default = 0;
76
76
-
# example = 96;
77
77
-
# };
78
78
-
79
79
-
# accuracyRadius = mkOption {
80
80
-
# type = types.float;
81
81
-
# default = 0;
82
82
-
# example = 1.83;
83
83
-
# };
84
84
-
# };
85
85
-
# });
86
86
-
87
87
-
appConfigToINICompatible = _: { desktopID, isAllowed, isSystem, users, ... }: {
88
88
-
name = desktopID;
89
89
-
value = {
90
90
-
allowed = isAllowed;
91
91
-
system = isSystem;
92
92
-
users = lib.concatStringsSep ";" users;
93
93
-
};
94
94
-
};
95
95
-
96
96
-
in
97
97
-
{
98
98
-
disabledModules = [ "services/desktops/geoclue2.nix" ];
99
99
-
100
100
-
options.services.geoclue2 = with lib; {
101
101
-
enable = mkOption {
102
102
-
type = types.bool;
103
103
-
default = false;
104
104
-
description = ''
105
105
-
Whether to enable GeoClue 2 daemon, a DBus service
106
106
-
that provides location information for accessing.
107
107
-
'';
108
108
-
};
109
109
-
110
110
-
enableDemoAgent = mkOption {
111
111
-
type = types.bool;
112
112
-
default = true;
113
113
-
description = ''
114
114
-
Whether to use the GeoClue demo agent. This should be
115
115
-
overridden by desktop environments that provide their own
116
116
-
agent.
117
117
-
'';
118
118
-
};
119
119
-
120
120
-
enableNmea = mkOption {
121
121
-
type = types.bool;
122
122
-
default = true;
123
123
-
description = ''
124
124
-
Whether to fetch location from NMEA sources on local network.
125
125
-
'';
126
126
-
};
127
127
-
128
128
-
enable3G = mkOption {
129
129
-
type = types.bool;
130
130
-
default = true;
131
131
-
description = ''
132
132
-
Whether to enable 3G source.
133
133
-
'';
134
134
-
};
135
135
-
136
136
-
enableCDMA = mkOption {
137
137
-
type = types.bool;
138
138
-
default = true;
139
139
-
description = ''
140
140
-
Whether to enable CDMA source.
141
141
-
'';
142
142
-
};
143
143
-
144
144
-
enableModemGPS = mkOption {
145
145
-
type = types.bool;
146
146
-
default = true;
147
147
-
description = ''
148
148
-
Whether to enable Modem-GPS source.
149
149
-
'';
150
150
-
};
151
151
-
152
152
-
enableWifi = mkOption {
153
153
-
type = types.bool;
154
154
-
default = true;
155
155
-
description = ''
156
156
-
Whether to enable WiFi source.
157
157
-
'';
158
158
-
};
159
159
-
160
160
-
geoProviderUrl = mkOption {
161
161
-
type = types.str;
162
162
-
default = "https://location.services.mozilla.com/v1/geolocate?key=geoclue";
163
163
-
example = "https://www.googleapis.com/geolocation/v1/geolocate?key=YOUR_KEY";
164
164
-
description = ''
165
165
-
The url to the wifi GeoLocation Service.
166
166
-
'';
167
167
-
};
168
168
-
169
169
-
submitData = mkOption {
170
170
-
type = types.bool;
171
171
-
default = false;
172
172
-
description = ''
173
173
-
Whether to submit data to a GeoLocation Service.
174
174
-
'';
175
175
-
};
176
176
-
177
177
-
submissionUrl = mkOption {
178
178
-
type = types.str;
179
179
-
default = "https://location.services.mozilla.com/v1/submit?key=geoclue";
180
180
-
description = ''
181
181
-
The url to submit data to a GeoLocation Service.
182
182
-
'';
183
183
-
};
184
184
-
185
185
-
submissionNick = mkOption {
186
186
-
type = types.str;
187
187
-
default = "geoclue";
188
188
-
description = ''
189
189
-
A nickname to submit network data with.
190
190
-
Must be 2-32 characters long.
191
191
-
'';
192
192
-
};
193
193
-
194
194
-
appConfig = mkOption {
195
195
-
type = types.attrsOf appConfigModule;
196
196
-
default = { };
197
197
-
example = {
198
198
-
"com.github.app" = {
199
199
-
isAllowed = true;
200
200
-
isSystem = true;
201
201
-
users = [ "300" ];
202
202
-
};
203
203
-
};
204
204
-
description = ''
205
205
-
Specify extra settings per application.
206
206
-
'';
207
207
-
};
208
208
-
209
209
-
# static = mkOption {
210
210
-
# type = types.nullOr (types.attrsOf staticModule);
211
211
-
# default = null;
212
212
-
# description = ''
213
213
-
# Add a fallback location that will be overridden by other location services
214
214
-
# '';
215
215
-
# };
216
216
-
217
217
-
staticFile = mkOption {
218
218
-
type = types.nullOr (types.str);
219
219
-
default = null;
220
220
-
description = ''
221
221
-
Add a fallback location that will be overridden by other location services
222
222
-
'';
223
223
-
};
224
224
-
};
225
225
-
226
226
-
config = lib.mkIf cfg.enable {
227
227
-
environment.systemPackages = [ package ];
228
228
-
229
229
-
services.dbus.packages = [ package ];
230
230
-
231
231
-
systemd.packages = [ package ];
232
232
-
233
233
-
# we cannot use DynamicUser as we need the the geoclue user to exist for the
234
234
-
# dbus policy to work
235
235
-
users = {
236
236
-
users.geoclue = {
237
237
-
isSystemUser = true;
238
238
-
home = "/var/lib/geoclue";
239
239
-
group = "geoclue";
240
240
-
description = "Geoinformation service";
241
241
-
};
242
242
-
243
243
-
groups.geoclue = { };
244
244
-
};
245
245
-
246
246
-
systemd.services.geoclue = {
247
247
-
wants = lib.optionals cfg.enableWifi [ "network-online.target" ];
248
248
-
after = lib.optionals cfg.enableWifi [ "network-online.target" ];
249
249
-
# restart geoclue service when the configuration changes
250
250
-
restartTriggers = [
251
251
-
config.environment.etc."geoclue/geoclue.conf".source
252
252
-
];
253
253
-
serviceConfig.StateDirectory = "geoclue";
254
254
-
};
255
255
-
256
256
-
# this needs to run as a user service, since it's associated with the
257
257
-
# user who is making the requests
258
258
-
systemd.user.services = lib.mkIf cfg.enableDemoAgent {
259
259
-
geoclue-agent = {
260
260
-
description = "Geoclue agent";
261
261
-
# this should really be `partOf = [ "geoclue.service" ]`, but
262
262
-
# we can't be part of a system service, and the agent should
263
263
-
# be okay with the main service coming and going
264
264
-
wantedBy = [ "default.target" ];
265
265
-
wants = lib.optionals cfg.enableWifi [ "network-online.target" ];
266
266
-
after = lib.optionals cfg.enableWifi [ "network-online.target" ];
267
267
-
unitConfig.ConditionUser = "!@system";
268
268
-
serviceConfig = {
269
269
-
Type = "exec";
270
270
-
ExecStart = "${package}/libexec/geoclue-2.0/demos/agent";
271
271
-
Restart = "on-failure";
272
272
-
PrivateTmp = true;
273
273
-
};
274
274
-
};
275
275
-
};
276
276
-
277
277
-
services.geoclue2.appConfig = {
278
278
-
epiphany = { isAllowed = true; isSystem = false; };
279
279
-
firefox = { isAllowed = true; isSystem = false; };
280
280
-
};
281
281
-
282
282
-
environment.etc."geoclue/geoclue.conf".text =
283
283
-
lib.generators.toINI { } ({
284
284
-
agent = {
285
285
-
whitelist = lib.concatStringsSep ";"
286
286
-
(lib.optional cfg.enableDemoAgent "geoclue-demo-agent" ++ defaultWhitelist);
287
287
-
};
288
288
-
network-nmea = {
289
289
-
enable = cfg.enableNmea;
290
290
-
};
291
291
-
"3g" = {
292
292
-
enable = cfg.enable3G;
293
293
-
};
294
294
-
cdma = {
295
295
-
enable = cfg.enableCDMA;
296
296
-
};
297
297
-
modem-gps = {
298
298
-
enable = cfg.enableModemGPS;
299
299
-
};
300
300
-
wifi = {
301
301
-
enable = cfg.enableWifi;
302
302
-
url = cfg.geoProviderUrl;
303
303
-
submit-data = lib.boolToString cfg.submitData;
304
304
-
submission-url = cfg.submissionUrl;
305
305
-
submission-nick = cfg.submissionNick;
306
306
-
};
307
307
-
} // lib.mapAttrs' appConfigToINICompatible cfg.appConfig);
308
308
-
309
309
-
# environment.etc."geolocation" = mkIf (cfg.static != null) {
310
310
-
# text = ''
311
311
-
# ${toString cfg.static.latitude}
312
312
-
# ${toString cfg.static.longitude}
313
313
-
# ${toString cfg.static.altitude}
314
314
-
# ${toString cfg.static.accuracyRadius}
315
315
-
# '';
316
316
-
# };
317
317
-
318
318
-
environment.etc."geolocation" = lib.mkIf (cfg.staticFile != null) { text = cfg.staticFile; };
319
319
-
};
320
320
-
321
321
-
meta = with lib; {
322
322
-
maintainers = with maintainers; [ ] ++ teams.pantheon.members;
323
323
-
};
324
324
-
}
-673
modules/nixos/headscale.nix
···
1
1
-
{ config
2
2
-
, lib
3
3
-
, pkgs
4
4
-
, ...
5
5
-
}:
6
6
-
let
7
7
-
cfg = config.services.headscale;
8
8
-
9
9
-
dataDir = "/var/lib/headscale";
10
10
-
runDir = "/run/headscale";
11
11
-
12
12
-
cliConfig = {
13
13
-
# Turn off update checks since the origin of our package
14
14
-
# is nixpkgs and not Github.
15
15
-
disable_check_updates = true;
16
16
-
17
17
-
unix_socket = "${runDir}/headscale.sock";
18
18
-
};
19
19
-
20
20
-
settingsFormat = pkgs.formats.yaml { };
21
21
-
configFile = settingsFormat.generate "headscale.yaml" cfg.settings;
22
22
-
cliConfigFile = settingsFormat.generate "headscale.yaml" cliConfig;
23
23
-
24
24
-
assertRemovedOption = option: message: {
25
25
-
assertion = !lib.hasAttrByPath option cfg;
26
26
-
message =
27
27
-
"The option `services.headscale.${lib.options.showOption option}` was removed. " + message;
28
28
-
};
29
29
-
in
30
30
-
{
31
31
-
options = {
32
32
-
services.headscale = {
33
33
-
enable = lib.mkEnableOption "headscale, Open Source coordination server for Tailscale";
34
34
-
35
35
-
package = lib.mkPackageOption pkgs "headscale" { };
36
36
-
37
37
-
user = lib.mkOption {
38
38
-
default = "headscale";
39
39
-
type = lib.types.str;
40
40
-
description = ''
41
41
-
User account under which headscale runs.
42
42
-
43
43
-
::: {.note}
44
44
-
If left as the default value this user will automatically be created
45
45
-
on system activation, otherwise you are responsible for
46
46
-
ensuring the user exists before the headscale service starts.
47
47
-
:::
48
48
-
'';
49
49
-
};
50
50
-
51
51
-
group = lib.mkOption {
52
52
-
default = "headscale";
53
53
-
type = lib.types.str;
54
54
-
description = ''
55
55
-
Group under which headscale runs.
56
56
-
57
57
-
::: {.note}
58
58
-
If left as the default value this group will automatically be created
59
59
-
on system activation, otherwise you are responsible for
60
60
-
ensuring the user exists before the headscale service starts.
61
61
-
:::
62
62
-
'';
63
63
-
};
64
64
-
65
65
-
address = lib.mkOption {
66
66
-
type = lib.types.str;
67
67
-
default = "127.0.0.1";
68
68
-
description = ''
69
69
-
Listening address of headscale.
70
70
-
'';
71
71
-
example = "0.0.0.0";
72
72
-
};
73
73
-
74
74
-
port = lib.mkOption {
75
75
-
type = lib.types.port;
76
76
-
default = 8080;
77
77
-
description = ''
78
78
-
Listening port of headscale.
79
79
-
'';
80
80
-
example = 443;
81
81
-
};
82
82
-
83
83
-
settings = lib.mkOption {
84
84
-
description = ''
85
85
-
Overrides to {file}`config.yaml` as a Nix attribute set.
86
86
-
Check the [example config](https://github.com/juanfont/headscale/blob/main/config-example.yaml)
87
87
-
for possible options.
88
88
-
'';
89
89
-
type = lib.types.submodule {
90
90
-
freeformType = settingsFormat.type;
91
91
-
92
92
-
options = {
93
93
-
server_url = lib.mkOption {
94
94
-
type = lib.types.str;
95
95
-
default = "http://127.0.0.1:8080";
96
96
-
description = ''
97
97
-
The url clients will connect to.
98
98
-
'';
99
99
-
example = "https://myheadscale.example.com:443";
100
100
-
};
101
101
-
102
102
-
noise.private_key_path = lib.mkOption {
103
103
-
type = lib.types.path;
104
104
-
default = "${dataDir}/noise_private.key";
105
105
-
description = ''
106
106
-
Path to noise private key file, generated automatically if it does not exist.
107
107
-
'';
108
108
-
};
109
109
-
110
110
-
prefixes =
111
111
-
let
112
112
-
prefDesc = ''
113
113
-
Each prefix consists of either an IPv4 or IPv6 address,
114
114
-
and the associated prefix length, delimited by a slash.
115
115
-
It must be within IP ranges supported by the Tailscale
116
116
-
client - i.e., subnets of 100.64.0.0/10 and fd7a:115c:a1e0::/48.
117
117
-
'';
118
118
-
in
119
119
-
{
120
120
-
v4 = lib.mkOption {
121
121
-
type = lib.types.str;
122
122
-
default = "100.64.0.0/10";
123
123
-
description = prefDesc;
124
124
-
};
125
125
-
126
126
-
v6 = lib.mkOption {
127
127
-
type = lib.types.str;
128
128
-
default = "fd7a:115c:a1e0::/48";
129
129
-
description = prefDesc;
130
130
-
};
131
131
-
132
132
-
allocation = lib.mkOption {
133
133
-
type = lib.types.enum [
134
134
-
"sequential"
135
135
-
"random"
136
136
-
];
137
137
-
example = "random";
138
138
-
default = "sequential";
139
139
-
description = ''
140
140
-
Strategy used for allocation of IPs to nodes, available options:
141
141
-
- sequential (default): assigns the next free IP from the previous given IP.
142
142
-
- random: assigns the next free IP from a pseudo-random IP generator (crypto/rand).
143
143
-
'';
144
144
-
};
145
145
-
};
146
146
-
147
147
-
derp = {
148
148
-
urls = lib.mkOption {
149
149
-
type = lib.types.listOf lib.types.str;
150
150
-
default = [ "https://controlplane.tailscale.com/derpmap/default" ];
151
151
-
description = ''
152
152
-
List of urls containing DERP maps.
153
153
-
See [How Tailscale works](https://tailscale.com/blog/how-tailscale-works/) for more information on DERP maps.
154
154
-
'';
155
155
-
};
156
156
-
157
157
-
paths = lib.mkOption {
158
158
-
type = lib.types.listOf lib.types.path;
159
159
-
default = [ ];
160
160
-
description = ''
161
161
-
List of file paths containing DERP maps.
162
162
-
See [How Tailscale works](https://tailscale.com/blog/how-tailscale-works/) for more information on DERP maps.
163
163
-
'';
164
164
-
};
165
165
-
166
166
-
auto_update_enable = lib.mkOption {
167
167
-
type = lib.types.bool;
168
168
-
default = true;
169
169
-
description = ''
170
170
-
Whether to automatically update DERP maps on a set frequency.
171
171
-
'';
172
172
-
example = false;
173
173
-
};
174
174
-
175
175
-
update_frequency = lib.mkOption {
176
176
-
type = lib.types.str;
177
177
-
default = "24h";
178
178
-
description = ''
179
179
-
Frequency to update DERP maps.
180
180
-
'';
181
181
-
example = "5m";
182
182
-
};
183
183
-
184
184
-
server.private_key_path = lib.mkOption {
185
185
-
type = lib.types.path;
186
186
-
default = "${dataDir}/derp_server_private.key";
187
187
-
description = ''
188
188
-
Path to derp private key file, generated automatically if it does not exist.
189
189
-
'';
190
190
-
};
191
191
-
};
192
192
-
193
193
-
ephemeral_node_inactivity_timeout = lib.mkOption {
194
194
-
type = lib.types.str;
195
195
-
default = "30m";
196
196
-
description = ''
197
197
-
Time before an inactive ephemeral node is deleted.
198
198
-
'';
199
199
-
example = "5m";
200
200
-
};
201
201
-
202
202
-
database = {
203
203
-
type = lib.mkOption {
204
204
-
type = lib.types.enum [
205
205
-
"sqlite"
206
206
-
"sqlite3"
207
207
-
"postgres"
208
208
-
];
209
209
-
example = "postgres";
210
210
-
default = "sqlite";
211
211
-
description = ''
212
212
-
Database engine to use.
213
213
-
Please note that using Postgres is highly discouraged as it is only supported for legacy reasons.
214
214
-
All new development, testing and optimisations are done with SQLite in mind.
215
215
-
'';
216
216
-
};
217
217
-
218
218
-
sqlite = {
219
219
-
path = lib.mkOption {
220
220
-
type = lib.types.nullOr lib.types.str;
221
221
-
default = "${dataDir}/db.sqlite";
222
222
-
description = "Path to the sqlite3 database file.";
223
223
-
};
224
224
-
225
225
-
write_ahead_log = lib.mkOption {
226
226
-
type = lib.types.bool;
227
227
-
default = true;
228
228
-
description = ''
229
229
-
Enable WAL mode for SQLite. This is recommended for production environments.
230
230
-
<https://www.sqlite.org/wal.html>
231
231
-
'';
232
232
-
example = true;
233
233
-
};
234
234
-
};
235
235
-
236
236
-
postgres = {
237
237
-
host = lib.mkOption {
238
238
-
type = lib.types.nullOr lib.types.str;
239
239
-
default = null;
240
240
-
example = "127.0.0.1";
241
241
-
description = "Database host address.";
242
242
-
};
243
243
-
244
244
-
port = lib.mkOption {
245
245
-
type = lib.types.nullOr lib.types.port;
246
246
-
default = null;
247
247
-
example = 3306;
248
248
-
description = "Database host port.";
249
249
-
};
250
250
-
251
251
-
name = lib.mkOption {
252
252
-
type = lib.types.nullOr lib.types.str;
253
253
-
default = null;
254
254
-
example = "headscale";
255
255
-
description = "Database name.";
256
256
-
};
257
257
-
258
258
-
user = lib.mkOption {
259
259
-
type = lib.types.nullOr lib.types.str;
260
260
-
default = null;
261
261
-
example = "headscale";
262
262
-
description = "Database user.";
263
263
-
};
264
264
-
265
265
-
password_file = lib.mkOption {
266
266
-
type = lib.types.nullOr lib.types.path;
267
267
-
default = null;
268
268
-
example = "/run/keys/headscale-dbpassword";
269
269
-
description = ''
270
270
-
A file containing the password corresponding to
271
271
-
{option}`database.user`.
272
272
-
'';
273
273
-
};
274
274
-
};
275
275
-
};
276
276
-
277
277
-
log = {
278
278
-
level = lib.mkOption {
279
279
-
type = lib.types.str;
280
280
-
default = "info";
281
281
-
description = ''
282
282
-
headscale log level.
283
283
-
'';
284
284
-
example = "debug";
285
285
-
};
286
286
-
287
287
-
format = lib.mkOption {
288
288
-
type = lib.types.str;
289
289
-
default = "text";
290
290
-
description = ''
291
291
-
headscale log format.
292
292
-
'';
293
293
-
example = "json";
294
294
-
};
295
295
-
};
296
296
-
297
297
-
dns = {
298
298
-
magic_dns = lib.mkOption {
299
299
-
type = lib.types.bool;
300
300
-
default = true;
301
301
-
description = ''
302
302
-
Whether to use [MagicDNS](https://tailscale.com/kb/1081/magicdns/).
303
303
-
'';
304
304
-
example = false;
305
305
-
};
306
306
-
307
307
-
base_domain = lib.mkOption {
308
308
-
type = lib.types.str;
309
309
-
default = "";
310
310
-
description = ''
311
311
-
Defines the base domain to create the hostnames for MagicDNS.
312
312
-
This domain must be different from the {option}`server_url`
313
313
-
domain.
314
314
-
{option}`base_domain` must be a FQDN, without the trailing dot.
315
315
-
The FQDN of the hosts will be `hostname.base_domain` (e.g.
316
316
-
`myhost.tailnet.example.com`).
317
317
-
'';
318
318
-
example = "tailnet.example.com";
319
319
-
};
320
320
-
321
321
-
nameservers = {
322
322
-
global = lib.mkOption {
323
323
-
type = lib.types.listOf lib.types.str;
324
324
-
default = [ ];
325
325
-
description = ''
326
326
-
List of nameservers to pass to Tailscale clients.
327
327
-
'';
328
328
-
};
329
329
-
};
330
330
-
331
331
-
search_domains = lib.mkOption {
332
332
-
type = lib.types.listOf lib.types.str;
333
333
-
default = [ ];
334
334
-
description = ''
335
335
-
Search domains to inject to Tailscale clients.
336
336
-
'';
337
337
-
example = [ "mydomain.internal" ];
338
338
-
};
339
339
-
};
340
340
-
341
341
-
oidc = {
342
342
-
issuer = lib.mkOption {
343
343
-
type = lib.types.str;
344
344
-
default = "";
345
345
-
description = ''
346
346
-
URL to OpenID issuer.
347
347
-
'';
348
348
-
example = "https://openid.example.com";
349
349
-
};
350
350
-
351
351
-
client_id = lib.mkOption {
352
352
-
type = lib.types.str;
353
353
-
default = "";
354
354
-
description = ''
355
355
-
OpenID Connect client ID.
356
356
-
'';
357
357
-
};
358
358
-
359
359
-
client_secret_path = lib.mkOption {
360
360
-
type = lib.types.nullOr lib.types.str;
361
361
-
default = null;
362
362
-
description = ''
363
363
-
Path to OpenID Connect client secret file. Expands environment variables in format ''${VAR}.
364
364
-
'';
365
365
-
};
366
366
-
367
367
-
scope = lib.mkOption {
368
368
-
type = lib.types.listOf lib.types.str;
369
369
-
default = [
370
370
-
"openid"
371
371
-
"profile"
372
372
-
"email"
373
373
-
];
374
374
-
description = ''
375
375
-
Scopes used in the OIDC flow.
376
376
-
'';
377
377
-
};
378
378
-
379
379
-
extra_params = lib.mkOption {
380
380
-
type = lib.types.attrsOf lib.types.str;
381
381
-
default = { };
382
382
-
description = ''
383
383
-
Custom query parameters to send with the Authorize Endpoint request.
384
384
-
'';
385
385
-
example = {
386
386
-
domain_hint = "example.com";
387
387
-
};
388
388
-
};
389
389
-
390
390
-
allowed_domains = lib.mkOption {
391
391
-
type = lib.types.listOf lib.types.str;
392
392
-
default = [ ];
393
393
-
description = ''
394
394
-
Allowed principal domains. if an authenticated user's domain
395
395
-
is not in this list authentication request will be rejected.
396
396
-
'';
397
397
-
example = [ "example.com" ];
398
398
-
};
399
399
-
400
400
-
allowed_users = lib.mkOption {
401
401
-
type = lib.types.listOf lib.types.str;
402
402
-
default = [ ];
403
403
-
description = ''
404
404
-
Users allowed to authenticate even if not in allowedDomains.
405
405
-
'';
406
406
-
example = [ "alice@example.com" ];
407
407
-
};
408
408
-
};
409
409
-
410
410
-
tls_letsencrypt_hostname = lib.mkOption {
411
411
-
type = lib.types.nullOr lib.types.str;
412
412
-
default = "";
413
413
-
description = ''
414
414
-
Domain name to request a TLS certificate for.
415
415
-
'';
416
416
-
};
417
417
-
418
418
-
tls_letsencrypt_challenge_type = lib.mkOption {
419
419
-
type = lib.types.enum [
420
420
-
"TLS-ALPN-01"
421
421
-
"HTTP-01"
422
422
-
];
423
423
-
default = "HTTP-01";
424
424
-
description = ''
425
425
-
Type of ACME challenge to use, currently supported types:
426
426
-
`HTTP-01` or `TLS-ALPN-01`.
427
427
-
'';
428
428
-
};
429
429
-
430
430
-
tls_letsencrypt_listen = lib.mkOption {
431
431
-
type = lib.types.nullOr lib.types.str;
432
432
-
default = ":http";
433
433
-
description = ''
434
434
-
When HTTP-01 challenge is chosen, letsencrypt must set up a
435
435
-
verification endpoint, and it will be listening on:
436
436
-
`:http = port 80`.
437
437
-
'';
438
438
-
};
439
439
-
440
440
-
tls_cert_path = lib.mkOption {
441
441
-
type = lib.types.nullOr lib.types.path;
442
442
-
default = null;
443
443
-
description = ''
444
444
-
Path to already created certificate.
445
445
-
'';
446
446
-
};
447
447
-
448
448
-
tls_key_path = lib.mkOption {
449
449
-
type = lib.types.nullOr lib.types.path;
450
450
-
default = null;
451
451
-
description = ''
452
452
-
Path to key for already created certificate.
453
453
-
'';
454
454
-
};
455
455
-
456
456
-
policy = {
457
457
-
mode = lib.mkOption {
458
458
-
type = lib.types.enum [
459
459
-
"file"
460
460
-
"database"
461
461
-
];
462
462
-
default = "file";
463
463
-
description = ''
464
464
-
The mode can be "file" or "database" that defines
465
465
-
where the ACL policies are stored and read from.
466
466
-
'';
467
467
-
};
468
468
-
469
469
-
path = lib.mkOption {
470
470
-
type = lib.types.nullOr lib.types.path;
471
471
-
default = null;
472
472
-
description = ''
473
473
-
If the mode is set to "file", the path to a
474
474
-
HuJSON file containing ACL policies.
475
475
-
'';
476
476
-
};
477
477
-
};
478
478
-
};
479
479
-
};
480
480
-
};
481
481
-
};
482
482
-
};
483
483
-
484
484
-
imports = with lib; [
485
485
-
(mkRenamedOptionModule
486
486
-
[ "services" "headscale" "derp" "autoUpdate" ]
487
487
-
[ "services" "headscale" "settings" "derp" "auto_update_enable" ]
488
488
-
)
489
489
-
(mkRenamedOptionModule
490
490
-
[ "services" "headscale" "derp" "paths" ]
491
491
-
[ "services" "headscale" "settings" "derp" "paths" ]
492
492
-
)
493
493
-
(mkRenamedOptionModule
494
494
-
[ "services" "headscale" "derp" "updateFrequency" ]
495
495
-
[ "services" "headscale" "settings" "derp" "update_frequency" ]
496
496
-
)
497
497
-
(mkRenamedOptionModule
498
498
-
[ "services" "headscale" "derp" "urls" ]
499
499
-
[ "services" "headscale" "settings" "derp" "urls" ]
500
500
-
)
501
501
-
(mkRenamedOptionModule
502
502
-
[ "services" "headscale" "ephemeralNodeInactivityTimeout" ]
503
503
-
[ "services" "headscale" "settings" "ephemeral_node_inactivity_timeout" ]
504
504
-
)
505
505
-
(mkRenamedOptionModule
506
506
-
[ "services" "headscale" "logLevel" ]
507
507
-
[ "services" "headscale" "settings" "log" "level" ]
508
508
-
)
509
509
-
(mkRenamedOptionModule
510
510
-
[ "services" "headscale" "openIdConnect" "clientId" ]
511
511
-
[ "services" "headscale" "settings" "oidc" "client_id" ]
512
512
-
)
513
513
-
(mkRenamedOptionModule
514
514
-
[ "services" "headscale" "openIdConnect" "clientSecretFile" ]
515
515
-
[ "services" "headscale" "settings" "oidc" "client_secret_path" ]
516
516
-
)
517
517
-
(mkRenamedOptionModule
518
518
-
[ "services" "headscale" "openIdConnect" "issuer" ]
519
519
-
[ "services" "headscale" "settings" "oidc" "issuer" ]
520
520
-
)
521
521
-
(mkRenamedOptionModule
522
522
-
[ "services" "headscale" "serverUrl" ]
523
523
-
[ "services" "headscale" "settings" "server_url" ]
524
524
-
)
525
525
-
(mkRenamedOptionModule
526
526
-
[ "services" "headscale" "tls" "certFile" ]
527
527
-
[ "services" "headscale" "settings" "tls_cert_path" ]
528
528
-
)
529
529
-
(mkRenamedOptionModule
530
530
-
[ "services" "headscale" "tls" "keyFile" ]
531
531
-
[ "services" "headscale" "settings" "tls_key_path" ]
532
532
-
)
533
533
-
(mkRenamedOptionModule
534
534
-
[ "services" "headscale" "tls" "letsencrypt" "challengeType" ]
535
535
-
[ "services" "headscale" "settings" "tls_letsencrypt_challenge_type" ]
536
536
-
)
537
537
-
(mkRenamedOptionModule
538
538
-
[ "services" "headscale" "tls" "letsencrypt" "hostname" ]
539
539
-
[ "services" "headscale" "settings" "tls_letsencrypt_hostname" ]
540
540
-
)
541
541
-
(mkRenamedOptionModule
542
542
-
[ "services" "headscale" "tls" "letsencrypt" "httpListen" ]
543
543
-
[ "services" "headscale" "settings" "tls_letsencrypt_listen" ]
544
544
-
)
545
545
-
546
546
-
(mkRemovedOptionModule [ "services" "headscale" "openIdConnect" "domainMap" ] ''
547
547
-
Headscale no longer uses domain_map. If you're using an old version of headscale you can still set this option via services.headscale.settings.oidc.domain_map.
548
548
-
'')
549
549
-
];
550
550
-
551
551
-
config = lib.mkIf cfg.enable {
552
552
-
assertions = [
553
553
-
{
554
554
-
assertion = with cfg.settings; dns.magic_dns -> dns.base_domain != "";
555
555
-
message = "dns.base_domain must be set when using MagicDNS";
556
556
-
}
557
557
-
(assertRemovedOption [ "settings" "acl_policy_path" ] "Use `policy.path` instead.")
558
558
-
(assertRemovedOption [ "settings" "db_host" ] "Use `database.postgres.host` instead.")
559
559
-
(assertRemovedOption [ "settings" "db_name" ] "Use `database.postgres.name` instead.")
560
560
-
(assertRemovedOption [
561
561
-
"settings"
562
562
-
"db_password_file"
563
563
-
] "Use `database.postgres.password_file` instead.")
564
564
-
(assertRemovedOption [ "settings" "db_path" ] "Use `database.sqlite.path` instead.")
565
565
-
(assertRemovedOption [ "settings" "db_port" ] "Use `database.postgres.port` instead.")
566
566
-
(assertRemovedOption [ "settings" "db_type" ] "Use `database.type` instead.")
567
567
-
(assertRemovedOption [ "settings" "db_user" ] "Use `database.postgres.user` instead.")
568
568
-
(assertRemovedOption [ "settings" "dns_config" ] "Use `dns` instead.")
569
569
-
(assertRemovedOption [ "settings" "dns_config" "domains" ] "Use `dns.search_domains` instead.")
570
570
-
(assertRemovedOption [
571
571
-
"settings"
572
572
-
"dns_config"
573
573
-
"nameservers"
574
574
-
] "Use `dns.nameservers.global` instead.")
575
575
-
];
576
576
-
577
577
-
services.headscale.settings = lib.mkMerge [
578
578
-
cliConfig
579
579
-
{
580
580
-
listen_addr = lib.mkDefault "${cfg.address}:${toString cfg.port}";
581
581
-
582
582
-
tls_letsencrypt_cache_dir = "${dataDir}/.cache";
583
583
-
}
584
584
-
];
585
585
-
586
586
-
environment = {
587
587
-
# Headscale CLI needs a minimal config to be able to locate the unix socket
588
588
-
# to talk to the server instance.
589
589
-
etc."headscale/config.yaml".source = cliConfigFile;
590
590
-
591
591
-
systemPackages = [ cfg.package ];
592
592
-
};
593
593
-
594
594
-
users.groups.headscale = lib.mkIf (cfg.group == "headscale") { };
595
595
-
596
596
-
users.users.headscale = lib.mkIf (cfg.user == "headscale") {
597
597
-
description = "headscale user";
598
598
-
home = dataDir;
599
599
-
group = cfg.group;
600
600
-
isSystemUser = true;
601
601
-
};
602
602
-
603
603
-
systemd.services.headscale = {
604
604
-
description = "headscale coordination server for Tailscale";
605
605
-
wants = [ "network-online.target" ];
606
606
-
after = [ "network-online.target" ];
607
607
-
wantedBy = [ "multi-user.target" ];
608
608
-
609
609
-
script = ''
610
610
-
${lib.optionalString (cfg.settings.database.postgres.password_file != null) ''
611
611
-
export HEADSCALE_DATABASE_POSTGRES_PASS="$(head -n1 ${lib.escapeShellArg cfg.settings.database.postgres.password_file})"
612
612
-
''}
613
613
-
614
614
-
exec ${lib.getExe cfg.package} serve --config ${configFile}
615
615
-
'';
616
616
-
617
617
-
serviceConfig =
618
618
-
let
619
619
-
capabilityBoundingSet = [ "CAP_CHOWN" ] ++ lib.optional (cfg.port < 1024) "CAP_NET_BIND_SERVICE";
620
620
-
in
621
621
-
{
622
622
-
Restart = "always";
623
623
-
Type = "simple";
624
624
-
User = cfg.user;
625
625
-
Group = cfg.group;
626
626
-
627
627
-
# Hardening options
628
628
-
RuntimeDirectory = "headscale";
629
629
-
# Allow headscale group access so users can be added and use the CLI.
630
630
-
RuntimeDirectoryMode = "0750";
631
631
-
632
632
-
StateDirectory = "headscale";
633
633
-
StateDirectoryMode = "0750";
634
634
-
635
635
-
ProtectSystem = "strict";
636
636
-
ProtectHome = true;
637
637
-
PrivateTmp = true;
638
638
-
PrivateDevices = true;
639
639
-
ProtectKernelTunables = true;
640
640
-
ProtectControlGroups = true;
641
641
-
RestrictSUIDSGID = true;
642
642
-
PrivateMounts = true;
643
643
-
ProtectKernelModules = true;
644
644
-
ProtectKernelLogs = true;
645
645
-
ProtectHostname = true;
646
646
-
ProtectClock = true;
647
647
-
ProtectProc = "invisible";
648
648
-
ProcSubset = "pid";
649
649
-
RestrictNamespaces = true;
650
650
-
RemoveIPC = true;
651
651
-
UMask = "0077";
652
652
-
653
653
-
CapabilityBoundingSet = capabilityBoundingSet;
654
654
-
AmbientCapabilities = capabilityBoundingSet;
655
655
-
NoNewPrivileges = true;
656
656
-
LockPersonality = true;
657
657
-
RestrictRealtime = true;
658
658
-
SystemCallFilter = [
659
659
-
"@system-service"
660
660
-
"~@privileged"
661
661
-
"@chown"
662
662
-
];
663
663
-
SystemCallArchitectures = "native";
664
664
-
RestrictAddressFamilies = "AF_INET AF_INET6 AF_UNIX";
665
665
-
};
666
666
-
};
667
667
-
};
668
668
-
669
669
-
meta.maintainers = with lib.maintainers; [
670
670
-
kradalby
671
671
-
misterio77
672
672
-
];
673
673
-
}
+5
-7
modules/nixos/logiops.nix
···
11
11
rendered-config = libconfig-format.generate "logid.cfg" cfg.settings;
12
12
in
13
13
{
14
14
-
options.services.logiops = with lib; {
15
15
-
enable = mkEnableOption (mdDoc "Logiops HID++ configuration");
14
14
+
options.services.logiops = {
15
15
+
enable = lib.mkEnableOption "Logiops HID++ configuration";
16
16
17
17
-
package = mkPackageOption pkgs "logiops" { };
17
17
+
package = lib.mkPackageOption pkgs "logiops_0_2_3" { };
18
18
19
19
-
settings = mkOption {
19
19
+
settings = lib.mkOption {
20
20
type = libconfig-format.type;
21
21
default = { };
22
22
example = {
···
54
54
];
55
55
}];
56
56
};
57
57
-
description = mdDoc ''
57
57
+
description = lib.mdDoc ''
58
58
Logid configuration. Refer to
59
59
[the `logiops` wiki](https://github.com/PixlOne/logiops/wiki/Configuration)
60
60
for details on supported values.
···
72
72
restartTriggers = [ rendered-config ];
73
73
};
74
74
};
75
75
-
76
76
-
meta.maintainers = with lib.maintainers; [ ckie ];
77
75
}
-2
nixos/fragments/logiops.nix
···
1
1
{ self
2
2
, config
3
3
, lib
4
4
-
, pkgs
5
4
, ...
6
5
}:
7
6
···
19
18
20
19
config.services.logiops = lib.mkIf cfg.enable {
21
20
enable = true;
22
22
-
package = pkgs.logiops_0_2_3;
23
21
24
22
settings =
25
23
let
+8
-9
nixos/fragments/security.nix
···
20
20
security.polkit.enable = true;
21
21
security.rtkit.enable = true;
22
22
23
23
-
# Systemd Login
24
24
-
services.logind = {
25
25
-
lidSwitch = "suspend";
26
26
-
extraConfig = lib.generators.toKeyValue { } {
27
27
-
IdleAction = "lock";
28
28
-
# Don’t shutdown when power button is short-pressed
29
29
-
HandlePowerKey = "lock";
30
30
-
HandlePowerKeyLongPress = "suspend";
31
31
-
};
23
23
+
# Systemd Login
24
24
+
services.logind.settings.Login = {
25
25
+
HandleLidSwitch = "suspend";
26
26
+
IdleAction = "lock";
27
27
+
# Don’t shutdown when power button is short-pressed
28
28
+
HandlePowerKey = "lock";
29
29
+
HandlePowerKeyLongPress = "suspend";
32
30
};
33
31
34
32
# `swaylock` pam service must be at least declared to work properly
···
40
38
# Signing
41
39
programs.gnupg.agent.enable = true;
42
40
services.gnome.gnome-keyring.enable = true;
41
41
+
services.gnome.gcr-ssh-agent.enable = false;
43
42
44
43
# SSH
45
44
services.openssh = {
+5
-18
nixos/profiles/laptop.nix
···
1
1
-
{ self
2
2
-
, config
1
1
+
{ config
3
2
, pkgs
4
3
, ...
5
4
}:
6
5
7
7
-
let
8
8
-
inherit (self.outputs) nixosModules;
9
9
-
in
10
6
{
11
11
-
imports = [
12
12
-
# Replaces nixpkgs module with a custom one that support fallback static location
13
13
-
nixosModules.geoclue2
14
14
-
];
15
15
-
16
7
config = {
17
8
local.fragment = {
18
9
agenix.enable = true;
···
42
33
kernel.sysctl."kernel.perf_event_paranoid" = -1;
43
34
44
35
kernelPackages = pkgs.linuxKernel.packages.linux_zen;
45
45
-
extraModulePackages = with config.boot.kernelPackages; [ perf xone ];
36
36
+
extraModulePackages = with config.boot.kernelPackages; [ xone ];
46
37
47
38
loader = {
48
39
systemd-boot.enable = true;
···
56
47
57
48
# Once in a while, the session stop job hangs and lasts the full default
58
49
# time (1min30). I just want to shutdown my computer please.
59
59
-
systemd.extraConfig = ''
60
60
-
DefaultTimeoutStopSec = 10s
61
61
-
'';
50
50
+
systemd.settings.Manager.DefaultTimeoutStopSec = "10s";
62
51
63
52
programs.dconf.enable = true;
64
53
···
86
75
};
87
76
};
88
77
89
89
-
programs.command-not-found.enable = false;
90
90
-
91
78
# This is needed for services like `darkman` and `gammastep`
92
79
services.geoclue2 = {
93
80
enable = true;
94
81
95
95
-
# Fallback using custom geoclue2 module waitng for an alternative to MLS
82
82
+
# Fallback using custom geoclue2 module waiting for an alternative to MLS
96
83
# (Mozilla Location Services). See related module in repo.
97
84
# INFO: lat vvvv vvv long → Paris rough location
98
98
-
staticFile = "48.8\n2.3\n0\n0\n";
85
85
+
# staticFile = "48.8\n2.3\n0\n0\n";
99
86
};
100
87
101
88
programs.wireshark = {
+6
-13
nixos/profiles/server.nix
···
1
1
{ self
2
2
, config
3
3
, pkgs
4
4
-
, upkgs
5
4
, ...
6
5
}:
7
6
8
7
let
9
9
-
inherit (self.inputs) unixpkgs srvos hypixel-bank-tracker tangled;
8
8
+
inherit (self.inputs) srvos hypixel-bank-tracker tangled;
10
9
11
10
json-format = pkgs.formats.json { };
12
11
···
100
99
authelia-metrics-port = 9004;
101
100
in
102
101
{
103
103
-
disabledModules = [ "services/networking/headscale.nix" ];
104
104
-
105
102
imports = [
106
103
srvos.nixosModules.server
107
104
srvos.nixosModules.hardware-hetzner-cloud
108
105
srvos.nixosModules.mixins-terminfo
109
106
110
110
-
self.nixosModules.headscale
111
111
-
112
107
hypixel-bank-tracker.nixosModules.default
113
108
114
109
tangled.nixosModules.knot
115
110
tangled.nixosModules.spindle
116
116
-
117
117
-
"${unixpkgs}/nixos/modules/services/matrix/tuwunel.nix"
118
111
];
119
112
120
113
config = {
···
296
289
};
297
290
298
291
age.secrets.pds-env.file = ../../secrets/pds-env.age;
299
299
-
services.pds = {
292
292
+
services.bluesky-pds = {
300
293
enable = true;
301
301
-
package = upkgs.bluesky-pds;
302
294
303
295
settings = {
304
296
PDS_HOSTNAME = "pds.wiro.world";
···
413
405
# TODO: add dependency on authelia
414
406
services.headscale = {
415
407
enable = true;
416
416
-
package = upkgs.headscale;
417
408
418
409
port = headscale-port;
419
410
settings = {
···
469
460
};
470
461
471
462
age.secrets.lldap-env.file = ../../secrets/lldap-env.age;
463
463
+
age.secrets.lldap-user-pass = { file = ../../secrets/lldap-user-pass.age; };
472
464
services.lldap = {
473
465
enable = true;
474
466
settings = {
475
467
http_url = "https://${lldap-hostname}";
476
468
http_port = lldap-port;
477
469
470
470
+
ldap_user_pass_file = config.age.secrets.lldap-user-pass.path;
471
471
+
force_ldap_user_pass_reset = "always";
472
472
+
478
473
ldap_base_dn = "dc=wiro,dc=world";
479
474
};
480
475
environmentFile = config.age.secrets.lldap-env.path;
···
624
619
age.secrets.tuwunel-registration-tokens = { file = ../../secrets/tuwunel-registration-tokens.age; owner = config.services.matrix-tuwunel.user; };
625
620
services.matrix-tuwunel = {
626
621
enable = true;
627
627
-
package = upkgs.matrix-tuwunel;
628
622
629
623
settings.global = {
630
624
address = [ "127.0.0.1" ];
···
655
649
age.secrets.vaultwarden-env.file = ../../secrets/vaultwarden-env.age;
656
650
services.vaultwarden = {
657
651
enable = true;
658
658
-
package = upkgs.vaultwarden;
659
652
660
653
environmentFile = config.age.secrets.vaultwarden-env.path;
661
654
config = {
+13
-6
pkgs/default.nix
···
1
1
-
{ self, system, ... }@pkgs:
1
1
+
{ self
2
2
+
3
3
+
, stdenv
4
4
+
, callPackage
5
5
+
, ...
6
6
+
}:
2
7
3
8
let
9
9
+
inherit (stdenv.hostPlatform) system;
10
10
+
4
11
inherit (self.inputs)
5
12
agenix
6
13
git-leave
···
8
15
;
9
16
in
10
17
{
11
11
-
asak = pkgs.callPackage ./asak.nix { };
12
12
-
ebnfer = pkgs.callPackage ./ebnfer.nix { };
13
13
-
find-unicode = pkgs.callPackage ./find-unicode.nix { };
14
14
-
names = pkgs.callPackage ./names.nix { };
15
15
-
probe-rs-udev-rules = pkgs.callPackage ./probe-rs-udev-rules.nix { };
18
18
+
asak = callPackage ./asak.nix { };
19
19
+
ebnfer = callPackage ./ebnfer.nix { };
20
20
+
find-unicode = callPackage ./find-unicode.nix { };
21
21
+
names = callPackage ./names.nix { };
22
22
+
probe-rs-udev-rules = callPackage ./probe-rs-udev-rules.nix { };
16
23
17
24
# Import packages defined in foreign repositories
18
25
inherit (agenix.packages.${system}) agenix;
+10
-10
secrets/keys.nix
···
1
1
rec {
2
2
# Machine SSH key (/etc/ssh/ssh_host_ed25519_key.pub)
3
3
-
archaic = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJDuBHC0f7N0q1KRczJMoaBVdY0JFOtcpPy6WlYsoxUh";
4
4
-
neo = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINR1/9o1HLnSRkXt3xxAM5So1YCCNdJpBN1leSu7giuR";
5
5
-
systems = [ archaic neo ];
3
3
+
archaic-wiro-laptop = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJDuBHC0f7N0q1KRczJMoaBVdY0JFOtcpPy6WlYsoxUh";
4
4
+
neo-wiro-laptop = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINR1/9o1HLnSRkXt3xxAM5So1YCCNdJpBN1leSu7giuR";
5
5
+
systems = [ archaic-wiro-laptop neo-wiro-laptop ];
6
6
7
7
-
weird-row = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAII5sThvKuIj8yfeZzUPYfxWxnjTTdNtSID2OL4czE8AL";
8
8
-
servers = [ weird-row ];
7
7
+
weird-row-server = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAII5sThvKuIj8yfeZzUPYfxWxnjTTdNtSID2OL4czE8AL";
8
8
+
servers = [ weird-row-server ];
9
9
10
10
# Sessions specific age key (~/.ssh/id_home_manager.pub)
11
11
-
neo-milomoisson = "age1vz2zmduaqhaw5jrqh277pmp36plyth8rz5k9ccxeftfcl2nlhalqwvx5xz";
12
12
-
sessions = [ neo-milomoisson ];
11
11
+
neo-milo = "age1vz2zmduaqhaw5jrqh277pmp36plyth8rz5k9ccxeftfcl2nlhalqwvx5xz";
12
12
+
sessions = [ neo-milo ];
13
13
14
14
-
# User keys (~/.ssh/id_ed25519.pub)
15
15
-
milomoisson = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJdt7atyPTOfaBIsgDYYb0DG1yid2u78abaCDji6Uxgi";
14
14
+
# User keys (~/.ssh/id_{ed25519,ecdsa}.pub)
15
15
+
milo-ed25519 = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJdt7atyPTOfaBIsgDYYb0DG1yid2u78abaCDji6Uxgi";
16
16
wirody = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMdW6ijH9oTsrswUJmQBF2LQkhjrMFkJ1LktnirPuL2S";
17
17
-
users = [ milomoisson wirody ];
17
17
+
users = [ milo-ed25519 wirody ];
18
18
}
+11
secrets/lldap-user-pass.age
···
1
1
+
age-encryption.org/v1
2
2
+
-> ssh-ed25519 sMF1bg rkX6nxV4pATfwzkzJtI08/Z0bvi0wYwnLJsppUAsz20
3
3
+
X+znUc5AKAunPqr1jdq10obvQBU+rqs/LmeQaZzI+F4
4
4
+
-> ssh-ed25519 SmMcWg xaZtLP6GOocdiMf3hgoujWigGgi7KxDUMGuPYNqS8WU
5
5
+
00Y+8L4QssKFqRlGB2e0yiv9SyoqbxeZ/lWL6DCLlpo
6
6
+
-> ssh-ed25519 Q8rMFA kHA5wVVhmpodSn3OcZuc78xttymjOoy9voa8GqIE+F8
7
7
+
a7HpZf6sjmxr49QoV9tXrATheu8u20JmKCEIkmAZdhA
8
8
+
-> U=6S`1*-grease \8na]onc
9
9
+
PP5XQ1vbpadHeiMBOkmEccTIAg
10
10
+
--- 1hkJN6ZLX8GJ8y0WuFcMEv66om+Phc0wYJFKCB8Amzg
11
11
+
�M� ��}ޘ*;f��y��]����2ef���}�d������J�\��8�h��1�u� ������SHN��yS�D>W��x�J���yh������
+1
secrets/secrets.nix
···
21
21
"pds-env.age".publicKeys = deploy;
22
22
# Defines `LLDAP_JWT_SECRET`, `LLDAP_KEY_SEED`.
23
23
"lldap-env.age".publicKeys = deploy;
24
24
+
"lldap-user-pass.age".publicKeys = deploy;
24
25
"headscale-oidc-secret.age".publicKeys = deploy;
25
26
"grafana-oidc-secret.age".publicKeys = deploy;
26
27
"authelia-jwt-secret.age".publicKeys = deploy;
+1
-1
templates/blank/flake.nix
···
1
1
{
2
2
inputs = {
3
3
-
nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.05";
3
3
+
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
4
4
};
5
5
6
6
outputs = { self, nixpkgs }:
+1
-1
templates/c/flake.nix
···
1
1
{
2
2
inputs = {
3
3
-
nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.05";
3
3
+
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
4
4
};
5
5
6
6
outputs = { self, nixpkgs }:
+1
-1
templates/rust-pkg/flake.nix
···
1
1
{
2
2
inputs = {
3
3
-
nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.05";
3
3
+
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
4
4
5
5
rust-overlay.url = "github:oxalica/rust-overlay";
6
6
rust-overlay.inputs.nixpkgs.follows = "nixpkgs";
+1
-1
templates/rust/flake.nix
···
1
1
{
2
2
inputs = {
3
3
-
nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.05";
3
3
+
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
4
4
5
5
rust-overlay.url = "github:oxalica/rust-overlay";
6
6
rust-overlay.inputs.nixpkgs.follows = "nixpkgs";