Compare commits
1515 Commits
2024-12-26
...
master
Author | SHA1 | Date | |
---|---|---|---|
1c5c9b80eb | |||
94289c2253 | |||
0c443fae25 | |||
a490a74390 | |||
2e71e06c05 | |||
203832b5a8 | |||
1204f4db69 | |||
a4b114fce2 | |||
7e17eb4056 | |||
259d980a60 | |||
5488486944 | |||
969717b1fe | |||
7391e34f77 | |||
7f45077485 | |||
ceb7ccbc6d | |||
9d63ec5dd2 | |||
7ce93eae96 | |||
1277c73304 | |||
0550498cd1 | |||
023396a41e | |||
ebb335ef4c | |||
fbb0046dda | |||
59d4197bf5 | |||
90e4e20274 | |||
7ecd368e20 | |||
79fc30da0e | |||
23f3647cc5 | |||
ad4910366d | |||
609becadfe | |||
3acabe60b6 | |||
87ec095b8a | |||
8831d8d1ac | |||
8b333a8887 | |||
028d903e9c | |||
dfed5f070b | |||
b29ee5ac03 | |||
e700ff392f | |||
91578c0b78 | |||
b35656c9ae | |||
726281a6dd | |||
f305027678 | |||
2b69c07d12 | |||
544b1e58e0 | |||
34c2d4f66f | |||
4addf857b7 | |||
a3f6c148d3 | |||
43a0abd68f | |||
b3c4e96d6e | |||
ade5ce5339 | |||
e543034fcb | |||
b5d96ed17b | |||
003ce70cd7 | |||
04f6964711 | |||
63cf19f839 | |||
806a1aa294 | |||
35a023f449 | |||
f0aec4416c | |||
e0bb1b7c62 | |||
9847e0171c | |||
03a1638628 | |||
f7327bef3e | |||
47fb8296db | |||
b409fbb5f7 | |||
84092395f4 | |||
![]() |
ffcdf08b20 | ||
faa0fd006a | |||
7c7780183a | |||
78be0fbd11 | |||
9a42a08910 | |||
09a027ef3f | |||
a54b476b12 | |||
98df75a449 | |||
d62788108b | |||
0b8807fb9e | |||
8588fc0ad0 | |||
7e671285ca | |||
844a838016 | |||
85ac4241d3 | |||
e515bf10c4 | |||
3e35c4ae85 | |||
10e005d8c8 | |||
61b30678c4 | |||
a1ba78c69f | |||
7ca9cd116f | |||
41e534fc66 | |||
e52e30990b | |||
190f50748a | |||
326b5ac98d | |||
0498ca9be3 | |||
9a0efcb8c2 | |||
4442fca519 | |||
fb0b7796b4 | |||
9060a426c2 | |||
4b5368d47e | |||
f659c358d9 | |||
7a0760440d | |||
bc89969a2c | |||
c767769b61 | |||
26acb7c4a7 | |||
9e7af6625e | |||
2ec26e9534 | |||
4dac9900b4 | |||
0f91fbe1ae | |||
38899ce392 | |||
f8eec18429 | |||
baabd39cb7 | |||
ca26af0278 | |||
7fd2c38ff1 | |||
df8b8eeb40 | |||
8a5443e50d | |||
464ec33aec | |||
7608534b25 | |||
2f7a7026c4 | |||
3b7d6d34c4 | |||
87f30b8fef | |||
ff13331fe6 | |||
981b79a00f | |||
b8d8a382d0 | |||
4eef8330e7 | |||
8b5284811d | |||
2184c17677 | |||
d64e955206 | |||
c4ae9d9e25 | |||
8dbb2fdbe3 | |||
8908394493 | |||
fb825b4630 | |||
d504e9216b | |||
c9261d1438 | |||
e3152da68c | |||
44da59ebee | |||
64a86d202c | |||
a4cb3ce359 | |||
3ff3d6b135 | |||
7ca476af97 | |||
a9091151e8 | |||
9641ffecbc | |||
d2d80d548b | |||
418f0dedeb | |||
59f45e3fc0 | |||
fcd479e35d | |||
225cbd1280 | |||
97e9d77add | |||
07bc8be439 | |||
f494698373 | |||
727f5fc8e6 | |||
1052649f5b | |||
ea624269c4 | |||
851b7fde8c | |||
a4630c21e0 | |||
55f06128ee | |||
da2c808194 | |||
cb2f1faafd | |||
22d3029c7c | |||
faeb311090 | |||
e1c85f111a | |||
2c8a9c4877 | |||
5d87480e60 | |||
8966c365cc | |||
3bc5a8f6c4 | |||
7cb342b1ab | |||
45fdb7badf | |||
29ee5efe24 | |||
a52f1f0f6a | |||
2d00c141e5 | |||
643b1ae661 | |||
23f13c24b7 | |||
a03ed72ea4 | |||
0f4854944c | |||
5b10ff1e1e | |||
1085978f99 | |||
62cf79e60d | |||
fb64d1ad50 | |||
a9301055a4 | |||
522365d498 | |||
3805f3f72d | |||
c5a574fe6a | |||
0b54c31b0c | |||
a69ff986cd | |||
2ba194e0a4 | |||
68889c364c | |||
5aafbb0dcb | |||
40fc2f9b9b | |||
e2932f1364 | |||
9afeeb62fa | |||
1157215198 | |||
709d70a4d9 | |||
9a1fcf8038 | |||
5edc6ba067 | |||
394e4c42b4 | |||
162953b004 | |||
6c37bc38fa | |||
ae08bfc496 | |||
713a85b3d3 | |||
49d4a79d87 | |||
3e09196687 | |||
1730ecc98f | |||
755dc417ba | |||
74f59eb596 | |||
b08ab26ea1 | |||
afe4857a58 | |||
8f74778955 | |||
557adce795 | |||
7e704ce55d | |||
2dbe1df67e | |||
890cb72b58 | |||
d8cb9a3370 | |||
4c504dcdd6 | |||
e87bbdf6cd | |||
f7a08ae2a0 | |||
c7fc738c85 | |||
385da61255 | |||
bfbd5624fc | |||
5a6dbada11 | |||
e9e9c044bf | |||
709edab85d | |||
05d46ad870 | |||
3eefd4ced1 | |||
a42c5362bf | |||
c2cd4dd71c | |||
4ec5eb1e88 | |||
0244242991 | |||
f9c72b6c58 | |||
1ae307c8f4 | |||
97dfb58bbb | |||
00acccb9c9 | |||
181578384d | |||
011c428c08 | |||
e2a183e8d3 | |||
7b66e2f0e2 | |||
45d98d4517 | |||
7cb91731be | |||
47ce18fbfb | |||
0758697534 | |||
5552decca6 | |||
42546baadc | |||
11ada7d35d | |||
32946c35d9 | |||
c2ab6748c4 | |||
d54eff32a7 | |||
4d20be490a | |||
91771b7bef | |||
55d23c92c0 | |||
0066b11754 | |||
96373e7eaf | |||
1afe5c3ba7 | |||
eeb2248831 | |||
d887e86c18 | |||
fff1488761 | |||
005dddfb8f | |||
30b0ba1a52 | |||
b41e29ac30 | |||
4dcc565c6c | |||
76c16deae1 | |||
457beaca20 | |||
179c3a7ad7 | |||
509208e305 | |||
9c4f6f5bd8 | |||
a40a9dcfcc | |||
26469d5a11 | |||
ae2f2c47a4 | |||
91133e096a | |||
a5223320af | |||
e32c9d42d9 | |||
52261d5bc3 | |||
99c4c4d043 | |||
de95f45cb9 | |||
ed311f902b | |||
f2a0dd4e8f | |||
fcd92407d7 | |||
5b7c93b490 | |||
1b4a6a53e6 | |||
b1cdf9b63e | |||
1411add8ba | |||
58b87e32e3 | |||
eb304c6b61 | |||
2db59f380c | |||
2691e3a8eb | |||
9f8193787f | |||
b43328f233 | |||
b45f3ea7db | |||
afbed1e18d | |||
3068ac35b7 | |||
6c4a6a596f | |||
913dfbd798 | |||
f49ce4b2fd | |||
496b2a10b4 | |||
9f8df5db63 | |||
6f590899bb | |||
f8d2dbca62 | |||
3b458d5337 | |||
3b9fd0a548 | |||
4ef705d143 | |||
233320e3a1 | |||
1a89305f18 | |||
3b8b227c09 | |||
5eb620d521 | |||
8fc16eaf39 | |||
fa38f70079 | |||
aed191b255 | |||
02fe7e02c2 | |||
0aaf453ba7 | |||
dd12514486 | |||
d0eb5851d5 | |||
2fc1baebd6 | |||
8477e51538 | |||
e016ed9272 | |||
e311e0e757 | |||
e6f724a54c | |||
bd735d4400 | |||
2d8dcb600c | |||
62a5711a2a | |||
bdbc632e1e | |||
e25d8a29b9 | |||
504a13832f | |||
a95bbd23b4 | |||
e2bb663c8e | |||
04e4d9ed23 | |||
44d83ffdfd | |||
ee92770d11 | |||
f39978ee43 | |||
96a18c86dd | |||
d426a9e9e8 | |||
96d3e3fcca | |||
a84d48d601 | |||
7e882212c4 | |||
bde9114ce9 | |||
d7a1859b97 | |||
958f8ef0c9 | |||
d37543e9e9 | |||
88454ff073 | |||
0c791e30a0 | |||
e4c6c01f8d | |||
87ce176081 | |||
0f29c667aa | |||
d7f3b7bcff | |||
009691212c | |||
82e049d99d | |||
17cdbb12d2 | |||
c1edaf792a | |||
36869a94b9 | |||
d669e66ffa | |||
2fcf88b89b | |||
023f006eb5 | |||
bdd012fa43 | |||
cbcb43ac2c | |||
fde708e602 | |||
e4fc268c24 | |||
5f829789fd | |||
28a13219be | |||
36f2bcd80c | |||
1b181755c7 | |||
ef68078de6 | |||
d35ef1be32 | |||
ad2a555256 | |||
87908fdf03 | |||
f079b3d920 | |||
82f7580d4c | |||
df63240580 | |||
e8c5dda396 | |||
127d731892 | |||
f2a1aafcc6 | |||
1f3957bcc4 | |||
fdbdf826d3 | |||
f66920854a | |||
33263c27ff | |||
25aa82b038 | |||
fbce38a47a | |||
604599b3b6 | |||
cf38651e8d | |||
48bd6d304f | |||
d5711e7de7 | |||
5e3854595e | |||
9f3cf94a0e | |||
bec6b6ed72 | |||
fdf2b5327e | |||
b7daf1ad04 | |||
b454a5a34f | |||
ae29f3066b | |||
70b1dda0a1 | |||
960ac80ba4 | |||
214df43af2 | |||
d67169aa13 | |||
019991cf1e | |||
c4f25ac198 | |||
831bddbcb6 | |||
4ac8805743 | |||
abd5e8a18d | |||
a6a1597f26 | |||
dede9e3ddb | |||
69ac264681 | |||
39fc431802 | |||
9b9a0fa953 | |||
85b41efc7e | |||
bd80c3b6f7 | |||
91624ba253 | |||
e52ae986b6 | |||
dead0a4b7c | |||
fc29c61ab7 | |||
7c0523f3e6 | |||
00fdcb7ec3 | |||
87fbeaa2bf | |||
3cd1bd2bff | |||
11f8127cc3 | |||
722c94d169 | |||
f1b8fd7a9d | |||
0c4d84de90 | |||
9ee805d2f4 | |||
ce7702fbb7 | |||
6a1bdeb3a9 | |||
a61a3afd73 | |||
728e97b122 | |||
558e9edc4b | |||
195e420181 | |||
dd2aee0e10 | |||
851071c8e1 | |||
73fcb27251 | |||
2e7f164738 | |||
689d9ead5a | |||
f1f0115e1b | |||
ecf90f3662 | |||
58ab12310a | |||
4ceab76cd1 | |||
a2634219bc | |||
cd6e128a6d | |||
a472f35775 | |||
0558eb71d4 | |||
5a7310759e | |||
7e84c7e237 | |||
d7f79ed7d9 | |||
ba9e4b95ba | |||
e1cc1570c7 | |||
ecfe480394 | |||
ca2e15c8c5 | |||
194151367c | |||
87d9415223 | |||
7d52b4210a | |||
3c1b1c2967 | |||
0b9e012bba | |||
aa7e60c415 | |||
70b0f3a100 | |||
1c268038b2 | |||
6d335a2122 | |||
cc37289967 | |||
1ee216f7b1 | |||
76ac917230 | |||
3ced6b5db9 | |||
b6a55de5bd | |||
f6b1754dd1 | |||
17b5cf31d1 | |||
67c314b96c | |||
7fefed160f | |||
d9c1a97ef6 | |||
dafa562f51 | |||
bf4e5bce27 | |||
059193d09a | |||
5365044412 | |||
8fb8d468f9 | |||
136abd88e0 | |||
dedd89bc43 | |||
e2b432f759 | |||
4dc007460d | |||
2e40a2cf0c | |||
8ace840d50 | |||
8aa2396c36 | |||
082db767af | |||
0220a3c22b | |||
0212be3ac8 | |||
ec8092a99d | |||
03c17dedd2 | |||
bd9d57c746 | |||
51203647d4 | |||
037e24e877 | |||
81c1db550f | |||
4703744aa1 | |||
7476f80cbe | |||
0261110fa5 | |||
34ea0a2756 | |||
d891dbce96 | |||
a5b5b58659 | |||
18b3877eaa | |||
751131bcb0 | |||
7c6d8e2da5 | |||
bb536e1a89 | |||
13800abfbe | |||
da88798ff2 | |||
8ddf1fce66 | |||
fbc2a06ab9 | |||
dd93ccd26f | |||
b6c638ac0b | |||
e241a1f78f | |||
42e863cb93 | |||
fb5f15e757 | |||
09fd2426e3 | |||
5fa2c56889 | |||
a76173c0ec | |||
e1bdd9fa0f | |||
2dafce82df | |||
d4e668e6fd | |||
af8f7c06ad | |||
6c11a90bff | |||
59d5d6592e | |||
8641ee16ad | |||
643e0f7bbc | |||
c2e686217c | |||
d4c9e47cff | |||
0b241ea4ab | |||
c944521cb2 | |||
d3cc96415b | |||
dabeadea09 | |||
f0126eae61 | |||
8f214ca89d | |||
ee3442567a | |||
5d956ce884 | |||
fa5122af8e | |||
1edf5b2d89 | |||
58e72a6457 | |||
8238ac10f5 | |||
c739e94658 | |||
85fb7b04d0 | |||
93d68e494f | |||
6f4e96145a | |||
a93e226058 | |||
980a62ecfc | |||
3d90e2a606 | |||
c83b5fc771 | |||
7c27e27e27 | |||
024fbd48a2 | |||
5ec78adf11 | |||
cfc08dc06c | |||
331cbaf926 | |||
5aed77b30d | |||
2c25c54a7e | |||
57711561d6 | |||
1f779320d0 | |||
7f57ead946 | |||
26eddd0eff | |||
d3bb04f84c | |||
a0a2f60b44 | |||
69c9b6badc | |||
9b3451f380 | |||
12584bcfde | |||
b87fdc2ae1 | |||
a730800d76 | |||
7b62be4fa8 | |||
d39a4e38c3 | |||
a6a55dca21 | |||
4ad9192444 | |||
c08af9e96f | |||
3765e24f16 | |||
ff667bc576 | |||
81201a97ba | |||
d86d32bb55 | |||
feaf2ead69 | |||
f811ac3a99 | |||
9e74337e2d | |||
9886f95e62 | |||
38074e0a95 | |||
881ddbc2f2 | |||
8d76f4ccae | |||
3bff1fd013 | |||
5acacb78fb | |||
3c71e2f363 | |||
e2b4f317fb | |||
2e4a6f061e | |||
80c8131120 | |||
e7ce064c69 | |||
f206a15f29 | |||
7818b14b49 | |||
40d63c837f | |||
dea48bf34b | |||
0951725e36 | |||
503cc832d4 | |||
f7b872aba0 | |||
8b152137f6 | |||
2eeb9a2ace | |||
bfae7cd4e9 | |||
cb79156d24 | |||
57694a732d | |||
51ee4826a5 | |||
0762c0aa20 | |||
aeeed83b8b | |||
01438ff7bb | |||
1db734375a | |||
65f3c3d8bd | |||
bc25feab80 | |||
19a14cc8ad | |||
d4c576c2ae | |||
c50f4b1a5a | |||
78be5777cb | |||
c01656686d | |||
3a6d05bbf8 | |||
9b8603e505 | |||
bc293726ee | |||
8bce4b6fba | |||
26e9d73541 | |||
984bab8296 | |||
55586b578a | |||
d2054a55dd | |||
9c6c18f157 | |||
3fb1fa3dd9 | |||
d7c496eb28 | |||
0fdf4271f2 | |||
ffe0ba614b | |||
f12ec0fdeb | |||
02653f1792 | |||
241023a370 | |||
ecee0fe032 | |||
b88136fe31 | |||
788cc28063 | |||
a250a99b69 | |||
2509ea571f | |||
bdc56a20ce | |||
1929ef3458 | |||
81d3c2c469 | |||
7fba13c628 | |||
f4a8a94af8 | |||
98f505887e | |||
1d1fe1d9b5 | |||
be73029e54 | |||
4d3005ca5d | |||
72f4f6b1a0 | |||
bf3b383957 | |||
474de5c3d7 | |||
9c39b4346b | |||
899e84ca75 | |||
28ab943be4 | |||
d837278324 | |||
39ec9f5cfb | |||
6ddac6b3f2 | |||
66163f5e0c | |||
10831169d1 | |||
3ad397b6bc | |||
2991208cd9 | |||
8fa774e140 | |||
2384c3575e | |||
41f0bfde53 | |||
d4723795e6 | |||
37ed00f441 | |||
e91eafdfc3 | |||
ec276e013b | |||
0555516ebb | |||
3f14b7d364 | |||
18b98125ac | |||
4bd4f29759 | |||
bdb203bc5f | |||
04c2912450 | |||
b11e329351 | |||
ef4373f704 | |||
db9b5dcfeb | |||
15fcdfca2b | |||
6226818ad7 | |||
7c18c0d13b | |||
fe1a8b7d5e | |||
3ef40e9cb3 | |||
af3d16794f | |||
c52704b2ed | |||
a09b05bb49 | |||
7b74ccf192 | |||
74bb17316d | |||
65d1fa76e6 | |||
629de56f54 | |||
01812da816 | |||
c297bc733a | |||
28b69fd1f9 | |||
ff786421c5 | |||
f05ec619e3 | |||
b8e0ae4ed5 | |||
2484822b9d | |||
eabc087ebb | |||
d178f2f2f6 | |||
377f2c4a75 | |||
83855f7d6a | |||
92f68baaf9 | |||
82096288e2 | |||
2aa2af823d | |||
047543ca93 | |||
065e4f8fb8 | |||
0c286946d9 | |||
9078cf3acc | |||
5dca51f840 | |||
32ca4476c5 | |||
a9b165a63d | |||
9337436b71 | |||
e25a8a35e9 | |||
c0a788f750 | |||
ed59897119 | |||
5091786d9c | |||
55aa9b75f1 | |||
d5de32ddea | |||
c082154d58 | |||
bb67240055 | |||
cea680b727 | |||
61fb2666d0 | |||
e328ec8c3f | |||
d3c76f3a43 | |||
69cf3ae762 | |||
b39c3ec7de | |||
c4cdf5ee72 | |||
ec5bf7cc1f | |||
b11bb8d2f9 | |||
448389d888 | |||
e5cd484138 | |||
99826b7f1b | |||
d0327f8f73 | |||
90b27d36c9 | |||
1405d24a8e | |||
2ab16e97c2 | |||
414bbc7217 | |||
8beada36d2 | |||
6b55711f10 | |||
6b0771f1fe | |||
e865534903 | |||
f4e9a0aa02 | |||
a963d63ca8 | |||
07ecda1116 | |||
ffdb00ea19 | |||
014008472b | |||
340f91de3f | |||
6fef1bbd4b | |||
99629c9e09 | |||
9ec2c1a22a | |||
e7e6997472 | |||
f74a0bbaca | |||
c4824f8f78 | |||
9daacae794 | |||
a375393f2a | |||
7fc6bda614 | |||
7423177796 | |||
cce19c38d7 | |||
ba657ae647 | |||
997e901fee | |||
793e7fca09 | |||
fcfe45da92 | |||
0c6d279c54 | |||
15d2a8bf65 | |||
efd04b6601 | |||
1c739bd8ad | |||
098a5ac959 | |||
bfd0a97e8a | |||
030fe9596f | |||
56b8d82c42 | |||
471341447e | |||
2701b484e5 | |||
5ca30a2e43 | |||
8bd273e51b | |||
f86b1d2ef1 | |||
34a1cba331 | |||
97d789c52a | |||
c645a73e2e | |||
7e655c6451 | |||
e46ae9b9e5 | |||
c4d0ead5e1 | |||
39e9b4aa3e | |||
e561417c7c | |||
d361ac1b5f | |||
d0c772533b | |||
cc3e0e8fa0 | |||
0e198ad482 | |||
f8fb4b9ef4 | |||
22cf60914b | |||
3a9a3353a0 | |||
218e06a8a8 | |||
78f42f984d | |||
c0878f1717 | |||
7d8fbf64dc | |||
d8c692fc79 | |||
d4f308caca | |||
f0bb931ca9 | |||
48f8f1c4e4 | |||
d06b767f85 | |||
39a7556dbe | |||
cf59cfab26 | |||
b1b1c1dfc3 | |||
dabeb9bef9 | |||
3ca0b9ae28 | |||
4645e6389e | |||
451a620916 | |||
c3ca009d05 | |||
79048f5bd5 | |||
14dcd5bf0c | |||
66cfb61e6c | |||
1b35317f97 | |||
e17ed9a265 | |||
17de44c0af | |||
d841e6782f | |||
db862eac69 | |||
c32822cfa9 | |||
0587d33000 | |||
02d10168b6 | |||
cff611d7c1 | |||
7e8c31dc2f | |||
85f8706136 | |||
e99e2f5a6e | |||
bac24e6ceb | |||
acdf9b7f94 | |||
17cdca36ca | |||
86528b5fcc | |||
fbde0005d8 | |||
15de5234ef | |||
a4f177a125 | |||
3336dbf5ef | |||
810a62ae4d | |||
c8e1d7d8ba | |||
38624342bb | |||
2a126684af | |||
f725b7ef94 | |||
73aecebd08 | |||
912753d723 | |||
d3cc39a7f0 | |||
2b36019dfa | |||
4f558743e5 | |||
f9462216b8 | |||
d7fc1beb16 | |||
fc1c51174b | |||
92c3cde5cd | |||
5e68fe2df6 | |||
9e199a9f74 | |||
517d12c700 | |||
5ad27f2ec0 | |||
ac456501df | |||
419968daa2 | |||
2c6bf71111 | |||
c1e53b32ad | |||
a18046cd3b | |||
6d189bf813 | |||
a17df1c1e4 | |||
5de6d7f41a | |||
3a7cc40703 | |||
1334fba055 | |||
4ffa0ec4ee | |||
f23a924025 | |||
dc88ce74a9 | |||
dbb26cb983 | |||
bd2a360e90 | |||
2e288d6221 | |||
03bd34982e | |||
b1997b1ca2 | |||
84c5ef3ac9 | |||
ccca3aa3b6 | |||
3477794172 | |||
bf7900fded | |||
a12230e1f8 | |||
fab4a9ea8d | |||
69cccaa5f3 | |||
945b637cc2 | |||
e8a27b43a3 | |||
be83452c4a | |||
c0c01f355b | |||
e06b735bcb | |||
7319bd1528 | |||
11be114e1d | |||
7cf7555c7d | |||
bc8395a541 | |||
f7b4069631 | |||
c0afdf69b1 | |||
1b8d2daf20 | |||
8e12201ecc | |||
8ae22c246e | |||
fdbf53e6bb | |||
d2d302137c | |||
37f49fbf09 | |||
9c31fc5a0a | |||
46d1433606 | |||
3dfde24a84 | |||
6693333a84 | |||
a8a6cd2973 | |||
eaae50f9ef | |||
60c4a1b1bd | |||
a77810f8e7 | |||
670a744eca | |||
fbeb6881db | |||
cf82e414f7 | |||
dd93a1fc87 | |||
26bc04ecbf | |||
42290c23a1 | |||
2f5ad8e7b0 | |||
641ac8bea7 | |||
3eb5a0385b | |||
c907f6fcd6 | |||
e1d15b8adf | |||
35a9adeb11 | |||
826483d4c2 | |||
110fddc026 | |||
49c1fe2dba | |||
92384f4b51 | |||
c5fbfa824b | |||
3b7883fe0f | |||
30b4337f11 | |||
4cf73cc03a | |||
f3b16d33d6 | |||
d8b44d7263 | |||
022bc55575 | |||
7f9ab477e7 | |||
8c4b3c3a02 | |||
4dad4d9291 | |||
aaa80bfb82 | |||
a8c2414f19 | |||
8a262749e8 | |||
1c6054c720 | |||
0dcbdd4262 | |||
![]() |
0481a2f419 | ||
db12529df3 | |||
66001bd723 | |||
fbde8816e9 | |||
35539ca2ec | |||
b49fac6651 | |||
bfef88be88 | |||
9dc6e0f93d | |||
d721845258 | |||
a13feca385 | |||
a099279a7a | |||
b4745b0c87 | |||
8782b529fd | |||
be2d34d869 | |||
daff05855c | |||
67ea8ba8c3 | |||
850299db58 | |||
1d4191c838 | |||
920b277a93 | |||
36be5f8a95 | |||
13f70c4626 | |||
960c39966b | |||
45f05e89ed | |||
5e553585f4 | |||
31a884e27e | |||
ab9f7a8768 | |||
75c60c8cb6 | |||
1597e6569e | |||
f48ca3c77a | |||
b733a7e6cd | |||
513e8c04e8 | |||
a006ef19c2 | |||
c0bb4ffa2b | |||
c6bc94f19a | |||
bb04885d0a | |||
d3846fd6fb | |||
f47ce15fd9 | |||
734bb04212 | |||
d6bb231993 | |||
fb630af35a | |||
dc9b621fa1 | |||
38da1d9c5c | |||
392eeed937 | |||
eddf48e88e | |||
da0361d2df | |||
51077bffb1 | |||
5e02f8cff0 | |||
9413ac3c8c | |||
d7addb1568 | |||
81e8e68ee0 | |||
3ef1d9fc4e | |||
c26479a31a | |||
719ebfb52f | |||
02c9105d63 | |||
f838b65027 | |||
c557cb573b | |||
f455eca161 | |||
2c2fbab3d3 | |||
9fdc909f9f | |||
d8079369fb | |||
1a352aee4b | |||
b1cbe1be32 | |||
fcfa54e284 | |||
3d08c79b42 | |||
dbe8747b15 | |||
c0fc8f15aa | |||
9e8e0e5e36 | |||
26e86f80eb | |||
8e8725258f | |||
9434a178a3 | |||
e7e15c55dc | |||
43f3e165a9 | |||
f64525898d | |||
d1e4f46135 | |||
780fceb5ef | |||
29002c62fb | |||
ccf2d5baa1 | |||
bca2cea95f | |||
5e69dddcb7 | |||
93566f9e69 | |||
278488a089 | |||
7ebb88a40e | |||
f7fc3bd981 | |||
df5fdf54af | |||
4374bb2b3b | |||
abac2d3b03 | |||
a4c763356b | |||
3e2040f83f | |||
533dd469da | |||
cec0612a64 | |||
2747079373 | |||
4eec2cba7a | |||
bb646b1828 | |||
097618056b | |||
582168f570 | |||
b60f4c2778 | |||
e618eb4258 | |||
f0fbf78b1a | |||
9fcaba8bf3 | |||
6da4a5ab9d | |||
a21618cb9c | |||
fa4a2c84c8 | |||
1cc630b7bb | |||
7742e48af7 | |||
4ec928ea55 | |||
65cb6a027d | |||
bff5d5a757 | |||
47659f9649 | |||
a01b99c2dc | |||
e83bcd07f8 | |||
03635fcf31 | |||
617babafad | |||
6a14303395 | |||
b016f9e3ef | |||
6c1d93d344 | |||
615afdea01 | |||
080eff357a | |||
0c24119f0f | |||
0cc171734a | |||
d2623272ae | |||
f459f921b7 | |||
3d2a93a645 | |||
60a165cbb5 | |||
ce236f6c7a | |||
30fca5512c | |||
f66b37a84f | |||
7d92241678 | |||
17f3002b99 | |||
7e354ce52a | |||
6601efb5de | |||
54b2151a00 | |||
7169193cc4 | |||
662525d159 | |||
e7e70ce611 | |||
1b3cdd7905 | |||
a7b5c86f25 | |||
8685e11a13 | |||
cd48bdad93 | |||
f8d2e9a19c | |||
18a8c487a8 | |||
3c52d8a38f | |||
dcc497cfad | |||
c8b1f9d221 | |||
b528d75d31 | |||
7743428c9e | |||
d50321fa0d | |||
a36c4ee2ff | |||
889a02311d | |||
dca343daed | |||
3d3bd5e5b2 | |||
c9699b7bc4 | |||
65acb2be75 | |||
0987f2f8f7 | |||
b56366bf98 | |||
33f894674c | |||
4b0d0cd226 | |||
56c6e97f8f | |||
b51352bd98 | |||
9a7ce9501e | |||
ab5d291840 | |||
2a6e5e5c9b | |||
687141ee1f | |||
8bf9dec92f | |||
8886fa867e | |||
cfde788dc4 | |||
73d79e10e7 | |||
6c9766c96b | |||
4d8aef47dd | |||
6087334f39 | |||
db4751467f | |||
ff1d845fcd | |||
f279ea5cc1 | |||
b689ffded6 | |||
adcc3fd4eb | |||
3ff8b1750f | |||
38381b890b | |||
6a69d54de7 | |||
272f8e6b2c | |||
406defeaef | |||
29415aa88a | |||
5133664603 | |||
48b4a61e7b | |||
9b9d0760b4 | |||
d868f4fa15 | |||
1ff24f5664 | |||
1dc0d20c81 | |||
a65d738765 | |||
6f26d87e0d | |||
0dc62d7fe2 | |||
208a88b8ca | |||
8974dd082b | |||
fb9d7ad886 | |||
6770bd158e | |||
7de157564a | |||
5532ecc12d | |||
9ebaefe7c2 | |||
7df509603b | |||
1653fd36d7 | |||
70da2d6ec4 | |||
ba9aced5e4 | |||
83884c66dd | |||
9b1db9aa18 | |||
fc426b5c0b | |||
f6a21f1c56 | |||
951d905cca | |||
470664d1c4 | |||
7ee91765fc | |||
04328e7f2a | |||
2d7a06e8cd | |||
f07c3efff8 | |||
6768cad5c5 | |||
1597f68cf2 | |||
41dfe31800 | |||
e19b2d87f8 | |||
2544bb4d68 | |||
ca6c6f7b57 | |||
9b4ff72758 | |||
2ac61bfa14 | |||
d549f4a0eb | |||
b488eeaf1d | |||
a5d36ca633 | |||
af87c40b97 | |||
c926bfc765 | |||
13a2acfd70 | |||
bbefa924cf | |||
855522daec | |||
8393c6f823 | |||
90df599adf | |||
5b718799a5 | |||
e264c8dd21 | |||
8818f271cb | |||
0fd424306a | |||
075a089696 | |||
b18797bf98 | |||
ba7a931b18 | |||
284eeceee9 | |||
5b1fa9bf32 | |||
30637c3da2 | |||
58a6f7cfd9 | |||
15546f9b31 | |||
ab8699732a | |||
3c1a762c25 | |||
69297280eb | |||
3956a2f166 | |||
6ed1375069 | |||
8be329096e | |||
e2e58fae5e | |||
763bce7824 | |||
05e27a5af6 | |||
7ae39338b7 | |||
0bdc5b4a59 | |||
ca1b9294e5 | |||
4441e1609f | |||
47fb71d980 | |||
58b89e88fe | |||
69c41081a0 | |||
73ddbe22f0 | |||
072a98dce4 | |||
3080c34398 | |||
7c78ba5776 | |||
4615203f09 | |||
7116f3a954 | |||
fd000c6ad8 | |||
dc8bdf09ad | |||
ef54ea84dc | |||
6554c8ea52 | |||
9a87622ce6 | |||
97e65a55e2 | |||
574a00b431 | |||
4f633e8492 | |||
2f7c79e97f | |||
0dc7c06b72 | |||
cd6d40154c | |||
4d259e93b0 | |||
e5c1e02255 | |||
f596efab0e | |||
ad453264fb | |||
9a1d2cbda1 | |||
881573c28a | |||
eea9b47121 | |||
e7c52340ab | |||
e126aafa9b | |||
![]() |
a405850cf8 | ||
4f4c06f753 | |||
5fbb790902 | |||
55bfcf3116 | |||
1d42dccb6e | |||
1d28dac94f | |||
6a42b9125b | |||
e80c7e020a | |||
b5d30f989b | |||
dd9daa06a8 | |||
8160840bf2 | |||
d9a31ddff3 | |||
0448603731 | |||
989f321c53 | |||
64a2d60d89 | |||
ccd343f0b6 | |||
4be7222f98 | |||
e8ab744bcc | |||
cf001326cd | |||
e93d04c09e | |||
df0e072645 | |||
5f8f8a44ba | |||
de8a544acd | |||
06add1cc55 | |||
fc40b9671e | |||
68fc360586 | |||
5f79ddde03 | |||
13f38d6fd7 | |||
3b44f05af0 | |||
79d567cd01 | |||
6bb6e4319c | |||
4c72d1af8e | |||
9b0c90be7d | |||
3f7000f2f8 | |||
ffb08b1195 | |||
4fd4f6fa2f | |||
9e6eb1eb94 | |||
33108ea9e1 | |||
8153e5e033 | |||
04d1da8e39 | |||
1aad4622a7 | |||
6f6851f565 | |||
acb00e7f8a | |||
621cc83740 | |||
d399a824e4 | |||
ec77f8f6b9 | |||
d5226957bf | |||
0b1c94d4a3 | |||
64f23282e2 | |||
a530ee8ae4 | |||
87c58c312d | |||
dad4dd1860 | |||
b8e2205a15 | |||
9029127ea8 | |||
4134525019 | |||
e4fe5e0cd4 | |||
dc0ad5ed20 | |||
e4ba0d3c83 | |||
e7ce6a2ef6 | |||
16f4afbc60 | |||
21cb18885c | |||
a636e19198 | |||
0327d7072a | |||
396efcd357 | |||
79b4e5a652 | |||
233ee5be43 | |||
da2217f194 | |||
ab55adb52d | |||
d419a3cb08 | |||
ba38fbc4e5 | |||
925c0faa05 | |||
8ec309e33f | |||
bec429a04d | |||
77f62d247f | |||
f6cddfb7e8 | |||
290fd281b9 | |||
690abc305f | |||
e6d028b01d | |||
9733f8af7a | |||
203aa4b470 | |||
6542919831 | |||
5d42f5a6e5 | |||
a5054deef0 | |||
3ed2d08a77 | |||
e2775ea266 | |||
d077036bb6 | |||
7a149d8f2f | |||
44f05916f2 | |||
5a88a10a19 | |||
ac899b614b | |||
f1c7c32e84 | |||
9399fd0254 | |||
cb1a72cb71 | |||
6d5c75b38c | |||
6ba9743f05 | |||
2ffaf1f3d8 | |||
3dea4370d7 | |||
cebedc43c7 | |||
14d5910e79 | |||
45526bd583 | |||
a42bd18d14 | |||
b536a30919 | |||
ec71b0219a | |||
41b1ed0c31 | |||
9fbb9c0c07 | |||
f90faf4516 | |||
0d6ae1cc3a | |||
b40c5abaf4 | |||
063c897b43 | |||
63bba23ff2 | |||
214bd1e696 | |||
3d584cb07b | |||
6f0f54f0ae | |||
5f8d64cdb5 | |||
049011e7db | |||
40e2cbec2c | |||
65997c9f00 | |||
3c41a0bd29 | |||
88ef815717 | |||
3f0e2c5cb2 | |||
54a23fd109 | |||
ccb90e7e4e | |||
8ab56cbe8e | |||
f3fb303cbf | |||
85cdef4b4e | |||
5ed6df90c2 | |||
63281e5486 | |||
3debab9a7a | |||
de6845834f | |||
d99a2382ff | |||
2a1b0cc90c | |||
b9cfd504cc | |||
429bb604d7 | |||
bb32cadc4a | |||
fcaa2079e1 | |||
dba7949943 | |||
a368fb3fb2 | |||
37bb0cf076 | |||
1a59005cef | |||
2364e9a819 | |||
b9237d9c46 | |||
74deec9bbf | |||
34eb0ed749 | |||
47a433d42a | |||
c05771ba0b | |||
977859776b | |||
9bbd4f0887 | |||
742f1ab700 | |||
b2c0ca0b42 | |||
c1565efb2d | |||
83477b9e70 | |||
e8ef317468 | |||
a741962f1f | |||
080de3d9ce | |||
05f97dc836 | |||
dc54383632 | |||
78feb634ad | |||
5740718d08 | |||
a7010f597d | |||
ffa9153101 | |||
8374418abc | |||
8607f3c2fd | |||
7f1be0d933 | |||
8fbf0e416b | |||
73c7dbb27a | |||
ac9a44cb48 | |||
ffaba82483 | |||
e43ad983cd | |||
e0447581d4 | |||
4365babde2 | |||
ea9d42b778 | |||
ffd3ecd465 | |||
2b34ef8ba4 | |||
a46faff066 | |||
68c9cf7189 | |||
0738bc7395 | |||
cb8b7676b6 | |||
fe28340922 | |||
67e5a386a6 | |||
8a79c0e995 | |||
1ad46f7411 | |||
271ac808fa | |||
1d8b45f37a | |||
38a9c3baf4 | |||
9fccd2cf86 | |||
65633eea57 | |||
3bd57f7370 | |||
9f49a12dac | |||
df0ade9319 | |||
5b358c8460 | |||
9bb6866b85 | |||
8d30074c79 | |||
66bcd52341 | |||
09fbe8f64e | |||
219b18d157 | |||
630278dedb | |||
121e86e78b | |||
3988191739 | |||
ccca829c79 | |||
8e5dba2dc1 | |||
013ddec10c | |||
6c55b4ae1c | |||
f014a9066e | |||
b228ea123d | |||
cdbb128fbe | |||
162c3d16c6 | |||
de83d06f48 | |||
8d6b336100 | |||
616e4c645d | |||
4f2c14f341 | |||
b03b20f2f4 | |||
5ea4e07847 | |||
06840bde34 | |||
fe149e699e | |||
b1690b5d8c | |||
91d56a8538 | |||
ec816311f9 | |||
3fffc50975 | |||
23513e34f2 | |||
22a362ea4b | |||
d942498282 | |||
133f8703dc | |||
b40d2cc2a5 | |||
95839bfad8 | |||
7ad1ca4e6b | |||
07525a7000 | |||
35ce9a412d | |||
14b475a0a6 | |||
a3ebeb0543 | |||
7faa36b225 | |||
1721839c8d | |||
9b13717ecd | |||
5cae0edb12 | |||
4c56ea3e6b | |||
091de5c788 | |||
02669d3ef4 | |||
fa5fcaa2bf | |||
ff9b1538fe | |||
de1acf946d | |||
65da9bd004 | |||
0915957337 | |||
2a1d6fff08 | |||
365d9c2457 | |||
5644dde395 | |||
cce27f52fb | |||
d3a3231861 | |||
7f069b0f23 | |||
57ef42991e | |||
db45fabb9c | |||
8ac9ea4a91 | |||
94ffab5874 | |||
5814ae82fb | |||
865b6a0679 | |||
513fe937ba | |||
bac941d16a | |||
0df054fac4 | |||
52bc98741c | |||
9b9a1ba22a | |||
f22ffd1fda | |||
6878d3f65b | |||
93934eb609 | |||
884b99048f | |||
b4ff9eb4ae | |||
2f717dc770 | |||
35f24282c7 | |||
b005897d84 | |||
4260909d2d | |||
22f3a19165 | |||
66103854fa | |||
93f140e0e4 | |||
51e5f13c06 | |||
fd58ec6e24 | |||
5ae42ce797 | |||
3842c4204b | |||
2b9700d2a6 | |||
4f4538c44d | |||
27365ff602 | |||
f25eba7f37 | |||
7c857f39e6 | |||
0b9b9a8271 | |||
e803a5959f | |||
10429055f9 | |||
77dde6057c | |||
92584b351b | |||
713e7247b3 | |||
ee57b94658 | |||
3fc6571294 | |||
863468e402 | |||
1c87ef5625 | |||
cfc2a2fc80 | |||
3a09943a19 | |||
4cf3889d7a | |||
63cc309cfd | |||
a02be29c02 | |||
332c2b3493 | |||
737ac7329b | |||
54e6b62778 | |||
002286e1ea | |||
5a487c18db | |||
0de134e208 | |||
05a7bad26c | |||
c47f4179a0 | |||
6b0a78bee0 | |||
7093385f98 | |||
fee5c7042b | |||
4d54877776 | |||
fdf038bf90 | |||
3ed002ea88 | |||
0a9e5b9f68 | |||
2d989327f7 | |||
ce447cf674 | |||
2b1637652a | |||
64b7a75664 | |||
d18cd69536 | |||
da27a0e857 | |||
93782cd71c | |||
42ac5353f1 | |||
5c0418ac6a | |||
fc8a6a2144 | |||
acd20e23d9 | |||
424f61f782 | |||
d2540f97ee | |||
d7be319067 | |||
43df4e1574 | |||
2a6ed9adb9 | |||
925d49efcc | |||
3fe4831f89 | |||
38372c60a1 | |||
3815f069fa | |||
bd647bd62b | |||
4606b00b73 | |||
f7ee19042e | |||
4ad470469f |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,4 +1,5 @@
|
||||
.working
|
||||
/build
|
||||
/.working
|
||||
result
|
||||
result-*
|
||||
/secrets/local.nix
|
||||
|
15
.sops.yaml
15
.sops.yaml
@@ -1,10 +1,12 @@
|
||||
keys:
|
||||
- &user_desko_colin age1tnl4jfgacwkargzeqnhzernw29xx8mkv73xh6ufdyde6q7859slsnzf24x
|
||||
- &user_flowy_colin age1nw3z25gn6l8gxneqw43tp8d2354c83d9sn3r0dqy5tapakdwhyvse0j2cc
|
||||
- &user_lappy_colin age1j2pqnl8j0krdzk6npe93s4nnqrzwx978qrc0u570gzlamqpnje9sc8le2g
|
||||
- &user_servo_colin age1z8fauff34cdecr6sjkre260luzxcca05kpcwvhx988d306tpcejsp63znu
|
||||
- &user_moby_colin age1zsrsvd7j6l62fjxpfd2qnhqlk8wk4p8r0dtxpe4sdgnh2474095qdu7xj9
|
||||
- &host_crappy age1hl50ufuxnqy0jnk8fqeu4tclh4vte2xn2d59pxff0gun20vsmv5sp78chj
|
||||
- &host_desko age1vnw7lnfpdpjn62l3u5nyv5xt2c965k96p98kc43mcnyzpetrts9q54mc9v
|
||||
- &host_flowy age1azm6carlm6tdjup37u5dr40585vjujajev70u4glwd9sv7swa99sk6mswx
|
||||
- &host_lappy age1w7mectcjku6x3sd8plm8wkn2qfrhv9n6zhzlf329e2r2uycgke8qkf9dyn
|
||||
- &host_servo age1tzlyex2z6t88tg9h82943e39shxhmqeyr7ywhlwpdjmyqsndv3qq27x0rf
|
||||
- &host_moby age18vq5ktwgeaysucvw9t67drqmg5zd5c5k3le34yqxckkfj7wqdqgsd4ejmt
|
||||
@@ -13,11 +15,13 @@ creation_rules:
|
||||
key_groups:
|
||||
- age:
|
||||
- *user_desko_colin
|
||||
- *user_flowy_colin
|
||||
- *user_lappy_colin
|
||||
- *user_servo_colin
|
||||
- *user_moby_colin
|
||||
- *host_crappy
|
||||
- *host_desko
|
||||
- *host_flowy
|
||||
- *host_lappy
|
||||
- *host_servo
|
||||
- *host_moby
|
||||
@@ -25,6 +29,7 @@ creation_rules:
|
||||
key_groups:
|
||||
- age:
|
||||
- *user_desko_colin
|
||||
- *user_flowy_colin
|
||||
- *user_lappy_colin
|
||||
- *user_servo_colin
|
||||
- *host_servo
|
||||
@@ -32,18 +37,28 @@ creation_rules:
|
||||
key_groups:
|
||||
- age:
|
||||
- *user_desko_colin
|
||||
- *user_flowy_colin
|
||||
- *user_lappy_colin
|
||||
- *host_desko
|
||||
- path_regex: secrets/flowy*
|
||||
key_groups:
|
||||
- age:
|
||||
- *user_lappy_colin
|
||||
- *user_flowy_colin
|
||||
- *user_desko_colin
|
||||
- *host_flowy
|
||||
- path_regex: secrets/lappy*
|
||||
key_groups:
|
||||
- age:
|
||||
- *user_lappy_colin
|
||||
- *user_flowy_colin
|
||||
- *user_desko_colin
|
||||
- *host_lappy
|
||||
- path_regex: secrets/moby*
|
||||
key_groups:
|
||||
- age:
|
||||
- *user_desko_colin
|
||||
- *user_flowy_colin
|
||||
- *user_lappy_colin
|
||||
- *user_moby_colin
|
||||
- *host_moby
|
||||
|
48
TODO.md
48
TODO.md
@@ -1,5 +1,6 @@
|
||||
## BUGS
|
||||
- gnome-calls eats 100% CPU and never renders UI (moby AND lappy, at least)
|
||||
- alacritty Ctrl+N frequently fails to `cd` to the previous directory
|
||||
- bunpen dbus sandboxing can't be *nested* (likely a problem in xdg-dbus-proxy)
|
||||
- dissent has a memory leak (3G+ after 24hr)
|
||||
- set a max memory use in the systemd service, to force it to restart as it leaks?
|
||||
- `rmDbusServices` may break sandboxing
|
||||
@@ -8,7 +9,7 @@
|
||||
- mpv: audiocast has mpv sending its output to the builtin speakers unless manually changed
|
||||
- syshud (volume overlay): when casting with `blast`, syshud doesn't react to volume changes
|
||||
- dissent: if i launch it without net connectivity, it gets stuck at the login, and never tries again
|
||||
- newflash on moby can't play videos
|
||||
- newsflash on moby can't play videos
|
||||
- "open in browser" works though -- in mpv
|
||||
- gnome-maps can't use geoclue *and* openstreetmap at the same time
|
||||
- get gnome-maps to speak xdg-desktop-portal, and this will be fixed
|
||||
@@ -19,6 +20,12 @@
|
||||
- rsync to ssh target fails because of restrictive sandboxing
|
||||
- `/mnt/.servo_ftp` retries every 10s, endlessly, rather than doing a linear backoff
|
||||
- repro by `systemctl stop sftpgo` on servo, then watching `mnt-.servo_ftp.{mount,timer}` on desko
|
||||
- `ovpns` (and presumably `doof`) net namespaces aren't firewalled
|
||||
- not great because things like `bitmagnet` expose unprotected admin APIs by default!
|
||||
- moby: NetworkManager doesn't connect to network until _after_ `systemctl restart NetworkManager`
|
||||
- probably a dependency ordering issue
|
||||
- e.g. we try to bring up NetworkManager before bringing up `lo`
|
||||
- could be a perms issue (over-restrictive sandboxing)
|
||||
|
||||
## REFACTORING:
|
||||
- fold hosts/modules/ into toplevel modules/
|
||||
@@ -27,6 +34,10 @@
|
||||
- ~/dev becomes a link to ~/ref/cat/mine
|
||||
- fold hosts/common/home/ssh.nix -> hosts/common/users/colin.nix
|
||||
- don't hardcode IP addresses so much in servo
|
||||
- modules/netns: migrate `sane.netns.$NS.services = [ FOO ]` option to be `systemd.services.$FOO.sane.netns = NS`
|
||||
- then change the ExecStartPre check to not ping `ipinfo.net` or whatever.
|
||||
either port all of `sane-ip-check` to use a self-hosted reflector,
|
||||
or settle for something like `test -eq "$(ip route get ...)" "$expectedGateway"`
|
||||
|
||||
### sops/secrets
|
||||
- user secrets could just use `gocryptfs`, like with ~/private?
|
||||
@@ -36,27 +47,20 @@
|
||||
- upstream blueprint-compiler cross fixes -> nixpkgs
|
||||
- upstream cargo cross fixes -> nixpkgs
|
||||
- upstream `gps-share` package -> nixpkgs
|
||||
- upstream PinePhonePro device trees -> linux
|
||||
|
||||
#### upstreaming to non-nixpkgs repos
|
||||
- gnome-calls: retry net connection when DNS is down
|
||||
- gtk: build schemas even on cross compilation: <https://github.com/NixOS/nixpkgs/pull/247844>
|
||||
- gnome-calls retry net connection when DNS is down
|
||||
- linux: upstream PinePhonePro device trees
|
||||
- nwg-panel: configurable media controls
|
||||
- nwg-panel / playerctl hang fix (i think nwg-panel is what should be patched here)
|
||||
|
||||
|
||||
## IMPROVEMENTS:
|
||||
- lack of a mesa shader cache for sandboxed programs DESTROYS PERF
|
||||
- adding ~/.cache/mesa_shader_cache_db to the sandbox massively improves launch time,
|
||||
probably reduces memory use,
|
||||
but has unknown data leak implications.
|
||||
- either (1) pre-populate the shader cache somehow, e.g. <https://gitlab.freedesktop.org/mesa/shader-db>
|
||||
or (2) use a seperate shader cache per-app
|
||||
or (3) disable the mesa cache and see if that actually helps (MESA_SHADER_CACHE_DISABLE=true)
|
||||
- tmpfs usage inside bunpen apps is not introspectable/debuggable
|
||||
- app sandboxes could be rooted in, say, `/run/bunpen/$PID`
|
||||
- for a nested sandbox, its vfs could be queried from the root ns at `/run/bunpen/$PID1/run/bunpen/$PID2`
|
||||
- servo: expand /boot to 2 GiB like all other hosts
|
||||
- moby: port to systemd-boot
|
||||
- sane-deadlines: show day of the week for upcoming items
|
||||
- and only show on "first" terminal opened; not on Ctrl+N terminals
|
||||
- curlftpfs: replace with something better
|
||||
- safer (rust? actively maintained? sandboxable?)
|
||||
- handles spaces/symbols in filenames
|
||||
@@ -73,7 +77,6 @@
|
||||
- likely requires updating envelope to a more recent version (for multi-accounting), and therefore updating libadwaita...
|
||||
|
||||
### security/resilience
|
||||
- enable `snapper` btrfs snapshots (`services.snapper`)
|
||||
- /mnt/desko/home, etc, shouldn't include secrets (~/private)
|
||||
- 95% of its use is for remote media access and stuff which isn't in VCS (~/records)
|
||||
- harden systemd services:
|
||||
@@ -89,12 +92,7 @@
|
||||
- port all sane.programs to be sandboxed
|
||||
- sandbox `nix`
|
||||
- enforce that all `environment.packages` has a sandbox profile (or explicitly opts out)
|
||||
- lock down dbus calls within the sandbox
|
||||
- <https://github.com/flatpak/xdg-dbus-proxy>
|
||||
- stuff on dbus presents too much surface area
|
||||
- ~~for example anyone can `systemd-run --user ...` to potentially escape a sandbox~~
|
||||
- for example, xdg-desktop-portal allows anyone to make arbitrary DNS requests
|
||||
- e.g. `gdbus call --session --timeout 10 --dest org.freedesktop.portal.Desktop --object-path /org/freedesktop/portal/desktop --method org.freedesktop.portal.NetworkMonitor.CanReach 'data1.exfiltrate.uninsane.org' 80`
|
||||
- enforce granular dbus sandboxing (bunpen-dbus-*)
|
||||
- make gnome-keyring-daemon less monolithic
|
||||
- no reason every application with _a_ secret needs to see _all_ secrets
|
||||
- check out oo7-daemon?
|
||||
@@ -102,6 +100,7 @@
|
||||
- make dconf stuff less monolithic
|
||||
- i.e. per-app dconf profiles for those which need it. possible static config.
|
||||
- flatpak/spectrum has some stuff to proxy dconf per-app
|
||||
- rework `programs` API to be just an overlay which wraps each binary in an env with XDG_DATA_DIRS etc set & the config/state links placed in /nix/store instead of $HOME.
|
||||
|
||||
### user experience
|
||||
- setup a real calendar system, for recurring events
|
||||
@@ -120,7 +119,6 @@
|
||||
- offline Wikipedia (or, add to `wike`)
|
||||
- some type of games manager/launcher
|
||||
- Gnome Highscore (retro games)?: <https://gitlab.gnome.org/World/highscore>
|
||||
- better maps for mobile (Osmin (QtQuick)? Pure Maps (Qt/Kirigami)?)
|
||||
- note-taking app: <https://linuxphoneapps.org/categories/note-taking/>
|
||||
- Folio is nice, uses standard markdown, though it only supports flat repos
|
||||
- OSK overlay specifically for mobile gaming
|
||||
@@ -136,6 +134,8 @@
|
||||
- blurble (https://linuxphoneapps.org/games/app.drey.blurble/). nix: not as of 2024-02-05
|
||||
- Trivia Quiz (https://linuxphoneapps.org/games/io.github.nokse22.trivia-quiz/)
|
||||
- sane-sync-music: remove empty dirs
|
||||
- soulseek: install a CLI app usable over ssh
|
||||
- moby: replace `spot` with its replacement, `riff` (<https://github.com/Diegovsky/riff>)
|
||||
|
||||
#### moby
|
||||
- moby: port battery support to something upstreamable
|
||||
@@ -152,6 +152,7 @@
|
||||
- SwayNC/nwg-panel: add option to change audio output
|
||||
- Newsflash: sync OPML on start, same way i do with gpodder
|
||||
- better podcasting client?
|
||||
- hardware upgrade (OnePlus)?
|
||||
|
||||
#### non-moby
|
||||
- RSS: integrate a paywall bypass
|
||||
@@ -160,13 +161,14 @@
|
||||
- and strip the ads out using Whisper transcription + asking a LLM where the ad breaks are
|
||||
- neovim: integrate ollama
|
||||
- neovim: better docsets (e.g. c++, glib)
|
||||
- firefox/librewolf: persist history
|
||||
- firefox: persist history
|
||||
- just not cookies or tabs
|
||||
- have xdg-open parse `<repo:...> URIs (or adjust them so that it _can_ parse)
|
||||
- sane-bt-search: show details like 5.1 vs stereo, h264 vs h265
|
||||
- maybe just color these "keywords" in all search results?
|
||||
- transmission: apply `sane-tag-media` path fix in `torrent-done` script
|
||||
- many .mkv files do appear to be tagged: i'd just need to add support in my own tooling
|
||||
- more aggressively cleanup non-media files after DL (ripper logos, info txts)
|
||||
- uninsane.org: make URLs relative to allow local use (and as offline homepage)
|
||||
- email: fix so that local mail doesn't go to junk
|
||||
- git sendmail flow adds the DKIM signatures, but gets delivered locally w/o having the sig checked, so goes into Junk
|
||||
|
@@ -1,7 +1,10 @@
|
||||
to add a host:
|
||||
- create the new nix targets
|
||||
- hosts/by-name/HOST
|
||||
- let the toplevel (flake.nix) know about HOST
|
||||
- let the toplevel (impure.nix) know about HOST
|
||||
- let the other hosts know about this host (hosts/common/hosts.nix)
|
||||
- let sops know about the host's pubkey (.sops.yaml)
|
||||
- re-encrypt all sops keys in secrets/common
|
||||
- build and flash an image
|
||||
- optionally expand the rootfs
|
||||
- `cfdisk /dev/sda2` -> resize partition
|
||||
@@ -22,4 +25,9 @@ to add a host:
|
||||
- instructions in hosts/common/secrets.nix
|
||||
- run `ssh-to-age` on user/host pubkeys
|
||||
- add age key to .sops.yaml
|
||||
- update encrypted secrets: `sops updatekeys path/to/secret.yaml`
|
||||
- update encrypted secrets: `find secrets -type f -exec sops updatekeys -y '{}' ';'`
|
||||
- setup wireguard keys
|
||||
- `pk=$(wg genkey)`
|
||||
- `echo "$pk" | sops encrypt --filename-override secrets/$(hostname)/wg-home.priv.bin --output secrets/$(hostname)/wg-home.priv.bin`
|
||||
- `pub=$(echo "$pk" | wg pubkey)`
|
||||
- add pubkey to hosts/common/hosts.nix
|
||||
|
49
doc/migrating-storage-device.md
Normal file
49
doc/migrating-storage-device.md
Normal file
@@ -0,0 +1,49 @@
|
||||
## migrating a host to a new drive
|
||||
### 1. copy persistent data off of the host:
|
||||
```sh
|
||||
$ mkdir -p mnt old/persist
|
||||
$ mount /dev/$old mnt
|
||||
$ rsync -arv mnt/persist/ old/persist/
|
||||
```
|
||||
|
||||
### 2. flash the new drive
|
||||
```
|
||||
$ nix-build -A hosts.moby.img
|
||||
$ dd if=$(readlink ./result) of=/dev/$new bs=4M oflag=direct conv=sync status=progress
|
||||
```
|
||||
|
||||
### 3.1. expand the partition
|
||||
```sh
|
||||
$ cfdisk /dev/$new
|
||||
# scroll to the last partition
|
||||
> Resize
|
||||
leave at default (max)
|
||||
> Write
|
||||
type "yes"
|
||||
> Quit
|
||||
```
|
||||
### 3.2. expand the filesystem
|
||||
```
|
||||
$ mkdir -p /mnt/$new
|
||||
$ mount /dev/$new /mnt/$new
|
||||
$ btrfs filesystem resize max /mnt/$new
|
||||
```
|
||||
|
||||
### 4. copy data onto the new host
|
||||
```
|
||||
$ mkdir /mnt/$new
|
||||
$ mount /dev/$new /mnt/$new
|
||||
# if you want to use btrfs snapshots (e.g. snapper), then create the data directory as a subvolume:
|
||||
$ btrfs subvolume create /mnt/$new/persist
|
||||
# restore the data
|
||||
$ rsync -arv old/persist/ /mnt/$new/persist/
|
||||
```
|
||||
|
||||
### 5. ensure/fix ownership
|
||||
```
|
||||
$ chmod -R a+rX /mnt/$new/nix
|
||||
# or, let the nix daemon do it:
|
||||
$ nix copy --no-check-sigs --to /mnt/$new $(nix-build -A hosts.moby)
|
||||
```
|
||||
|
||||
### 6. insert the disk into the system, and boot!
|
@@ -1,5 +1,5 @@
|
||||
## deploying to SD card
|
||||
- build a toplevel config: `nix build '.#hostSystems.moby'`
|
||||
- build a toplevel config: `nix build '.#hosts.moby.img'`
|
||||
- mount a system:
|
||||
- `mkdir -p root/{nix,boot}`
|
||||
- `mount /dev/sdX1 root/boot`
|
||||
|
19
hosts/by-name/cadey/default.nix
Normal file
19
hosts/by-name/cadey/default.nix
Normal file
@@ -0,0 +1,19 @@
|
||||
# MAME arcade cabinet
|
||||
# Raspberry Pi 400:
|
||||
# - quad-core Cortex-A72 @ 1.8 GHz (ARMv8-A 64; BCM2711)
|
||||
# - 4GiB RAM
|
||||
{ ... }:
|
||||
{
|
||||
imports = [
|
||||
./fs.nix
|
||||
];
|
||||
|
||||
sane.hal.rpi-400.enable = true;
|
||||
sane.roles.client = true; # for WiFi creds
|
||||
|
||||
# TODO: port to `sane.programs` interface
|
||||
services.xserver.desktopManager.kodi.enable = true;
|
||||
|
||||
# /boot space is at a premium, especially with uncompressed kernels. default was 20.
|
||||
# boot.loader.generic-extlinux-compatible.configurationLimit = 10;
|
||||
}
|
17
hosts/by-name/cadey/fs.nix
Normal file
17
hosts/by-name/cadey/fs.nix
Normal file
@@ -0,0 +1,17 @@
|
||||
{ ... }:
|
||||
|
||||
{
|
||||
fileSystems."/nix" = {
|
||||
device = "/dev/disk/by-uuid/cccccccc-aaaa-dddd-eeee-000020250621";
|
||||
fsType = "btrfs";
|
||||
options = [
|
||||
"compress=zstd"
|
||||
"defaults"
|
||||
];
|
||||
};
|
||||
|
||||
fileSystems."/boot" = {
|
||||
device = "/dev/disk/by-uuid/2025-0621";
|
||||
fsType = "vfat";
|
||||
};
|
||||
}
|
@@ -1,10 +1,13 @@
|
||||
{ config, pkgs, ... }:
|
||||
{ config, lib, ... }:
|
||||
{
|
||||
imports = [
|
||||
./fs.nix
|
||||
];
|
||||
|
||||
sane.services.hickory-dns.asSystemResolver = false; # TEMPORARY: TODO: re-enable hickory-dns
|
||||
# firewall has to be open to allow clients to use services hosted on this device,
|
||||
# like `ollama`
|
||||
sane.ports.openFirewall = true;
|
||||
|
||||
# sane.programs.devPkgs.enableFor.user.colin = true;
|
||||
# sane.guest.enable = true;
|
||||
|
||||
@@ -23,9 +26,9 @@
|
||||
sane.roles.build-machine.enable = true;
|
||||
sane.roles.client = true;
|
||||
sane.roles.pc = true;
|
||||
sane.services.ollama.enable = true;
|
||||
sane.roles.work = true;
|
||||
sane.services.ollama.enable = lib.mkIf (config.sane.maxBuildCost >= 3) true;
|
||||
sane.services.wg-home.enable = true;
|
||||
sane.services.wg-home.ip = config.sane.hosts.by-name."desko".wg-home.ip;
|
||||
sane.ovpn.addrV4 = "172.26.55.21";
|
||||
# sane.ovpn.addrV6 = "fd00:0000:1337:cafe:1111:1111:20c1:a73c";
|
||||
sane.services.rsync-net.enable = true;
|
||||
@@ -47,25 +50,8 @@
|
||||
|
||||
sane.programs.mpv.config.defaultProfile = "high-quality";
|
||||
|
||||
sane.image.extraBootFiles = [ pkgs.bootpart-uefi-x86_64 ];
|
||||
|
||||
# needed to use libimobiledevice/ifuse, for iphone sync
|
||||
services.usbmuxd.enable = true;
|
||||
|
||||
hardware.amdgpu.opencl.enable = true; # desktop (AMD's opencl implementation AKA "ROCM"); probably required for ollama
|
||||
|
||||
# TODO: enable snapper (need to make `/nix` or `/nix/persist` a subvolume, somehow).
|
||||
# default config: https://man.archlinux.org/man/snapper-configs.5
|
||||
# defaults to something like:
|
||||
# - hourly snapshots
|
||||
# - auto cleanup; keep the last 10 hourlies, last 10 daylies, last 10 monthlys.
|
||||
# to list snapshots: `sudo snapper --config nix list`
|
||||
# to take a snapshot: `sudo snapper --config nix create`
|
||||
# services.snapper.configs.nix = {
|
||||
# # TODO: for the impermanent setup, we'd prefer to just do /nix/persist,
|
||||
# # but that also requires setting up the persist dir as a subvol
|
||||
# SUBVOLUME = "/nix";
|
||||
# # TODO: ALLOW_USERS doesn't seem to work. still need `sudo snapper -c nix list`
|
||||
# ALLOW_USERS = [ "colin" ];
|
||||
# };
|
||||
}
|
||||
|
@@ -6,7 +6,7 @@
|
||||
fileSystems."/tmp".options = [ "size=128G" ];
|
||||
|
||||
fileSystems."/nix" = {
|
||||
device = "/dev/disk/by-uuid/845d85bf-761d-431b-a406-e6f20909154f";
|
||||
device = "/dev/disk/by-uuid/dddddddd-eeee-5555-cccc-000020250527";
|
||||
fsType = "btrfs";
|
||||
options = [
|
||||
"compress=zstd"
|
||||
@@ -15,7 +15,7 @@
|
||||
};
|
||||
|
||||
fileSystems."/boot" = {
|
||||
device = "/dev/disk/by-uuid/5049-9AFD";
|
||||
device = "/dev/disk/by-uuid/2025-0527";
|
||||
fsType = "vfat";
|
||||
};
|
||||
}
|
||||
|
58
hosts/by-name/flowy/default.nix
Normal file
58
hosts/by-name/flowy/default.nix
Normal file
@@ -0,0 +1,58 @@
|
||||
{ lib, pkgs, ... }:
|
||||
{
|
||||
imports = [
|
||||
./fs.nix
|
||||
];
|
||||
|
||||
sane.roles.client = true;
|
||||
sane.roles.pc = true;
|
||||
sane.roles.work = true;
|
||||
sane.services.wg-home.enable = true;
|
||||
# sane.ovpn.addrV4 = "172.23.119.72";
|
||||
|
||||
# sane.guest.enable = true;
|
||||
|
||||
sane.programs.sane-private-unlock-remote.enableFor.user.colin = true;
|
||||
sane.programs.sane-private-unlock-remote.config.hosts = [ "servo" ];
|
||||
|
||||
sane.programs.firefox.config.formFactor = "laptop";
|
||||
sane.programs.itgmania.enableFor.user.colin = true;
|
||||
sane.programs.sway.enableFor.user.colin = true;
|
||||
|
||||
sops.secrets.colin-passwd.neededForUsers = true;
|
||||
|
||||
sane.services.rsync-net.enable = true;
|
||||
|
||||
# add an entry to boot into Windows, as if it had been launched directly from the BIOS.
|
||||
boot.loader.systemd-boot.rebootForBitlocker = true;
|
||||
boot.loader.systemd-boot.windows.primary.efiDeviceHandle = "HD0b";
|
||||
|
||||
system.activationScripts.makeDefaultBootEntry = {
|
||||
text = let
|
||||
makeDefaultBootEntry = pkgs.writeShellApplication {
|
||||
name = "makeDefaultBootEntry";
|
||||
runtimeInputs = with pkgs; [
|
||||
efibootmgr
|
||||
gnugrep
|
||||
];
|
||||
text = ''
|
||||
# configure the EFI firmware to boot into NixOS by default.
|
||||
# do this by querying the active boot entry, and just making that be the default.
|
||||
# this is needed on flowy because enabling secure boot / booting into Windows
|
||||
# resets the default boot order; manually reconfiguring that is tiresome.
|
||||
efi=$(efibootmgr)
|
||||
bootCurrent=$(echo "$efi" | grep '^BootCurrent: ')
|
||||
bootCurrent=''${bootCurrent/BootCurrent: /}
|
||||
bootOrder=$(echo "$efi" | grep '^BootOrder: ')
|
||||
bootOrder=''${bootOrder/BootOrder: /}
|
||||
if ! [[ "$bootOrder" =~ ^"$bootCurrent", ]]; then
|
||||
# booted entry was not the default,
|
||||
# so prepend it to the boot order:
|
||||
newBootOrder="$bootCurrent,$bootOrder"
|
||||
(set -x; efibootmgr -o "$newBootOrder")
|
||||
fi
|
||||
'';
|
||||
};
|
||||
in lib.getExe makeDefaultBootEntry;
|
||||
};
|
||||
}
|
17
hosts/by-name/flowy/fs.nix
Normal file
17
hosts/by-name/flowy/fs.nix
Normal file
@@ -0,0 +1,17 @@
|
||||
{ ... }:
|
||||
|
||||
{
|
||||
fileSystems."/nix" = {
|
||||
device = "/dev/disk/by-uuid/ffffffff-1111-0000-eeee-000020250531";
|
||||
fsType = "btrfs";
|
||||
options = [
|
||||
"compress=zstd"
|
||||
"defaults"
|
||||
];
|
||||
};
|
||||
|
||||
fileSystems."/boot" = {
|
||||
device = "/dev/disk/by-uuid/2025-0531";
|
||||
fsType = "vfat";
|
||||
};
|
||||
}
|
@@ -1,4 +1,4 @@
|
||||
{ config, pkgs, ... }:
|
||||
{ lib, ... }:
|
||||
{
|
||||
imports = [
|
||||
./fs.nix
|
||||
@@ -7,18 +7,17 @@
|
||||
sane.roles.client = true;
|
||||
sane.roles.pc = true;
|
||||
sane.services.wg-home.enable = true;
|
||||
sane.services.wg-home.ip = config.sane.hosts.by-name."lappy".wg-home.ip;
|
||||
sane.ovpn.addrV4 = "172.23.119.72";
|
||||
# sane.ovpn.addrV6 = "fd00:0000:1337:cafe:1111:1111:0332:aa96/128";
|
||||
|
||||
# sane.guest.enable = true;
|
||||
sane.image.extraBootFiles = [ pkgs.bootpart-uefi-x86_64 ];
|
||||
|
||||
sane.programs.sane-private-unlock-remote.enableFor.user.colin = true;
|
||||
sane.programs.sane-private-unlock-remote.config.hosts = [ "servo" ];
|
||||
|
||||
sane.programs.firefox.config.formFactor = "laptop";
|
||||
sane.programs.stepmania.enableFor.user.colin = true;
|
||||
sane.programs.itgmania.enableFor.user.colin = true;
|
||||
# sane.programs.stepmania.enableFor.user.colin = true; #< TODO: fix build
|
||||
sane.programs.sway.enableFor.user.colin = true;
|
||||
|
||||
sops.secrets.colin-passwd.neededForUsers = true;
|
||||
@@ -29,18 +28,10 @@
|
||||
# 1024 solves *most* crackles, but still noticable under heavier loads.
|
||||
sane.programs.pipewire.config.min-quantum = 2048;
|
||||
|
||||
# TODO: enable snapper (need to make `/nix` or `/nix/persist` a subvolume, somehow).
|
||||
# default config: https://man.archlinux.org/man/snapper-configs.5
|
||||
# defaults to something like:
|
||||
# - hourly snapshots
|
||||
# - auto cleanup; keep the last 10 hourlies, last 10 daylies, last 10 monthlys.
|
||||
# to list snapshots: `sudo snapper --config nix list`
|
||||
# to take a snapshot: `sudo snapper --config nix create`
|
||||
# services.snapper.configs.nix = {
|
||||
# # TODO: for the impermanent setup, we'd prefer to just do /nix/persist,
|
||||
# # but that also requires setting up the persist dir as a subvol
|
||||
# SUBVOLUME = "/nix";
|
||||
# # TODO: ALLOW_USERS doesn't seem to work. still need `sudo snapper -c nix list`
|
||||
# ALLOW_USERS = [ "colin" ];
|
||||
# };
|
||||
# limit how many snapshots we keep, due to extremely limited disk space (TODO: remove this override after upgrading lappy hard drive)
|
||||
services.snapper.configs.root.TIMELINE_LIMIT_HOURLY = lib.mkForce 2;
|
||||
services.snapper.configs.root.TIMELINE_LIMIT_DAILY = lib.mkForce 2;
|
||||
services.snapper.configs.root.TIMELINE_LIMIT_WEEKLY = lib.mkForce 0;
|
||||
services.snapper.configs.root.TIMELINE_LIMIT_MONTHLY = lib.mkForce 0;
|
||||
services.snapper.configs.root.TIMELINE_LIMIT_YEARLY = lib.mkForce 0;
|
||||
}
|
||||
|
@@ -6,7 +6,7 @@
|
||||
# - Mobian wiki: <https://wiki.mobian-project.org/doku.php?id=start>
|
||||
# - recommended apps, chatrooms
|
||||
|
||||
{ config, ... }:
|
||||
{ ... }:
|
||||
{
|
||||
imports = [
|
||||
./fs.nix
|
||||
@@ -16,7 +16,6 @@
|
||||
sane.roles.client = true;
|
||||
sane.roles.handheld = true;
|
||||
sane.services.wg-home.enable = true;
|
||||
sane.services.wg-home.ip = config.sane.hosts.by-name."moby".wg-home.ip;
|
||||
sane.ovpn.addrV4 = "172.24.87.255";
|
||||
# sane.ovpn.addrV6 = "fd00:0000:1337:cafe:1111:1111:18cd:a72b";
|
||||
|
||||
@@ -60,5 +59,9 @@
|
||||
sane.programs.mpv.config.defaultProfile = "fast";
|
||||
|
||||
# /boot space is at a premium, especially with uncompressed kernels. default was 20.
|
||||
boot.loader.generic-extlinux-compatible.configurationLimit = 10;
|
||||
# boot.loader.generic-extlinux-compatible.configurationLimit = 10;
|
||||
|
||||
# TODO: switch to systemd-boot
|
||||
boot.loader.generic-extlinux-compatible.enable = true;
|
||||
boot.loader.systemd-boot.enable = false;
|
||||
}
|
||||
|
@@ -1,10 +1,9 @@
|
||||
{ pkgs, ... }:
|
||||
{ ... }:
|
||||
{
|
||||
imports = [
|
||||
./fs.nix
|
||||
];
|
||||
|
||||
sane.image.extraBootFiles = [ pkgs.bootpart-uefi-x86_64 ];
|
||||
sane.persist.enable = false; # what we mean here is that the image is immutable; `/` is still tmpfs.
|
||||
sane.nixcache.enable = false; # don't want to be calling out to dead machines that we're *trying* to rescue
|
||||
|
||||
|
@@ -1,10 +1,11 @@
|
||||
{ config, pkgs, ... }:
|
||||
{ ... }:
|
||||
|
||||
{
|
||||
imports = [
|
||||
./fs.nix
|
||||
./net
|
||||
./services
|
||||
./users
|
||||
];
|
||||
|
||||
# for administering services
|
||||
@@ -30,8 +31,6 @@
|
||||
# XXX(2024-07-27): this is incompatible if using s6, which needs to auto-login as `colin` to start its user services.
|
||||
services.getty.autologinUser = "root";
|
||||
|
||||
sane.image.extraBootFiles = [ pkgs.bootpart-uefi-x86_64 ];
|
||||
|
||||
# both transmission and ipfs try to set different net defaults.
|
||||
# we just use the most aggressive of the two here:
|
||||
boot.kernel.sysctl = {
|
||||
|
@@ -16,7 +16,7 @@
|
||||
fileSystems."/tmp".options = [ "size=32G" ];
|
||||
|
||||
fileSystems."/nix" = {
|
||||
device = "/dev/disk/by-uuid/cc81cca0-3cc7-4d82-a00c-6243af3e7776";
|
||||
device = "/dev/disk/by-uuid/55555555-eeee-ffff-bbbb-000020250820";
|
||||
fsType = "btrfs";
|
||||
options = [
|
||||
"compress=zstd"
|
||||
@@ -25,7 +25,7 @@
|
||||
};
|
||||
|
||||
fileSystems."/boot" = {
|
||||
device = "/dev/disk/by-uuid/6EE3-4171";
|
||||
device = "/dev/disk/by-uuid/2025-0820";
|
||||
fsType = "vfat";
|
||||
};
|
||||
|
||||
@@ -41,10 +41,12 @@
|
||||
# i don't know what guarantees NixOS/systemd make about that, so specifying all devices for now
|
||||
# "device=/dev/disk/by-partuuid/14a7d00a-be53-2b4e-96f9-7e2c964674ec" #< removed 2024-11-24 (for capacity upgrade)
|
||||
"device=/dev/disk/by-partuuid/409a147e-2282-49eb-87a7-c968032ede88" #< added 2024-11-24
|
||||
"device=/dev/disk/by-partuuid/6b86cc10-c3cc-ec4d-b20d-b6688f0959a6"
|
||||
# "device=/dev/disk/by-partuuid/6b86cc10-c3cc-ec4d-b20d-b6688f0959a6" #< removed 2025-06-04 (early drive failure; capacity upgrade)
|
||||
# "device=/dev/disk/by-partuuid/7fd85cac-b6f3-8248-af4e-68e703d11020" #< removed 2024-11-13 (early drive failure)
|
||||
"device=/dev/disk/by-partuuid/92ebbbfb-022f-427d-84d5-39349d4bc02a" #< added 2025-05-14
|
||||
"device=/dev/disk/by-partuuid/9e6c06b0-4a39-4d69-813f-1f5992f62ed7" #< added 2025-06-05
|
||||
"device=/dev/disk/by-partuuid/d9ad5ebc-0fc4-4d89-9fd0-619ce5210f1b" #< added 2024-11-13
|
||||
"device=/dev/disk/by-partuuid/ef0e5c7b-fccf-f444-bac4-534424326159"
|
||||
# "device=/dev/disk/by-partuuid/ef0e5c7b-fccf-f444-bac4-534424326159" #< removed 2025-05-14 (early drive failure)
|
||||
"nofail"
|
||||
# "x-systemd.before=local-fs.target"
|
||||
"x-systemd.device-bound=false" #< don't unmount when `device` disappears (i thought this was necessary, for drive replacement, but it might not be)
|
||||
@@ -67,8 +69,9 @@
|
||||
mode = "0775";
|
||||
}];
|
||||
sane.fs."/var/media/archive".dir = {};
|
||||
sane.fs."/var/media/archive/temp".dir = {};
|
||||
# this is file.text instead of symlink.text so that it may be read over a remote mount (where consumers might not have any /nix/store/.../README.md path)
|
||||
sane.fs."/var/media/archive/README.md".file.text = ''
|
||||
sane.fs."/var/media/archive/temp/README.md".file.text = ''
|
||||
this directory is for media i wish to remove from my library,
|
||||
but keep for a short time in case i reverse my decision.
|
||||
treat it like a system trash can.
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{ config, ... }:
|
||||
{
|
||||
sane.ovpn.addrV4 = "172.23.174.114";
|
||||
sane.ovpn.addrV4 = "172.23.174.114"; #< this applies to the dynamic VPNs -- NOT the static VPN
|
||||
# sane.ovpn.addrV6 = "fd00:0000:1337:cafe:1111:1111:8df3:14b0";
|
||||
|
||||
# OVPN CONFIG (https://www.ovpn.com):
|
||||
@@ -12,9 +12,9 @@
|
||||
dns.ipv4 = "46.227.67.134"; #< DNS requests inside the namespace are forwarded here
|
||||
# wg.port = 51822;
|
||||
wg.privateKeyFile = config.sops.secrets.wg_ovpns_privkey.path;
|
||||
wg.address.ipv4 = "185.157.162.178";
|
||||
wg.peer.publicKey = "SkkEZDCBde22KTs/Hc7FWvDBfdOCQA4YtBEuC3n5KGs=";
|
||||
wg.peer.endpoint = "vpn36.prd.amsterdam.ovpn.com:9930";
|
||||
# wg.peer.endpoint = "185.157.162.10:9930";
|
||||
wg.address.ipv4 = "146.70.100.165"; #< IP address for my end of the VPN tunnel. for OVPN public IPv4, this is also the public IP address.
|
||||
wg.peer.publicKey = "xc9p/lf2uLg6IGDh54E0Pbc6WI/J9caaByhwD4Uiu0Q="; #< pubkey by which i can authenticate OVPN, varies per OVPN endpoint
|
||||
wg.peer.endpoint = "vpn31.prd.losangeles.ovpn.com:9930";
|
||||
# wg.peer.endpoint = "45.83.89.131:9930";
|
||||
};
|
||||
}
|
||||
|
@@ -4,7 +4,6 @@
|
||||
sane.services.wg-home.visibleToWan = true;
|
||||
sane.services.wg-home.forwardToWan = true;
|
||||
sane.services.wg-home.routeThroughServo = false;
|
||||
sane.services.wg-home.ip = config.sane.hosts.by-name."servo".wg-home.ip;
|
||||
services.unbound.settings.server.interface = [
|
||||
# provide DNS to my wireguard clients
|
||||
config.sane.hosts.by-name."servo".wg-home.ip
|
||||
|
70
hosts/by-name/servo/services/bitmagnet.nix
Normal file
70
hosts/by-name/servo/services/bitmagnet.nix
Normal file
@@ -0,0 +1,70 @@
|
||||
# bitmagnet is a DHT crawler. it discovers publicly reachable torrents and indexes:
|
||||
# - torrent's magnet URI
|
||||
# - torrent's name
|
||||
# - torrent's file list (the first 100 files, per torrent), including size and "type" (e.g. video)
|
||||
# - seeder/leecher counts
|
||||
# - torrent's size
|
||||
# it provides a web UI to query these, especially a search form.
|
||||
# data is stored in postgresql as `bitmagnet` db (`sudo -u bitmagnet psql`)
|
||||
# after 30 days of operation:
|
||||
# - 12m torrents discovered
|
||||
# - 77GB database size => 6500B per torrent
|
||||
{ config, ... }:
|
||||
{
|
||||
services.bitmagnet.enable = true;
|
||||
sane.netns.ovpns.services = [ "bitmagnet" ];
|
||||
sane.ports.ports."3334" = {
|
||||
protocol = [ "tcp" "udp" ];
|
||||
# visibleTo.ovpns = true; #< not needed: it runs in the ovpns namespace
|
||||
description = "colin-bitmagnet";
|
||||
};
|
||||
|
||||
services.bitmagnet.settings = {
|
||||
# dht_crawler.scaling_factor: how rapidly to crawl the DHT.
|
||||
# influences number of worker threads, buffer sizes, etc.
|
||||
# default: 10.
|
||||
# docs claim "diminishing returns" above 10, but seems weakly confident about that.
|
||||
dht_crawler.scaling_factor = 64;
|
||||
# http_server.local_address: `$addr:$port` to `listen` to.
|
||||
# default is `:3333`, which listens on _all_ interfaces.
|
||||
# the http server exposes unprotected admin endpoints though, so restrict to private interfaces:
|
||||
http_server.local_address = "${config.sane.netns.ovpns.veth.netns.ipv4}:3333";
|
||||
# tmdb.enabled: whether to query The Movie DataBase to resolve filename -> movie title.
|
||||
# default: true.
|
||||
# docs claim 1 query per second rate limit, unless you supply your own API key.
|
||||
tmdb.enabled = false;
|
||||
};
|
||||
|
||||
# bitmagnet web client
|
||||
# protected by passwd because it exposes some mutation operations:
|
||||
# - queuing "jobs"
|
||||
# - deleting torrent infos (in bulk)
|
||||
# it uses graphql for _everything_, so no easy way to disable just the mutations (and remove the password) AFAICT.
|
||||
services.nginx.virtualHosts."bitmagnet.uninsane.org" = {
|
||||
# basicAuth is cleartext user/pw, so FORCE this to happen over SSL
|
||||
forceSSL = true;
|
||||
enableACME = true;
|
||||
locations."/" = {
|
||||
proxyPass = "http://${config.sane.netns.ovpns.veth.netns.ipv4}:3333";
|
||||
recommendedProxySettings = true;
|
||||
};
|
||||
basicAuthFile = config.sops.secrets.bitmagnet_passwd.path;
|
||||
};
|
||||
sops.secrets."bitmagnet_passwd" = {
|
||||
owner = config.users.users.nginx.name;
|
||||
mode = "0400";
|
||||
};
|
||||
|
||||
sane.dns.zones."uninsane.org".inet.CNAME."bitmagnet" = "native";
|
||||
|
||||
systemd.services.bitmagnet = {
|
||||
# hardening (systemd-analyze security bitmagnet). base nixos service is already partially hardened.
|
||||
serviceConfig.CapabilityBoundingSet = "";
|
||||
serviceConfig.SystemCallArchitectures = "native";
|
||||
serviceConfig.PrivateDevices = true;
|
||||
serviceConfig.PrivateUsers = true;
|
||||
serviceConfig.ProtectProc = "invisible";
|
||||
serviceConfig.ProcSubset = "pid";
|
||||
serviceConfig.SystemCallFilter = [ "@system-service" "~@privileged" "~@resources" ];
|
||||
};
|
||||
}
|
@@ -1,4 +1,5 @@
|
||||
# as of 2023/12/02: complete blockchain is 530 GiB (on-disk size may be larger)
|
||||
# as of 2025/08/06: on-disk blockchain as reported by `du` is 732 GiB
|
||||
#
|
||||
# ports:
|
||||
# - 8333: for node-to-node communications
|
||||
@@ -72,13 +73,18 @@ in
|
||||
proxy=127.0.0.1:9050
|
||||
'';
|
||||
extraCmdlineOptions = [
|
||||
# `man bitcoind` for options
|
||||
# "-assumevalid=0" # to perform script validation on all blocks, instead of just the latest checkpoint published by bitcoin-core
|
||||
# "-debug"
|
||||
# "-debug=estimatefee"
|
||||
# "-debug=leveldb"
|
||||
# "-debug=http"
|
||||
# "-debug=net"
|
||||
"-debug=proxy"
|
||||
"-debug=rpc"
|
||||
# "-debug=validation"
|
||||
# "-reindex" # wipe chainstate, block index, other indices; rebuild from blk*.dat (takes 2.5hrs)
|
||||
# "-reindex-chainstate" # wipe chainstate; rebuild from blk*.dat
|
||||
];
|
||||
};
|
||||
|
||||
|
@@ -115,11 +115,19 @@
|
||||
# - fee-per-satoshi=<ppm>
|
||||
# - feature configs (i.e. experimental-xyz options)
|
||||
sane.services.clightning.extraConfig = ''
|
||||
# log levels: "io", "debug", "info", "unusual", "broken"
|
||||
log-level=info
|
||||
# log levels: "io", "trace", "debug", "info", "unusual", "broken"
|
||||
# log-level=info
|
||||
# log-level=info:lightningd
|
||||
# log-level=debug:lightningd
|
||||
# log-level=debug
|
||||
log-level=debug
|
||||
# log-level=io
|
||||
|
||||
disable-plugin=cln-xpay
|
||||
|
||||
# let me use `lightning-cli dev-*` subcommands, fucktards.
|
||||
developer
|
||||
# `developer` enables `dev-*` but *disables* the older commands. asshats.
|
||||
allow-deprecated-apis=true
|
||||
|
||||
# peerswap:
|
||||
# - config example: <https://github.com/fort-nix/nix-bitcoin/pull/462/files#diff-b357d832705b8ce8df1f41934d613f79adb77c4cd5cd9e9eb12a163fca3e16c6>
|
||||
|
@@ -1,6 +1,7 @@
|
||||
{ ... }:
|
||||
{
|
||||
imports = [
|
||||
./bitmagnet.nix
|
||||
./coturn.nix
|
||||
./cryptocurrencies
|
||||
./email
|
||||
@@ -21,12 +22,12 @@
|
||||
./minidlna.nix
|
||||
./mumble.nix
|
||||
./navidrome.nix
|
||||
./nginx.nix
|
||||
./nginx
|
||||
./nixos-prebuild.nix
|
||||
./ntfy
|
||||
./pict-rs.nix
|
||||
./pleroma.nix
|
||||
./postgres.nix
|
||||
./postgresql
|
||||
./prosody
|
||||
./slskd.nix
|
||||
./transmission
|
||||
|
@@ -25,10 +25,10 @@
|
||||
#
|
||||
# debugging: general connectivity issues
|
||||
# - test that inbound port 25 is unblocked:
|
||||
# - `curl https://canyouseeme.org/ --data 'port=25&IP=185.157.162.178' | grep 'see your service'`
|
||||
# - `curl https://canyouseeme.org/ --data 'port=25&IP=$MX_IP' | grep 'see your service'`
|
||||
# - and retry with port 465, 587
|
||||
# - i think this API requires the queried IP match the source IP
|
||||
# - if necessary, `systemctl stop postfix` and `sudo nc -l 185.157.162.178 25`, then try https://canyouseeme.org
|
||||
# - if necessary, `systemctl stop postfix` and `sudo nc -l $MX_IP 25`, then try https://canyouseeme.org
|
||||
|
||||
{ ... }:
|
||||
{
|
||||
|
@@ -124,7 +124,9 @@
|
||||
# ];
|
||||
};
|
||||
};
|
||||
services.dovecot2.modules = [
|
||||
environment.systemPackages = [
|
||||
# XXX(2025-03-16): dovecot loads modules from /run/current-system/sw/lib/dovecot/modules
|
||||
# see: <https://github.com/NixOS/nixpkgs/pull/387642>
|
||||
pkgs.dovecot_pigeonhole # enables sieve execution (?)
|
||||
];
|
||||
services.dovecot2.sieve = {
|
||||
@@ -141,5 +143,5 @@
|
||||
'';
|
||||
};
|
||||
|
||||
systemd.services.dovecot2.serviceConfig.RestartSec = lib.mkForce "15s"; # nixos defaults this to 1s
|
||||
systemd.services.dovecot.serviceConfig.RestartSec = lib.mkForce "15s"; # nixos defaults this to 1s
|
||||
}
|
||||
|
@@ -99,8 +99,10 @@ in
|
||||
services.postfix.hostname = "mx.uninsane.org";
|
||||
services.postfix.origin = "uninsane.org";
|
||||
services.postfix.destination = [ "localhost" "uninsane.org" ];
|
||||
services.postfix.sslCert = "/var/lib/acme/mx.uninsane.org/fullchain.pem";
|
||||
services.postfix.sslKey = "/var/lib/acme/mx.uninsane.org/key.pem";
|
||||
services.postfix.config.smtpd_tls_chain_files = [
|
||||
"/var/lib/acme/mx.uninsane.org/key.pem"
|
||||
"/var/lib/acme/mx.uninsane.org/fullchain.pem"
|
||||
];
|
||||
|
||||
# see: `man 5 virtual`
|
||||
services.postfix.virtual = ''
|
||||
@@ -112,7 +114,7 @@ in
|
||||
# smtpd_milters = local:/run/opendkim/opendkim.sock
|
||||
# milter docs: http://www.postfix.org/MILTER_README.html
|
||||
# mail filters for receiving email and from authorized SMTP clients (i.e. via submission)
|
||||
# smtpd_milters = inet:185.157.162.190:8891
|
||||
# smtpd_milters = inet:$IP:8891
|
||||
# opendkim.sock will add a Authentication-Results header, with `dkim=pass|fail|...` value to received messages
|
||||
smtpd_milters = "unix:/run/opendkim/opendkim.sock";
|
||||
# mail filters for sendmail
|
||||
|
@@ -1,6 +1,6 @@
|
||||
# config options: <https://docs.gitea.io/en-us/administration/config-cheat-sheet/>
|
||||
# TODO: service shouldn't run as `git` user, but as `gitea`
|
||||
{ pkgs, lib, ... }:
|
||||
{ config, pkgs, lib, ... }:
|
||||
|
||||
{
|
||||
sane.persist.sys.byStore.private = [
|
||||
@@ -104,7 +104,7 @@
|
||||
};
|
||||
};
|
||||
|
||||
systemd.services.gitea.requires = [ "postgresql.service" ];
|
||||
systemd.services.gitea.wants = [ "postgresql.service" ];
|
||||
systemd.services.gitea.serviceConfig = {
|
||||
# nix default is AF_UNIX AF_INET AF_INET6.
|
||||
# we need more protos for sendmail to work. i thought it only needed +AF_LOCAL, but that didn't work.
|
||||
@@ -113,28 +113,66 @@
|
||||
ReadWritePaths = [
|
||||
"/var/lib/postfix/queue/maildrop"
|
||||
];
|
||||
# rate limit the restarts to prevent systemd from disabling it
|
||||
RestartSec = 5;
|
||||
RestartMaxDelaySec = 30;
|
||||
StartLimitBurst = 120;
|
||||
RestartSteps = 5;
|
||||
};
|
||||
|
||||
# services.openssh.settings.UsePAM = true; #< required for `git` user to authenticate
|
||||
|
||||
services.anubis.instances."git.uninsane.org" = {
|
||||
settings.TARGET = "http://127.0.0.1:3000";
|
||||
# allow IM clients/etc to show embeds/previews, else they just show "please verify you aren't a bot..."
|
||||
botPolicy.openGraph.enabled = true;
|
||||
};
|
||||
|
||||
# hosted git (web view and for `git <cmd>` use
|
||||
# TODO: enable publog?
|
||||
services.nginx.virtualHosts."git.uninsane.org" = {
|
||||
services.nginx.virtualHosts."git.uninsane.org" = let
|
||||
# XXX(2025-07-24): gitea's still being crawled, even with robots.txt.
|
||||
# the load is less than when Anthropic first started, but it's still pretty high (like 600%).
|
||||
# place behind anubis to prevent AI crawlers from hogging my CPU (gitea is slow to render pages).
|
||||
proxyPassHeavy = "http://unix:${config.services.anubis.instances."git.uninsane.org".settings.BIND}";
|
||||
# but anubis breaks embeds, so only protect the expensive repos.
|
||||
proxyPassLight = "http://127.0.0.1:3000";
|
||||
proxyTo = proxy: root: {
|
||||
proxyPass = proxy;
|
||||
recommendedProxySettings = true;
|
||||
};
|
||||
in {
|
||||
forceSSL = true; # gitea complains if served over a different protocol than its config file says
|
||||
enableACME = true;
|
||||
# inherit kTLS;
|
||||
extraConfig = ''
|
||||
client_max_body_size 100m;
|
||||
'';
|
||||
|
||||
locations."/" = {
|
||||
proxyPass = "http://127.0.0.1:3000";
|
||||
proxyPass = proxyPassLight;
|
||||
recommendedProxySettings = true;
|
||||
};
|
||||
# selectively proxy the heavyweight items through anubis.
|
||||
# a typical interaction is:
|
||||
# nginx:/colin/linux -> anubis:/colin/linux -> browser is served a loading page
|
||||
# -> nginx:.within.website/x/cmd/anubis/api/pass-challenge?response=... -> anubis:.within.website/x/cmd/anubis/api/pass-challenge?response=... -> browser is forwarded to /colin/linux
|
||||
# -> nginx:/colin/linux -> anubis:/colin/linux -> gitea:/colin/linux -> browser is served the actual content
|
||||
locations."/.within.website/" = proxyTo proxyPassHeavy;
|
||||
locations."/colin/linux" = proxyTo proxyPassHeavy;
|
||||
locations."/colin/nixpkgs" = proxyTo proxyPassHeavy;
|
||||
locations."/colin/opencellid-mirror" = proxyTo proxyPassHeavy;
|
||||
locations."/colin/podcastindex-db-mirror" = proxyTo proxyPassHeavy;
|
||||
|
||||
# fuck you @anthropic
|
||||
locations."= /robots.txt".extraConfig = ''
|
||||
return 200 "User-agent: *\nDisallow: /\n";
|
||||
'';
|
||||
# locations."= /robots.txt".extraConfig = ''
|
||||
# return 200 "User-agent: *\nDisallow: /\n";
|
||||
# '';
|
||||
# gitea serves all `raw` files as content-type: plain, but i'd like to serve them as their actual content type.
|
||||
# or at least, enough to make specific pages viewable (serving unoriginal content as arbitrary content type is dangerous).
|
||||
locations."~ ^/colin/phone-case-cq/raw/.*.html" = {
|
||||
proxyPass = "http://127.0.0.1:3000";
|
||||
proxyPass = proxyPassLight;
|
||||
recommendedProxySettings = true;
|
||||
extraConfig = ''
|
||||
proxy_hide_header Content-Type;
|
||||
default_type text/html;
|
||||
@@ -142,7 +180,8 @@
|
||||
'';
|
||||
};
|
||||
locations."~ ^/colin/phone-case-cq/raw/.*.js" = {
|
||||
proxyPass = "http://127.0.0.1:3000";
|
||||
proxyPass = proxyPassLight;
|
||||
recommendedProxySettings = true;
|
||||
extraConfig = ''
|
||||
proxy_hide_header Content-Type;
|
||||
default_type text/html;
|
||||
|
@@ -56,6 +56,7 @@ lib.mkIf false #< 2024/09/30: disabled because i haven't used it in several mon
|
||||
|
||||
locations."/ws" = {
|
||||
proxyPass = "http://127.0.0.1:7890";
|
||||
recommendedProxySettings = true;
|
||||
# XXX not sure how much of this is necessary
|
||||
extraConfig = ''
|
||||
proxy_http_version 1.1;
|
||||
|
@@ -1,5 +1,5 @@
|
||||
# TODO: split this file apart into smaller files to make it easier to understand
|
||||
{ config, lib, pkgs, ... }:
|
||||
{ config, lib, ... }:
|
||||
|
||||
let
|
||||
dyn-dns = config.sane.services.dyn-dns;
|
||||
@@ -55,8 +55,7 @@ in
|
||||
];
|
||||
};
|
||||
|
||||
services.hickory-dns.settings.zones = [ "uninsane.org" ];
|
||||
|
||||
services.hickory-dns.settings.zones = builtins.attrNames config.sane.dns.zones;
|
||||
|
||||
networking.nat.enable = true; #< TODO: try removing this?
|
||||
# networking.nat.extraCommands = ''
|
||||
|
@@ -27,6 +27,7 @@ lib.mkIf false # i don't actively use ipfs anymore
|
||||
|
||||
locations."/" = {
|
||||
proxyPass = "http://127.0.0.1:8080";
|
||||
recommendedProxySettings = true;
|
||||
extraConfig = ''
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Ipfs-Gateway-Prefix "";
|
||||
|
@@ -14,158 +14,160 @@
|
||||
#
|
||||
# N.B.: default install DOES NOT SUPPORT DLNA out of the box.
|
||||
# one must install it as a "plugin", which can be done through the UI.
|
||||
{ lib, ... }:
|
||||
{ config, lib, ... }:
|
||||
|
||||
# lib.mkIf false #< XXX(2024-11-17): disabled because it hasn't been working for months; web UI hangs on load, TVs see no files
|
||||
{
|
||||
# https://jellyfin.org/docs/general/networking/index.html
|
||||
sane.ports.ports."1900" = {
|
||||
protocol = [ "udp" ];
|
||||
visibleTo.lan = true;
|
||||
description = "colin-upnp-for-jellyfin";
|
||||
};
|
||||
sane.ports.ports."7359" = {
|
||||
protocol = [ "udp" ];
|
||||
visibleTo.lan = true;
|
||||
description = "colin-jellyfin-specific-client-discovery";
|
||||
# ^ not sure if this is necessary: copied this port from nixos jellyfin.openFirewall
|
||||
};
|
||||
# not sure if 8096/8920 get used either:
|
||||
sane.ports.ports."8096" = {
|
||||
protocol = [ "tcp" ];
|
||||
visibleTo.lan = true;
|
||||
description = "colin-jellyfin-http-lan";
|
||||
};
|
||||
sane.ports.ports."8920" = {
|
||||
protocol = [ "tcp" ];
|
||||
visibleTo.lan = true;
|
||||
description = "colin-jellyfin-https-lan";
|
||||
};
|
||||
|
||||
sane.persist.sys.byStore.plaintext = [
|
||||
{ user = "jellyfin"; group = "jellyfin"; mode = "0700"; path = "/var/lib/jellyfin/data"; method = "bind"; }
|
||||
{ user = "jellyfin"; group = "jellyfin"; mode = "0700"; path = "/var/lib/jellyfin/metadata"; method = "bind"; }
|
||||
# TODO: ship plugins statically, via nix. that'll be less fragile
|
||||
{ user = "jellyfin"; group = "jellyfin"; mode = "0700"; path = "/var/lib/jellyfin/plugins/DLNA_5.0.0.0"; method = "bind"; }
|
||||
{ user = "jellyfin"; group = "jellyfin"; mode = "0700"; path = "/var/lib/jellyfin/root"; method = "bind"; }
|
||||
];
|
||||
sane.persist.sys.byStore.ephemeral = [
|
||||
{ user = "jellyfin"; group = "jellyfin"; mode = "0700"; path = "/var/lib/jellyfin/log"; method = "bind"; }
|
||||
{ user = "jellyfin"; group = "jellyfin"; mode = "0700"; path = "/var/lib/jellyfin/transcodes"; method = "bind"; }
|
||||
];
|
||||
|
||||
services.jellyfin.enable = true;
|
||||
users.users.jellyfin.extraGroups = [ "media" ];
|
||||
|
||||
sane.fs."/var/lib/jellyfin".dir.acl = {
|
||||
user = "jellyfin";
|
||||
group = "jellyfin";
|
||||
mode = "0700";
|
||||
};
|
||||
|
||||
# `"Jellyfin.Plugin.Dlna": "Debug"` logging: <https://jellyfin.org/docs/general/networking/dlna>
|
||||
# TODO: switch Dlna back to 'Information' once satisfied with stability
|
||||
sane.fs."/var/lib/jellyfin/config/logging.json".symlink.text = ''
|
||||
{
|
||||
"Serilog": {
|
||||
"MinimumLevel": {
|
||||
"Default": "Information",
|
||||
"Override": {
|
||||
"Microsoft": "Warning",
|
||||
"System": "Warning",
|
||||
"Jellyfin.Plugin.Dlna": "Debug"
|
||||
}
|
||||
},
|
||||
"WriteTo": [
|
||||
{
|
||||
"Name": "Console",
|
||||
"Args": {
|
||||
"outputTemplate": "[{Timestamp:HH:mm:ss}] [{Level:u3}] [{ThreadId}] {SourceContext}: {Message:lj}{NewLine}{Exception}"
|
||||
}
|
||||
}
|
||||
],
|
||||
"Enrich": [ "FromLogContext", "WithThreadId" ]
|
||||
}
|
||||
}
|
||||
'';
|
||||
|
||||
sane.fs."/var/lib/jellyfin/config/network.xml".file.text = ''
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<NetworkConfiguration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
<BaseUrl />
|
||||
<EnableHttps>false</EnableHttps>
|
||||
<RequireHttps>false</RequireHttps>
|
||||
<InternalHttpPort>8096</InternalHttpPort>
|
||||
<InternalHttpsPort>8920</InternalHttpsPort>
|
||||
<PublicHttpPort>8096</PublicHttpPort>
|
||||
<PublicHttpsPort>8920</PublicHttpsPort>
|
||||
<AutoDiscovery>true</AutoDiscovery>
|
||||
<EnableUPnP>false</EnableUPnP>
|
||||
<EnableIPv4>true</EnableIPv4>
|
||||
<EnableIPv6>false</EnableIPv6>
|
||||
<EnableRemoteAccess>true</EnableRemoteAccess>
|
||||
<LocalNetworkSubnets>
|
||||
<string>10.78.76.0/22</string>
|
||||
</LocalNetworkSubnets>
|
||||
<KnownProxies>
|
||||
<string>127.0.0.1</string>
|
||||
<string>localhost</string>
|
||||
<string>10.78.79.1</string>
|
||||
</KnownProxies>
|
||||
<IgnoreVirtualInterfaces>false</IgnoreVirtualInterfaces>
|
||||
<VirtualInterfaceNames />
|
||||
<EnablePublishedServerUriByRequest>false</EnablePublishedServerUriByRequest>
|
||||
<PublishedServerUriBySubnet />
|
||||
<RemoteIPFilter />
|
||||
<IsRemoteIPFilterBlacklist>false</IsRemoteIPFilterBlacklist>
|
||||
</NetworkConfiguration>
|
||||
'';
|
||||
|
||||
# guest user id is `5ad194d60dca41de84b332950ffc4308`
|
||||
sane.fs."/var/lib/jellyfin/plugins/configurations/Jellyfin.Plugin.Dlna.xml".file.text = ''
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<DlnaPluginConfiguration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
<EnablePlayTo>true</EnablePlayTo>
|
||||
<ClientDiscoveryIntervalSeconds>60</ClientDiscoveryIntervalSeconds>
|
||||
<BlastAliveMessages>true</BlastAliveMessages>
|
||||
<AliveMessageIntervalSeconds>180</AliveMessageIntervalSeconds>
|
||||
<SendOnlyMatchedHost>true</SendOnlyMatchedHost>
|
||||
<DefaultUserId>5ad194d6-0dca-41de-84b3-32950ffc4308</DefaultUserId>
|
||||
</DlnaPluginConfiguration>
|
||||
'';
|
||||
|
||||
# fix LG TV to play more files.
|
||||
# there are certain files for which it only supports Direct Play (not even "Direct Stream" -- but "Direct Play").
|
||||
# this isn't a 100% fix: patching the profile allows e.g. Azumanga Daioh to play,
|
||||
# but A Place Further Than the Universe still fails as before.
|
||||
#
|
||||
# profile is based on upstream: <https://github.com/jellyfin/jellyfin-plugin-dlna>
|
||||
sane.fs."/var/lib/jellyfin/plugins/DLNA_5.0.0.0/profiles/LG Smart TV.xml".symlink.target = ./dlna/user/LG_Smart_TV.xml;
|
||||
# XXX(2024-11-17): old method, but the file referenced seems not to be used and setting just it causes failures:
|
||||
# > [DBG] Jellyfin.Plugin.Dlna.ContentDirectory.ContentDirectoryService: Not eligible for DirectPlay due to unsupported subtitles
|
||||
# sane.fs."/var/lib/jellyfin/plugins/configurations/dlna/user/LG Smart TV.xml".symlink.target = ./dlna/user/LG_Smart_TV.xml;
|
||||
|
||||
systemd.services.jellyfin.unitConfig.RequiresMountsFor = [
|
||||
"/var/media"
|
||||
];
|
||||
|
||||
# Jellyfin multimedia server
|
||||
# this is mostly taken from the official jellfin.org docs
|
||||
services.nginx.virtualHosts."jelly.uninsane.org" = {
|
||||
forceSSL = true;
|
||||
enableACME = true;
|
||||
# inherit kTLS;
|
||||
|
||||
locations."/" = {
|
||||
proxyPass = "http://127.0.0.1:8096";
|
||||
proxyWebsockets = true;
|
||||
recommendedProxySettings = true;
|
||||
# extraConfig = ''
|
||||
# # Disable buffering when the nginx proxy gets very resource heavy upon streaming
|
||||
# proxy_buffering off;
|
||||
# '';
|
||||
config = lib.mkIf (config.sane.maxBuildCost >= 2) {
|
||||
# https://jellyfin.org/docs/general/networking/index.html
|
||||
sane.ports.ports."1900" = {
|
||||
protocol = [ "udp" ];
|
||||
visibleTo.lan = true;
|
||||
description = "colin-upnp-for-jellyfin";
|
||||
};
|
||||
sane.ports.ports."7359" = {
|
||||
protocol = [ "udp" ];
|
||||
visibleTo.lan = true;
|
||||
description = "colin-jellyfin-specific-client-discovery";
|
||||
# ^ not sure if this is necessary: copied this port from nixos jellyfin.openFirewall
|
||||
};
|
||||
# not sure if 8096/8920 get used either:
|
||||
sane.ports.ports."8096" = {
|
||||
protocol = [ "tcp" ];
|
||||
visibleTo.lan = true;
|
||||
description = "colin-jellyfin-http-lan";
|
||||
};
|
||||
sane.ports.ports."8920" = {
|
||||
protocol = [ "tcp" ];
|
||||
visibleTo.lan = true;
|
||||
description = "colin-jellyfin-https-lan";
|
||||
};
|
||||
};
|
||||
|
||||
sane.dns.zones."uninsane.org".inet.CNAME."jelly" = "native";
|
||||
sane.persist.sys.byStore.plaintext = [
|
||||
{ user = "jellyfin"; group = "jellyfin"; mode = "0700"; path = "/var/lib/jellyfin/data"; method = "bind"; }
|
||||
{ user = "jellyfin"; group = "jellyfin"; mode = "0700"; path = "/var/lib/jellyfin/metadata"; method = "bind"; }
|
||||
# TODO: ship plugins statically, via nix. that'll be less fragile
|
||||
{ user = "jellyfin"; group = "jellyfin"; mode = "0700"; path = "/var/lib/jellyfin/plugins/DLNA_5.0.0.0"; method = "bind"; }
|
||||
{ user = "jellyfin"; group = "jellyfin"; mode = "0700"; path = "/var/lib/jellyfin/root"; method = "bind"; }
|
||||
];
|
||||
sane.persist.sys.byStore.ephemeral = [
|
||||
{ user = "jellyfin"; group = "jellyfin"; mode = "0700"; path = "/var/lib/jellyfin/log"; method = "bind"; }
|
||||
{ user = "jellyfin"; group = "jellyfin"; mode = "0700"; path = "/var/lib/jellyfin/transcodes"; method = "bind"; }
|
||||
];
|
||||
|
||||
services.jellyfin.enable = true;
|
||||
users.users.jellyfin.extraGroups = [ "media" ];
|
||||
|
||||
sane.fs."/var/lib/jellyfin".dir.acl = {
|
||||
user = "jellyfin";
|
||||
group = "jellyfin";
|
||||
mode = "0700";
|
||||
};
|
||||
|
||||
# `"Jellyfin.Plugin.Dlna": "Debug"` logging: <https://jellyfin.org/docs/general/networking/dlna>
|
||||
# TODO: switch Dlna back to 'Information' once satisfied with stability
|
||||
sane.fs."/var/lib/jellyfin/config/logging.json".symlink.text = ''
|
||||
{
|
||||
"Serilog": {
|
||||
"MinimumLevel": {
|
||||
"Default": "Information",
|
||||
"Override": {
|
||||
"Microsoft": "Warning",
|
||||
"System": "Warning",
|
||||
"Jellyfin.Plugin.Dlna": "Debug"
|
||||
}
|
||||
},
|
||||
"WriteTo": [
|
||||
{
|
||||
"Name": "Console",
|
||||
"Args": {
|
||||
"outputTemplate": "[{Timestamp:HH:mm:ss}] [{Level:u3}] [{ThreadId}] {SourceContext}: {Message:lj}{NewLine}{Exception}"
|
||||
}
|
||||
}
|
||||
],
|
||||
"Enrich": [ "FromLogContext", "WithThreadId" ]
|
||||
}
|
||||
}
|
||||
'';
|
||||
|
||||
sane.fs."/var/lib/jellyfin/config/network.xml".file.text = ''
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<NetworkConfiguration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
<BaseUrl />
|
||||
<EnableHttps>false</EnableHttps>
|
||||
<RequireHttps>false</RequireHttps>
|
||||
<InternalHttpPort>8096</InternalHttpPort>
|
||||
<InternalHttpsPort>8920</InternalHttpsPort>
|
||||
<PublicHttpPort>8096</PublicHttpPort>
|
||||
<PublicHttpsPort>8920</PublicHttpsPort>
|
||||
<AutoDiscovery>true</AutoDiscovery>
|
||||
<EnableUPnP>false</EnableUPnP>
|
||||
<EnableIPv4>true</EnableIPv4>
|
||||
<EnableIPv6>false</EnableIPv6>
|
||||
<EnableRemoteAccess>true</EnableRemoteAccess>
|
||||
<LocalNetworkSubnets>
|
||||
<string>10.78.76.0/22</string>
|
||||
</LocalNetworkSubnets>
|
||||
<KnownProxies>
|
||||
<string>127.0.0.1</string>
|
||||
<string>localhost</string>
|
||||
<string>10.78.79.1</string>
|
||||
</KnownProxies>
|
||||
<IgnoreVirtualInterfaces>false</IgnoreVirtualInterfaces>
|
||||
<VirtualInterfaceNames />
|
||||
<EnablePublishedServerUriByRequest>false</EnablePublishedServerUriByRequest>
|
||||
<PublishedServerUriBySubnet />
|
||||
<RemoteIPFilter />
|
||||
<IsRemoteIPFilterBlacklist>false</IsRemoteIPFilterBlacklist>
|
||||
</NetworkConfiguration>
|
||||
'';
|
||||
|
||||
# guest user id is `5ad194d60dca41de84b332950ffc4308`
|
||||
sane.fs."/var/lib/jellyfin/plugins/configurations/Jellyfin.Plugin.Dlna.xml".file.text = ''
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<DlnaPluginConfiguration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
<EnablePlayTo>true</EnablePlayTo>
|
||||
<ClientDiscoveryIntervalSeconds>60</ClientDiscoveryIntervalSeconds>
|
||||
<BlastAliveMessages>true</BlastAliveMessages>
|
||||
<AliveMessageIntervalSeconds>180</AliveMessageIntervalSeconds>
|
||||
<SendOnlyMatchedHost>true</SendOnlyMatchedHost>
|
||||
<DefaultUserId>5ad194d6-0dca-41de-84b3-32950ffc4308</DefaultUserId>
|
||||
</DlnaPluginConfiguration>
|
||||
'';
|
||||
|
||||
# fix LG TV to play more files.
|
||||
# there are certain files for which it only supports Direct Play (not even "Direct Stream" -- but "Direct Play").
|
||||
# this isn't a 100% fix: patching the profile allows e.g. Azumanga Daioh to play,
|
||||
# but A Place Further Than the Universe still fails as before.
|
||||
#
|
||||
# profile is based on upstream: <https://github.com/jellyfin/jellyfin-plugin-dlna>
|
||||
sane.fs."/var/lib/jellyfin/plugins/DLNA_5.0.0.0/profiles/LG Smart TV.xml".symlink.target = ./dlna/user/LG_Smart_TV.xml;
|
||||
# XXX(2024-11-17): old method, but the file referenced seems not to be used and setting just it causes failures:
|
||||
# > [DBG] Jellyfin.Plugin.Dlna.ContentDirectory.ContentDirectoryService: Not eligible for DirectPlay due to unsupported subtitles
|
||||
# sane.fs."/var/lib/jellyfin/plugins/configurations/dlna/user/LG Smart TV.xml".symlink.target = ./dlna/user/LG_Smart_TV.xml;
|
||||
|
||||
systemd.services.jellyfin.unitConfig.RequiresMountsFor = [
|
||||
"/var/media"
|
||||
];
|
||||
|
||||
# Jellyfin multimedia server
|
||||
# this is mostly taken from the official jellfin.org docs
|
||||
services.nginx.virtualHosts."jelly.uninsane.org" = {
|
||||
forceSSL = true;
|
||||
enableACME = true;
|
||||
# inherit kTLS;
|
||||
|
||||
locations."/" = {
|
||||
proxyPass = "http://127.0.0.1:8096";
|
||||
proxyWebsockets = true;
|
||||
recommendedProxySettings = true;
|
||||
# extraConfig = ''
|
||||
# # Disable buffering when the nginx proxy gets very resource heavy upon streaming
|
||||
# proxy_buffering off;
|
||||
# '';
|
||||
};
|
||||
};
|
||||
|
||||
sane.dns.zones."uninsane.org".inet.CNAME."jelly" = "native";
|
||||
};
|
||||
}
|
||||
|
@@ -1,22 +1,42 @@
|
||||
{ pkgs, ... }:
|
||||
{ config, lib, pkgs, ... }:
|
||||
{
|
||||
sane.services.kiwix-serve = {
|
||||
enable = true;
|
||||
port = 8013;
|
||||
zimPaths = [
|
||||
"${pkgs.zimPackages.wikipedia_en_all_maxi}/share/zim/wikipedia_en_all_maxi.zim"
|
||||
];
|
||||
};
|
||||
config = lib.mkIf (config.sane.maxBuildCost >= 3) {
|
||||
sane.services.kiwix-serve = {
|
||||
enable = true;
|
||||
port = 8013;
|
||||
zimPaths = with pkgs.zimPackages; [
|
||||
alpinelinux_en_all_maxi.zimPath
|
||||
archlinux_en_all_maxi.zimPath
|
||||
bitcoin_en_all_maxi.zimPath
|
||||
devdocs_en_nix.zimPath
|
||||
gentoo_en_all_maxi.zimPath
|
||||
# khanacademy_en_all.zimPath #< TODO: enable
|
||||
openstreetmap-wiki_en_all_maxi.zimPath
|
||||
psychonautwiki_en_all_maxi.zimPath
|
||||
rationalwiki_en_all_maxi.zimPath
|
||||
# wikipedia_en_100.zimPath
|
||||
wikipedia_en_all_maxi.zimPath
|
||||
# wikipedia_en_all_mini.zimPath
|
||||
zimgit-food-preparation_en.zimPath
|
||||
zimgit-medicine_en.zimPath
|
||||
zimgit-post-disaster_en.zimPath
|
||||
zimgit-water_en.zimPath
|
||||
];
|
||||
};
|
||||
|
||||
services.nginx.virtualHosts."w.uninsane.org" = {
|
||||
forceSSL = true;
|
||||
enableACME = true;
|
||||
# inherit kTLS;
|
||||
locations."/".proxyPass = "http://127.0.0.1:8013";
|
||||
locations."= /robots.txt".extraConfig = ''
|
||||
return 200 "User-agent: *\nDisallow: /\n";
|
||||
'';
|
||||
};
|
||||
services.nginx.virtualHosts."w.uninsane.org" = {
|
||||
forceSSL = true;
|
||||
enableACME = true;
|
||||
# inherit kTLS;
|
||||
locations."/" = {
|
||||
proxyPass = "http://127.0.0.1:8013";
|
||||
recommendedProxySettings = true;
|
||||
};
|
||||
locations."= /robots.txt".extraConfig = ''
|
||||
return 200 "User-agent: *\nDisallow: /\n";
|
||||
'';
|
||||
};
|
||||
|
||||
sane.dns.zones."uninsane.org".inet.CNAME."w" = "native";
|
||||
sane.dns.zones."uninsane.org".inet.CNAME."w" = "native";
|
||||
};
|
||||
}
|
||||
|
@@ -17,6 +17,7 @@ lib.mkIf false #< 2024/09/30: disabled because i haven't used this for several
|
||||
enableACME = true;
|
||||
locations."/" = {
|
||||
proxyPass = "http://127.0.0.1:${builtins.toString port}";
|
||||
recommendedProxySettings = true;
|
||||
};
|
||||
locations."= /robots.txt".extraConfig = ''
|
||||
return 200 "User-agent: *\nDisallow: /\n";
|
||||
|
@@ -3,7 +3,7 @@
|
||||
# - <repo:LemmyNet/lemmy:docker/nginx.conf>
|
||||
# - <repo:LemmyNet/lemmy-ansible:templates/nginx.conf>
|
||||
|
||||
{ lib, pkgs, ... }:
|
||||
{ config, lib, pkgs, ... }:
|
||||
let
|
||||
uiPort = 1234; # default ui port is 1234
|
||||
backendPort = 8536; # default backend port is 8536
|
||||
@@ -24,150 +24,156 @@ let
|
||||
media.video.max_frame_count = 30 * 60 * 60;
|
||||
};
|
||||
in {
|
||||
services.lemmy = {
|
||||
enable = true;
|
||||
settings.hostname = "lemmy.uninsane.org";
|
||||
# federation.debug forces outbound federation queries to be run synchronously
|
||||
# N.B.: this option might not be read for 0.17.0+? <https://github.com/LemmyNet/lemmy/blob/c32585b03429f0f76d1e4ff738786321a0a9df98/RELEASES.md#upgrade-instructions>
|
||||
# settings.federation.debug = true;
|
||||
settings.port = backendPort;
|
||||
ui.port = uiPort;
|
||||
database.createLocally = true;
|
||||
nginx.enable = true;
|
||||
};
|
||||
config = lib.mkIf (config.sane.maxBuildCost >= 2) {
|
||||
services.lemmy = {
|
||||
enable = true;
|
||||
settings.hostname = "lemmy.uninsane.org";
|
||||
# federation.debug forces outbound federation queries to be run synchronously
|
||||
# N.B.: this option might not be read for 0.17.0+? <https://github.com/LemmyNet/lemmy/blob/c32585b03429f0f76d1e4ff738786321a0a9df98/RELEASES.md#upgrade-instructions>
|
||||
# settings.federation.debug = true;
|
||||
settings.port = backendPort;
|
||||
ui.port = uiPort;
|
||||
database.createLocally = true;
|
||||
nginx.enable = true;
|
||||
};
|
||||
|
||||
systemd.services.lemmy.environment = {
|
||||
RUST_BACKTRACE = "full";
|
||||
RUST_LOG = "error";
|
||||
# RUST_LOG = "warn";
|
||||
# RUST_LOG = "debug";
|
||||
# RUST_LOG = "trace";
|
||||
# upstream defaults LEMMY_DATABASE_URL = "postgres:///lemmy?host=/run/postgresql";
|
||||
# - Postgres complains that we didn't specify a user
|
||||
# lemmy formats the url as:
|
||||
# - postgres://{user}:{password}@{host}:{port}/{database}
|
||||
# SO suggests (https://stackoverflow.com/questions/3582552/what-is-the-format-for-the-postgresql-connection-string-url):
|
||||
# - postgresql://[user[:password]@][netloc][:port][/dbname][?param1=value1&...]
|
||||
# LEMMY_DATABASE_URL = "postgres://lemmy@/run/postgresql"; # connection to server on socket "/run/postgresql/.s.PGSQL.5432" failed: FATAL: database "run/postgresql" does not exist
|
||||
# LEMMY_DATABASE_URL = "postgres://lemmy?host=/run/postgresql"; # no PostgreSQL user name specified in startup packet
|
||||
# LEMMY_DATABASE_URL = lib.mkForce "postgres://lemmy@?host=/run/postgresql"; # WORKS
|
||||
LEMMY_DATABASE_URL = lib.mkForce "postgres://lemmy@/lemmy?host=/run/postgresql";
|
||||
};
|
||||
users.groups.lemmy = {};
|
||||
users.users.lemmy = {
|
||||
group = "lemmy";
|
||||
isSystemUser = true;
|
||||
};
|
||||
systemd.services.lemmy.environment = {
|
||||
RUST_BACKTRACE = "full";
|
||||
RUST_LOG = "error";
|
||||
# RUST_LOG = "warn";
|
||||
# RUST_LOG = "debug";
|
||||
# RUST_LOG = "trace";
|
||||
# upstream defaults LEMMY_DATABASE_URL = "postgres:///lemmy?host=/run/postgresql";
|
||||
# - Postgres complains that we didn't specify a user
|
||||
# lemmy formats the url as:
|
||||
# - postgres://{user}:{password}@{host}:{port}/{database}
|
||||
# SO suggests (https://stackoverflow.com/questions/3582552/what-is-the-format-for-the-postgresql-connection-string-url):
|
||||
# - postgresql://[user[:password]@][netloc][:port][/dbname][?param1=value1&...]
|
||||
# LEMMY_DATABASE_URL = "postgres://lemmy@/run/postgresql"; # connection to server on socket "/run/postgresql/.s.PGSQL.5432" failed: FATAL: database "run/postgresql" does not exist
|
||||
# LEMMY_DATABASE_URL = "postgres://lemmy?host=/run/postgresql"; # no PostgreSQL user name specified in startup packet
|
||||
# LEMMY_DATABASE_URL = lib.mkForce "postgres://lemmy@?host=/run/postgresql"; # WORKS
|
||||
LEMMY_DATABASE_URL = lib.mkForce "postgres://lemmy@/lemmy?host=/run/postgresql";
|
||||
};
|
||||
users.groups.lemmy = {};
|
||||
users.users.lemmy = {
|
||||
group = "lemmy";
|
||||
isSystemUser = true;
|
||||
};
|
||||
|
||||
services.nginx.virtualHosts."lemmy.uninsane.org" = {
|
||||
forceSSL = true;
|
||||
enableACME = true;
|
||||
};
|
||||
services.nginx.virtualHosts."lemmy.uninsane.org" = {
|
||||
forceSSL = true;
|
||||
enableACME = true;
|
||||
};
|
||||
|
||||
sane.dns.zones."uninsane.org".inet.CNAME."lemmy" = "native";
|
||||
sane.dns.zones."uninsane.org".inet.CNAME."lemmy" = "native";
|
||||
|
||||
systemd.services.lemmy = {
|
||||
# fix to use a normal user so we can configure perms correctly
|
||||
# XXX(2024-07-28): this hasn't been rigorously tested:
|
||||
# possible that i've set something too strict and won't notice right away
|
||||
serviceConfig.DynamicUser = lib.mkForce false;
|
||||
serviceConfig.User = "lemmy";
|
||||
serviceConfig.Group = "lemmy";
|
||||
systemd.services.lemmy = {
|
||||
# fix to use a normal user so we can configure perms correctly
|
||||
# XXX(2024-07-28): this hasn't been rigorously tested:
|
||||
# possible that i've set something too strict and won't notice right away
|
||||
serviceConfig.DynamicUser = lib.mkForce false;
|
||||
serviceConfig.User = "lemmy";
|
||||
serviceConfig.Group = "lemmy";
|
||||
|
||||
# hardening (systemd-analyze security lemmy)
|
||||
# a handful of these are specified in upstream nixpkgs, but mostly not
|
||||
serviceConfig.LockPersonality = true;
|
||||
serviceConfig.NoNewPrivileges = true;
|
||||
serviceConfig.MemoryDenyWriteExecute = true;
|
||||
serviceConfig.PrivateDevices = true;
|
||||
serviceConfig.PrivateMounts = true;
|
||||
serviceConfig.PrivateTmp = true;
|
||||
serviceConfig.PrivateUsers = true;
|
||||
serviceConfig.ProcSubset = "pid";
|
||||
# switch postgres from Requires -> Wants, so that postgres may restart without taking lemmy down with it.
|
||||
requires = lib.mkForce [];
|
||||
wants = [ "postgresql.service" ];
|
||||
|
||||
serviceConfig.ProtectClock = true;
|
||||
serviceConfig.ProtectControlGroups = true;
|
||||
serviceConfig.ProtectHome = true;
|
||||
serviceConfig.ProtectHostname = true;
|
||||
serviceConfig.ProtectKernelLogs = true;
|
||||
serviceConfig.ProtectKernelModules = true;
|
||||
serviceConfig.ProtectKernelTunables = true;
|
||||
serviceConfig.ProtectProc = "invisible";
|
||||
serviceConfig.ProtectSystem = "strict";
|
||||
serviceConfig.RemoveIPC = true;
|
||||
serviceConfig.RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6";
|
||||
# hardening (systemd-analyze security lemmy)
|
||||
# a handful of these are specified in upstream nixpkgs, but mostly not
|
||||
serviceConfig.LockPersonality = true;
|
||||
serviceConfig.NoNewPrivileges = true;
|
||||
serviceConfig.MemoryDenyWriteExecute = true;
|
||||
serviceConfig.PrivateDevices = true;
|
||||
serviceConfig.PrivateMounts = true;
|
||||
serviceConfig.PrivateTmp = true;
|
||||
serviceConfig.PrivateUsers = true;
|
||||
serviceConfig.ProcSubset = "pid";
|
||||
|
||||
serviceConfig.RestrictNamespaces = true;
|
||||
serviceConfig.RestrictSUIDSGID = true;
|
||||
serviceConfig.SystemCallArchitectures = "native";
|
||||
serviceConfig.SystemCallFilter = [ "@system-service" ];
|
||||
};
|
||||
serviceConfig.ProtectClock = true;
|
||||
serviceConfig.ProtectControlGroups = true;
|
||||
serviceConfig.ProtectHome = true;
|
||||
serviceConfig.ProtectHostname = true;
|
||||
serviceConfig.ProtectKernelLogs = true;
|
||||
serviceConfig.ProtectKernelModules = true;
|
||||
serviceConfig.ProtectKernelTunables = true;
|
||||
serviceConfig.ProtectProc = "invisible";
|
||||
serviceConfig.ProtectSystem = "strict";
|
||||
serviceConfig.RemoveIPC = true;
|
||||
serviceConfig.RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6";
|
||||
|
||||
systemd.services.lemmy-ui = {
|
||||
# hardening (systemd-analyze security lemmy-ui)
|
||||
# TODO: upstream into nixpkgs
|
||||
serviceConfig.LockPersonality = true;
|
||||
serviceConfig.NoNewPrivileges = true;
|
||||
# serviceConfig.MemoryDenyWriteExecute = true; #< it uses v8, JIT
|
||||
serviceConfig.PrivateDevices = true;
|
||||
serviceConfig.PrivateMounts = true;
|
||||
serviceConfig.PrivateTmp = true;
|
||||
serviceConfig.PrivateUsers = true;
|
||||
serviceConfig.ProcSubset = "pid";
|
||||
serviceConfig.RestrictNamespaces = true;
|
||||
serviceConfig.RestrictSUIDSGID = true;
|
||||
serviceConfig.SystemCallArchitectures = "native";
|
||||
serviceConfig.SystemCallFilter = [ "@system-service" ];
|
||||
};
|
||||
|
||||
serviceConfig.ProtectClock = true;
|
||||
serviceConfig.ProtectControlGroups = true;
|
||||
serviceConfig.ProtectHome = true;
|
||||
serviceConfig.ProtectHostname = true;
|
||||
serviceConfig.ProtectKernelLogs = true;
|
||||
serviceConfig.ProtectKernelModules = true;
|
||||
serviceConfig.ProtectKernelTunables = true;
|
||||
serviceConfig.ProtectProc = "invisible";
|
||||
serviceConfig.ProtectSystem = "strict";
|
||||
serviceConfig.RemoveIPC = true;
|
||||
serviceConfig.RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6";
|
||||
systemd.services.lemmy-ui = {
|
||||
# hardening (systemd-analyze security lemmy-ui)
|
||||
# TODO: upstream into nixpkgs
|
||||
serviceConfig.LockPersonality = true;
|
||||
serviceConfig.NoNewPrivileges = true;
|
||||
# serviceConfig.MemoryDenyWriteExecute = true; #< it uses v8, JIT
|
||||
serviceConfig.PrivateDevices = true;
|
||||
serviceConfig.PrivateMounts = true;
|
||||
serviceConfig.PrivateTmp = true;
|
||||
serviceConfig.PrivateUsers = true;
|
||||
serviceConfig.ProcSubset = "pid";
|
||||
|
||||
serviceConfig.RestrictNamespaces = true;
|
||||
serviceConfig.RestrictSUIDSGID = true;
|
||||
serviceConfig.SystemCallArchitectures = "native";
|
||||
serviceConfig.SystemCallFilter = [ "@system-service" "@pkey" "@sandbox" ];
|
||||
};
|
||||
serviceConfig.ProtectClock = true;
|
||||
serviceConfig.ProtectControlGroups = true;
|
||||
serviceConfig.ProtectHome = true;
|
||||
serviceConfig.ProtectHostname = true;
|
||||
serviceConfig.ProtectKernelLogs = true;
|
||||
serviceConfig.ProtectKernelModules = true;
|
||||
serviceConfig.ProtectKernelTunables = true;
|
||||
serviceConfig.ProtectProc = "invisible";
|
||||
serviceConfig.ProtectSystem = "strict";
|
||||
serviceConfig.RemoveIPC = true;
|
||||
serviceConfig.RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6";
|
||||
|
||||
#v DO NOT REMOVE: defaults to 0.3, instead of latest, so always need to explicitly set this.
|
||||
services.pict-rs.package = pict-rs;
|
||||
serviceConfig.RestrictNamespaces = true;
|
||||
serviceConfig.RestrictSUIDSGID = true;
|
||||
serviceConfig.SystemCallArchitectures = "native";
|
||||
serviceConfig.SystemCallFilter = [ "@system-service" "@pkey" "@sandbox" ];
|
||||
};
|
||||
|
||||
systemd.services.pict-rs = {
|
||||
serviceConfig.ExecStart = lib.mkForce (lib.concatStringsSep " " [
|
||||
(lib.getExe pict-rs)
|
||||
"--config-file"
|
||||
tomlConfig
|
||||
"run"
|
||||
]);
|
||||
#v DO NOT REMOVE: defaults to 0.3, instead of latest, so always need to explicitly set this.
|
||||
services.pict-rs.package = pict-rs;
|
||||
|
||||
# hardening (systemd-analyze security pict-rs)
|
||||
# TODO: upstream into nixpkgs
|
||||
serviceConfig.LockPersonality = true;
|
||||
serviceConfig.NoNewPrivileges = true;
|
||||
serviceConfig.MemoryDenyWriteExecute = true;
|
||||
serviceConfig.PrivateDevices = true;
|
||||
serviceConfig.PrivateMounts = true;
|
||||
serviceConfig.PrivateTmp = true;
|
||||
serviceConfig.PrivateUsers = true;
|
||||
serviceConfig.ProcSubset = "pid";
|
||||
serviceConfig.ProtectClock = true;
|
||||
serviceConfig.ProtectControlGroups = true;
|
||||
serviceConfig.ProtectHome = true;
|
||||
serviceConfig.ProtectHostname = true;
|
||||
serviceConfig.ProtectKernelLogs = true;
|
||||
serviceConfig.ProtectKernelModules = true;
|
||||
serviceConfig.ProtectKernelTunables = true;
|
||||
serviceConfig.ProtectProc = "invisible";
|
||||
serviceConfig.ProtectSystem = "strict";
|
||||
serviceConfig.RemoveIPC = true;
|
||||
serviceConfig.RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6";
|
||||
serviceConfig.RestrictNamespaces = true;
|
||||
serviceConfig.RestrictSUIDSGID = true;
|
||||
serviceConfig.SystemCallArchitectures = "native";
|
||||
serviceConfig.SystemCallFilter = [ "@system-service" ];
|
||||
systemd.services.pict-rs = {
|
||||
serviceConfig.ExecStart = lib.mkForce (lib.concatStringsSep " " [
|
||||
(lib.getExe pict-rs)
|
||||
"--config-file"
|
||||
tomlConfig
|
||||
"run"
|
||||
]);
|
||||
|
||||
# hardening (systemd-analyze security pict-rs)
|
||||
# TODO: upstream into nixpkgs
|
||||
serviceConfig.LockPersonality = true;
|
||||
serviceConfig.NoNewPrivileges = true;
|
||||
serviceConfig.MemoryDenyWriteExecute = true;
|
||||
serviceConfig.PrivateDevices = true;
|
||||
serviceConfig.PrivateMounts = true;
|
||||
serviceConfig.PrivateTmp = true;
|
||||
serviceConfig.PrivateUsers = true;
|
||||
serviceConfig.ProcSubset = "pid";
|
||||
serviceConfig.ProtectClock = true;
|
||||
serviceConfig.ProtectControlGroups = true;
|
||||
serviceConfig.ProtectHome = true;
|
||||
serviceConfig.ProtectHostname = true;
|
||||
serviceConfig.ProtectKernelLogs = true;
|
||||
serviceConfig.ProtectKernelModules = true;
|
||||
serviceConfig.ProtectKernelTunables = true;
|
||||
serviceConfig.ProtectProc = "invisible";
|
||||
serviceConfig.ProtectSystem = "strict";
|
||||
serviceConfig.RemoveIPC = true;
|
||||
serviceConfig.RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6";
|
||||
serviceConfig.RestrictNamespaces = true;
|
||||
serviceConfig.RestrictSUIDSGID = true;
|
||||
serviceConfig.SystemCallArchitectures = "native";
|
||||
serviceConfig.SystemCallFilter = [ "@system-service" ];
|
||||
};
|
||||
};
|
||||
}
|
||||
|
@@ -70,6 +70,15 @@ in
|
||||
config.sops.secrets."matrix_synapse_secrets.yaml".path
|
||||
];
|
||||
|
||||
# tune restart settings to ensure systemd doesn't disable it, and we don't overwhelm postgres
|
||||
systemd.services.matrix-synapse.serviceConfig.RestartSec = 5;
|
||||
systemd.services.matrix-synapse.serviceConfig.RestartMaxDelaySec = 20;
|
||||
systemd.services.matrix-synapse.serviceConfig.StartLimitBurst = 120;
|
||||
systemd.services.matrix-synapse.serviceConfig.RestartSteps = 3;
|
||||
# switch postgres from Requires -> Wants, so that postgres may restart without taking matrix down with it.
|
||||
systemd.services.matrix-synapse.requires = lib.mkForce [];
|
||||
systemd.services.matrix-synapse.wants = [ "postgresql.service" ];
|
||||
|
||||
systemd.services.matrix-synapse.postStart = lib.optionalString ntfy ''
|
||||
ACCESS_TOKEN=$(${lib.getExe' pkgs.coreutils "cat"} ${config.sops.secrets.matrix_access_token.path})
|
||||
TOPIC=$(${lib.getExe' pkgs.coreutils "cat"} ${config.sops.secrets.ntfy-sh-topic.path})
|
||||
@@ -114,6 +123,7 @@ in
|
||||
|
||||
locations."/" = {
|
||||
proxyPass = "http://127.0.0.1:8008";
|
||||
recommendedProxySettings = true;
|
||||
extraConfig = ''
|
||||
# allow uploading large files (matrix enforces a separate limit, downstream)
|
||||
client_max_body_size 512m;
|
||||
|
@@ -154,6 +154,7 @@ in
|
||||
# notable channels:
|
||||
# - #sxmo
|
||||
# - #sxmo-offtopic
|
||||
# supposedly also available at <irc://37lnq2veifl4kar7.onion:6667/> (unofficial)
|
||||
};
|
||||
"irc.rizon.net" = ircServer { name = "Rizon"; };
|
||||
# "irc.sdf.org" = ircServer {
|
||||
@@ -183,6 +184,7 @@ in
|
||||
enableACME = true;
|
||||
locations."/media" = {
|
||||
proxyPass = "http://127.0.0.1:11111";
|
||||
recommendedProxySettings = true;
|
||||
};
|
||||
};
|
||||
|
||||
|
@@ -34,7 +34,10 @@ lib.mkIf false #< i don't actively use navidrome
|
||||
forceSSL = true;
|
||||
enableACME = true;
|
||||
# inherit kTLS;
|
||||
locations."/".proxyPass = "http://127.0.0.1:4533";
|
||||
locations."/" = {
|
||||
proxyPass = "http://127.0.0.1:4533";
|
||||
recommendedProxySettings = true;
|
||||
};
|
||||
};
|
||||
|
||||
sane.dns.zones."uninsane.org".inet.CNAME."music" = "native";
|
||||
|
@@ -1,270 +0,0 @@
|
||||
# docs: <https://nixos.wiki/wiki/Nginx>
|
||||
# docs: <https://nginx.org/en/docs/>
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
let
|
||||
# make the logs for this host "public" so that they show up in e.g. metrics
|
||||
publog = vhost: lib.attrsets.unionOfDisjoint vhost {
|
||||
extraConfig = (vhost.extraConfig or "") + ''
|
||||
access_log /var/log/nginx/public.log vcombined;
|
||||
'';
|
||||
};
|
||||
|
||||
# kTLS = true; # in-kernel TLS for better perf
|
||||
in
|
||||
{
|
||||
|
||||
sane.ports.ports."80" = {
|
||||
protocol = [ "tcp" ];
|
||||
visibleTo.lan = true;
|
||||
visibleTo.ovpns = true; # so that letsencrypt can procure a cert for the mx record
|
||||
visibleTo.doof = true;
|
||||
description = "colin-http-uninsane.org";
|
||||
};
|
||||
sane.ports.ports."443" = {
|
||||
protocol = [ "tcp" ];
|
||||
visibleTo.lan = true;
|
||||
visibleTo.doof = true;
|
||||
description = "colin-https-uninsane.org";
|
||||
};
|
||||
|
||||
services.nginx.enable = true;
|
||||
# nginxStable is one release behind nginxMainline.
|
||||
# nginx itself recommends running mainline; nixos defaults to stable.
|
||||
# services.nginx.package = pkgs.nginxMainline;
|
||||
# XXX(2024-07-31): nixos defaults to zlib-ng -- supposedly more performant, but spams log with
|
||||
# "gzip filter failed to use preallocated memory: ..."
|
||||
services.nginx.package = pkgs.nginxMainline.override { zlib = pkgs.zlib; };
|
||||
services.nginx.appendConfig = ''
|
||||
# use 1 process per core.
|
||||
# may want to increase worker_connections too, but `ulimit -n` must be increased first.
|
||||
worker_processes auto;
|
||||
'';
|
||||
|
||||
# this is the standard `combined` log format, with the addition of $host
|
||||
# so that we have the virtualHost in the log.
|
||||
# KEEP IN SYNC WITH GOACCESS
|
||||
# goaccess calls this VCOMBINED:
|
||||
# - <https://gist.github.com/jyap808/10570005>
|
||||
services.nginx.commonHttpConfig = ''
|
||||
log_format vcombined '$host:$server_port $remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referrer" "$http_user_agent"';
|
||||
access_log /var/log/nginx/private.log vcombined;
|
||||
'';
|
||||
# enables gzip and sets gzip_comp_level = 5
|
||||
services.nginx.recommendedGzipSettings = true;
|
||||
# enables zstd and sets zstd_comp_level = 9
|
||||
services.nginx.recommendedZstdSettings = true;
|
||||
# enables OCSP stapling (so clients don't need contact the OCSP server -- i do instead)
|
||||
# - doesn't seem to, actually: <https://www.ssllabs.com/ssltest/analyze.html?d=uninsane.org>
|
||||
# caches TLS sessions for 10m
|
||||
services.nginx.recommendedTlsSettings = true;
|
||||
# enables sendfile, tcp_nopush, tcp_nodelay, keepalive_timeout 65
|
||||
services.nginx.recommendedOptimisation = true;
|
||||
|
||||
# web blog/personal site
|
||||
# alternative way to link stuff into the share:
|
||||
# sane.fs."/var/www/sites/uninsane.org/share/Ubunchu".mount.bind = "/var/media/Books/Visual/HiroshiSeo/Ubunchu";
|
||||
# sane.fs."/var/media/Books/Visual/HiroshiSeo/Ubunchu".dir = {};
|
||||
services.nginx.virtualHosts."uninsane.org" = publog {
|
||||
# a lot of places hardcode https://uninsane.org,
|
||||
# and then when we mix http + non-https, we get CORS violations
|
||||
# and things don't look right. so force SSL.
|
||||
forceSSL = true;
|
||||
enableACME = true;
|
||||
# inherit kTLS;
|
||||
# for OCSP stapling
|
||||
sslTrustedCertificate = "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt";
|
||||
|
||||
locations."/" = {
|
||||
root = "${pkgs.uninsane-dot-org}/share/uninsane-dot-org";
|
||||
tryFiles = "$uri $uri/ @fallback";
|
||||
};
|
||||
|
||||
# unversioned files
|
||||
locations."@fallback" = {
|
||||
root = "/var/www/sites/uninsane.org";
|
||||
extraConfig = ''
|
||||
# instruct Google to not index these pages.
|
||||
# see: <https://developers.google.com/search/docs/crawling-indexing/robots-meta-tag#xrobotstag>
|
||||
add_header X-Robots-Tag 'none, noindex, nofollow';
|
||||
|
||||
# best-effort attempt to block archive.org from archiving these pages.
|
||||
# reply with 403: Forbidden
|
||||
# User Agent is *probably* "archive.org_bot"; maybe used to be "ia_archiver"
|
||||
# source: <https://archive.org/details/archive.org_bot>
|
||||
# additional UAs: <https://github.com/mitchellkrogza/nginx-ultimate-bad-bot-blocker>
|
||||
#
|
||||
# validate with: `curl -H 'User-Agent: "bot;archive.org_bot;like: something else"' -v https://uninsane.org/dne`
|
||||
if ($http_user_agent ~* "(?:\b)archive.org_bot(?:\b)") {
|
||||
return 403;
|
||||
}
|
||||
if ($http_user_agent ~* "(?:\b)archive.org(?:\b)") {
|
||||
return 403;
|
||||
}
|
||||
if ($http_user_agent ~* "(?:\b)ia_archiver(?:\b)") {
|
||||
return 403;
|
||||
}
|
||||
'';
|
||||
};
|
||||
|
||||
# uninsane.org/share/foo => /var/www/sites/uninsane.org/share/foo.
|
||||
# special-cased to enable directory listings
|
||||
locations."/share" = {
|
||||
root = "/var/www/sites/uninsane.org";
|
||||
extraConfig = ''
|
||||
# autoindex => render directory listings
|
||||
autoindex on;
|
||||
# don't follow any symlinks when serving files
|
||||
# otherwise it allows a directory escape
|
||||
disable_symlinks on;
|
||||
'';
|
||||
};
|
||||
locations."/share/Milkbags/" = {
|
||||
alias = "/var/media/Videos/Milkbags/";
|
||||
extraConfig = ''
|
||||
# autoindex => render directory listings
|
||||
autoindex on;
|
||||
# don't follow any symlinks when serving files
|
||||
# otherwise it allows a directory escape
|
||||
disable_symlinks on;
|
||||
'';
|
||||
};
|
||||
locations."/share/Ubunchu/" = {
|
||||
alias = "/var/media/Books/Visual/HiroshiSeo/Ubunchu/";
|
||||
extraConfig = ''
|
||||
# autoindex => render directory listings
|
||||
autoindex on;
|
||||
# don't follow any symlinks when serving files
|
||||
# otherwise it allows a directory escape
|
||||
disable_symlinks on;
|
||||
'';
|
||||
};
|
||||
|
||||
# allow matrix users to discover that @user:uninsane.org is reachable via matrix.uninsane.org
|
||||
locations."= /.well-known/matrix/server".extraConfig =
|
||||
let
|
||||
# use 443 instead of the default 8448 port to unite
|
||||
# the client-server and server-server port for simplicity
|
||||
server = { "m.server" = "matrix.uninsane.org:443"; };
|
||||
in ''
|
||||
add_header Content-Type application/json;
|
||||
return 200 '${builtins.toJSON server}';
|
||||
'';
|
||||
locations."= /.well-known/matrix/client".extraConfig =
|
||||
let
|
||||
client = {
|
||||
"m.homeserver" = { "base_url" = "https://matrix.uninsane.org"; };
|
||||
"m.identity_server" = { "base_url" = "https://vector.im"; };
|
||||
};
|
||||
# ACAO required to allow element-web on any URL to request this json file
|
||||
in ''
|
||||
add_header Content-Type application/json;
|
||||
add_header Access-Control-Allow-Origin *;
|
||||
return 200 '${builtins.toJSON client}';
|
||||
'';
|
||||
|
||||
# static URLs might not be aware of .well-known (e.g. registration confirmation URLs),
|
||||
# so hack around that.
|
||||
locations."/_matrix" = {
|
||||
proxyPass = "http://127.0.0.1:8008";
|
||||
};
|
||||
locations."/_synapse" = {
|
||||
proxyPass = "http://127.0.0.1:8008";
|
||||
};
|
||||
|
||||
# allow ActivityPub clients to discover how to reach @user@uninsane.org
|
||||
# see: https://git.pleroma.social/pleroma/pleroma/-/merge_requests/3361/
|
||||
# not sure this makes sense while i run multiple AP services (pleroma, lemmy)
|
||||
# locations."/.well-known/nodeinfo" = {
|
||||
# proxyPass = "http://127.0.0.1:4000";
|
||||
# extraConfig = pleromaExtraConfig;
|
||||
# };
|
||||
|
||||
# redirect common feed URIs to the canonical feed
|
||||
locations."= /atom".extraConfig = "return 301 /atom.xml;";
|
||||
locations."= /feed".extraConfig = "return 301 /atom.xml;";
|
||||
locations."= /feed.xml".extraConfig = "return 301 /atom.xml;";
|
||||
locations."= /rss".extraConfig = "return 301 /atom.xml;";
|
||||
locations."= /rss.xml".extraConfig = "return 301 /atom.xml;";
|
||||
locations."= /blog/atom".extraConfig = "return 301 /atom.xml;";
|
||||
locations."= /blog/atom.xml".extraConfig = "return 301 /atom.xml;";
|
||||
locations."= /blog/feed".extraConfig = "return 301 /atom.xml;";
|
||||
locations."= /blog/feed.xml".extraConfig = "return 301 /atom.xml;";
|
||||
locations."= /blog/rss".extraConfig = "return 301 /atom.xml;";
|
||||
locations."= /blog/rss.xml".extraConfig = "return 301 /atom.xml;";
|
||||
};
|
||||
|
||||
|
||||
# serve any site not listed above, if it's static.
|
||||
# because we define it dynamically, SSL isn't trivial. support only http
|
||||
# documented <https://nginx.org/en/docs/http/ngx_http_core_module.html#server_name>
|
||||
services.nginx.virtualHosts."~^(?<domain>.+)$" = {
|
||||
default = true;
|
||||
addSSL = true;
|
||||
enableACME = false;
|
||||
sslCertificate = "/var/www/certs/wildcard/cert.pem";
|
||||
sslCertificateKey = "/var/www/certs/wildcard/key.pem";
|
||||
# sslCertificate = "/var/lib/acme/.minica/cert.pem";
|
||||
# sslCertificateKey = "/var/lib/acme/.minica/key.pem";
|
||||
# serverName = null;
|
||||
locations."/" = {
|
||||
# somehow this doesn't escape -- i get error 400 if i:
|
||||
# curl 'http://..' --resolve '..:80:127.0.0.1'
|
||||
root = "/var/www/sites/$domain";
|
||||
# tryFiles = "$domain/$uri $domain/$uri/ =404";
|
||||
};
|
||||
};
|
||||
|
||||
security.acme.acceptTerms = true;
|
||||
security.acme.defaults.email = "admin.acme@uninsane.org";
|
||||
|
||||
sane.persist.sys.byStore.plaintext = [
|
||||
{ user = "acme"; group = "acme"; path = "/var/lib/acme"; method = "bind"; }
|
||||
];
|
||||
sane.persist.sys.byStore.private = [
|
||||
{ user = "colin"; group = "users"; path = "/var/www/sites"; method = "bind"; }
|
||||
];
|
||||
sane.persist.sys.byStore.ephemeral = [
|
||||
# logs *could* be persisted to private storage, but then there's the issue of
|
||||
# "what if servo boots, isn't unlocked, and the whole / tmpfs is consumed by logs"
|
||||
{ user = "nginx"; group = "nginx"; path = "/var/log/nginx"; method = "bind"; }
|
||||
];
|
||||
|
||||
# let's encrypt default chain looks like:
|
||||
# - End-entity certificate ← R3 ← ISRG Root X1 ← DST Root CA X3
|
||||
# - <https://community.letsencrypt.org/t/production-chain-changes/150739>
|
||||
# DST Root CA X3 expired in 2021 (?)
|
||||
# the alternative chain is:
|
||||
# - End-entity certificate ← R3 ← ISRG Root X1 (self-signed)
|
||||
# using this alternative chain grants more compatibility for services like ejabberd
|
||||
# but might decrease compatibility with very old clients that don't get updates (e.g. old android, iphone <= 4).
|
||||
# security.acme.defaults.extraLegoFlags = [
|
||||
security.acme.certs."uninsane.org" = rec {
|
||||
# ISRG Root X1 results in lets encrypt sending the same chain as default,
|
||||
# just without the final ISRG Root X1 ← DST Root CA X3 link.
|
||||
# i.e. we could alternative clip the last item and achieve the exact same thing.
|
||||
extraLegoRunFlags = [
|
||||
"--preferred-chain" "ISRG Root X1"
|
||||
];
|
||||
extraLegoRenewFlags = extraLegoRunFlags;
|
||||
};
|
||||
# TODO: alternatively, we could clip the last cert IF it's expired,
|
||||
# optionally outputting that to a new cert file.
|
||||
# security.acme.defaults.postRun = "";
|
||||
|
||||
# create a self-signed SSL certificate for use with literally any domain.
|
||||
# browsers will reject this, but proxies and local testing tools can be configured
|
||||
# to accept it.
|
||||
system.activationScripts.generate-x509-self-signed.text = ''
|
||||
mkdir -p /var/www/certs/wildcard
|
||||
test -f /var/www/certs/wildcard/key.pem || ${lib.getExe pkgs.openssl} \
|
||||
req -x509 -newkey rsa:4096 \
|
||||
-keyout /var/www/certs/wildcard/key.pem \
|
||||
-out /var/www/certs/wildcard/cert.pem \
|
||||
-sha256 -nodes -days 3650 \
|
||||
-addext 'subjectAltName=DNS:*' \
|
||||
-subj '/CN=self-signed'
|
||||
chmod 640 /var/www/certs/wildcard/{key,cert}.pem
|
||||
chown root:nginx /var/www/certs/wildcard /var/www/certs/wildcard/{key,cert}.pem
|
||||
'';
|
||||
}
|
111
hosts/by-name/servo/services/nginx/default.nix
Normal file
111
hosts/by-name/servo/services/nginx/default.nix
Normal file
@@ -0,0 +1,111 @@
|
||||
# docs: <https://nixos.wiki/wiki/Nginx>
|
||||
# docs: <https://nginx.org/en/docs/>
|
||||
{ lib, pkgs, ... }:
|
||||
{
|
||||
imports = [
|
||||
./uninsane.org.nix
|
||||
./waka.laka.osaka
|
||||
];
|
||||
|
||||
sane.ports.ports."80" = {
|
||||
protocol = [ "tcp" ];
|
||||
visibleTo.lan = true;
|
||||
visibleTo.ovpns = true; # so that letsencrypt can procure a cert for the mx record
|
||||
visibleTo.doof = true;
|
||||
description = "colin-http-uninsane.org";
|
||||
};
|
||||
sane.ports.ports."443" = {
|
||||
protocol = [ "tcp" ];
|
||||
visibleTo.lan = true;
|
||||
visibleTo.doof = true;
|
||||
description = "colin-https-uninsane.org";
|
||||
};
|
||||
|
||||
services.nginx.enable = true;
|
||||
|
||||
users.users.nginx.extraGroups = [ "anubis" ];
|
||||
# nginxStable is one release behind nginxMainline.
|
||||
# nginx itself recommends running mainline; nixos defaults to stable.
|
||||
# services.nginx.package = pkgs.nginxMainline;
|
||||
# XXX(2024-07-31): nixos defaults to zlib-ng -- supposedly more performant, but spams log with
|
||||
# "gzip filter failed to use preallocated memory: ..."
|
||||
# XXX(2025-07-24): "gzip filter" spam is gone => use default nginx package
|
||||
# services.nginx.package = pkgs.nginxMainline.override { zlib = pkgs.zlib; };
|
||||
services.nginx.appendConfig = ''
|
||||
# use 1 process per core.
|
||||
# may want to increase worker_connections too, but `ulimit -n` must be increased first.
|
||||
worker_processes auto;
|
||||
'';
|
||||
|
||||
# this is the standard `combined` log format, with the addition of $host
|
||||
# so that we have the virtualHost in the log.
|
||||
# KEEP IN SYNC WITH GOACCESS
|
||||
# goaccess calls this VCOMBINED:
|
||||
# - <https://gist.github.com/jyap808/10570005>
|
||||
services.nginx.commonHttpConfig = ''
|
||||
log_format vcombined '$host:$server_port $remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referrer" "$http_user_agent"';
|
||||
access_log /var/log/nginx/private.log vcombined;
|
||||
'';
|
||||
# enables gzip and sets gzip_comp_level = 5
|
||||
services.nginx.recommendedGzipSettings = true;
|
||||
# enables zstd and sets zstd_comp_level = 9
|
||||
# services.nginx.recommendedZstdSettings = true; #< XXX(2025-07-18): nginx zstd integration is unmaintained in NixOS
|
||||
# enables OCSP stapling (so clients don't need contact the OCSP server -- i do instead)
|
||||
# - doesn't seem to, actually: <https://www.ssllabs.com/ssltest/analyze.html?d=uninsane.org>
|
||||
# caches TLS sessions for 10m
|
||||
services.nginx.recommendedTlsSettings = true;
|
||||
# enables sendfile, tcp_nopush, tcp_nodelay, keepalive_timeout 65
|
||||
services.nginx.recommendedOptimisation = true;
|
||||
|
||||
|
||||
# serve any site not otherwise declared, if it's static.
|
||||
# because we define it dynamically, SSL isn't trivial. support only http
|
||||
# documented <https://nginx.org/en/docs/http/ngx_http_core_module.html#server_name>
|
||||
services.nginx.virtualHosts."~^(?<domain>.+)$" = {
|
||||
default = true;
|
||||
addSSL = true;
|
||||
enableACME = false;
|
||||
sslCertificate = "/var/www/certs/wildcard/cert.pem";
|
||||
sslCertificateKey = "/var/www/certs/wildcard/key.pem";
|
||||
# sslCertificate = "/var/lib/acme/.minica/cert.pem";
|
||||
# sslCertificateKey = "/var/lib/acme/.minica/key.pem";
|
||||
# serverName = null;
|
||||
locations."/" = {
|
||||
# somehow this doesn't escape -- i get error 400 if i:
|
||||
# curl 'http://..' --resolve '..:80:127.0.0.1'
|
||||
root = "/var/www/sites/$domain";
|
||||
# tryFiles = "$domain/$uri $domain/$uri/ =404";
|
||||
};
|
||||
};
|
||||
|
||||
security.acme.acceptTerms = true;
|
||||
security.acme.defaults.email = "admin.acme@uninsane.org";
|
||||
|
||||
sane.persist.sys.byStore.plaintext = [
|
||||
{ user = "acme"; group = "acme"; path = "/var/lib/acme"; method = "bind"; }
|
||||
];
|
||||
sane.persist.sys.byStore.private = [
|
||||
{ user = "colin"; group = "users"; path = "/var/www/sites"; method = "bind"; }
|
||||
];
|
||||
sane.persist.sys.byStore.ephemeral = [
|
||||
# logs *could* be persisted to private storage, but then there's the issue of
|
||||
# "what if servo boots, isn't unlocked, and the whole / tmpfs is consumed by logs"
|
||||
{ user = "nginx"; group = "nginx"; path = "/var/log/nginx"; method = "bind"; }
|
||||
];
|
||||
|
||||
# create a self-signed SSL certificate for use with literally any domain.
|
||||
# browsers will reject this, but proxies and local testing tools can be configured
|
||||
# to accept it.
|
||||
system.activationScripts.generate-x509-self-signed.text = ''
|
||||
mkdir -p /var/www/certs/wildcard
|
||||
test -f /var/www/certs/wildcard/key.pem || ${lib.getExe pkgs.openssl} \
|
||||
req -x509 -newkey rsa:4096 \
|
||||
-keyout /var/www/certs/wildcard/key.pem \
|
||||
-out /var/www/certs/wildcard/cert.pem \
|
||||
-sha256 -nodes -days 3650 \
|
||||
-addext 'subjectAltName=DNS:*' \
|
||||
-subj '/CN=self-signed'
|
||||
chmod 640 /var/www/certs/wildcard/{key,cert}.pem
|
||||
chown root:nginx /var/www/certs/wildcard /var/www/certs/wildcard/{key,cert}.pem
|
||||
'';
|
||||
}
|
132
hosts/by-name/servo/services/nginx/uninsane.org.nix
Normal file
132
hosts/by-name/servo/services/nginx/uninsane.org.nix
Normal file
@@ -0,0 +1,132 @@
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
# alternative way to link stuff into the share:
|
||||
# sane.fs."/var/www/sites/uninsane.org/share/Ubunchu".mount.bind = "/var/media/Books/Visual/HiroshiSeo/Ubunchu";
|
||||
# sane.fs."/var/media/Books/Visual/HiroshiSeo/Ubunchu".dir = {};
|
||||
services.nginx.virtualHosts."uninsane.org" = {
|
||||
# a lot of places hardcode https://uninsane.org,
|
||||
# and then when we mix http + non-https, we get CORS violations
|
||||
# and things don't look right. so force SSL.
|
||||
forceSSL = true;
|
||||
enableACME = true;
|
||||
|
||||
# extraConfig = ''
|
||||
# # "public" log so requests show up in goaccess metrics
|
||||
# access_log /var/log/nginx/public.log vcombined;
|
||||
# '';
|
||||
|
||||
locations."/" = {
|
||||
root = "${pkgs.uninsane-dot-org}/share/uninsane-dot-org";
|
||||
tryFiles = "$uri $uri/ @fallback";
|
||||
};
|
||||
|
||||
# unversioned files
|
||||
locations."@fallback" = {
|
||||
root = "/var/www/sites/uninsane.org";
|
||||
extraConfig = ''
|
||||
# instruct Google to not index these pages.
|
||||
# see: <https://developers.google.com/search/docs/crawling-indexing/robots-meta-tag#xrobotstag>
|
||||
add_header X-Robots-Tag 'none, noindex, nofollow';
|
||||
|
||||
# best-effort attempt to block archive.org from archiving these pages.
|
||||
# reply with 403: Forbidden
|
||||
# User Agent is *probably* "archive.org_bot"; maybe used to be "ia_archiver"
|
||||
# source: <https://archive.org/details/archive.org_bot>
|
||||
# additional UAs: <https://github.com/mitchellkrogza/nginx-ultimate-bad-bot-blocker>
|
||||
#
|
||||
# validate with: `curl -H 'User-Agent: "bot;archive.org_bot;like: something else"' -v https://uninsane.org/dne`
|
||||
if ($http_user_agent ~* "(?:\b)archive.org_bot(?:\b)") {
|
||||
return 403;
|
||||
}
|
||||
if ($http_user_agent ~* "(?:\b)archive.org(?:\b)") {
|
||||
return 403;
|
||||
}
|
||||
if ($http_user_agent ~* "(?:\b)ia_archiver(?:\b)") {
|
||||
return 403;
|
||||
}
|
||||
'';
|
||||
};
|
||||
|
||||
# uninsane.org/share/foo => /var/www/sites/uninsane.org/share/foo.
|
||||
# special-cased to enable directory listings
|
||||
locations."/share" = {
|
||||
root = "/var/www/sites/uninsane.org";
|
||||
extraConfig = ''
|
||||
# autoindex => render directory listings
|
||||
autoindex on;
|
||||
# don't follow any symlinks when serving files
|
||||
# otherwise it allows a directory escape
|
||||
disable_symlinks on;
|
||||
'';
|
||||
};
|
||||
locations."/share/Milkbags/" = {
|
||||
alias = "/var/media/Videos/Milkbags/";
|
||||
extraConfig = ''
|
||||
# autoindex => render directory listings
|
||||
autoindex on;
|
||||
# don't follow any symlinks when serving files
|
||||
# otherwise it allows a directory escape
|
||||
disable_symlinks on;
|
||||
'';
|
||||
};
|
||||
locations."/share/Ubunchu/" = {
|
||||
alias = "/var/media/Books/Visual/HiroshiSeo/Ubunchu/";
|
||||
extraConfig = ''
|
||||
# autoindex => render directory listings
|
||||
autoindex on;
|
||||
# don't follow any symlinks when serving files
|
||||
# otherwise it allows a directory escape
|
||||
disable_symlinks on;
|
||||
'';
|
||||
};
|
||||
|
||||
# allow matrix users to discover that @user:uninsane.org is reachable via matrix.uninsane.org
|
||||
locations."= /.well-known/matrix/server".extraConfig =
|
||||
let
|
||||
# use 443 instead of the default 8448 port to unite
|
||||
# the client-server and server-server port for simplicity
|
||||
server = { "m.server" = "matrix.uninsane.org:443"; };
|
||||
in ''
|
||||
add_header Content-Type application/json;
|
||||
return 200 '${builtins.toJSON server}';
|
||||
'';
|
||||
locations."= /.well-known/matrix/client".extraConfig =
|
||||
let
|
||||
client = {
|
||||
"m.homeserver" = { "base_url" = "https://matrix.uninsane.org"; };
|
||||
"m.identity_server" = { "base_url" = "https://vector.im"; };
|
||||
};
|
||||
# ACAO required to allow element-web on any URL to request this json file
|
||||
in ''
|
||||
add_header Content-Type application/json;
|
||||
add_header Access-Control-Allow-Origin *;
|
||||
return 200 '${builtins.toJSON client}';
|
||||
'';
|
||||
|
||||
# static URLs might not be aware of .well-known (e.g. registration confirmation URLs),
|
||||
# so hack around that.
|
||||
locations."/_matrix".extraConfig = "return 301 https://matrix.uninsane.org$request_uri;";
|
||||
locations."/_synapse".extraConfig = "return 301 https://matrix.uninsane.org$request_uri;";
|
||||
|
||||
# allow ActivityPub clients to discover how to reach @user@uninsane.org
|
||||
# see: https://git.pleroma.social/pleroma/pleroma/-/merge_requests/3361/
|
||||
# not sure this makes sense while i run multiple AP services (pleroma, lemmy)
|
||||
# locations."/.well-known/nodeinfo" = {
|
||||
# proxyPass = "http://127.0.0.1:4000";
|
||||
# extraConfig = pleromaExtraConfig;
|
||||
# };
|
||||
|
||||
# redirect common feed URIs to the canonical feed
|
||||
locations."= /atom".extraConfig = "return 301 /atom.xml;";
|
||||
locations."= /feed".extraConfig = "return 301 /atom.xml;";
|
||||
locations."= /feed.xml".extraConfig = "return 301 /atom.xml;";
|
||||
locations."= /rss".extraConfig = "return 301 /atom.xml;";
|
||||
locations."= /rss.xml".extraConfig = "return 301 /atom.xml;";
|
||||
locations."= /blog/atom".extraConfig = "return 301 /atom.xml;";
|
||||
locations."= /blog/atom.xml".extraConfig = "return 301 /atom.xml;";
|
||||
locations."= /blog/feed".extraConfig = "return 301 /atom.xml;";
|
||||
locations."= /blog/feed.xml".extraConfig = "return 301 /atom.xml;";
|
||||
locations."= /blog/rss".extraConfig = "return 301 /atom.xml;";
|
||||
locations."= /blog/rss.xml".extraConfig = "return 301 /atom.xml;";
|
||||
};
|
||||
}
|
@@ -0,0 +1,35 @@
|
||||
{ config, pkgs, ... }:
|
||||
let
|
||||
wakaLakaOsaka = pkgs.linkFarm "waka-laka-osaka" {
|
||||
"index.html" = ./index.html;
|
||||
"waka.laka.for.osaka.mp4" = pkgs.fetchurl {
|
||||
# saved from: <https://www.youtube.com/watch?v=ehB_7bBKprY>
|
||||
url = "https://uninsane.org/share/Milkbags/PG_Plays_Video_Games-Waka_Laka_For_Osaka_4K.mp4";
|
||||
hash = "sha256-UW0qR4btX4pZ1bJp4Oxk20m3mvQGj9HweLKO27JBTFs=";
|
||||
};
|
||||
};
|
||||
in
|
||||
{
|
||||
services.nginx.virtualHosts."laka.osaka" = {
|
||||
addSSL = true;
|
||||
enableACME = true;
|
||||
locations."/" = {
|
||||
# redirect everything to waka.laka.osaka
|
||||
return = "301 https://waka.laka.osaka$request_uri";
|
||||
};
|
||||
};
|
||||
services.nginx.virtualHosts."waka.laka.osaka" = {
|
||||
addSSL = true;
|
||||
enableACME = true;
|
||||
locations."/" = {
|
||||
root = wakaLakaOsaka;
|
||||
};
|
||||
};
|
||||
|
||||
sane.dns.zones."laka.osaka".inet = {
|
||||
SOA."@" = config.sane.dns.zones."uninsane.org".inet.SOA."@";
|
||||
A."@" = config.sane.dns.zones."uninsane.org".inet.A."@";
|
||||
NS."@" = config.sane.dns.zones."uninsane.org".inet.NS."@";
|
||||
CNAME."waka" = "native.uninsane.org.";
|
||||
};
|
||||
}
|
@@ -0,0 +1,46 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width initial-scale=1" />
|
||||
<meta name="description" content="Waka Laka (for Osaka)" />
|
||||
<title>Waka Laka (for Osaka)</title>
|
||||
<style>
|
||||
html,body {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
}
|
||||
* {
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
border: 0px;
|
||||
}
|
||||
.bg-image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-width: 100%;
|
||||
min-height: 100%;
|
||||
position: fixed;
|
||||
background-repeat: no-repeat;
|
||||
background-position: 50% 50%;
|
||||
background-size: contain;
|
||||
}
|
||||
body {
|
||||
background-color: #000000;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- TODO: how to autoplay video _without_ it being muted? -->
|
||||
<video class="bg-image" id="waka-video" width="1440" height="1080"
|
||||
autoplay loop muted
|
||||
onclick="document.getElementById('waka-video').muted = !document.getElementById('waka-video').muted;"
|
||||
>
|
||||
<!-- from https://www.youtube.com/watch?v=ehB_7bBKprY -->
|
||||
<!-- original and more info at https://www.aquilinestudios.org/wakalaka.html -->
|
||||
<source src="waka.laka.for.osaka.mp4" type="video/mp4">
|
||||
</video>
|
||||
</body>
|
||||
</html>
|
@@ -6,7 +6,7 @@ lib.optionalAttrs false # disabled until i can be sure it's not gonna OOM my se
|
||||
description = "build a nixos image with all updated deps";
|
||||
path = with pkgs; [ coreutils git nix ];
|
||||
script = ''
|
||||
working=$(mktemp -d /tmp/nixos-prebuild.XXXXXX)
|
||||
working=$(mktemp -d nixos-prebuild.XXXXXX --tmpdir)
|
||||
pushd "$working"
|
||||
git clone https://git.uninsane.org/colin/nix-files.git \
|
||||
&& cd nix-files \
|
||||
|
@@ -14,207 +14,209 @@ let
|
||||
# logLevel = "debug";
|
||||
in
|
||||
{
|
||||
sane.persist.sys.byStore.private = [
|
||||
# contains media i've uploaded to the server
|
||||
{ user = "pleroma"; group = "pleroma"; path = "/var/lib/pleroma"; method = "bind"; }
|
||||
];
|
||||
services.pleroma.enable = true;
|
||||
services.pleroma.secretConfigFile = config.sops.secrets.pleroma_secrets.path;
|
||||
services.pleroma.configs = [
|
||||
''
|
||||
import Config
|
||||
config = lib.mkIf (config.sane.maxBuildCost >= 2) {
|
||||
sane.persist.sys.byStore.private = [
|
||||
# contains media i've uploaded to the server
|
||||
{ user = "pleroma"; group = "pleroma"; path = "/var/lib/pleroma"; method = "bind"; }
|
||||
];
|
||||
services.pleroma.enable = true;
|
||||
services.pleroma.secretConfigFile = config.sops.secrets.pleroma_secrets.path;
|
||||
services.pleroma.configs = [
|
||||
''
|
||||
import Config
|
||||
|
||||
config :pleroma, Pleroma.Web.Endpoint,
|
||||
url: [host: "fed.uninsane.org", scheme: "https", port: 443],
|
||||
http: [ip: {127, 0, 0, 1}, port: 4040]
|
||||
# secret_key_base: "{secrets.pleroma.secret_key_base}",
|
||||
# signing_salt: "{secrets.pleroma.signing_salt}"
|
||||
config :pleroma, Pleroma.Web.Endpoint,
|
||||
url: [host: "fed.uninsane.org", scheme: "https", port: 443],
|
||||
http: [ip: {127, 0, 0, 1}, port: 4040]
|
||||
# secret_key_base: "{secrets.pleroma.secret_key_base}",
|
||||
# signing_salt: "{secrets.pleroma.signing_salt}"
|
||||
|
||||
config :pleroma, :instance,
|
||||
name: "Perfectly Sane",
|
||||
description: "Single-user Pleroma instance",
|
||||
email: "admin.pleroma@uninsane.org",
|
||||
notify_email: "notify.pleroma@uninsane.org",
|
||||
limit: 5000,
|
||||
registrations_open: true,
|
||||
account_approval_required: true,
|
||||
max_pinned_statuses: 5,
|
||||
external_user_synchronization: true
|
||||
config :pleroma, :instance,
|
||||
name: "Perfectly Sane",
|
||||
description: "Single-user Pleroma instance",
|
||||
email: "admin.pleroma@uninsane.org",
|
||||
notify_email: "notify.pleroma@uninsane.org",
|
||||
limit: 5000,
|
||||
registrations_open: true,
|
||||
account_approval_required: true,
|
||||
max_pinned_statuses: 5,
|
||||
external_user_synchronization: true
|
||||
|
||||
# docs: https://hexdocs.pm/swoosh/Swoosh.Adapters.Sendmail.html
|
||||
# test mail config with sudo -u pleroma ./bin/pleroma_ctl email test --to someone@somewhere.net
|
||||
config :pleroma, Pleroma.Emails.Mailer,
|
||||
enabled: true,
|
||||
adapter: Swoosh.Adapters.Sendmail,
|
||||
cmd_path: "${lib.getExe' pkgs.postfix "sendmail"}"
|
||||
# docs: https://hexdocs.pm/swoosh/Swoosh.Adapters.Sendmail.html
|
||||
# test mail config with sudo -u pleroma ./bin/pleroma_ctl email test --to someone@somewhere.net
|
||||
config :pleroma, Pleroma.Emails.Mailer,
|
||||
enabled: true,
|
||||
adapter: Swoosh.Adapters.Sendmail,
|
||||
cmd_path: "${lib.getExe' pkgs.postfix "sendmail"}"
|
||||
|
||||
config :pleroma, Pleroma.User,
|
||||
restricted_nicknames: [ "admin", "uninsane", "root" ]
|
||||
config :pleroma, Pleroma.User,
|
||||
restricted_nicknames: [ "admin", "uninsane", "root" ]
|
||||
|
||||
config :pleroma, :media_proxy,
|
||||
enabled: false,
|
||||
redirect_on_failure: true
|
||||
#base_url: "https://cache.pleroma.social"
|
||||
config :pleroma, :media_proxy,
|
||||
enabled: false,
|
||||
redirect_on_failure: true
|
||||
#base_url: "https://cache.pleroma.social"
|
||||
|
||||
# see for reference:
|
||||
# - `force_custom_plan`: <https://docs.pleroma.social/backend/configuration/postgresql/#disable-generic-query-plans>
|
||||
config :pleroma, Pleroma.Repo,
|
||||
adapter: Ecto.Adapters.Postgres,
|
||||
username: "pleroma",
|
||||
database: "pleroma",
|
||||
hostname: "localhost",
|
||||
pool_size: 10,
|
||||
prepare: :named,
|
||||
parameters: [
|
||||
plan_cache_mode: "force_custom_plan"
|
||||
]
|
||||
# XXX: prepare: :named is needed only for PG <= 12
|
||||
# prepare: :named,
|
||||
# password: "{secrets.pleroma.db_password}",
|
||||
# see for reference:
|
||||
# - `force_custom_plan`: <https://docs.pleroma.social/backend/configuration/postgresql/#disable-generic-query-plans>
|
||||
config :pleroma, Pleroma.Repo,
|
||||
adapter: Ecto.Adapters.Postgres,
|
||||
username: "pleroma",
|
||||
database: "pleroma",
|
||||
hostname: "localhost",
|
||||
pool_size: 10,
|
||||
prepare: :named,
|
||||
parameters: [
|
||||
plan_cache_mode: "force_custom_plan"
|
||||
]
|
||||
# XXX: prepare: :named is needed only for PG <= 12
|
||||
# prepare: :named,
|
||||
# password: "{secrets.pleroma.db_password}",
|
||||
|
||||
# Configure web push notifications
|
||||
config :web_push_encryption, :vapid_details,
|
||||
subject: "mailto:notify.pleroma@uninsane.org"
|
||||
# public_key: "{secrets.pleroma.vapid_public_key}",
|
||||
# private_key: "{secrets.pleroma.vapid_private_key}"
|
||||
# Configure web push notifications
|
||||
config :web_push_encryption, :vapid_details,
|
||||
subject: "mailto:notify.pleroma@uninsane.org"
|
||||
# public_key: "{secrets.pleroma.vapid_public_key}",
|
||||
# private_key: "{secrets.pleroma.vapid_private_key}"
|
||||
|
||||
# config :joken, default_signer: "{secrets.pleroma.joken_default_signer}"
|
||||
# config :joken, default_signer: "{secrets.pleroma.joken_default_signer}"
|
||||
|
||||
config :pleroma, :database, rum_enabled: false
|
||||
config :pleroma, :instance, static_dir: "/var/lib/pleroma/instance/static"
|
||||
config :pleroma, Pleroma.Uploaders.Local, uploads: "/var/lib/pleroma/uploads"
|
||||
config :pleroma, configurable_from_database: false
|
||||
config :pleroma, :database, rum_enabled: false
|
||||
config :pleroma, :instance, static_dir: "/var/lib/pleroma/instance/static"
|
||||
config :pleroma, Pleroma.Uploaders.Local, uploads: "/var/lib/pleroma/uploads"
|
||||
config :pleroma, configurable_from_database: false
|
||||
|
||||
# strip metadata from uploaded images
|
||||
config :pleroma, Pleroma.Upload, filters: [Pleroma.Upload.Filter.Exiftool.StripLocation]
|
||||
# strip metadata from uploaded images
|
||||
config :pleroma, Pleroma.Upload, filters: [Pleroma.Upload.Filter.Exiftool.StripLocation]
|
||||
|
||||
# fix log spam: <https://git.pleroma.social/pleroma/pleroma/-/issues/1659>
|
||||
# specifically, remove LAN addresses from `reserved`
|
||||
config :pleroma, Pleroma.Web.Plugs.RemoteIp,
|
||||
enabled: true,
|
||||
reserved: ["127.0.0.0/8", "::1/128", "fc00::/7", "172.16.0.0/12"]
|
||||
# fix log spam: <https://git.pleroma.social/pleroma/pleroma/-/issues/1659>
|
||||
# specifically, remove LAN addresses from `reserved`
|
||||
config :pleroma, Pleroma.Web.Plugs.RemoteIp,
|
||||
enabled: true,
|
||||
reserved: ["127.0.0.0/8", "::1/128", "fc00::/7", "172.16.0.0/12"]
|
||||
|
||||
# TODO: GET /api/pleroma/captcha is broken
|
||||
# there was a nixpkgs PR to fix this around 2022/10 though.
|
||||
config :pleroma, Pleroma.Captcha,
|
||||
enabled: false,
|
||||
method: Pleroma.Captcha.Native
|
||||
# TODO: GET /api/pleroma/captcha is broken
|
||||
# there was a nixpkgs PR to fix this around 2022/10 though.
|
||||
config :pleroma, Pleroma.Captcha,
|
||||
enabled: false,
|
||||
method: Pleroma.Captcha.Native
|
||||
|
||||
|
||||
# (enabled by colin)
|
||||
# Enable Strict-Transport-Security once SSL is working:
|
||||
config :pleroma, :http_security,
|
||||
sts: true
|
||||
# (enabled by colin)
|
||||
# Enable Strict-Transport-Security once SSL is working:
|
||||
config :pleroma, :http_security,
|
||||
sts: true
|
||||
|
||||
# docs: https://docs.pleroma.social/backend/configuration/cheatsheet/#logger
|
||||
config :logger,
|
||||
backends: [{ExSyslogger, :ex_syslogger}]
|
||||
# docs: https://docs.pleroma.social/backend/configuration/cheatsheet/#logger
|
||||
config :logger,
|
||||
backends: [{ExSyslogger, :ex_syslogger}]
|
||||
|
||||
config :logger, :ex_syslogger,
|
||||
level: :${logLevel}
|
||||
config :logger, :ex_syslogger,
|
||||
level: :${logLevel}
|
||||
|
||||
# policies => list of message rewriting facilities to be enabled
|
||||
# transparence => whether to publish these rules in node_info (and /about)
|
||||
config :pleroma, :mrf,
|
||||
policies: [Pleroma.Web.ActivityPub.MRF.SimplePolicy],
|
||||
transparency: true
|
||||
# policies => list of message rewriting facilities to be enabled
|
||||
# transparence => whether to publish these rules in node_info (and /about)
|
||||
config :pleroma, :mrf,
|
||||
policies: [Pleroma.Web.ActivityPub.MRF.SimplePolicy],
|
||||
transparency: true
|
||||
|
||||
# reject => { host, reason }
|
||||
config :pleroma, :mrf_simple,
|
||||
reject: [ {"threads.net", "megacorp"}, {"*.threads.net", "megacorp"} ]
|
||||
# reject: [ [host: "threads.net", reason: "megacorp"], [host: "*.threads.net", reason: "megacorp"] ]
|
||||
# reject => { host, reason }
|
||||
config :pleroma, :mrf_simple,
|
||||
reject: [ {"threads.net", "megacorp"}, {"*.threads.net", "megacorp"} ]
|
||||
# reject: [ [host: "threads.net", reason: "megacorp"], [host: "*.threads.net", reason: "megacorp"] ]
|
||||
|
||||
# XXX colin: not sure if this actually _does_ anything
|
||||
# better to steal emoji from other instances?
|
||||
# - <https://docs.pleroma.social/backend/configuration/cheatsheet/#mrf_steal_emoji>
|
||||
config :pleroma, :emoji,
|
||||
shortcode_globs: ["/emoji/**/*.png"],
|
||||
groups: [
|
||||
"Cirno": "/emoji/cirno/*.png",
|
||||
"Kirby": "/emoji/kirby/*.png",
|
||||
"Bun": "/emoji/bun/*.png",
|
||||
"Yuru Camp": "/emoji/yuru_camp/*.png",
|
||||
]
|
||||
''
|
||||
];
|
||||
# XXX colin: not sure if this actually _does_ anything
|
||||
# better to steal emoji from other instances?
|
||||
# - <https://docs.pleroma.social/backend/configuration/cheatsheet/#mrf_steal_emoji>
|
||||
config :pleroma, :emoji,
|
||||
shortcode_globs: ["/emoji/**/*.png"],
|
||||
groups: [
|
||||
"Cirno": "/emoji/cirno/*.png",
|
||||
"Kirby": "/emoji/kirby/*.png",
|
||||
"Bun": "/emoji/bun/*.png",
|
||||
"Yuru Camp": "/emoji/yuru_camp/*.png",
|
||||
]
|
||||
''
|
||||
];
|
||||
|
||||
systemd.services.pleroma.path = [
|
||||
# something inside pleroma invokes `sh` w/o specifying it by path, so this is needed to allow pleroma to start
|
||||
pkgs.bash
|
||||
# used by Pleroma to strip geo tags from uploads
|
||||
pkgs.exiftool
|
||||
# config.sane.programs.exiftool.package #< XXX(2024-10-20): breaks image uploading
|
||||
# i saw some errors when pleroma was shutting down about it not being able to find `awk`. probably not critical
|
||||
# config.sane.programs.gawk.package
|
||||
# needed for email operations like password reset
|
||||
pkgs.postfix
|
||||
];
|
||||
systemd.services.pleroma.path = [
|
||||
# something inside pleroma invokes `sh` w/o specifying it by path, so this is needed to allow pleroma to start
|
||||
pkgs.bash
|
||||
# used by Pleroma to strip geo tags from uploads
|
||||
pkgs.exiftool
|
||||
# config.sane.programs.exiftool.package #< XXX(2024-10-20): breaks image uploading
|
||||
# i saw some errors when pleroma was shutting down about it not being able to find `awk`. probably not critical
|
||||
# config.sane.programs.gawk.package
|
||||
# needed for email operations like password reset
|
||||
pkgs.postfix
|
||||
];
|
||||
|
||||
systemd.services.pleroma = {
|
||||
# postgres can be slow to service early requests, preventing pleroma from starting on the first try
|
||||
serviceConfig.Restart = "on-failure";
|
||||
serviceConfig.RestartSec = "10s";
|
||||
systemd.services.pleroma = {
|
||||
# postgres can be slow to service early requests, preventing pleroma from starting on the first try
|
||||
serviceConfig.Restart = "on-failure";
|
||||
serviceConfig.RestartSec = "10s";
|
||||
|
||||
# hardening (systemd-analyze security pleroma)
|
||||
# XXX(2024-07-28): this hasn't been rigorously tested:
|
||||
# possible that i've set something too strict and won't notice right away
|
||||
# make sure to test:
|
||||
# - image/media uploading
|
||||
serviceConfig.CapabilityBoundingSet = lib.mkForce [ "" "" ]; # nixos default is `~CAP_SYS_ADMIN`
|
||||
serviceConfig.LockPersonality = true;
|
||||
serviceConfig.NoNewPrivileges = true;
|
||||
serviceConfig.MemoryDenyWriteExecute = true;
|
||||
serviceConfig.PrivateDevices = lib.mkForce true; #< dunno why nixpkgs has this set false; it seems to work as true
|
||||
serviceConfig.PrivateMounts = true;
|
||||
serviceConfig.PrivateTmp = true;
|
||||
serviceConfig.PrivateUsers = true;
|
||||
# hardening (systemd-analyze security pleroma)
|
||||
# XXX(2024-07-28): this hasn't been rigorously tested:
|
||||
# possible that i've set something too strict and won't notice right away
|
||||
# make sure to test:
|
||||
# - image/media uploading
|
||||
serviceConfig.CapabilityBoundingSet = lib.mkForce [ "" "" ]; # nixos default is `~CAP_SYS_ADMIN`
|
||||
serviceConfig.LockPersonality = true;
|
||||
serviceConfig.NoNewPrivileges = true;
|
||||
serviceConfig.MemoryDenyWriteExecute = true;
|
||||
serviceConfig.PrivateDevices = lib.mkForce true; #< dunno why nixpkgs has this set false; it seems to work as true
|
||||
serviceConfig.PrivateMounts = true;
|
||||
serviceConfig.PrivateTmp = true;
|
||||
serviceConfig.PrivateUsers = true;
|
||||
|
||||
serviceConfig.ProtectProc = "invisible";
|
||||
serviceConfig.ProcSubset = "all"; #< needs /proc/sys/kernel/overflowuid for bwrap
|
||||
serviceConfig.ProtectProc = "invisible";
|
||||
serviceConfig.ProcSubset = "all"; #< needs /proc/sys/kernel/overflowuid for bwrap
|
||||
|
||||
serviceConfig.ProtectClock = true;
|
||||
serviceConfig.ProtectControlGroups = true;
|
||||
serviceConfig.ProtectHome = true;
|
||||
serviceConfig.ProtectKernelModules = true;
|
||||
serviceConfig.ProtectSystem = lib.mkForce "strict";
|
||||
serviceConfig.RemoveIPC = true;
|
||||
serviceConfig.RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6 AF_NETLINK";
|
||||
serviceConfig.ProtectClock = true;
|
||||
serviceConfig.ProtectControlGroups = true;
|
||||
serviceConfig.ProtectHome = true;
|
||||
serviceConfig.ProtectKernelModules = true;
|
||||
serviceConfig.ProtectSystem = lib.mkForce "strict";
|
||||
serviceConfig.RemoveIPC = true;
|
||||
serviceConfig.RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6 AF_NETLINK";
|
||||
|
||||
serviceConfig.RestrictSUIDSGID = true;
|
||||
serviceConfig.SystemCallArchitectures = "native";
|
||||
serviceConfig.SystemCallFilter = [ "@system-service" "@mount" "@sandbox" ]; #< "sandbox" might not actually be necessary
|
||||
serviceConfig.RestrictSUIDSGID = true;
|
||||
serviceConfig.SystemCallArchitectures = "native";
|
||||
serviceConfig.SystemCallFilter = [ "@system-service" "@mount" "@sandbox" ]; #< "sandbox" might not actually be necessary
|
||||
|
||||
serviceConfig.ProtectHostname = false; #< else brap can't mount /proc
|
||||
serviceConfig.ProtectKernelLogs = false; #< else breaks exiftool ("bwrap: Can't mount proc on /newroot/proc: Operation not permitted")
|
||||
serviceConfig.ProtectKernelTunables = false; #< else breaks exiftool
|
||||
serviceConfig.RestrictNamespaces = false; # media uploads require bwrap
|
||||
};
|
||||
serviceConfig.ProtectHostname = false; #< else brap can't mount /proc
|
||||
serviceConfig.ProtectKernelLogs = false; #< else breaks exiftool ("bwrap: Can't mount proc on /newroot/proc: Operation not permitted")
|
||||
serviceConfig.ProtectKernelTunables = false; #< else breaks exiftool
|
||||
serviceConfig.RestrictNamespaces = false; # media uploads require bwrap
|
||||
};
|
||||
|
||||
# this is required to allow pleroma to send email.
|
||||
# raw `sendmail` works, but i think pleroma's passing it some funny flags or something, idk.
|
||||
# hack to fix that.
|
||||
users.users.pleroma.extraGroups = [ "postdrop" ];
|
||||
# this is required to allow pleroma to send email.
|
||||
# raw `sendmail` works, but i think pleroma's passing it some funny flags or something, idk.
|
||||
# hack to fix that.
|
||||
users.users.pleroma.extraGroups = [ "postdrop" ];
|
||||
|
||||
# Pleroma server and web interface
|
||||
# TODO: enable publog?
|
||||
services.nginx.virtualHosts."fed.uninsane.org" = {
|
||||
forceSSL = true; # pleroma redirects to https anyway
|
||||
enableACME = true;
|
||||
# inherit kTLS;
|
||||
locations."/" = {
|
||||
proxyPass = "http://127.0.0.1:4040";
|
||||
recommendedProxySettings = true;
|
||||
# documented: https://git.pleroma.social/pleroma/pleroma/-/blob/develop/installation/pleroma.nginx
|
||||
extraConfig = ''
|
||||
# client_max_body_size defines the maximum upload size
|
||||
client_max_body_size 16m;
|
||||
'';
|
||||
# Pleroma server and web interface
|
||||
# TODO: enable publog?
|
||||
services.nginx.virtualHosts."fed.uninsane.org" = {
|
||||
forceSSL = true; # pleroma redirects to https anyway
|
||||
enableACME = true;
|
||||
# inherit kTLS;
|
||||
locations."/" = {
|
||||
proxyPass = "http://127.0.0.1:4040";
|
||||
recommendedProxySettings = true;
|
||||
# documented: https://git.pleroma.social/pleroma/pleroma/-/blob/develop/installation/pleroma.nginx
|
||||
extraConfig = ''
|
||||
# client_max_body_size defines the maximum upload size
|
||||
client_max_body_size 16m;
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
sane.dns.zones."uninsane.org".inet.CNAME."fed" = "native";
|
||||
|
||||
sops.secrets."pleroma_secrets" = {
|
||||
owner = config.users.users.pleroma.name;
|
||||
};
|
||||
};
|
||||
|
||||
sane.dns.zones."uninsane.org".inet.CNAME."fed" = "native";
|
||||
|
||||
sops.secrets."pleroma_secrets" = {
|
||||
owner = config.users.users.pleroma.name;
|
||||
};
|
||||
}
|
||||
|
@@ -1,4 +1,4 @@
|
||||
{ pkgs, ... }:
|
||||
{ lib, pkgs, ... }:
|
||||
|
||||
let
|
||||
GiB = n: MiB 1024*n;
|
||||
@@ -35,7 +35,6 @@ in
|
||||
services.postgresql.package = pkgs.postgresql_16;
|
||||
|
||||
|
||||
|
||||
# XXX colin: for a proper deploy, we'd want to include something for Pleroma here too.
|
||||
# services.postgresql.initialScript = pkgs.writeText "synapse-init.sql" ''
|
||||
# CREATE ROLE "matrix-synapse" WITH LOGIN PASSWORD '<password goes here>';
|
||||
@@ -46,10 +45,10 @@ in
|
||||
# LC_CTYPE = "C";
|
||||
# '';
|
||||
|
||||
# perf tuning
|
||||
# - for recommended values see: <https://pgtune.leopard.in.ua/>
|
||||
# - for official docs (sparse), see: <https://www.postgresql.org/docs/11/config-setting.html#CONFIG-SETTING-CONFIGURATION-FILE>
|
||||
services.postgresql.settings = {
|
||||
# perf tuning
|
||||
# - for recommended values see: <https://pgtune.leopard.in.ua/>
|
||||
# - for official docs (sparse), see: <https://www.postgresql.org/docs/11/config-setting.html#CONFIG-SETTING-CONFIGURATION-FILE>
|
||||
# DB Version: 16
|
||||
# OS Type: linux
|
||||
# DB Type: web
|
||||
@@ -73,8 +72,19 @@ in
|
||||
max_parallel_workers_per_gather = 4;
|
||||
max_parallel_workers = 12;
|
||||
max_parallel_maintenance_workers = 4;
|
||||
|
||||
# DEBUG OPTIONS:
|
||||
log_min_messages = "DEBUG1";
|
||||
};
|
||||
|
||||
# regulate the restarts, so that systemd never disables it
|
||||
systemd.services.postgresql.serviceConfig.Restart = lib.mkForce "on-failure";
|
||||
systemd.services.postgresql.serviceConfig.RestartSec = 2;
|
||||
systemd.services.postgresql.serviceConfig.RestartMaxDelaySec = 10;
|
||||
systemd.services.postgresql.serviceConfig.RestartSteps = 4;
|
||||
systemd.services.postgresql.serviceConfig.StartLimitBurst = 120;
|
||||
# systemd.services.postgresql.serviceConfig.TimeoutStartSec = "14400s"; #< 14400 = 4 hours; recoveries are long
|
||||
|
||||
# daily backups to /var/backup
|
||||
services.postgresqlBackup.enable = true;
|
||||
|
81
hosts/by-name/servo/services/postgresql/recollate.sh
Executable file
81
hosts/by-name/servo/services/postgresql/recollate.sh
Executable file
@@ -0,0 +1,81 @@
|
||||
#!/bin/sh
|
||||
# source: <https://gist.githubusercontent.com/troykelly/616df024050dd50744dde4a9579e152e/raw/fe84e53cedf0caa6903604894454629a15867439/reindex_and_refresh_collation.sh>
|
||||
#
|
||||
# run this whenever postgres complains like:
|
||||
# > WARNING: database "gitea" has a collation version mismatch
|
||||
# > DETAIL: The database was created using collation version 2.39, but the operating system provides version 2.40.
|
||||
# > HINT: Rebuild all objects in this database that use the default collation and run ALTER DATABASE gitea REFRESH COLLATION VERSION, or build PostgreSQL with the right library version.
|
||||
#
|
||||
# this script checks which databases are in need of a collation update,
|
||||
# and re-collates them as appropriate.
|
||||
# invoking this script should have low perf impact in the non-upgrade case,
|
||||
# so safe to do this as a cron job.
|
||||
#
|
||||
# invoke as postgres user
|
||||
|
||||
log_info() {
|
||||
>&2 echo "$@"
|
||||
}
|
||||
|
||||
list_databases() {
|
||||
log_info "Retrieving list of databases from the PostgreSQL server..."
|
||||
psql --dbname="postgres" -Atc \
|
||||
"SELECT datname FROM pg_database WHERE datistemplate = false"
|
||||
}
|
||||
|
||||
refresh_collation_version() {
|
||||
local db=$1
|
||||
log_info "Refreshing collation version for database: $db..."
|
||||
psql --dbname="$db" -c \
|
||||
"ALTER DATABASE \"$db\" REFRESH COLLATION VERSION;"
|
||||
}
|
||||
|
||||
check_collation_mismatches() {
|
||||
local error=
|
||||
log_info "Checking for collation mismatches in all databases..."
|
||||
# Loop through each database and check for mismatching collations in table columns.
|
||||
while IFS= read -r db; do
|
||||
if [ -n "$db" ]; then
|
||||
log_info "Checking database: $db for collation mismatches..."
|
||||
local mismatches=$(psql --dbname="$db" -Atc \
|
||||
"SELECT 'Mismatch in table ' || table_name || ' column ' || column_name || ' with collation ' || collation_name
|
||||
FROM information_schema.columns
|
||||
WHERE collation_name IS NOT NULL AND collation_name <> 'default' AND table_schema = 'public'
|
||||
EXCEPT
|
||||
SELECT 'No mismatch - default collation of ' || datcollate || ' used.'
|
||||
FROM pg_database WHERE datname = '$db';"
|
||||
)
|
||||
if [ -z "$mismatches" ]; then
|
||||
log_info "No collation mismatches found in database: $db"
|
||||
else
|
||||
# Print an informational message to stderr.
|
||||
log_info "Collation mismatches found in database: $db:"
|
||||
log_info "$mismatches"
|
||||
error=1
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
if [ -n "$error" ]; then
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
log_info "Starting the reindexing and collation refresh process for all databases..."
|
||||
|
||||
databases=$(list_databases)
|
||||
|
||||
if [ -z "$databases" ]; then
|
||||
log_info "No databases found for reindexing or collation refresh. Please check connection details to PostgreSQL server."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
for db in $databases; do
|
||||
refresh_collation_version "$db"
|
||||
done
|
||||
|
||||
# Checking for collation mismatches after reindexing and collation refresh.
|
||||
# Pass the list of databases to the check_collation_mismatches function through stdin.
|
||||
echo "$databases" | check_collation_mismatches
|
||||
|
||||
log_info "Reindexing and collation refresh process completed."
|
@@ -173,7 +173,7 @@ in
|
||||
domain = "conference.xmpp.uninsane.org";
|
||||
}
|
||||
];
|
||||
uploadHttp.domain = "upload.xmpp.uninsane.org";
|
||||
httpFileShare.domain = "upload.xmpp.uninsane.org";
|
||||
|
||||
virtualHosts = {
|
||||
# "Prosody requires at least one enabled VirtualHost to function. You can
|
||||
@@ -282,6 +282,7 @@ in
|
||||
ntfy_binary = "${lib.getExe' pkgs.ntfy-sh "ntfy"}"
|
||||
ntfy_topic = readAll("/run/secrets/ntfy-sh-topic")
|
||||
'';
|
||||
checkConfig = false; # secrets aren't available at build time
|
||||
};
|
||||
|
||||
systemd.services.prosody = {
|
||||
|
@@ -36,6 +36,7 @@
|
||||
locations."/" = {
|
||||
proxyPass = "http://${config.sane.netns.ovpns.veth.netns.ipv4}:5030";
|
||||
proxyWebsockets = true;
|
||||
recommendedProxySettings = true;
|
||||
};
|
||||
};
|
||||
|
||||
|
@@ -159,6 +159,7 @@ in
|
||||
locations."/" = {
|
||||
# proxyPass = "http://ovpns.uninsane.org:9091";
|
||||
proxyPass = "http://${config.sane.netns.ovpns.veth.netns.ipv4}:9091";
|
||||
recommendedProxySettings = true;
|
||||
};
|
||||
};
|
||||
|
||||
|
@@ -3,8 +3,20 @@
|
||||
|
||||
# transmission invokes this with no args, and the following env vars:
|
||||
# - TR_TORRENT_DIR: full path to the folder i told transmission to download it to.
|
||||
# e.g. /var/media/torrents/Videos/Film/Jason.Bourne-2016
|
||||
# optionally:
|
||||
# e.g. "/var/media/torrents/Videos/Film/Jason.Bourne-2016"
|
||||
# - TR_APP_VERSION
|
||||
# - TR_TIME_LOCALTIME
|
||||
# - TR_TORRENT_BYTES_DOWNLOADED
|
||||
# - TR_TORRENT_HASH
|
||||
# - TR_TORRENT_ID: local number to uniquely identify this torrent, used by e.g. transmission-remote.
|
||||
# e.g. "67"
|
||||
# - TR_TORRENT_LABELS
|
||||
# - TR_TORRENT_NAME: file/folder name of the toplevel torrent item
|
||||
# e.g. "Jason Bourne (2016) [2160p] [4K] [BluRay] [5.1] [YTS.MX]"
|
||||
# - TR_TORRENT_PRIORITY
|
||||
# - TR_TORRENT_TRACKERS
|
||||
|
||||
# optionally, set these variables for debugging (these are specific to my script and not used upstream):
|
||||
# - TR_DRY_RUN=1
|
||||
# - TR_DEBUG=1
|
||||
|
||||
@@ -24,7 +36,7 @@ debug() {
|
||||
fi
|
||||
}
|
||||
|
||||
echo "TR_TORRENT_DIR=$TR_TORRENT_DIR torrent-done $*"
|
||||
echo "TR_TORRENT_DIR=$TR_TORRENT_DIR TR_TORRENT_NAME=$TR_TORRENT_NAME torrent-done $*"
|
||||
|
||||
if [[ "$TR_TORRENT_DIR" =~ ^.*freeleech.*$ ]]; then
|
||||
# freeleech torrents have no place in my permanent library
|
||||
@@ -33,20 +45,35 @@ if [[ "$TR_TORRENT_DIR" =~ ^.*freeleech.*$ ]]; then
|
||||
fi
|
||||
if ! [[ "$TR_TORRENT_DIR" =~ ^$DOWNLOAD_DIR/.*$ ]]; then
|
||||
echo "unexpected torrent dir, aborting: $TR_TORRENT_DIR"
|
||||
exit 0
|
||||
exit 1
|
||||
fi
|
||||
|
||||
TORRENT_PATH="$TR_TORRENT_DIR/$TR_TORRENT_NAME"
|
||||
if [[ ! -e "$TORRENT_PATH" ]]; then
|
||||
echo "torrent unexpectedly doesn't exist at $TORRENT_PATH. will try fallback"
|
||||
TORRENT_PATH="$TR_TORRENT_DIR"
|
||||
fi
|
||||
|
||||
if [[ -d "$TORRENT_PATH" ]]; then
|
||||
# trailing slash so that rsync copies the directory contents, without creating an extra toplevel dir.
|
||||
TORRENT_PATH="$TORRENT_PATH/"
|
||||
elif [[ ! -e "$TORRENT_PATH" ]]; then
|
||||
echo "torrent unexpectedly doesn't exist at TR_TORRENT_DIR=$TORRENT_PATH: bailing"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
REL_DIR="${TR_TORRENT_DIR#$DOWNLOAD_DIR/}"
|
||||
MEDIA_DIR="/var/media/$REL_DIR"
|
||||
|
||||
destructive mkdir -p "$(dirname "$MEDIA_DIR")"
|
||||
destructive rsync -rlv "$TR_TORRENT_DIR/" "$MEDIA_DIR/"
|
||||
destructive rsync -rlv "$TORRENT_PATH" "$MEDIA_DIR/"
|
||||
# make the media rwx by anyone in the group
|
||||
destructive find "$MEDIA_DIR" -type d -exec setfacl --recursive --modify d:g::rwx,o::rx {} \;
|
||||
destructive find "$MEDIA_DIR" -type d -exec chmod g+rw,a+rx {} \;
|
||||
destructive find "$MEDIA_DIR" -type f -exec chmod g+rw,a+r {} \;
|
||||
|
||||
# if there's a single directory inside the media dir, then inline that
|
||||
# if there's a single directory inside the media dir, then inline that.
|
||||
# TODO: this is probably obsolete now that i process TR_TORRENT_NAME
|
||||
subdirs=("$MEDIA_DIR"/*)
|
||||
debug "top-level items in torrent dir:" "${subdirs[@]}"
|
||||
if [ ${#subdirs[@]} -eq 1 ]; then
|
||||
@@ -61,10 +88,24 @@ fi
|
||||
# -iname means "insensitive", but the syntax is NOT regex -- more similar to shell matching
|
||||
destructive find "$MEDIA_DIR/" -type f \(\
|
||||
-iname '*downloaded?from*' \
|
||||
-o -iname 'source.txt' \
|
||||
-o -iname '(xxxpav69).txt' \
|
||||
-o -iname '*upcoming?releases*' \
|
||||
-o -iname 'www.YTS*.jpg' \
|
||||
-o -iname 'ETRG.mp4' \
|
||||
-o -iname 'Encoded by*.txt' \
|
||||
-o -iname 'PSArips.com.txt' \
|
||||
-o -iname 'RARBG.com*' \
|
||||
-o -iname 'RARBG.txt' \
|
||||
-o -iname 'RARBG_DO_NOT_MIRROR.exe' \
|
||||
-o -iname 'Tellytorrent.net.txt' \
|
||||
-o -iname 'WWW.VPPV.LA.txt' \
|
||||
-o -iname 'WWW.YIFY*.COM.jpg' \
|
||||
-o -iname 'YIFY*.com.txt' \
|
||||
-o -iname 'YTS*.com.txt' \
|
||||
-o -iname 'YTSYify*.txt' \
|
||||
-o -iname 'www.YTS*.jpg' \
|
||||
\) -exec rm {} \;
|
||||
|
||||
# might want to keep, might want to remove:
|
||||
# -o -iname 'info.txt'
|
||||
# -o -iname 'source.txt'
|
||||
# -o -iname 'sample.mkv'
|
||||
|
6
hosts/by-name/servo/users/default.nix
Normal file
6
hosts/by-name/servo/users/default.nix
Normal file
@@ -0,0 +1,6 @@
|
||||
{ ... }:
|
||||
{
|
||||
imports = [
|
||||
./shelvacu.nix
|
||||
];
|
||||
}
|
65
hosts/by-name/servo/users/shelvacu.nix
Normal file
65
hosts/by-name/servo/users/shelvacu.nix
Normal file
@@ -0,0 +1,65 @@
|
||||
{ lib, pkgs, ... }:
|
||||
{
|
||||
users.users.shelvacu = {
|
||||
isNormalUser = true;
|
||||
home = "/home/shelvacu";
|
||||
subUidRanges = [
|
||||
{ startUid=300000; count=1; }
|
||||
];
|
||||
group = "users";
|
||||
initialPassword = lib.mkDefault "";
|
||||
shell = pkgs.bash;
|
||||
|
||||
openssh.authorizedKeys.keys = [
|
||||
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKoy1TrmfhBGWtVedgOM1FB1oD2UdodN3LkBnnLx6Tug compute-deck"
|
||||
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAxAFFxQMXAgi+0cmGaNE/eAkVfEl91wafUqFIuAkI5I compute-deck-root"
|
||||
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINQ2c0GzlVMjV06CS7bWbCaAbzG2+7g5FCg/vClJPe0C fw"
|
||||
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGHLPOxRd68+DJ/bYmqn0wsgwwIcMSMyuU1Ya16hCb/m fw-root"
|
||||
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOre0FnYDm3arsFj9c/l5H2Q8mdmv7kmvq683pL4heru legtop"
|
||||
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINznGot+L8kYoVQqdLV/R17XCd1ILMoDCILOg+I3s5wC pixel9pro-nod"
|
||||
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDcRDekd8ZOYfQS5X95/yNof3wFYIbHqWeq4jY0+ywQX pro1x-nod"
|
||||
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJNFbzt0NHVTaptBI38YtwLG+AsmeNYy0Nr5yX2zZEPE root@vacuInstaller toptop-root"
|
||||
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICVeSzDkGTueZijB0xUa08e06ovAEwwZK/D+Cc7bo91g triple-dezert"
|
||||
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOtwtao/TXbiuQOYJbousRPVesVcb/2nP0PCFUec0Nv8 triple-dezert-root"
|
||||
];
|
||||
};
|
||||
|
||||
security.sudo.extraRules = [
|
||||
{
|
||||
users = [ "shelvacu" ];
|
||||
runAs = "postgres";
|
||||
commands = [
|
||||
{
|
||||
command = "ALL";
|
||||
options = [ "NOPASSWD" ];
|
||||
}
|
||||
];
|
||||
}
|
||||
];
|
||||
|
||||
security.polkit.extraConfig = ''
|
||||
// allow:
|
||||
// - systemctl restart|start|stop SERVICE
|
||||
polkit.addRule(function(action, subject) {
|
||||
if (subject.user == "shelvacu" && action.id == "org.freedesktop.systemd1.manage-units") {
|
||||
switch (action.lookup("verb")) {
|
||||
// case "cancel":
|
||||
// case "reenable":
|
||||
case "restart":
|
||||
// case "reload":
|
||||
// case "reload-or-restart":
|
||||
case "start":
|
||||
case "stop":
|
||||
// case "try-reload-or-restart":
|
||||
// case "try-restart":
|
||||
return polkit.Result.YES;
|
||||
default:
|
||||
}
|
||||
}
|
||||
})
|
||||
'';
|
||||
|
||||
sane.persist.sys.byStore.private = [
|
||||
{ path = "/home/shelvacu/persist"; user = "shelvacu"; group = "users"; mode = "0700"; }
|
||||
];
|
||||
}
|
@@ -4,11 +4,12 @@
|
||||
# useful emergency utils
|
||||
boot.initrd.extraUtilsCommands = ''
|
||||
copy_bin_and_libs ${lib.getExe' pkgs.btrfs-progs "btrfstune"}
|
||||
copy_bin_and_libs ${lib.getExe' pkgs.util-linux "{cfdisk,lsblk,lscpu}"}
|
||||
copy_bin_and_libs ${lib.getExe' pkgs.gptfdisk "{cgdisk,gdisk}"}
|
||||
copy_bin_and_libs ${lib.getExe' pkgs.smartmontools "smartctl"}
|
||||
copy_bin_and_libs ${lib.getExe' pkgs.e2fsprogs "resize2fs"}
|
||||
copy_bin_and_libs ${lib.getExe' pkgs.gptfdisk "{cgdisk,gdisk}"}
|
||||
copy_bin_and_libs ${lib.getExe' pkgs.mtools "mlabel"}
|
||||
copy_bin_and_libs ${lib.getExe pkgs.nvme-cli}
|
||||
copy_bin_and_libs ${lib.getExe' pkgs.smartmontools "smartctl"}
|
||||
copy_bin_and_libs ${lib.getExe' pkgs.util-linux "{cfdisk,lsblk,lscpu}"}
|
||||
'';
|
||||
boot.kernelParams = [
|
||||
"boot.shell_on_fail"
|
||||
@@ -28,6 +29,7 @@
|
||||
# simpler to keep near the latest kernel on all devices,
|
||||
# and also makes certain that any weird system-level bugs i see aren't likely to be stale kernel bugs.
|
||||
boot.kernelPackages = lib.mkDefault pkgs.linuxPackages_latest;
|
||||
# boot.kernelPackages = lib.mkDefault pkgs.linuxPackages_testing;
|
||||
|
||||
# hack in the `boot.shell_on_fail` arg since that doesn't always seem to work.
|
||||
boot.initrd.preFailCommands = "allowShell=1";
|
||||
@@ -36,7 +38,12 @@
|
||||
boot.consoleLogLevel = 7;
|
||||
|
||||
boot.loader.grub.enable = lib.mkDefault false;
|
||||
boot.loader.generic-extlinux-compatible.enable = lib.mkDefault true;
|
||||
# boot.loader.generic-extlinux-compatible.enable = lib.mkDefault true;
|
||||
boot.loader.systemd-boot.enable = lib.mkDefault true;
|
||||
boot.loader.systemd-boot.configurationLimit = lib.mkDefault 20;
|
||||
boot.loader.systemd-boot.edk2-uefi-shell.enable = lib.mkDefault true;
|
||||
boot.loader.systemd-boot.memtest86.enable = lib.mkDefault
|
||||
(lib.meta.availableOn pkgs.stdenv.hostPlatform pkgs.memtest86plus);
|
||||
|
||||
hardware.enableAllFirmware = true; # firmware with licenses that don't allow for redistribution. fuck lawyers, fuck IP, give me the goddamn firmware.
|
||||
# hardware.enableRedistributableFirmware = true; # proprietary but free-to-distribute firmware (extraneous to `enableAllFirmware` option)
|
||||
|
@@ -14,6 +14,7 @@
|
||||
./programs
|
||||
./quirks.nix
|
||||
./secrets.nix
|
||||
./snapper.nix
|
||||
./ssh.nix
|
||||
./systemd.nix
|
||||
./users
|
||||
@@ -29,6 +30,7 @@
|
||||
sane.persist.enable = lib.mkDefault true;
|
||||
sane.root-on-tmpfs = lib.mkDefault true;
|
||||
sane.programs.sysadminUtils.enableFor.system = lib.mkDefault true;
|
||||
sane.programs.sysadminExtraUtils.enableFor.system = lib.mkDefault true;
|
||||
sane.programs.consoleUtils.enableFor.user.colin = lib.mkDefault true;
|
||||
|
||||
services.buffyboard.enable = true;
|
||||
|
@@ -1,12 +1,15 @@
|
||||
# where to find good stuff?
|
||||
# - universal search/directory: <https://podcastindex.org>
|
||||
# - the full database is downloadable
|
||||
# - find adjacent podcasts: <https://rephonic.com/graph>
|
||||
# - charts: <https://rephonic.com/charts/apple/united-states/technology>
|
||||
# - list of lists: <https://en.wikipedia.org/wiki/Category:Lists_of_podcasts>
|
||||
# - podcasts w/ a community: <https://lemmyverse.net/communities?query=podcast>
|
||||
# - podcast recs:
|
||||
# - active lemmy: <https://slrpnk.net/c/podcasts>
|
||||
# - old thread: <https://lemmy.ml/post/1565858>
|
||||
#
|
||||
# - paywall bypass / bootlegs: <https://jumble.top/>
|
||||
{ lib, sane-data, ... }:
|
||||
let
|
||||
hourly = { freq = "hourly"; };
|
||||
@@ -60,41 +63,48 @@ let
|
||||
podcasts = [
|
||||
(fromDb "404media.co/the-404-media-podcast" // tech)
|
||||
(fromDb "acquiredlpbonussecretsecret.libsyn.com" // tech) # ACQ2 - more "Acquired" episodes
|
||||
(fromDb "allinchamathjason.libsyn.com" // pol)
|
||||
(fromDb "adventofcomputing.com" // tech) # computing history
|
||||
(fromDb "api.oyez.org/podcasts/oral-arguments/2015" // pol) # Supreme Court Oral Arguments ("2015" in URL means nothing -- it's still updated)
|
||||
(fromDb "anchor.fm/s/34c7232c/podcast/rss" // tech) # Civboot -- https://anchor.fm/civboot
|
||||
(fromDb "anchor.fm/s/2da69154/podcast/rss" // tech) # POD OF JAKE -- https://podofjake.com/
|
||||
(fromDb "bluecityblues.org.podcastpage.io" // pol) # hosts overlap with Seattle Nice
|
||||
(fromDb "buzzsprout.com/2126417" // tech) # Mystery AI Hype Theater 3000
|
||||
(fromDb "cast.postmarketos.org" // tech)
|
||||
(fromDb "congressionaldish.libsyn.com" // pol) # Jennifer Briney
|
||||
(fromDb "craphound.com" // pol) # Cory Doctorow -- both podcast & text entries
|
||||
(fromDb "darknetdiaries.com" // tech)
|
||||
(fromDb "dwarkeshpatel.com" // tech)
|
||||
(fromDb "feeds.99percentinvisible.org/99percentinvisible" // pol) # 99% Invisible -- also available here: <https://feeds.simplecast.com/BqbsxVfO>
|
||||
(fromDb "feeds.acast.com/public/shows/lawfare" // pol) # <https://www.lawfaremedia.org/podcasts-multimedia/podcast/the-lawfare-podcast>
|
||||
(fromDb "feeds.buzzsprout.com/2412334.rss") # Matt Stoller's _Organized Money_ <https://www.organizedmoney.fm/>
|
||||
(fromDb "feeds.eff.org/howtofixtheinternet" // pol)
|
||||
(fromDb "feeds.feedburner.com/80000HoursPodcast" // rat)
|
||||
(fromDb "feeds.feedburner.com/dancarlin/history" // rat)
|
||||
(fromDb "feeds.feedburner.com/radiolab" // pol) # Radiolab -- also available here, but ONLY OVER HTTP: <http://feeds.wnyc.org/radiolab>
|
||||
(fromDb "feeds.megaphone.fm/CHTAL4990341033" // pol) # ChinaTalk: https://www.chinatalk.media/podcast
|
||||
(fromDb "feeds.megaphone.fm/GLT1412515089" // pol) # JRE: Joe Rogan Experience
|
||||
(fromDb "feeds.megaphone.fm/behindthebastards" // pol) # also Maggie Killjoy
|
||||
(fromDb "feeds.megaphone.fm/cspantheweekly" // pol)
|
||||
(fromDb "feeds.megaphone.fm/econ102") # Noah Smith + Erik Torenberg <https://www.podpage.com/econ102/>
|
||||
(fromDb "feeds.megaphone.fm/history102") # <https://www.podpage.com/history-102-with-whatifalthist/>
|
||||
(fromDb "feeds.megaphone.fm/recodedecode" // tech) # The Verge - Decoder
|
||||
(fromDb "feeds.megaphone.fm/thiswontlast" // tech) # <https://www.podpage.com/thiswontlast/>
|
||||
(fromDb "feeds.megaphone.fm/unexplainable")
|
||||
(fromDb "feeds.simplecast.com/wgl4xEgL" // rat) # Econ Talk
|
||||
(fromDb "feeds.simplecast.com/xKJ93w_w" // uncat) # Atlas Obscura
|
||||
(fromDb "feeds.simplecast.com/whlwDbyc" // tech) # Tech Lounge: <https://chrischinchilla.com/podcast/techlounge/>
|
||||
(fromDb "feeds.transistor.fm/acquired" // tech)
|
||||
(fromDb "feeds.transistor.fm/complex-systems-with-patrick-mckenzie-patio11" // tech) # Patrick Mackenzie (from Bits About Money)
|
||||
(fromDb "feeds.twit.tv/floss.xml" // tech)
|
||||
(fromDb "fulltimenix.com" // tech)
|
||||
(fromDb "futureofcoding.org/episodes" // tech)
|
||||
(fromDb "hackerpublicradio.org" // tech)
|
||||
(fromDb "lastweekinai.com" // tech)
|
||||
(fromDb "lexfridman.com/podcast" // rat)
|
||||
(fromDb "linktr.ee/betteroffline" // pol)
|
||||
(fromDb "linuxdevtime.com" // tech)
|
||||
(fromDb "malicious.life" // tech)
|
||||
(fromDb "mapspodcast.libsyn.com" // uncat) # Multidisciplinary Association for Psychedelic Studies
|
||||
(fromDb "motherearthnewsandfriends.libsyn.com" // uncat) # off-grid living
|
||||
(fromDb "microarch.club" // tech)
|
||||
(fromDb "nocturnepodcast.org")
|
||||
(fromDb "omegataupodcast.net" // tech) # 3/4 German; 1/4 eps are English
|
||||
(fromDb "omny.fm/shows/cool-people-who-did-cool-stuff" // pol) # Maggie Killjoy -- referenced by Cory Doctorow
|
||||
(fromDb "omny.fm/shows/money-stuff-the-podcast") # Matt Levine
|
||||
@@ -102,41 +112,51 @@ let
|
||||
(fromDb "omny.fm/shows/the-dollop-with-dave-anthony-and-gareth-reynolds") # The Dollop history/comedy
|
||||
(fromDb "omny.fm/shows/weird-little-guys") # Cool Zone Media
|
||||
(fromDb "originstories.libsyn.com" // uncat)
|
||||
(fromDb "politicspoliticspolitics.com" // pol) # don't judge me. Justin Robert Young.
|
||||
(fromDb "podcast.ergaster.org/@flintandsilicon" // tech) # Thib's podcast: public interest tech, gnome, etc: <https://fed.uninsane.org/users/$ALLO9MZ5g5CsQTCBH6>
|
||||
(fromDb "podcast.sustainoss.org" // tech)
|
||||
(fromDb "pods.media/api/rss/feed/channel/unchained" // tech) # cryptocurrency happenings; rec via patio11
|
||||
(fromDb "politicalorphanage.libsyn.com" // pol)
|
||||
(fromDb "reverseengineering.libsyn.com/rss" // tech) # UnNamed Reverse Engineering Podcast
|
||||
(fromDb "rss.acast.com/ft-tech-tonic" // tech)
|
||||
(fromDb "rss.art19.com/60-minutes" // pol)
|
||||
(fromDb "rss.acast.com/ft-tech-tonic" // tech) # Financial Time's: Tech Tonic
|
||||
(fromDb "rss.art19.com/the-portal" // rat) # Eric Weinstein
|
||||
(fromDb "seattlenice.buzzsprout.com" // pol)
|
||||
(fromDb "seattlenice.buzzsprout.com" // pol) # Seattle Nice
|
||||
(fromDb "speedboatdope.com" // pol) # Chapo Trap House (premium feed)
|
||||
(fromDb "srslywrong.com" // pol)
|
||||
(fromDb "sharkbytes.transistor.fm" // tech) # Wireshark Podcast o_0
|
||||
(fromDb "sharptech.fm/feed/podcast" // tech)
|
||||
(fromDb "sscpodcast.libsyn.com" // rat) # Astral Codex Ten
|
||||
(fromDb "sharptech.fm/feed/podcast" // tech) # Ben Thompson
|
||||
(fromDb "sscpodcast.libsyn.com" // rat) # Astral Codex Ten; Scott Alexander
|
||||
(fromDb "talesfromthebridge.buzzsprout.com" // tech) # Sci-Fi? has Peter Watts; author of No Moods, Ads or Cutesy Fucking Icons (rifters.com)
|
||||
(fromDb "techtalesshow.com" // tech) # Corbin Davenport
|
||||
(fromDb "techwontsave.us" // pol) # rec by Cory Doctorow
|
||||
(fromDb "theamphour.com" // tech)
|
||||
(fromDb "theamphour.com" // tech) # The Amp Hour
|
||||
(fromDb "the-ben-marc-show.simplecast.com" // tech // pol) # Ben Horowitz + Marc Andreessen; love to hate em
|
||||
(fromDb "timclicks.dev/compose-podcast" // tech) # Rust-heavy dev interviews
|
||||
(fromDb "werenotwrong.fireside.fm" // pol)
|
||||
(fromDb "werenotwrong.fireside.fm" // pol) # We're Not Wrong
|
||||
(fromDb "whycast.podcast.audio/@whycast" // tech) # What Hackers Yearn [for]: <https://why2025.org/>
|
||||
(mkPod "https://sfconservancy.org/casts/the-corresponding-source/feeds/ogg/" // tech)
|
||||
|
||||
# (fromDb "allinchamathjason.libsyn.com" // pol)
|
||||
# (fromDb "feed.podbean.com/matrixlive/feed.xml" // tech) # Matrix (chat) Live
|
||||
# (fromDb "feeds.libsyn.com/421877" // rat) # Less Wrong Curated
|
||||
# (fromDb "feeds.megaphone.fm/hubermanlab" // uncat) # Daniel Huberman on sleep
|
||||
# (fromDb "feeds.simplecast.com/54nAGcIl" // pol) # The Daily
|
||||
# (fromDb "feeds.simplecast.com/82FI35Px" // pol) # Ezra Klein Show
|
||||
# (fromDb "feeds.simplecast.com/l2i9YnTd" // tech // pol) # Hard Fork (NYtimes tech)
|
||||
# (fromDb "feeds.simplecast.com/whlwDbyc" // tech) # Tech Lounge: <https://chrischinchilla.com/podcast/techlounge/>
|
||||
# (fromDb "feeds.simplecast.com/xKJ93w_w" // uncat) # Atlas Obscura
|
||||
# (fromDb "iheart.com/podcast/1119-away-days-podcast-reporti-275359753" // pol) # Away Days (Cool Zone Media)
|
||||
# (fromDb "lastweekinai.com" // tech) # Last Week in AI
|
||||
# (fromDb "mintcast.org" // tech)
|
||||
# (fromDb "podcast.posttv.com/itunes/post-reports.xml" // pol)
|
||||
# (fromDb "podcast.sustainoss.org" // tech) # "Sustainable tech", only... it somehow manages to avoid any tech which is actually sustainable, and most of the time doesn't even talk about Open Source Software (!). normie/surface-level/"feel good"
|
||||
# (fromDb "podcast.thelinuxexp.com" // tech) # low-brow linux/foss PR announcements
|
||||
# (fromDb "politicspoliticspolitics.com" // pol) # don't judge me. Justin Robert Young.
|
||||
# (fromDb "rss.acast.com/deconstructed") # The Intercept - Deconstructed
|
||||
# (fromDb "rss.acast.com/intercepted-with-jeremy-scahill") # The Intercept - Intercepted
|
||||
# (fromDb "rss.art19.com/60-minutes" // pol)
|
||||
# (fromDb "rss.art19.com/your-welcome" // pol) # Michael Malice - Your Welcome -- also available here: <https://origin.podcastone.com/podcast?categoryID2=2232>
|
||||
# (fromDb "rss.prod.firstlook.media/deconstructed/podcast.rss" // pol) #< possible URL rot
|
||||
# (fromDb "rss.prod.firstlook.media/intercepted/podcast.rss" // pol) #< possible URL rot
|
||||
# (fromDb "sites.libsyn.com/438684" // humor) # Quorators - digging up *weird* Quota questions
|
||||
# (fromDb "techwontsave.us" // pol) # rec by Cory Doctorow, but way too info-sparse
|
||||
# (fromDb "trashfuturepodcast.podbean.com" // pol) # rec by Cory Doctorow, but way rambly
|
||||
# (fromDb "wakingup.libsyn.com" // pol) # Sam Harris, but he just repeats himself now
|
||||
# (mkPod "https://anchor.fm/s/21bc734/podcast/rss" // pol // infrequent) # Emerge: making sense of what's next -- <https://www.whatisemerging.com/emergepodcast>
|
||||
@@ -259,20 +279,26 @@ let
|
||||
(fromDb "youtube.com/@Exurb1a")
|
||||
(fromDb "youtube.com/@hbomberguy")
|
||||
(fromDb "youtube.com/@JackStauber")
|
||||
(fromDb "youtube.com/@jaketran")
|
||||
(fromDb "youtube.com/@kurzgesagt")
|
||||
(fromDb "youtube.com/@mii_beta" // tech) # Baby Wogue / gnome reviewer
|
||||
(fromDb "youtube.com/@Matrixdotorg" // tech) # Matrix Live
|
||||
(fromDb "youtube.com/@NativLang")
|
||||
(fromDb "youtube.com/@PolyMatter")
|
||||
(fromDb "youtube.com/@scenesbyben" // pol) # video essays
|
||||
(fromDb "youtube.com/@TechnologyConnections" // tech)
|
||||
(fromDb "youtube.com/@tested" // tech) # Adam Savage
|
||||
(fromDb "youtube.com/@theodd1sout")
|
||||
(fromDb "youtube.com/@TomScottGo")
|
||||
(fromDb "youtube.com/@TVW_Washington" // pol) # interviews with WA public officials
|
||||
(fromDb "youtube.com/@veritasium")
|
||||
(fromDb "youtube.com/@Vihart")
|
||||
(fromDb "youtube.com/@InnuendoStudios" // pol) # breaks down the nastier political strategies, from a "politics is power" angle
|
||||
|
||||
# (fromDb "youtube.com/@CasuallyExplained" // pol)
|
||||
# (fromDb "youtube.com/@ColdFusion")
|
||||
# (fromDb "youtube.com/@rossmanngroup" // pol // tech) # Louis Rossmann
|
||||
# (fromDb "youtube.com/@TheB1M")
|
||||
# (fromDb "youtube.com/@tested" // tech) # Adam Savage (uploads too frequently)
|
||||
# (fromDb "youtube.com/@Vox")
|
||||
# (fromDb "youtube.com/@Vsauce") # they're all like 1-minute long videos now? what happened @Vsauce?
|
||||
];
|
||||
|
@@ -24,9 +24,20 @@ let
|
||||
type = fsType;
|
||||
options = lib.concatStringsSep "," options;
|
||||
wantedBy = [ "default.target" ];
|
||||
after = [ "network-online.target" ];
|
||||
after = [
|
||||
"emergency.service"
|
||||
"network-online.target"
|
||||
];
|
||||
requires = [ "network-online.target" ];
|
||||
|
||||
unitConfig.Conflicts = [
|
||||
# emergency.service drops the user into a root shell;
|
||||
# only accessible via physical TTY, but unmount sensitive data before that as a precaution.
|
||||
"emergency.service"
|
||||
];
|
||||
|
||||
# mountConfig.LazyUnmount = true; #< else it _ocassionally_ fails "target is busy"
|
||||
|
||||
mountConfig.ExecSearchPath = [ "/run/current-system/sw/bin" ];
|
||||
mountConfig.User = "colin";
|
||||
mountConfig.AmbientCapabilities = "CAP_SETPCAP CAP_SYS_ADMIN";
|
||||
@@ -67,7 +78,8 @@ in
|
||||
lib.mkMerge [
|
||||
(ifSshAuthorized (remoteHome "crappy" {}))
|
||||
(ifSshAuthorized (remoteHome "desko" {}))
|
||||
(ifSshAuthorized (remoteHome "lappy" {}))
|
||||
(ifSshAuthorized (remoteHome "flowy" {}))
|
||||
# (ifSshAuthorized (remoteHome "lappy" {}))
|
||||
(ifSshAuthorized (remoteHome "moby" { host = "moby-hn"; }))
|
||||
(ifSshAuthorized (remoteHome "servo" {}))
|
||||
]
|
||||
|
@@ -12,9 +12,7 @@ let
|
||||
"stderr_path=/var/log/curlftpfs/servo-hn.stderr"
|
||||
];
|
||||
|
||||
remoteServo = subdir: let
|
||||
systemdBindName = utils.escapeSystemdPath "/mnt/servo/${subdir}";
|
||||
in {
|
||||
remoteServo = subdir: {
|
||||
# sane.fs."/mnt/servo/${subdir}".mount.bind = "/mnt/.servo_ftp/${subdir}";
|
||||
systemd.mounts = [{
|
||||
where = "/mnt/servo/${subdir}";
|
||||
|
@@ -14,7 +14,9 @@
|
||||
];
|
||||
|
||||
sane.user.persist.byStore.ephemeral = [
|
||||
# this is persisted simply to save on RAM. mesa_shader_cache is < 10 MB per boot.
|
||||
# this is persisted simply to save on RAM. mesa_shader_cache_db is < 10 MB per boot.
|
||||
# TODO: see about removing this. the programs which benefit from shader caches should be configured to persist their _own_ dbs.
|
||||
".cache/mesa_shader_cache_db"
|
||||
];
|
||||
|
||||
sane.user.persist.byStore.private = [
|
||||
@@ -29,28 +31,6 @@
|
||||
|
||||
"knowledge"
|
||||
"Videos/local"
|
||||
|
||||
# TODO: pre-compile mesa shaders, and then run in read-only mode?
|
||||
# mesa shader cache can be configured with e.g.:
|
||||
# - MESA_SHADER_CACHE_DISABLE=true
|
||||
# - MESA_SHADER_CACHE_DIR=/path/to/cache_db
|
||||
# - MESA_DISK_CACHE_SINGLE_FILE=1 (in which case default cache file is ~/.cache/mesa_shader_cache_sf)
|
||||
# - MESA_DISK_CACHE_MULTI_FILE=1 (in which case default cache dir is ~/.cache/mesa_shader_cache)
|
||||
# - MESA_DISK_CACHE_READ_ONLY_FOZ_DBS=foo,bar
|
||||
# - to use read-only mesa caches, one from foo.db the other bar.db
|
||||
# - MESA_DISK_CACHE_READ_ONLY_FOZ_DBS_DYNAMIC_LIST=/path/to/txt
|
||||
# - where /path/to/txt contains a list of names which represent read-only caches
|
||||
# - allows to change the cache providers w/o having to update variables
|
||||
#
|
||||
# see also: <https://gitlab.freedesktop.org/mesa/shader-db>
|
||||
# - database of common shaders (gtk4, chromium, etc) & instructions to compile for any arch
|
||||
# see also: <https://github.com/ValveSoftware/Fossilize>
|
||||
# which may help in generating readonly cache files
|
||||
#
|
||||
# for now, mesa shader cache is persisted because some programs *greatly* benefit from it.
|
||||
# esp gnome-contacts has a first-launch bug where it shows a misleading warning if shaders take too long to compile,
|
||||
# so we persist to private instead of ephemeral.
|
||||
".cache/mesa_shader_cache_db"
|
||||
];
|
||||
|
||||
# convenience
|
||||
|
@@ -2,6 +2,12 @@
|
||||
|
||||
{
|
||||
# TODO: this should be populated per-host
|
||||
|
||||
sane.hosts.by-name."cadey" = {
|
||||
ssh.authorized = lib.mkDefault false;
|
||||
lan-ip = "10.78.79.70";
|
||||
};
|
||||
|
||||
sane.hosts.by-name."crappy" = {
|
||||
ssh.user_pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMIvSQAGKqmymXIL4La9B00LPxBIqWAr5AsJxk3UQeY5";
|
||||
ssh.host_pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMN0cpRAloCBOE5/2wuzgik35iNDv5KLceWMCVaa7DIQ";
|
||||
@@ -18,14 +24,22 @@
|
||||
lan-ip = "10.78.79.52";
|
||||
};
|
||||
|
||||
sane.hosts.by-name."lappy" = {
|
||||
ssh.user_pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDpmFdNSVPRol5hkbbCivRhyeENzb9HVyf9KutGLP2Zu";
|
||||
ssh.host_pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILSJnqmVl9/SYQ0btvGb0REwwWY8wkdkGXQZfn/1geEc";
|
||||
wg-home.pubkey = "FTUWGw2p4/cEcrrIE86PWVnqctbv8OYpw8Gt3+dC/lk=";
|
||||
wg-home.ip = "10.0.10.20";
|
||||
lan-ip = "10.78.79.53";
|
||||
sane.hosts.by-name."flowy" = {
|
||||
ssh.user_pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAa9U2+aUc5Kr6f2oeILAy2EC86W5OZSprmBb1F+8n7/";
|
||||
ssh.host_pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMNuTITzc07mqYspWw6fqRw40ObxwnmWCwg188apHB/o";
|
||||
wg-home.pubkey = "o6Vh+gHF87wAOOofgKKYIhV91kgDRnLvwnd5W2WHsDE=";
|
||||
wg-home.ip = "10.0.10.56";
|
||||
lan-ip = "10.78.79.56";
|
||||
};
|
||||
|
||||
# sane.hosts.by-name."lappy" = {
|
||||
# ssh.user_pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDpmFdNSVPRol5hkbbCivRhyeENzb9HVyf9KutGLP2Zu";
|
||||
# ssh.host_pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILSJnqmVl9/SYQ0btvGb0REwwWY8wkdkGXQZfn/1geEc";
|
||||
# wg-home.pubkey = "FTUWGw2p4/cEcrrIE86PWVnqctbv8OYpw8Gt3+dC/lk=";
|
||||
# wg-home.ip = "10.0.10.20";
|
||||
# lan-ip = "10.78.79.53";
|
||||
# };
|
||||
|
||||
sane.hosts.by-name."moby" = {
|
||||
# ssh.authorized = lib.mkDefault false; # moby's too easy to hijack: don't let it ssh places
|
||||
ssh.user_pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICrR+gePnl0nV/vy7I5BzrGeyVL+9eOuXHU1yNE3uCwU";
|
||||
@@ -36,7 +50,7 @@
|
||||
};
|
||||
|
||||
sane.hosts.by-name."servo" = {
|
||||
ssh.authorized = lib.mkDefault false; # servo presents too many services to the internet: easy atack vector
|
||||
# ssh.authorized = lib.mkDefault false; # servo presents too many services to the internet: easy atack vector
|
||||
ssh.user_pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPS1qFzKurAdB9blkWomq8gI1g0T3sTs9LsmFOj5VtqX";
|
||||
ssh.host_pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOfdSmFkrVT6DhpgvFeQKm3Fh9VKZ9DbLYOPOJWYQ0E8";
|
||||
wg-home.pubkey = "roAw+IUFVtdpCcqa4khB385Qcv9l5JAB//730tyK4Wk=";
|
||||
|
@@ -66,6 +66,11 @@
|
||||
sane.ids.plugdev.gid = 2421;
|
||||
sane.ids.ollama.uid = 2422;
|
||||
sane.ids.ollama.gid = 2422;
|
||||
sane.ids.bitmagnet.uid = 2423;
|
||||
sane.ids.bitmagnet.gid = 2423;
|
||||
sane.ids.anubis.uid = 2424;
|
||||
sane.ids.anubis.gid = 2424;
|
||||
sane.ids.shelvacu.uid = 5431;
|
||||
|
||||
sane.ids.colin.uid = 1000;
|
||||
sane.ids.guest.uid = 1100;
|
||||
@@ -89,6 +94,9 @@
|
||||
sane.ids.smartd.gid = 2010;
|
||||
sane.ids.radicale.uid = 2011;
|
||||
sane.ids.radicale.gid = 2011;
|
||||
sane.ids.named.uid = 2012;
|
||||
sane.ids.named.gid = 2012;
|
||||
sane.ids.lpadmin.gid = 2013;
|
||||
|
||||
# found on graphical hosts
|
||||
sane.ids.nm-iodine.uid = 2101; # desko/moby/lappy
|
||||
|
162
hosts/common/net/dns/bind.nix
Normal file
162
hosts/common/net/dns/bind.nix
Normal file
@@ -0,0 +1,162 @@
|
||||
# debugging:
|
||||
# - /var/log/named/named.log
|
||||
## config
|
||||
# - `man named`
|
||||
# - `man named.conf`
|
||||
# - show defaults with: `named -C`
|
||||
# - defaults live in <repo:isc-projects/bind:bin/named/config.c>
|
||||
# - per-option docs live in <repo:isc-projects/bind:bind9/doc/arm/reference.rst>
|
||||
#
|
||||
## statistics
|
||||
# - `netstat --statistics --udp`
|
||||
# - `rdnc stats`? dumps to `named.stats` in named's PWD?
|
||||
#
|
||||
## interactive debugging
|
||||
# - `systemctl stop bind`
|
||||
# - `sudo /nix/store/0zpdy93sd3fgbxgvf8dsxhn8fbbya8d2-bind-9.18.28/sbin/named -g -u named -4 -c /nix/store/f1mp0myzmfms71h9vinwxpn2i9362a9a-named.conf`
|
||||
# - `-g` = don't fork
|
||||
# - `-u named` = start as superuser (to claim port 53), then drop to user `named`
|
||||
#
|
||||
{ config, lib, pkgs, ... }:
|
||||
let
|
||||
hostCfg = config.sane.hosts.by-name."${config.networking.hostName}" or null;
|
||||
bindCfg = config.services.bind;
|
||||
in
|
||||
{
|
||||
config = lib.mkIf (!config.sane.services.hickory-dns.asSystemResolver) {
|
||||
services.resolved.enable = lib.mkForce false;
|
||||
|
||||
networking.nameservers = [
|
||||
# be compatible with systemd-resolved
|
||||
# "127.0.0.53"
|
||||
# or don't be compatible with systemd-resolved, but with libc and pasta instead
|
||||
# see <pkgs/by-name/sane-scripts/src/sane-vpn>
|
||||
"127.0.0.1"
|
||||
# enable IPv6, or don't; unbound is spammy when IPv6 is enabled but unroutable
|
||||
# "::1"
|
||||
];
|
||||
|
||||
networking.resolvconf.extraConfig = ''
|
||||
# DNS serviced by `BIND` recursive resolver
|
||||
name_servers='127.0.0.1'
|
||||
'';
|
||||
|
||||
services.bind.enable = lib.mkDefault true;
|
||||
services.bind.forwarders = []; #< don't forward queries to upstream resolvers
|
||||
services.bind.cacheNetworks = [
|
||||
"127.0.0.0/24"
|
||||
"::1/128"
|
||||
"10.0.10.0/24" #< wireguard clients (servo)
|
||||
];
|
||||
services.bind.listenOn = [
|
||||
"127.0.0.1"
|
||||
] ++ lib.optionals (hostCfg != null && hostCfg.wg-home.ip != null) [
|
||||
# allow wireguard clients to use us as a recursive resolver (only needed for servo)
|
||||
hostCfg.wg-home.ip
|
||||
];
|
||||
services.bind.listenOnIpv6 = [
|
||||
# "::1"
|
||||
];
|
||||
|
||||
services.bind.ipv4Only = true; # unbound is spammy when it tries IPv6 without a routable address
|
||||
|
||||
# when testing, deploy on a port other than 53
|
||||
# services.bind.extraOptions = ''
|
||||
# listen-on port 953 { any; };
|
||||
# '';
|
||||
|
||||
# services.bind.extraArgs = [
|
||||
# # -d = debug logging level: higher = more verbose
|
||||
# "-d" "2"
|
||||
# # -L = where to log. default is `named.run` in PWD -- unless running interactively in which case it logs to stdout
|
||||
# "-L" "/var/log/named/named.log"
|
||||
# ];
|
||||
|
||||
networking.resolvconf.useLocalResolver = false; #< we manage resolvconf explicitly, above
|
||||
|
||||
# TODO: how to exempt `pool.ntp.org` from DNSSEC checks, as i did when using unbound?
|
||||
|
||||
# allow runtime insertion of zones or other config changes:
|
||||
# add your supplemental config as a toplevel file in /run/named/dhcp-configs/, then `systemctl restart bind`
|
||||
services.bind.extraConfig = ''
|
||||
include "/run/named/dhcp-configs.conf";
|
||||
'';
|
||||
services.bind.extraOptions = ''
|
||||
// we can't guarantee that all forwarders support DNSSEC,
|
||||
// and as of 2025-01-30 BIND9 gives no way to disable DNSSEC per-forwarder/zone,
|
||||
// so just disable it globally
|
||||
dnssec-validation no;
|
||||
// XXX(2025-06-30): i need reverse DNS of private IP space such as 10.0.0.0/8.
|
||||
// configuring those zones (done in a secrets/ file), unfortunately requires disabling
|
||||
// ALL local entries for reserved zones (IN-ADDR.ARPA, IP6.ARPA, EMPTY.AS112.ARPA, HOME.ARPA, RESOLVER.ARPA).
|
||||
// TODO: figure a better solution, as this likely causes reverse-DNS queries of LAN hosts to be sent to the WAN!
|
||||
// - see <https://www.as112.net/>
|
||||
empty-zones-enable no;
|
||||
'';
|
||||
# re-implement the nixos default bind config, but without `options { forwarders { }; };`,
|
||||
# as having an empty `forwarders` at the top-level prevents me from forwarding the `.` zone in a separate statement
|
||||
# (which i want to do to allow sane-vpn to forward all DNS).
|
||||
services.bind.configFile = pkgs.writeText "named.conf" ''
|
||||
include "/etc/bind/rndc.key";
|
||||
controls {
|
||||
inet 127.0.0.1 allow {localhost;} keys {"rndc-key";};
|
||||
};
|
||||
|
||||
acl cachenetworks { ${lib.concatMapStrings (entry: " ${entry}; ") bindCfg.cacheNetworks} };
|
||||
acl badnetworks { ${lib.concatMapStrings (entry: " ${entry}; ") bindCfg.blockedNetworks} };
|
||||
|
||||
options {
|
||||
listen-on { ${lib.concatMapStrings (entry: " ${entry}; ") bindCfg.listenOn} };
|
||||
listen-on-v6 { ${lib.concatMapStrings (entry: " ${entry}; ") bindCfg.listenOnIpv6} };
|
||||
allow-query-cache { cachenetworks; };
|
||||
blackhole { badnetworks; };
|
||||
//v disable top-level forwards, so that i can do forwarding more generically in `zone FOO { ... }` directives.
|
||||
// forward ${bindCfg.forward};
|
||||
// forwarders { ${lib.concatMapStrings (entry: " ${entry}; ") bindCfg.forwarders} };
|
||||
directory "${bindCfg.directory}";
|
||||
pid-file "/run/named/named.pid";
|
||||
${bindCfg.extraOptions}
|
||||
};
|
||||
|
||||
// XXX(2025-06-18): some tools i use for work assume 'localhost' can be resolved by the system nameserver,
|
||||
// and not just by /etc/hosts
|
||||
zone "localhost" {
|
||||
type master;
|
||||
file "${pkgs.writeText "localhost" ''
|
||||
$TTL 300
|
||||
@ IN SOA localhost. root.localhost. (
|
||||
202506181 ; Serial
|
||||
28800 ; Refresh
|
||||
7200 ; Retry
|
||||
604800 ; Expire
|
||||
86400) ; Minimum TTL
|
||||
NS localhost.
|
||||
|
||||
localhost. A 127.0.0.1
|
||||
AAAA ::1
|
||||
''}";
|
||||
};
|
||||
|
||||
${bindCfg.extraConfig}
|
||||
'';
|
||||
|
||||
systemd.services.bind.serviceConfig.ExecStartPre = pkgs.writeShellScript "named-generate-config" ''
|
||||
mkdir -p /run/named/dhcp-configs
|
||||
chmod g+w /run/named/dhcp-configs
|
||||
echo "// FILE GENERATED BY bind.service's ExecStartPre: CHANGES TO THIS FILE WILL BE OVERWRITTEN" > /run/named/dhcp-configs.conf
|
||||
for c in $(ls /run/named/dhcp-configs/); do
|
||||
cat "/run/named/dhcp-configs/$c" >> /run/named/dhcp-configs.conf
|
||||
done
|
||||
'';
|
||||
systemd.services.bind.serviceConfig.ReadWritePaths = [
|
||||
"/var/log/named"
|
||||
];
|
||||
|
||||
sane.persist.sys.byPath."/var/log/named" = {
|
||||
store = "ephemeral";
|
||||
method = "symlink";
|
||||
acl.mode = "0750";
|
||||
acl.user = "named";
|
||||
};
|
||||
};
|
||||
}
|
@@ -23,6 +23,7 @@
|
||||
{ config, pkgs, ... }:
|
||||
{
|
||||
imports = [
|
||||
./bind.nix
|
||||
./hickory-dns.nix
|
||||
./unbound.nix
|
||||
];
|
||||
|
@@ -1,7 +1,9 @@
|
||||
# `man unbound.conf` for info on settings
|
||||
# it's REALLY EASY to combine settings in a way that produce bad effects.
|
||||
# generally, prefer to stay close to defaults unless there's a compelling reason to differ.
|
||||
{ config, lib, pkgs, ... }: {
|
||||
{ config, lib, ... }:
|
||||
lib.optionalAttrs false #< XXX(2024-12-29): unbound caches failed DNS resolutions, just randomly breaks connectivity daily
|
||||
{
|
||||
config = lib.mkIf (!config.sane.services.hickory-dns.asSystemResolver) {
|
||||
services.resolved.enable = lib.mkForce false;
|
||||
|
||||
|
@@ -1,7 +1,10 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
{
|
||||
networking.networkmanager.enable = true;
|
||||
systemd.network.wait-online.enable = false; # systemd-networkd-wait-online.service reliably fails on lappy. docs don't match behavior. shit software.
|
||||
# systemd-networkd-wait-online.service reliably fails on lappy. docs don't match behavior. shit software.
|
||||
# XXX(2025-07-18): `systemd-networkd-wait-online.service` also fails on desko (timeout).
|
||||
systemd.network.wait-online.enable = false;
|
||||
|
||||
# plugins mostly add support for establishing different VPN connections.
|
||||
# the default plugin set includes mostly proprietary VPNs:
|
||||
# - fortisslvpn (Fortinet)
|
||||
@@ -203,6 +206,7 @@
|
||||
};
|
||||
|
||||
networking.networkmanager.settings = {
|
||||
# docs: `man 5 NetworkManager.conf`
|
||||
# keyfile.path = where networkmanager should look for connection credentials
|
||||
keyfile.path = "/var/lib/NetworkManager/system-connections";
|
||||
|
||||
@@ -214,20 +218,30 @@
|
||||
|
||||
# main.dhcp = "internal"; #< default
|
||||
# main.dns controls what to do when NM gets a DNS server via DHCP
|
||||
# - "none" (populate /run/NetworkManager/resolv.conf with DHCP settings)
|
||||
# - "internal" (?)
|
||||
# - "systemd-resolved" (tell systemd-resolved about it, and point /run/NetworkManager/resolv.conf -> systemd)
|
||||
# without this, systemd-resolved won't be able to resolve anything (because it has no upstream servers)
|
||||
# - "default": NM manages /etc/resolv.conf itself.
|
||||
# - "none": NM doesn't manage /etc/resolv.conf, but does populate /run/NetworkManager/resolv.conf with DHCP settings
|
||||
# - "systemd-resolved": tell systemd-resolved about it, and point /run/NetworkManager/resolv.conf -> systemd
|
||||
# - without this, systemd-resolved won't be able to resolve anything (because it has no upstream servers)
|
||||
# - (empty): perform a best-guess for how to manage /etc/resolv.conf
|
||||
# -> if /etc/resolv.conf is a symlink to systemd-resolved, then behaves as "systemd-resolved".
|
||||
# -> else, behaves as "default".
|
||||
# note that NM's resolv.conf isn't (necessarily) /etc/resolv.conf -- that is managed by nixos (via symlinking)
|
||||
main.dns = if config.services.resolved.enable then
|
||||
"systemd-resolved"
|
||||
else if
|
||||
(config.sane.services.hickory-dns.enable && config.sane.services.hickory-dns.asSystemResolver)
|
||||
|| (config.services.unbound.enable && config.services.unbound.resolveLocalQueries) then
|
||||
"none"
|
||||
else
|
||||
"internal"
|
||||
;
|
||||
main.dns = let
|
||||
dns = if config.services.resolved.enable then
|
||||
"systemd-resolved"
|
||||
else if
|
||||
(config.sane.services.hickory-dns.enable && config.sane.services.hickory-dns.asSystemResolver)
|
||||
|| (config.services.unbound.enable && config.services.unbound.resolveLocalQueries)
|
||||
|| config.services.bind.enable # bind config isn't easily inspectable; assume that it's acting as local resolver
|
||||
then
|
||||
"none"
|
||||
else
|
||||
# omitting the option instructs NM to do a "best guess".
|
||||
# this is nearly equivalent to "default", however NM will do checks like "is /etc/resolv.conf a symlink to systemd-resolved", etc,
|
||||
# to actually try to understand the environment.
|
||||
null
|
||||
;
|
||||
in lib.mkIf (dns != null) dns;
|
||||
main.systemd-resolved = false;
|
||||
};
|
||||
environment.etc."NetworkManager/system-connections".source = "/var/lib/NetworkManager/system-connections";
|
||||
|
@@ -7,7 +7,8 @@
|
||||
];
|
||||
|
||||
networking.firewall.extraCommands = with pkgs; ''
|
||||
# after an outgoing SSDP query to the multicast address, open FW for incoming responses.
|
||||
# after an outgoing SSDP query to the multicast address (dest port=1900, src port=any),
|
||||
# open FW for incoming responses (i.e. accept any packet, so long as it's sent to the port we sent from).
|
||||
# necessary for anything DLNA, especially go2tv
|
||||
# source: <https://serverfault.com/a/911286>
|
||||
# context: <https://github.com/alexballas/go2tv/issues/72>
|
||||
@@ -16,6 +17,7 @@
|
||||
${ipset}/bin/ipset create -! upnp hash:ip,port timeout 10
|
||||
${iptables}/bin/iptables -A OUTPUT -d 239.255.255.250/32 -p udp -m udp --dport 1900 -j SET --add-set upnp src,src --exist
|
||||
${iptables}/bin/iptables -A INPUT -p udp -m set --match-set upnp dst,dst -j ACCEPT
|
||||
|
||||
# IPv6 ruleset. ff02::/16 means *any* link-local multicast group (so this is probably more broad than it needs to be)
|
||||
${ipset}/bin/ipset create -! upnp6 hash:ip,port timeout 10 family inet6
|
||||
${iptables}/bin/ip6tables -A OUTPUT -d ff02::/16 -p udp -m udp --dport 1900 -j SET --add-set upnp6 src,src --exist
|
||||
|
@@ -55,7 +55,17 @@
|
||||
# this is actually a no-op, and the real action happens in assigning `nix.settings.nix-path`.
|
||||
nix.nixPath = (lib.optionals (config.sane.maxBuildCost >= 2) [
|
||||
"nixpkgs=${pkgs.path}"
|
||||
]) ++ [
|
||||
]) ++ (let
|
||||
# XXX(2024-09-02): nix 2.24.4 errors when nixpkgs-overlays includes a symlink component:
|
||||
# "error: path '/home/colin/dev' is a symlink"
|
||||
# apparently nix has to explicitly handle symlinks in every place it might encounter them,
|
||||
# so the fixes inside nix for this are manual and fragile. dereference it ourselves:
|
||||
dev = if (config.sane.fs."/home/colin/dev" or {}) != {} then
|
||||
config.sane.fs."/home/colin/dev".symlink.target
|
||||
else
|
||||
"/home/colin/dev"
|
||||
;
|
||||
in [
|
||||
# note the import starts at repo root: this allows `./overlay/default.nix` to access the stuff at the root
|
||||
# "nixpkgs-overlays=${../../..}/hosts/common/nix-path/overlay"
|
||||
# as long as my system itself doesn't rely on NIXPKGS at runtime, we can point the overlays to git
|
||||
@@ -65,12 +75,8 @@
|
||||
# when it goes wrong. should i port my `nix-shell` scripts to something more tailored to my uses
|
||||
# and then delete `nixpkgs-overlays`?
|
||||
# "nixpkgs-overlays=/home/colin/dev/nixos/integrations/nixpkgs/nixpkgs-overlays.nix"
|
||||
# XXX(2024-09-02): nix 2.24.4 errors when nixpkgs-overlays includes a symlink component:
|
||||
# "error: path '/home/colin/dev' is a symlink"
|
||||
# apparently nix has to explicitly handle symlinks in every place it might encounter them,
|
||||
# so the fixes inside nix for this are manual and fragile. dereference it ourselves:
|
||||
"nixpkgs-overlays=${config.sane.fs."/home/colin/dev".symlink.target}/nixos/integrations/nixpkgs/nixpkgs-overlays.nix"
|
||||
];
|
||||
"nixpkgs-overlays=${dev}/nixos/integrations/nixpkgs/nixpkgs-overlays.nix"
|
||||
]);
|
||||
|
||||
# ensure new deployments have a source of this repo with which they can bootstrap.
|
||||
# this however changes on every commit and can be slow to copy for e.g. `moby`.
|
||||
|
@@ -6,11 +6,15 @@ let
|
||||
# nixpkgs' pam hardcodes unix_chkpwd path to the /run/wrappers one,
|
||||
# but i don't want the wrapper, so undo that.
|
||||
# ideally i would patch this via an overlay, but pam is in the bootstrap so that forces a full rebuild.
|
||||
# see: <repo:nixos/nixpkgs:pkgs/by-name/li/linux-pam/package.nix>
|
||||
postPatch = (upstream.postPatch or "") + ''
|
||||
substituteInPlace modules/pam_unix/Makefile.am --replace-fail \
|
||||
substituteInPlace modules/module-meson.build --replace-fail \
|
||||
"/run/wrappers/bin/unix_chkpwd" "$out/bin/unix_chkpwd"
|
||||
'';
|
||||
});
|
||||
# `mkDefault` is `mkOverride 1000`.
|
||||
# `mkOverrideDefault` will override `mkDefault` values, but not ordinary values.
|
||||
mkOverrideDefault = lib.mkOverride 900;
|
||||
in
|
||||
{
|
||||
# remove a few items from /run/wrappers we don't need.
|
||||
@@ -106,6 +110,7 @@ in
|
||||
conveniencePackages = [
|
||||
config.boot.kernelPackages.cpupower # <repo:nixos/nixpkgs:nixos/modules/tasks/cpu-freq.nix> places it on PATH for convenience if powerManagement.cpuFreqGovernor is set
|
||||
pkgs.kbd # <repo:nixos/nixpkgs:nixos/modules/config/console.nix> places it on PATH as part of console/virtual TTYs, but probably not needed unless you want to set console fonts
|
||||
pkgs.nixos-firewall-tool # <repo:nixos/nixpkgs:nixos/modules/services/networking/firewall.nix> for end-user management of the firewall? cool but doesn't cross-compile
|
||||
];
|
||||
in lib.filter (p: ! builtins.elem p (requiredPackages ++ conveniencePackages));
|
||||
};
|
||||
@@ -134,11 +139,20 @@ in
|
||||
environment.variables.NIXPKGS_CONFIG = lib.mkForce "";
|
||||
# XDG_CONFIG_DIRS defaults to "/etc/xdg", which doesn't exist.
|
||||
# in practice, pam appends the values i want to XDG_CONFIG_DIRS, though this approach causes an extra leading `:`
|
||||
environment.sessionVariables.XDG_CONFIG_DIRS = lib.mkForce [];
|
||||
# XXX(2025-06-06): some nixpkgs' systemd services actually depend on the default XDG_CONFIG_DIRS=/etc/xdg!
|
||||
# specifically: `services.bitmagnet`
|
||||
# environment.sessionVariables.XDG_CONFIG_DIRS = lib.mkForce [];
|
||||
# XCURSOR_PATH: defaults to `[ "$HOME/.icons" "$HOME/.local/share/icons" ]`, neither of which i use, just adding noise.
|
||||
# see: <repo:nixos/nixpkgs:nixos/modules/config/xdg/icons.nix>
|
||||
environment.sessionVariables.XCURSOR_PATH = lib.mkForce [];
|
||||
|
||||
environment.shellAliases = {
|
||||
# unset default aliases; see <repo:nixos/nixpkgs:nixos/modules/config/shells-environment.nix>
|
||||
ls = mkOverrideDefault null;
|
||||
ll = mkOverrideDefault null;
|
||||
l = mkOverrideDefault null;
|
||||
};
|
||||
|
||||
# disable nixos' portal module, otherwise /share/applications gets linked into the system and complicates things (sandboxing).
|
||||
# instead, i manage portals myself via the sane.programs API (e.g. sane.programs.xdg-desktop-portal).
|
||||
xdg.portal.enable = false;
|
||||
|
@@ -1,8 +1,11 @@
|
||||
# Terminal UI mail client
|
||||
{ ... }:
|
||||
{ pkgs, ... }:
|
||||
|
||||
{
|
||||
sane.programs.aerc = {
|
||||
packageUnwrapped = pkgs.aerc.override {
|
||||
withNotmuch = false; #< not used; regularly fails to build
|
||||
};
|
||||
sandbox.wrapperType = "inplace"; #< /share/aerc/aerc.conf mentions (in comments) other (non-sandboxed) /share files by absolute path
|
||||
sandbox.net = "clearnet";
|
||||
secrets.".config/aerc/accounts.conf" = ../../../secrets/common/aerc_accounts.conf.bin;
|
||||
|
63
hosts/common/programs/alpaca.nix
Normal file
63
hosts/common/programs/alpaca.nix
Normal file
@@ -0,0 +1,63 @@
|
||||
# alpaca: ollama llm client
|
||||
# - super simple, easy UI
|
||||
#
|
||||
# shortcomings (as of 6.1.7, 2025-07-23):
|
||||
# - doesn't seem to do any prompt tuning;
|
||||
# inherits all the pathologies of the underlying model (e.g. makes up citations)
|
||||
#
|
||||
# it creates a config dir, `~/.config/com.jeffser.Alpaca`, but apparently empty
|
||||
#
|
||||
# TODO: configure ollama connection details statically
|
||||
# - until then, on first run:
|
||||
# - select the non-"managed" ollama option.
|
||||
# - connect to http://10.0.10.22:11434
|
||||
# TODO: update the nix package 6.1.7 -> 7.5.2
|
||||
# - i.e. review <https://github.com/NixOS/nixpkgs/pull/420698>
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
sane.programs.alpaca = {
|
||||
packageUnwrapped = (pkgs.alpaca.override {
|
||||
# ollama is only added to `PATH`; since i'm using it via http, remove it here.
|
||||
# fixes cross compilation & simplifies closure.
|
||||
ollama = null;
|
||||
python3Packages = pkgs.python3Packages // {
|
||||
# XXX(2025-07-23): does not cross compile (markitdown -> pydub -> ... -> opencv)
|
||||
markitdown = null;
|
||||
};
|
||||
}).overrideAttrs (upstream: {
|
||||
postPatch = (upstream.postPatch or "") + ''
|
||||
# for nulled dependencies (above), patch so the application only errors
|
||||
# at runtime, on first attempted use.
|
||||
substituteInPlace src/widgets/attachments.py \
|
||||
--replace-fail 'from markitdown' '# from markitdown'
|
||||
'';
|
||||
});
|
||||
buildCost = 2; #< liable to break cross during updates; not important enough to block deploy over
|
||||
|
||||
sandbox.net = "all"; # maybe only needs wireguard, actually
|
||||
sandbox.whitelistWayland = true;
|
||||
sandbox.mesaCacheDir = ".cache/com.jeffser.Alpaca/mesa";
|
||||
|
||||
sandbox.whitelistDbus.user.own = [ "com.jeffser.Alpaca" ];
|
||||
sandbox.whitelistPortal = [
|
||||
"OpenURI"
|
||||
];
|
||||
sandbox.whitelistSendNotifications = true;
|
||||
|
||||
persist.byStore.ephemeral = [
|
||||
".cache/com.jeffser.Alpaca" #< ?
|
||||
];
|
||||
|
||||
persist.byStore.private = [
|
||||
# alpaca.db: sqlite3 database with the following tables:
|
||||
# - attachment
|
||||
# - chat
|
||||
# - instances
|
||||
# - message
|
||||
# - model_preferences
|
||||
# - preferences
|
||||
# - tool_parameters
|
||||
".local/share/com.jeffser.Alpaca"
|
||||
];
|
||||
};
|
||||
}
|
@@ -1,15 +1,30 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
let
|
||||
cfg = config.sane.programs.alsa-ucm-conf;
|
||||
in
|
||||
{
|
||||
sane.programs.alsa-ucm-conf = {
|
||||
packageUnwrapped = pkgs.alsa-ucm-conf.overrideAttrs (base: {
|
||||
deprioritize = pkg: pkg.overrideAttrs (base: {
|
||||
meta = (base.meta or {}) // {
|
||||
# let the other alsa ucm packages override configs from this one
|
||||
priority = ((base.meta or {}).priority or 10) + 20;
|
||||
};
|
||||
});
|
||||
});
|
||||
alsa-ucm-latest = pkgs.alsa-ucm-conf.overrideAttrs (upstream: rec {
|
||||
# XXX(2025-07-18): see <https://github.com/NixOS/nixpkgs/pull/414818>
|
||||
version = "1.2.14";
|
||||
src = lib.warnIf (lib.versionAtLeast upstream.version "1.2.14") "upstream alsa-ucm-conf is up to date with my own: remove override?" pkgs.fetchurl {
|
||||
url = "mirror://alsa/lib/alsa-ucm-conf-${version}.tar.bz2";
|
||||
hash = "sha256-MumAn1ktkrl4qhAy41KTwzuNDx7Edfk3Aiw+6aMGnCE=";
|
||||
};
|
||||
installPhase = lib.replaceStrings
|
||||
[ ''for file in "''${files[@]}"'' ]
|
||||
[ ''for file in ucm2/common/ctl/led.conf'' ]
|
||||
upstream.installPhase
|
||||
;
|
||||
});
|
||||
in
|
||||
{
|
||||
sane.programs.alsa-ucm-conf = {
|
||||
packageUnwrapped = deprioritize pkgs.alsa-ucm-conf;
|
||||
# packageUnwrapped = deprioritize alsa-ucm-latest;
|
||||
sandbox.enable = false; #< only provides $out/share/alsa
|
||||
|
||||
# alsa-lib package only looks in its $out/share/alsa to find runtime config data, by default.
|
||||
|
@@ -19,16 +19,15 @@
|
||||
packageUnwrapped = with pkgs; animatch.override {
|
||||
# allegro has no native wayland support, and so by default crashes when run without Xwayland.
|
||||
# enable the allegro SDL backend, and achieve Wayland support via SDL's Wayland support.
|
||||
# TODO: see about upstreaming this to nixpkgs?
|
||||
allegro5 = allegro5.overrideAttrs (upstream: {
|
||||
buildInputs = upstream.buildInputs ++ [
|
||||
SDL2
|
||||
];
|
||||
cmakeFlags = upstream.cmakeFlags ++ [
|
||||
"-DALLEGRO_SDL=on"
|
||||
];
|
||||
});
|
||||
allegro5 = allegro5.override { useSDL = true; };
|
||||
};
|
||||
# nativeBuildInputs = (upstream.nativeBuildInputs or []) ++ [
|
||||
# makeWrapper
|
||||
# ];
|
||||
# postFixup = (upstream.postFixup or "") + ''
|
||||
# wrapProgram $out/bin/animatch \
|
||||
# --set SDL_VIDEODRIVER wayland
|
||||
# '';
|
||||
|
||||
buildCost = 1;
|
||||
|
||||
|
@@ -48,9 +48,11 @@ in
|
||||
"dtc" # device tree [de]compiler
|
||||
"e2fsprogs" # resize2fs
|
||||
"efibootmgr"
|
||||
"erdtree" # like normal `tree` but colorful & prints sizes
|
||||
"errno"
|
||||
"ethtool"
|
||||
"evtest"
|
||||
"expect"
|
||||
"fatresize"
|
||||
"fd"
|
||||
"fftest" # for debugging moby haptics/vibrator, mostly
|
||||
@@ -65,6 +67,7 @@ in
|
||||
"hdparm"
|
||||
"hping"
|
||||
"htop"
|
||||
"htpasswd"
|
||||
"iftop"
|
||||
"inetutils" # for telnet
|
||||
"iotop"
|
||||
@@ -84,15 +87,18 @@ in
|
||||
"mmcli"
|
||||
"nano"
|
||||
# "ncdu" # ncurses disk usage. doesn't cross compile (zig)
|
||||
"nfs-utils" # required, for mounting nfs filesystems
|
||||
"neovim"
|
||||
"netcat"
|
||||
"nethogs"
|
||||
"nix"
|
||||
"nix-tree"
|
||||
"nmap"
|
||||
"nmcli"
|
||||
"nmon"
|
||||
"nvimpager"
|
||||
"nvme-cli" # nvme
|
||||
# "openssl"
|
||||
"openssl"
|
||||
"parted"
|
||||
"pciutils"
|
||||
"picocom" # serial TTY
|
||||
@@ -103,8 +109,11 @@ in
|
||||
"rsync"
|
||||
# "s6-rc" # service manager
|
||||
# "screen"
|
||||
"see-cat" # pretty-print equivalent to 'cat'
|
||||
"ssh"
|
||||
"sshpass"
|
||||
"smartmontools" # smartctl
|
||||
# "socat"
|
||||
"socat"
|
||||
"strace"
|
||||
"subversion"
|
||||
"tcpdump"
|
||||
@@ -112,6 +121,7 @@ in
|
||||
"unixtools.ps"
|
||||
"unixtools.sysctl"
|
||||
"unixtools.xxd"
|
||||
"uptime"
|
||||
"usbutils" # lsusb
|
||||
"util-linux" # lsblk, lscpu, etc
|
||||
"valgrind"
|
||||
@@ -132,8 +142,11 @@ in
|
||||
# - debugging?
|
||||
consoleUtils = declPackageSet [
|
||||
"alsa-utils" # for aplay, speaker-test
|
||||
"bc" # CLI calculator
|
||||
"cdecl" # like <https://cdecl.org>. `cdecl explain 'struct foo *const inst'`
|
||||
# "cdrtools"
|
||||
# "clinfo"
|
||||
"colordiff"
|
||||
# "dmidecode"
|
||||
"dtrx" # `unar` alternative, "Do The Right eXtraction"
|
||||
# "efivar"
|
||||
@@ -148,12 +161,14 @@ in
|
||||
# "gopass-jsonapi"
|
||||
# "helix" # text editor
|
||||
"htop" # needed as a user package, for ~/.config/htop
|
||||
"lddtree"
|
||||
# "libsecret" # for managing user keyrings (secret-tool)
|
||||
# "lm_sensors" # for sensors-detect
|
||||
# "lshw"
|
||||
# "memtester"
|
||||
"mercurial" # hg
|
||||
"mimeo" # like xdg-open
|
||||
"mozlz4a" # for extracting .mozlz4 files (firefox)
|
||||
"neovim" # needed as a user package, for swap persistence
|
||||
"nix" # needed as user package, for ~/.cache/nix persistence
|
||||
# "nettools"
|
||||
@@ -162,10 +177,13 @@ in
|
||||
# "node2nix"
|
||||
# "oathToolkit" # for oathtool
|
||||
"objdump"
|
||||
"oils-for-unix"
|
||||
"patchelf"
|
||||
# "ponymix"
|
||||
"pulsemixer"
|
||||
"python3-repl"
|
||||
# "python3.pkgs.eyeD3" # music tagging
|
||||
"readline" # for the config
|
||||
"ripgrep" # needed as a user package so that its user-level config file can be installed
|
||||
# "rsyslog" # KEEP THIS HERE if you want persistent logging (TODO: port to systemd, store in /var/log/...)
|
||||
"sane-deadlines"
|
||||
@@ -173,16 +191,17 @@ in
|
||||
"sane-scripts.cli"
|
||||
"sane-secrets-unlock"
|
||||
"sane-sysload"
|
||||
"sc-im"
|
||||
# "snapper"
|
||||
"sc-im" # CLI spreadsheet editor
|
||||
"snapper"
|
||||
"sops" # for manually viewing secrets; outside `sane-secrets` (TODO: improve sane-secrets!)
|
||||
"speedtest-cli"
|
||||
# "ssh-to-age"
|
||||
"ssh" # specified as a user program, to enable ssh-agent service
|
||||
"ssh-to-age" # used when provisioning a new nixos host
|
||||
"strings"
|
||||
"sudo"
|
||||
# "tageditor" # music tagging
|
||||
# "unar"
|
||||
# "unzip"
|
||||
"unzip"
|
||||
"wireguard-tools" # for `wg`
|
||||
"xdg-utils" # for xdg-open
|
||||
# "yarn"
|
||||
@@ -193,13 +212,14 @@ in
|
||||
"dasht" # docset documentation viewer
|
||||
# "gh" # MS GitHub cli
|
||||
"haredoc"
|
||||
"nix-check-deps" # run `nix-check-deps packageName -f .` before submitting stuff upstream
|
||||
"nix-index"
|
||||
"nixfmt-rfc-style" # run `nixpkgs path/to/package.nix` before submitting stuff upstream
|
||||
"nixfmt-rfc-style" # run `nixfmt path/to/package.nix` before submitting stuff upstream
|
||||
"nixpkgs-hammering"
|
||||
"nixpkgs-review"
|
||||
"qmk-udev-rules"
|
||||
"sane-scripts.dev"
|
||||
"sequoia"
|
||||
"sequoia" # gpg tool
|
||||
# "via"
|
||||
"wally-cli"
|
||||
# "zsa-udev-rules"
|
||||
@@ -218,9 +238,12 @@ in
|
||||
|
||||
pcTuiApps = declPackageSet [
|
||||
"aerc" # email client
|
||||
# "cassini" # Elegoo printer control. need here especially, for opening firewalls.
|
||||
"mslicer" # TODO: upstream, and then move this to the phone-case-cq repo
|
||||
# "msmtp" # sendmail
|
||||
# "offlineimap" # email mailbox sync
|
||||
# "sfeed" # RSS fetcher
|
||||
# "uvtools"
|
||||
"visidata" # TUI spreadsheet viewer/editor
|
||||
"w3m" # web browser
|
||||
];
|
||||
@@ -230,7 +253,6 @@ in
|
||||
"clang"
|
||||
"lua"
|
||||
"nodejs"
|
||||
"patchelf"
|
||||
"rustc"
|
||||
# "tree-sitter"
|
||||
];
|
||||
@@ -247,10 +269,10 @@ in
|
||||
"celeste64"
|
||||
# "cutemaze" # meh: trivial maze game; qt6 and keyboard-only
|
||||
# "cuyo" # trivial puyo-puyo clone
|
||||
"endless-sky" # space merchantilism/exploration
|
||||
# "endless-sky" # space merchantilism/exploration
|
||||
# "factorio"
|
||||
# "frozen-bubble" # WAN + LAN + 1P/2P bubble bobble
|
||||
"hase" # WAN worms game
|
||||
# "hase" # WAN worms game
|
||||
# "hedgewars" # WAN + LAN worms game (5~10 people online at any moment; <https://hedgewars.org>)
|
||||
# "libremines" # meh: trivial minesweeper; qt6
|
||||
# "mario0" # SMB + portal
|
||||
@@ -260,16 +282,17 @@ in
|
||||
# "osu-lazer"
|
||||
# "pinball" # 3d pinball; kb/mouse. old sourceforge project
|
||||
# "powermanga" # STYLISH space invaders derivative (keyboard-only)
|
||||
"shattered-pixel-dungeon" # doesn't cross compile
|
||||
# "shattered-pixel-dungeon" # doesn't cross compile
|
||||
# "sm64ex-coop"
|
||||
"sm64coopdx"
|
||||
"space-cadet-pinball" # LMB/RMB controls (bindable though. volume buttons?)
|
||||
"steam"
|
||||
"superTux" # keyboard-only controls
|
||||
"superTuxKart" # poor FPS on pinephone
|
||||
"tumiki-fighters" # keyboard-only
|
||||
# "tumiki-fighters" # keyboard-only
|
||||
"vvvvvv" # keyboard-only controls
|
||||
# "wine"
|
||||
"zelda64recomp"
|
||||
];
|
||||
|
||||
guiApps = declPackageSet [
|
||||
@@ -281,7 +304,10 @@ in
|
||||
guiBaseApps = declPackageSet [
|
||||
# "abaddon" # discord client
|
||||
"alacritty" # terminal emulator
|
||||
"alpaca" # ollama/LLM client
|
||||
"blanket" # ambient noise generator
|
||||
"calls" # gnome calls (dialer/handler)
|
||||
"confy" # conference planning app
|
||||
"dbus"
|
||||
# "dconf" # or use `gsettings`, with its keyfile backend
|
||||
# "delfin" # Jellyfin client
|
||||
@@ -289,11 +315,11 @@ in
|
||||
"dino" # XMPP client
|
||||
"dissent" # Discord client (formerly known as: gtkcord4)
|
||||
# "emote"
|
||||
"envelope" # GTK4 email client (alpha)
|
||||
# "envelope" # GTK4 email client (alpha)
|
||||
# "evince" # PDF viewer
|
||||
# "flare-signal" # gtk4 signal client
|
||||
"fractal" # matrix client
|
||||
"g4music" # local music player
|
||||
# "g4music" # local music player
|
||||
# "gnome.cheese"
|
||||
# "gnome-feeds" # RSS reader (with claimed mobile support)
|
||||
# "gnome.file-roller"
|
||||
@@ -308,6 +334,7 @@ in
|
||||
"gnome-frog" # OCR/QR decoder
|
||||
"gnome-maps"
|
||||
"gnome-screenshot" # libcamera-based screenshotter, for debugging; should be compatible with gc2145 camera on Pinephone
|
||||
"gnome-sound-recorder" # a simple microphone recorder/tester
|
||||
"gnome-weather"
|
||||
"gpodder"
|
||||
"gsettings"
|
||||
@@ -323,8 +350,9 @@ in
|
||||
"mepo" # maps viewer
|
||||
# "mesa-demos" # for eglinfo, glxinfo & other testing tools
|
||||
"mpv"
|
||||
# "networkmanagerapplet" # for nm-connection-editor GUI. XXX(2024-09-03): broken, probably by NetworkManager sandboxing
|
||||
"networkmanagerapplet"
|
||||
# "ntfy-sh" # notification service
|
||||
"newelle" # ollama/LLM client
|
||||
"newsflash" # RSS viewer
|
||||
"papers" # PDF viewer
|
||||
"pavucontrol"
|
||||
@@ -340,10 +368,11 @@ in
|
||||
# "tdesktop" # broken on phosh
|
||||
# "tokodon"
|
||||
"tuba" # mastodon/pleroma client (stores pw in keyring)
|
||||
"v4l-utils" # for `media-ctl`; to debug cameras: <https://wiki.postmarketos.org/wiki/PINE64_PinePhone_(pine64-pinephone)#Cameras>
|
||||
# "v4l-utils" # for `media-ctl`; to debug cameras: <https://wiki.postmarketos.org/wiki/PINE64_PinePhone_(pine64-pinephone)#Cameras>
|
||||
"video-trimmer"
|
||||
"vulkan-tools" # vulkaninfo
|
||||
# "whalebird" # pleroma client (Electron). input is broken on phosh.
|
||||
"wiremix" # wireplumber TUI
|
||||
"xdg-terminal-exec"
|
||||
"youtube-tui"
|
||||
# "zathura" # PDF/CBZ/ePUB viewer
|
||||
@@ -363,7 +392,7 @@ in
|
||||
"megapixels" # camera app (does not support PPP as of 2024-11-29)
|
||||
"megapixels-next" # camera app (which supports PPP, as of 2024-11-29)
|
||||
"notejot" # note taking, e.g. shopping list
|
||||
"planify" # todo-tracker/planner
|
||||
# "planify" # todo-tracker/planner (XXX(2025-05-16): does not build; gxml tests fail against glib 2.84.1; planify itself fails still, if gxml.doCheck forced false)
|
||||
"portfolio-filemanager"
|
||||
# "tangram" # web browser
|
||||
"wike" # Wikipedia Reader
|
||||
@@ -376,11 +405,10 @@ in
|
||||
"pcTuiApps"
|
||||
####
|
||||
"audacity"
|
||||
# "blanket" # ambient noise generator
|
||||
"brave" # for the integrated wallet -- as a backup
|
||||
# "cantata" # music player (mpd frontend)
|
||||
# "chromium" # chromium takes hours to build. brave is chromium-based, distributed in binary form, so prefer it.
|
||||
# "cups"
|
||||
"cups"
|
||||
"discord" # x86-only
|
||||
# "electrum"
|
||||
"element-desktop"
|
||||
@@ -403,7 +431,7 @@ in
|
||||
# "kid3" # audio tagging
|
||||
"krita"
|
||||
"libreoffice" # TODO: replace with an office suite that uses saner packaging?
|
||||
"losslesscut-bin" # x86-only
|
||||
"losslesscut-bin" # x86-only (TODO: replace with from-source build: <https://github.com/NixOS/nixpkgs/pull/385535>)
|
||||
# "makemkv" # x86-only
|
||||
# "monero-gui" # x86-only
|
||||
"mumble"
|
||||
@@ -449,29 +477,13 @@ in
|
||||
|
||||
bash-language-server.sandbox.whitelistPwd = true;
|
||||
|
||||
blanket.buildCost = 1;
|
||||
blanket.sandbox.whitelistAudio = true;
|
||||
# blanket.sandbox.whitelistDbus = [ "user" ]; # TODO: untested
|
||||
blanket.sandbox.whitelistWayland = true;
|
||||
|
||||
blueberry.sandbox.wrapperType = "inplace"; #< it places binaries in /lib and then /etc/xdg/autostart files refer to the /lib paths, and fail to be patched
|
||||
blueberry.sandbox.whitelistWayland = true;
|
||||
blueberry.sandbox.extraPaths = [
|
||||
"/dev/rfkill"
|
||||
"/run/dbus"
|
||||
"/sys/class/rfkill"
|
||||
"/sys/devices"
|
||||
];
|
||||
bc.sandbox.autodetectCliPaths = "existingFile";
|
||||
|
||||
bridge-utils.sandbox.net = "all";
|
||||
|
||||
"cacert.unbundled".sandbox.enable = false; #< data only
|
||||
|
||||
cargo.persist.byStore.plaintext = [ ".cargo" ];
|
||||
# probably this sandboxing is too restrictive; i'm sandboxing it for rust-analyzer / neovim LSP
|
||||
cargo.sandbox.whitelistPwd = true;
|
||||
cargo.sandbox.net = "all";
|
||||
cargo.sandbox.extraHomePaths = [ "dev" "ref" ];
|
||||
cdecl = {};
|
||||
|
||||
clang = {};
|
||||
|
||||
@@ -481,6 +493,8 @@ in
|
||||
"/var/lib/clightning/bitcoin/lightning-rpc"
|
||||
];
|
||||
|
||||
colordiff.sandbox.autodetectCliPaths = "existingFile"; # for `aplay ./file.wav`
|
||||
|
||||
# cryptsetup: typical use is `cryptsetup open /dev/loopxyz mappedName`, and creates `/dev/mapper/mappedName`
|
||||
cryptsetup.sandbox.extraPaths = [
|
||||
"/dev/mapper"
|
||||
@@ -501,13 +515,15 @@ in
|
||||
|
||||
delfin.buildCost = 1;
|
||||
delfin.sandbox.whitelistAudio = true;
|
||||
delfin.sandbox.whitelistDbus = [ "user" ]; # else `mpris` plugin crashes the player
|
||||
delfin.sandbox.whitelistDbus.user = true; #< TODO: reduce # else `mpris` plugin crashes the player
|
||||
delfin.sandbox.whitelistDri = true;
|
||||
delfin.sandbox.whitelistWayland = true;
|
||||
delfin.sandbox.net = "clearnet";
|
||||
# auth token, preferences
|
||||
delfin.persist.byStore.private = [ ".config/delfin" ];
|
||||
|
||||
difftastic.sandbox.autodetectCliPaths = "existing";
|
||||
|
||||
dig.sandbox.net = "all";
|
||||
|
||||
dmidecode.sandbox.extraPaths = [ "/sys/firmware/dmi" ];
|
||||
@@ -530,10 +546,10 @@ in
|
||||
|
||||
endless-sky.buildCost = 1;
|
||||
endless-sky.persist.byStore.plaintext = [ ".local/share/endless-sky" ];
|
||||
endless-sky.sandbox.mesaCacheDir = ".cache/endless-sky/mesa";
|
||||
endless-sky.sandbox.whitelistAudio = true;
|
||||
endless-sky.sandbox.whitelistDri = true;
|
||||
endless-sky.sandbox.whitelistWayland = true;
|
||||
# endless-sky.sandbox.whitelistX = true;
|
||||
endless-sky.packageUnwrapped = pkgs.endless-sky.overrideAttrs (base: {
|
||||
nativeBuildInputs = (base.nativeBuildInputs or []) ++ [
|
||||
pkgs.makeWrapper
|
||||
@@ -548,6 +564,10 @@ in
|
||||
# TODO: package [smile](https://github.com/mijorus/smile) for probably a better mobile experience.
|
||||
emote.persist.byStore.plaintext = [ ".local/share/Emote" ];
|
||||
|
||||
erdtree.sandbox.tryKeepUsers = true; #< to keep user/group info when running as root
|
||||
erdtree.sandbox.autodetectCliPaths = "existingDir";
|
||||
erdtree.sandbox.whitelistPwd = true;
|
||||
|
||||
ethtool.sandbox.capabilities = [ "net_admin" ];
|
||||
ethtool.sandbox.net = "all";
|
||||
ethtool.sandbox.tryKeepUsers = true;
|
||||
@@ -563,11 +583,12 @@ in
|
||||
eza.sandbox.tryKeepUsers = true; #< to keep user/group info when running as root
|
||||
eza.sandbox.autodetectCliPaths = "existing";
|
||||
eza.sandbox.whitelistPwd = true;
|
||||
eza.sandbox.extraHomePaths = [
|
||||
# so that e.g. `eza -l ~` can show which symlink exist
|
||||
".persist/ephemeral"
|
||||
".persist/plaintext"
|
||||
];
|
||||
# eza.sandbox.extraHomePaths = [
|
||||
# # so that e.g. `eza -l ~` can show which symlink exist
|
||||
# # hol' up: this is almost like just un-sandboxing it
|
||||
# ".persist/ephemeral"
|
||||
# ".persist/plaintext"
|
||||
# ];
|
||||
|
||||
fatresize.sandbox.autodetectCliPaths = "parent"; # /dev/sda1 -> needs /dev/sda
|
||||
fatresize.sandbox.tryKeepUsers = true;
|
||||
@@ -595,6 +616,7 @@ in
|
||||
# ];
|
||||
|
||||
font-manager.buildCost = 1;
|
||||
font-manager.sandbox.mesaCacheDir = ".cache/font-manager/mesa";
|
||||
font-manager.sandbox.whitelistWayland = true;
|
||||
font-manager.packageUnwrapped = pkgs.rmDbusServicesInPlace (pkgs.font-manager.override {
|
||||
# build without the "Google Fonts" integration feature, to save closure / avoid webkitgtk_4_0
|
||||
@@ -645,12 +667,14 @@ in
|
||||
gitea = {};
|
||||
|
||||
gnome-calculator.buildCost = 1;
|
||||
gnome-calculator.sandbox.mesaCacheDir = ".cache/gnome-calculator/mesa"; # TODO: is this the correct app-id?
|
||||
gnome-calculator.sandbox.whitelistWayland = true;
|
||||
|
||||
gnome-calendar.buildCost = 2; # depends on webkitgtk_6_0 via evolution-data-server
|
||||
gnome-calendar.sandbox.mesaCacheDir = ".cache/gnome-calendar/mesa"; # TODO: is this the correct app-id?
|
||||
# gnome-calendar surely has data to persist, but i use it strictly to do date math, not track events.
|
||||
gnome-calendar.sandbox.whitelistWayland = true;
|
||||
gnome-calendar.sandbox.whitelistDbus = [ "user" ];
|
||||
gnome-calendar.sandbox.whitelistDbus.user = true; #< TODO: reduce
|
||||
gnome-calendar.suggestedPrograms = [
|
||||
"evolution-data-server" #< to access/persist calendar events
|
||||
];
|
||||
@@ -658,7 +682,7 @@ in
|
||||
# gnome-disks
|
||||
# XXX(2024-09-02): fails to show any disks even when run as `BUNPEN_DISABLE=1 sudo -E gnome-disks`.
|
||||
gnome-disk-utility.buildCost = 1;
|
||||
gnome-disk-utility.sandbox.whitelistDbus = [ "system" ];
|
||||
gnome-disk-utility.sandbox.whitelistDbus.system = true;
|
||||
gnome-disk-utility.sandbox.whitelistWayland = true;
|
||||
gnome-disk-utility.sandbox.extraHomePaths = [
|
||||
"tmp"
|
||||
@@ -691,34 +715,14 @@ in
|
||||
# seahorse: dump gnome-keyring secrets.
|
||||
seahorse.buildCost = 1;
|
||||
# N.B. it can lso manage ~/.ssh keys, but i explicitly don't add those to the sandbox for now.
|
||||
seahorse.sandbox.whitelistDbus = [ "user" ];
|
||||
seahorse.sandbox.whitelistDbus.user = true; #< TODO: reduce
|
||||
seahorse.sandbox.whitelistWayland = true;
|
||||
|
||||
gnome-2048.buildCost = 1;
|
||||
gnome-2048.sandbox.whitelistWayland = true;
|
||||
gnome-2048.sandbox.mesaCacheDir = ".cache/gnome-2048/mesa";
|
||||
gnome-2048.persist.byStore.plaintext = [ ".local/share/gnome-2048/scores" ];
|
||||
|
||||
gnome-frog.buildCost = 1;
|
||||
gnome-frog.sandbox.whitelistWayland = true;
|
||||
gnome-frog.sandbox.whitelistDbus = [ "user" ];
|
||||
gnome-frog.sandbox.extraPaths = [
|
||||
# needed when processing screenshots
|
||||
"/tmp"
|
||||
];
|
||||
gnome-frog.sandbox.extraHomePaths = [
|
||||
# for OCR'ing photos from disk
|
||||
"tmp"
|
||||
"Pictures/albums"
|
||||
"Pictures/cat"
|
||||
"Pictures/from"
|
||||
"Pictures/Photos"
|
||||
"Pictures/Screenshots"
|
||||
"Pictures/servo-macros"
|
||||
];
|
||||
gnome-frog.persist.byStore.ephemeral = [
|
||||
".local/share/tessdata" # 15M; dunno what all it is.
|
||||
];
|
||||
|
||||
gnugrep.sandbox.autodetectCliPaths = "existing";
|
||||
gnugrep.sandbox.whitelistPwd = true;
|
||||
gnugrep.sandbox.extraHomePaths = [
|
||||
@@ -740,7 +744,6 @@ in
|
||||
# N.B.: if the user doesn't specify an output path, `grim` will output to ~/Pictures (which isn't included in this sandbox)
|
||||
grim.sandbox.autodetectCliPaths = "existingOrParent";
|
||||
grim.sandbox.whitelistWayland = true;
|
||||
grim.sandbox.mesaCacheDir = null; # not a GUI even though it uses wayland
|
||||
|
||||
hase.buildCost = 1;
|
||||
hase.sandbox.net = "clearnet";
|
||||
@@ -816,7 +819,7 @@ in
|
||||
"/sys/devices"
|
||||
];
|
||||
|
||||
libnotify.sandbox.whitelistDbus = [ "user" ]; # notify-send
|
||||
libnotify.sandbox.whitelistDbus.user = true; #< TODO: reduce # notify-send
|
||||
|
||||
lightning-cli.packageUnwrapped = pkgs.linkBinIntoOwnPackage pkgs.clightning "lightning-cli";
|
||||
lightning-cli.sandbox.extraHomePaths = [
|
||||
@@ -838,6 +841,7 @@ in
|
||||
losslesscut-bin.sandbox.whitelistDri = true;
|
||||
losslesscut-bin.sandbox.whitelistWayland = true;
|
||||
# losslesscut-bin.sandbox.whitelistX = true;
|
||||
losslesscut-bin.sandbox.mesaCacheDir = ".cache/losslesscut/mesa"; # TODO: is this the correct app-id?
|
||||
losslesscut-bin.packageUnwrapped = pkgs.losslesscut-bin.overrideAttrs (base: {
|
||||
extraMakeWrapperArgs = (base.extraMakeWrapperArgs or []) ++ [
|
||||
"--append-flags '--ozone-platform-hint=auto --ozone-platform=wayland --enable-features=WaylandWindowDecorations'"
|
||||
@@ -865,18 +869,15 @@ in
|
||||
|
||||
marksman.sandbox.whitelistPwd = true;
|
||||
|
||||
mercurial.sandbox.net = "clearnet";
|
||||
mercurial.sandbox.whitelistPwd = true;
|
||||
|
||||
mesa-demos.sandbox.whitelistDri = true;
|
||||
mesa-demos.sandbox.whitelistWayland = true;
|
||||
mesa-demos.sandbox.whitelistX = true;
|
||||
|
||||
meson = {};
|
||||
|
||||
millipixels.packageUnwrapped = pkgs.millipixels.override {
|
||||
v4l-utils = config.sane.programs.v4l-utils.packageUnwrapped; # necessary for cross compilation
|
||||
};
|
||||
# millipixels.packageUnwrapped = pkgs.millipixels.override {
|
||||
# v4l-utils = config.sane.programs.v4l-utils.packageUnwrapped; # necessary for cross compilation
|
||||
# };
|
||||
millipixels.sandbox.method = null; #< TODO: sandbox
|
||||
|
||||
# actual monero blockchain (not wallet/etc; safe to delete, just slow to regenerate)
|
||||
@@ -888,6 +889,10 @@ in
|
||||
"records/finance/cryptocurrencies/monero"
|
||||
];
|
||||
|
||||
mozlz4a.sandbox.autodetectCliPaths = "existingOrParent";
|
||||
|
||||
mslicer.sandbox.method = null; #< TODO: sandbox
|
||||
|
||||
nano.sandbox.autodetectCliPaths = "existingFileOrParent";
|
||||
|
||||
netcat.sandbox.net = "all";
|
||||
@@ -901,13 +906,25 @@ in
|
||||
nettools.sandbox.capabilities = [ "net_admin" "net_raw" ];
|
||||
|
||||
networkmanagerapplet.sandbox.whitelistWayland = true;
|
||||
networkmanagerapplet.sandbox.whitelistDbus = [ "system" ];
|
||||
networkmanagerapplet.sandbox.whitelistDbus.system = true;
|
||||
|
||||
nfs-utils.sandbox.method = null; #< TODO: sandbox
|
||||
|
||||
nil.sandbox.whitelistPwd = true;
|
||||
nil.sandbox.keepPids = true;
|
||||
|
||||
nixd.sandbox.whitelistPwd = true;
|
||||
|
||||
nix-check-deps.sandbox.whitelistPwd = true;
|
||||
nix-check-deps.sandbox.net = "all";
|
||||
nix-check-deps.sandbox.extraPaths = [
|
||||
"/nix/var"
|
||||
];
|
||||
|
||||
nix-tree.sandbox.extraPaths = [
|
||||
"/nix/var"
|
||||
];
|
||||
|
||||
nixfmt-rfc-style.sandbox.autodetectCliPaths = "existingDirOrParent"; #< it formats via rename
|
||||
|
||||
nixpkgs-hammering.sandbox.whitelistPwd = true;
|
||||
@@ -950,8 +967,12 @@ in
|
||||
# settings (electron app)
|
||||
obsidian.persist.byStore.plaintext = [ ".config/obsidian" ];
|
||||
|
||||
oils-for-unix.sandbox.enable = false; #< it's a shell; doesn't make sense to sandbox
|
||||
|
||||
openscad-lsp.sandbox.whitelistPwd = true;
|
||||
|
||||
openssl.sandbox.net = "clearnet";
|
||||
|
||||
passt.sandbox.enable = false; #< sandbox helper (netns specifically)
|
||||
|
||||
parted.sandbox.extraPaths = [
|
||||
@@ -964,6 +985,7 @@ in
|
||||
pavucontrol.sandbox.whitelistAudio = true;
|
||||
pavucontrol.sandbox.whitelistDri = true; #< to be a little more responsive
|
||||
pavucontrol.sandbox.whitelistWayland = true;
|
||||
pavucontrol.sandbox.mesaCacheDir = ".cache/pavucontrol/mesa";
|
||||
|
||||
pciutils.sandbox.extraPaths = [
|
||||
"/sys/bus/pci"
|
||||
@@ -1005,17 +1027,21 @@ in
|
||||
pwvucontrol.sandbox.whitelistAudio = true;
|
||||
pwvucontrol.sandbox.whitelistDri = true; # else perf on moby is unusable
|
||||
pwvucontrol.sandbox.whitelistWayland = true;
|
||||
pwvucontrol.sandbox.mesaCacheDir = ".cache/pwvucontrol/mesa"; # TODO: is this the correct app-id?
|
||||
|
||||
pyright.sandbox.whitelistPwd = true;
|
||||
|
||||
python3-repl.packageUnwrapped = pkgs.python3.withPackages (ps: with ps; [
|
||||
libgpiod
|
||||
numpy
|
||||
psutil
|
||||
pykakasi
|
||||
requests
|
||||
scipy
|
||||
unidecode
|
||||
]);
|
||||
python3-repl.sandbox.net = "clearnet";
|
||||
python3-repl.sandbox.autodetectCliPaths = "existing"; #< for invoking scripts like `python3 ./my-script.py`
|
||||
python3-repl.sandbox.extraHomePaths = [
|
||||
"/" #< this is 'safe' because with don't expose .persist/private, so no .ssh/id_ed25519
|
||||
".persist/plaintext"
|
||||
@@ -1027,7 +1053,9 @@ in
|
||||
rsync.sandbox.net = "clearnet";
|
||||
rsync.sandbox.autodetectCliPaths = "existingOrParent";
|
||||
rsync.sandbox.tryKeepUsers = true; # if running as root, keep the user namespace so that `-a` can set the correct owners, etc
|
||||
rsync.sandbox.whitelistSsh = true;
|
||||
|
||||
rust-analyzer.buildCost = 2;
|
||||
rust-analyzer.sandbox.whitelistPwd = true;
|
||||
rust-analyzer.suggestedPrograms = [
|
||||
"cargo"
|
||||
@@ -1042,7 +1070,7 @@ in
|
||||
sane-cast.sandbox.whitelistAudio = true; #< for sblast audio casting
|
||||
sane-cast.suggestedPrograms = [ "go2tv" "sblast" ];
|
||||
|
||||
sane-color-picker.sandbox.whitelistDbus = [ "user" ]; #< required for eyedropper to work
|
||||
sane-color-picker.sandbox.whitelistDbus.user = true; #< TODO: reduce #< required for eyedropper to work
|
||||
sane-color-picker.sandbox.whitelistWayland = true;
|
||||
sane-color-picker.sandbox.keepPidsAndProc = true; #< required by wl-clipboard
|
||||
sane-color-picker.suggestedPrograms = [
|
||||
@@ -1050,6 +1078,7 @@ in
|
||||
"wl-clipboard"
|
||||
# "zenity"
|
||||
];
|
||||
sane-color-picker.sandbox.mesaCacheDir = ".cache/sane-color-picker/mesa"; # TODO: is this the correct app-id?
|
||||
|
||||
sane-die-with-parent.sandbox.enable = false; #< it's a launcher; can't sandbox
|
||||
|
||||
@@ -1059,10 +1088,10 @@ in
|
||||
|
||||
screen.sandbox.enable = false; #< tty; needs to run anything
|
||||
|
||||
sequoia.packageUnwrapped = pkgs.sequoia.overrideAttrs (_: {
|
||||
# XXX(2024-07-30): sq_autocrypt_import test failure: "Warning: 9B7DD433F254904A is expired."
|
||||
doCheck = false;
|
||||
});
|
||||
# sequoia.packageUnwrapped = pkgs.sequoia.overrideAttrs (_: {
|
||||
# # XXX(2024-07-30): sq_autocrypt_import test failure: "Warning: 9B7DD433F254904A is expired."
|
||||
# doCheck = false;
|
||||
# });
|
||||
sequoia.buildCost = 1;
|
||||
sequoia.sandbox.whitelistPwd = true;
|
||||
sequoia.sandbox.autodetectCliPaths = "existingFileOrParent"; # supports `-o <file-to-create>`
|
||||
@@ -1072,6 +1101,7 @@ in
|
||||
shattered-pixel-dungeon.sandbox.whitelistAudio = true;
|
||||
shattered-pixel-dungeon.sandbox.whitelistDri = true;
|
||||
shattered-pixel-dungeon.sandbox.whitelistWayland = true;
|
||||
shattered-pixel-dungeon.sandbox.mesaCacheDir = ".cache/.shatteredpixel/mesa";
|
||||
|
||||
# printer/filament settings
|
||||
slic3r.buildCost = 1;
|
||||
@@ -1081,25 +1111,20 @@ in
|
||||
slic3r.sandbox.autodetectCliPaths = "existingFileOrParent"; # slic3r <my-file>.stl -o <out>.gcode
|
||||
|
||||
slurp.sandbox.whitelistWayland = true;
|
||||
slurp.sandbox.mesaCacheDir = null; # not a GUI even though it uses wayland
|
||||
|
||||
snapper.sandbox.tryKeepUsers = true;
|
||||
snapper.sandbox.whitelistDbus.system = true; #< all `snapper` does is speak to the daemon, via dbus
|
||||
|
||||
# snapshot camera, based on libcamera
|
||||
# TODO: enable dma heaps for more efficient buffer sharing: <https://gitlab.com/postmarketOS/pmaports/-/issues/2789>
|
||||
snapshot.sandbox.method = null; #< TODO: sandbox
|
||||
|
||||
sops.sandbox.extraHomePaths = [
|
||||
".config/sops"
|
||||
"nixos"
|
||||
# TODO: sops should only need access to knowledge/secrets,
|
||||
# except that i currently put its .sops.yaml config in the root of ~/knowledge
|
||||
"knowledge"
|
||||
];
|
||||
|
||||
sox.sandbox.autodetectCliPaths = "existingFileOrParent";
|
||||
sox.sandbox.whitelistAudio = true;
|
||||
|
||||
space-cadet-pinball.buildCost = 1;
|
||||
space-cadet-pinball.persist.byStore.plaintext = [ ".local/share/SpaceCadetPinball" ];
|
||||
space-cadet-pinball.sandbox.mesaCacheDir = ".cache/SpaceCadetPinball/mesa"; # TODO: is this the correct app-id?
|
||||
space-cadet-pinball.sandbox.whitelistAudio = true;
|
||||
space-cadet-pinball.sandbox.whitelistDri = true;
|
||||
space-cadet-pinball.sandbox.whitelistWayland = true;
|
||||
@@ -1108,6 +1133,8 @@ in
|
||||
|
||||
sqlite.sandbox.method = null; #< TODO: sandbox
|
||||
|
||||
ssh-to-age.sandbox.autodetectCliPaths = "existingFile";
|
||||
|
||||
# N.B. if you call sshfs-fuse from the CLI -- without `mount.fuse` -- disable sandboxing
|
||||
sshfs-fuse.sandbox.net = "all";
|
||||
sshfs-fuse.sandbox.autodetectCliPaths = "parent";
|
||||
@@ -1120,6 +1147,8 @@ in
|
||||
];
|
||||
sshfs-fuse.sandbox.keepPids = true; #< XXX: bwrap didn't need this, but bunpen does. why?
|
||||
|
||||
sshpass.sandbox.autodetectCliPaths = "existingFile"; #< for `sshpass -f <path/to/password/file>`
|
||||
|
||||
strace.sandbox.enable = false; #< needs to `exec` its args, and therefore support *anything*
|
||||
|
||||
subversion.sandbox.net = "clearnet";
|
||||
@@ -1131,6 +1160,7 @@ in
|
||||
superTux.sandbox.whitelistDri = true;
|
||||
superTux.sandbox.whitelistWayland = true;
|
||||
# superTux.sandbox.whitelistX = true;
|
||||
superTux.sandbox.mesaCacheDir = ".cache/supertux2/mesa"; # TODO: is this the correct app-id?
|
||||
superTux.persist.byStore.plaintext = [ ".local/share/supertux2" ];
|
||||
superTux.packageUnwrapped = pkgs.superTux.overrideAttrs (base: {
|
||||
nativeBuildInputs = (base.nativeBuildInputs or []) ++ [
|
||||
@@ -1141,6 +1171,8 @@ in
|
||||
'';
|
||||
});
|
||||
|
||||
swaybg.sandbox.method = null; #< TODO: sandbox
|
||||
|
||||
swappy.sandbox.autodetectCliPaths = "existingFileOrParent";
|
||||
swappy.sandbox.whitelistWayland = true;
|
||||
|
||||
@@ -1150,11 +1182,6 @@ in
|
||||
systemctl.sandbox.capabilities = [ "cap_dac_override" "cap_sys_admin" ];
|
||||
systemctl.sandbox.keepPidsAndProc = true;
|
||||
|
||||
tcpdump.sandbox.net = "all";
|
||||
tcpdump.sandbox.autodetectCliPaths = "existingFileOrParent";
|
||||
tcpdump.sandbox.capabilities = [ "net_admin" "net_raw" ];
|
||||
tcpdump.sandbox.tryKeepUsers = true;
|
||||
|
||||
tdesktop.persist.byStore.private = [ ".local/share/TelegramDesktop" ];
|
||||
|
||||
tokodon.buildCost = 1;
|
||||
@@ -1165,13 +1192,19 @@ in
|
||||
tree.sandbox.tryKeepUsers = true;
|
||||
tree.sandbox.capabilities = [ "dac_read_search" ];
|
||||
|
||||
typescript-language-server.buildCost = 2;
|
||||
typescript-language-server.sandbox.whitelistPwd = true;
|
||||
typescript-language-server.persist.byStore.ephemeral = [
|
||||
".cache/typescript"
|
||||
".npm" # .npm/{_cacache,_logs}
|
||||
];
|
||||
|
||||
tumiki-fighters.buildCost = 1;
|
||||
tumiki-fighters.sandbox.whitelistAudio = true;
|
||||
tumiki-fighters.sandbox.whitelistDri = true; #< not strictly necessary, but triples CPU perf
|
||||
tumiki-fighters.sandbox.whitelistWayland = true;
|
||||
tumiki-fighters.sandbox.whitelistX = true;
|
||||
tumiki-fighters.sandbox.mesaCacheDir = ".cache/tumiki-fighters/mesa"; # TODO: is this the correct app-id?
|
||||
tumiki-fighters.suggestedPrograms = [
|
||||
"xwayland" #< XXX(2024-11-10): does not start without X(wayland), not even with SDL_VIDEDRIVER=wayland
|
||||
];
|
||||
@@ -1190,6 +1223,8 @@ in
|
||||
"/sys/bus/usb"
|
||||
];
|
||||
|
||||
uvtools.sandbox.method = null; #< TODO: sandbox
|
||||
|
||||
vala-language-server.sandbox.whitelistPwd = true;
|
||||
vala-language-server.suggestedPrograms = [
|
||||
# might someday support cmake, too: <https://github.com/vala-lang/vala-language-server/issues/73>
|
||||
@@ -1202,7 +1237,6 @@ in
|
||||
# `vulkaninfo`, `vkcube`
|
||||
vulkan-tools.sandbox.whitelistDri = true;
|
||||
vulkan-tools.sandbox.whitelistWayland = true;
|
||||
vulkan-tools.sandbox.mesaCacheDir = null; # doesn't use mesa even though it uses wayland
|
||||
vulkan-tools.sandbox.whitelistX = true;
|
||||
vulkan-tools.sandbox.extraPaths = [
|
||||
"/sys/dev/char"
|
||||
@@ -1213,6 +1247,7 @@ in
|
||||
vvvvvv.sandbox.whitelistAudio = true;
|
||||
vvvvvv.sandbox.whitelistDri = true; #< playable without, but burns noticably more CPU
|
||||
vvvvvv.sandbox.whitelistWayland = true;
|
||||
vvvvvv.sandbox.mesaCacheDir = ".cache/VVVVVV/mesa";
|
||||
vvvvvv.persist.byStore.plaintext = [ ".local/share/VVVVVV" ];
|
||||
|
||||
w3m.sandbox.net = "all";
|
||||
@@ -1223,6 +1258,7 @@ in
|
||||
|
||||
watch.sandbox.enable = false; #< it executes the command it's given
|
||||
|
||||
wdisplays.sandbox.mesaCacheDir = ".cache/wdisplays/mesa"; # TODO: is this the correct app-id?
|
||||
wdisplays.sandbox.whitelistWayland = true;
|
||||
|
||||
wget.sandbox.net = "all";
|
||||
@@ -1241,18 +1277,19 @@ in
|
||||
wirelesstools.sandbox.capabilities = [ "net_admin" ];
|
||||
wirelesstools.sandbox.tryKeepUsers = true;
|
||||
|
||||
wiremix.sandbox.whitelistAudio = true;
|
||||
|
||||
wl-clipboard.sandbox.whitelistWayland = true;
|
||||
wl-clipboard.sandbox.keepPids = true; #< this is needed, but not sure why?
|
||||
wl-clipboard.sandbox.mesaCacheDir = null; # not a GUI even though it uses wayland
|
||||
|
||||
wtype = {};
|
||||
wtype.sandbox.whitelistWayland = true;
|
||||
wtype.sandbox.mesaCacheDir = null; # not a GUI even though it uses wayland
|
||||
|
||||
xwayland.sandbox.wrapperType = "inplace"; #< consumers use it as a library (e.g. wlroots)
|
||||
xwayland.sandbox.whitelistWayland = true; #< just assuming this is needed
|
||||
xwayland.sandbox.whitelistX = true;
|
||||
xwayland.sandbox.whitelistDri = true; #< would assume this gives better gfx perf
|
||||
xwayland.sandbox.mesaCacheDir = ".cache/xwayland/mesa"; # TODO: is this the correct app-id?
|
||||
|
||||
xterm.sandbox.enable = false; # need to be able to do everything
|
||||
|
||||
@@ -1261,7 +1298,11 @@ in
|
||||
|
||||
sane.persist.sys.byStore.plaintext = lib.mkIf config.sane.programs.guiApps.enabled [
|
||||
# "/var/lib/alsa" # preserve output levels, default devices
|
||||
"/var/lib/systemd/backlight" # backlight brightness
|
||||
{
|
||||
# backlight brightness; MUST be `bind`, else systemd loses its shit with "Too many levels of symbolic links".
|
||||
path = "/var/lib/systemd/backlight";
|
||||
method = "bind";
|
||||
}
|
||||
];
|
||||
|
||||
hardware.graphics = lib.mkIf config.sane.programs.guiApps.enabled ({
|
||||
|
@@ -3,22 +3,32 @@
|
||||
# - default recording input will be silent, on lappy.
|
||||
# - Audio Setup -> Rescan Audio Devices ...
|
||||
# - Audio Setup -> Recording device -> sysdefault
|
||||
{ pkgs, ... }:
|
||||
{ lib, pkgs, ... }:
|
||||
let
|
||||
# wxGTK32 uses webkitgtk-4.0.
|
||||
# audacity doesn't actually need webkit though, so diable to reduce closure
|
||||
wxGTK32 = pkgs.wxGTK32.override {
|
||||
withWebKit = false;
|
||||
};
|
||||
# basePkg = pkgs.audacity.overrideAttrs (base: {
|
||||
# # upstream audacity.desktop specifies GDK_BACKEND=x11, with which it doesn't actually launch :|
|
||||
# postInstall = (base.postInstall or "") + ''
|
||||
# substituteInPlace $out/share/applications/${appId}.desktop \
|
||||
# --replace-fail 'GDK_BACKEND=x11 ' ""
|
||||
# '';
|
||||
|
||||
# # XXX(2025-03-03): upstream nixpkgs incorrectly defaults `GDK_BACKEND=x11`,
|
||||
# # even though audacity runs fine on wayland
|
||||
# postFixup = lib.replaceStrings [ "--set-default GDK_BACKEND x11" ] [ "" ] base.postFixup;
|
||||
# });
|
||||
basePkg = pkgs.tenacity; #< XXX(2025-07-27): upstream audacity fails build; use tenacity until fixed
|
||||
appId = basePkg.pname;
|
||||
in
|
||||
{
|
||||
sane.programs.audacity = {
|
||||
packageUnwrapped = (pkgs.audacity.override {
|
||||
# wxGTK32 uses webkitgtk-4.0.
|
||||
# audacity doesn't actually need webkit though, so diable to reduce closure
|
||||
wxGTK32 = pkgs.wxGTK32.override {
|
||||
withWebKit = false;
|
||||
};
|
||||
}).overrideAttrs (base: {
|
||||
# upstream audacity.desktop specifies GDK_BACKEND=x11, with which it doesn't actually launch :|
|
||||
postInstall = (base.postInstall or "") + ''
|
||||
substituteInPlace $out/share/applications/audacity.desktop \
|
||||
--replace-fail 'GDK_BACKEND=x11 ' ""
|
||||
'';
|
||||
});
|
||||
packageUnwrapped = basePkg.override {
|
||||
inherit wxGTK32;
|
||||
};
|
||||
|
||||
buildCost = 1;
|
||||
|
||||
@@ -30,20 +40,21 @@
|
||||
"tmp"
|
||||
"Music"
|
||||
# audacity needs the entire config dir mounted if running in a sandbox
|
||||
".config/audacity"
|
||||
".config/${appId}"
|
||||
];
|
||||
sandbox.extraPaths = [
|
||||
"/dev/snd" # for recording audio inputs to work
|
||||
];
|
||||
|
||||
# disable first-run splash screen
|
||||
fs.".config/audacity/audacity.cfg".file.text = ''
|
||||
fs.".config/${appId}/${appId}.cfg".file.text = ''
|
||||
PrefsVersion=1.1.1r1
|
||||
[GUI]
|
||||
ShowSplashScreen=0
|
||||
[Version]
|
||||
Major=3
|
||||
Minor=4
|
||||
Major=${lib.versions.major basePkg.version}
|
||||
Minor=${lib.versions.minor basePkg.version}
|
||||
Micro=${lib.versions.patch basePkg.version}
|
||||
'';
|
||||
};
|
||||
}
|
||||
|
@@ -3,7 +3,5 @@
|
||||
{
|
||||
sane.programs.ausyscall = {
|
||||
packageUnwrapped = pkgs.linkBinIntoOwnPackage pkgs.audit "ausyscall";
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
@@ -22,13 +22,13 @@ in
|
||||
# do this here, because the nixos service isn't so easily patched.
|
||||
postInstall = (upstream.postInstall or "") + ''
|
||||
wrapProgram "$out/sbin/avahi-daemon" \
|
||||
--add-flags --no-drop-root
|
||||
--add-flag --no-drop-root
|
||||
'';
|
||||
nativeBuildInputs = upstream.nativeBuildInputs ++ [
|
||||
pkgs.makeBinaryWrapper
|
||||
];
|
||||
});
|
||||
sandbox.whitelistDbus = [ "system" ];
|
||||
sandbox.whitelistDbus.system = true;
|
||||
sandbox.net = "all"; #< otherwise it will show 'null' in place of each interface name.
|
||||
# sandbox.extraPaths = [ ]; #< may be missing some paths; only tried service discovery, not service advertisement.
|
||||
};
|
||||
|
@@ -88,21 +88,6 @@ in
|
||||
{
|
||||
sane.programs.bemenu = {
|
||||
sandbox.whitelistWayland = true;
|
||||
sandbox.extraHomePaths = [
|
||||
".cache/fontconfig" #< else it complains, and is *way* slower
|
||||
];
|
||||
|
||||
packageUnwrapped = pkgs.bemenu.overrideAttrs (upstream: {
|
||||
nativeBuildInputs = (upstream.nativeBuildInputs or []) ++ [
|
||||
pkgs.makeBinaryWrapper
|
||||
];
|
||||
# can alternatively be specified as CLI flags
|
||||
postInstall = (upstream.postInstall or "") + ''
|
||||
wrapProgram $out/bin/bemenu \
|
||||
--set BEMENU_OPTS "${bemenuOpts}"
|
||||
wrapProgram $out/bin/bemenu-run \
|
||||
--set BEMENU_OPTS "${bemenuOpts}"
|
||||
'';
|
||||
});
|
||||
env.BEMENU_OPTS = bemenuOpts;
|
||||
};
|
||||
}
|
||||
|
13
hosts/common/programs/blanket.nix
Normal file
13
hosts/common/programs/blanket.nix
Normal file
@@ -0,0 +1,13 @@
|
||||
{ ... }:
|
||||
{
|
||||
sane.programs.blanket = {
|
||||
# com.rafaelmardojai.Blanket
|
||||
buildCost = 1;
|
||||
sandbox.whitelistAudio = true;
|
||||
sandbox.whitelistDbus.user.own = [
|
||||
"com.rafaelmardojai.Blanket"
|
||||
"org.mpris.MediaPlayer2.Blanket"
|
||||
];
|
||||
sandbox.whitelistWayland = true;
|
||||
};
|
||||
}
|
24
hosts/common/programs/blueberry.nix
Normal file
24
hosts/common/programs/blueberry.nix
Normal file
@@ -0,0 +1,24 @@
|
||||
{ config, lib, ... }:
|
||||
let
|
||||
cfg = config.sane.programs.blueberry;
|
||||
in
|
||||
{
|
||||
sane.programs.blueberry = {
|
||||
sandbox.wrapperType = "inplace"; #< it places binaries in /lib and then /etc/xdg/autostart files refer to the /lib paths, and fail to be patched
|
||||
sandbox.whitelistWayland = true;
|
||||
sandbox.extraPaths = [
|
||||
"/dev/rfkill"
|
||||
"/run/dbus"
|
||||
"/sys/class/rfkill"
|
||||
"/sys/devices"
|
||||
];
|
||||
sandbox.keepPids = true; #< not sure why, but it fails to launch GUI without this
|
||||
};
|
||||
|
||||
# TODO: hardware.bluetooth puts like 100 binaries from `bluez` onto PATH;
|
||||
# i can probably patch this so it's just `bluetoothd`.
|
||||
# see: <repo:nixos/nixpkgs:nixos/modules/services/hardware/bluetooth.nix>
|
||||
hardware.bluetooth = lib.mkIf cfg.enabled {
|
||||
enable = true;
|
||||
};
|
||||
}
|
6
hosts/common/programs/blueman.nix
Normal file
6
hosts/common/programs/blueman.nix
Normal file
@@ -0,0 +1,6 @@
|
||||
{ ... }:
|
||||
{
|
||||
sane.programs.blueman = {
|
||||
sandbox.method = null; #< TODO: sandbox
|
||||
};
|
||||
}
|
@@ -50,9 +50,10 @@ in
|
||||
};
|
||||
};
|
||||
|
||||
# plug into the (proposed) nixpkgs bonsaid service.
|
||||
# plug into the nixpkgs bonsaid service.
|
||||
# it's a user service, and since i don't use the service manager it doesn't actually activate:
|
||||
# i just steal the config file generation from it :)
|
||||
services.bonsaid.package = config.sane.programs.bonsai.package;
|
||||
services.bonsaid.settings = lib.mkIf cfg.enabled (lib.mkMerge [
|
||||
cfg.config.transitions
|
||||
[{
|
||||
|
@@ -22,6 +22,7 @@
|
||||
sandbox.extraPaths = [
|
||||
"/tmp" # needed particularly if run from `sane-vpn do`
|
||||
];
|
||||
sandbox.mesaCacheDir = ".cache/BraveSoftware/mesa";
|
||||
sandbox.whitelistAudio = true;
|
||||
sandbox.whitelistDri = true;
|
||||
sandbox.whitelistWayland = true;
|
||||
|
@@ -9,7 +9,7 @@ in
|
||||
"/sys/class/leds"
|
||||
"/sys/devices"
|
||||
];
|
||||
# sandbox.whitelistDbus = [ "system" ]; #< only necessary if not granting udev perms
|
||||
# sandbox.whitelistDbus.system = true; #< only necessary if not granting udev perms
|
||||
};
|
||||
|
||||
services.udev.extraRules = let
|
||||
|
@@ -4,7 +4,8 @@ let
|
||||
in
|
||||
{
|
||||
sane.programs.btrfs-progs = {
|
||||
sandbox.autodetectCliPaths = "existing"; # e.g. `btrfs filesystem df /my/fs`
|
||||
# sandbox.autodetectCliPaths = "existing"; # e.g. `btrfs filesystem df /my/fs`
|
||||
sandbox.autodetectCliPaths = "parent"; # e.g. `btrfs subvolume create ./my_subvol`
|
||||
sandbox.extraPaths = [
|
||||
"/dev/btrfs-control"
|
||||
#vvv required for `sudo btrfs filesystem show` with no args
|
||||
@@ -12,13 +13,28 @@ in
|
||||
"/sys/block"
|
||||
"/sys/dev/block"
|
||||
"/sys/devices"
|
||||
#vvv required for `sudo btrfs scrub start`
|
||||
"/sys/fs"
|
||||
#vvv required for `sudo btrfs scrub status` to show stats
|
||||
"/var/lib/btrfs"
|
||||
];
|
||||
sandbox.tryKeepUsers = true;
|
||||
sandbox.capabilities = [ "sys_admin" ]; # for `btrfs scrub`
|
||||
sandbox.keepPids = true; # required for `sudo btrfs scrub start`
|
||||
sandbox.capabilities = [
|
||||
"dac_read_search" # for `btrfs replace`
|
||||
"sys_admin" # for `btrfs scrub`
|
||||
];
|
||||
};
|
||||
|
||||
# TODO: service sandboxing
|
||||
services.btrfs.autoScrub.enable = lib.mkIf cfg.enabled true;
|
||||
services.btrfs.autoScrub.interval = "weekly";
|
||||
|
||||
# nixos/modules/tasks/filesystems/btrfs.nix fires this assertion, but its implementation totally handles the case of 0 btrfs filesystems.
|
||||
sane.silencedAssertions = lib.mkIf cfg.enabled [''
|
||||
If 'services.btrfs.autoScrub' is enabled, you need to have at least one
|
||||
btrfs file system mounted via 'fileSystems' or specify a list manually
|
||||
in 'services.btrfs.autoScrub.fileSystems'.
|
||||
''];
|
||||
}
|
||||
|
||||
|
@@ -7,7 +7,7 @@ in
|
||||
packageUnwrapped = pkgs.bunpen.overrideAttrs (base: {
|
||||
# create a directory which holds just the `bunpen` so that we
|
||||
# can add bunpen as a dependency to binaries via `PATH=/run/current-system/libexec/bunpen` without forcing rebuild every time bunpen changes
|
||||
postInstall = ''
|
||||
postInstall = (base.postInstall or "") + ''
|
||||
mkdir -p $out/libexec/bunpen
|
||||
ln -s $out/bin/bunpen $out/libexec/bunpen/bunpen
|
||||
'';
|
||||
|
@@ -14,7 +14,7 @@
|
||||
packageUnwrapped = pkgs.rmDbusServices pkgs.callaudiod;
|
||||
|
||||
sandbox.whitelistAudio = true;
|
||||
sandbox.whitelistDbus = [ "user" ];
|
||||
sandbox.whitelistDbus.user = true; #< TODO: reduce
|
||||
|
||||
services.callaudiod = {
|
||||
description = "callaudiod: dbus service to switch audio profiles and mute microphone";
|
||||
|
@@ -65,6 +65,7 @@ in
|
||||
rev = "b924a57e8eeb24e8b9afc5fd0fb9b51d5993fe5d";
|
||||
hash = "sha256-1VbKV+eAJ80IMlubNl7774B7QvLv4hE8SXANDSD9sRU=";
|
||||
};
|
||||
patches = [];
|
||||
});
|
||||
}).overrideAttrs (upstream: {
|
||||
# src = lib.warnIf (lib.versionOlder "47.0" upstream.version) "gnome-calls outdated; remove src override? (keep UI patches though!)" pkgs.fetchFromGitLab {
|
||||
@@ -101,9 +102,15 @@ in
|
||||
];
|
||||
}));
|
||||
|
||||
sandbox.mesaCacheDir = ".cache/calls/mesa";
|
||||
sandbox.net = "vpn.wg-home"; #< XXX(2024/07/05): my cell carrier seems to block RTP, so tunnel it.
|
||||
sandbox.whitelistAudio = true;
|
||||
sandbox.whitelistDbus = [ "user" ]; # necessary for secrets, at the minimum
|
||||
sandbox.whitelistDbus.user.call."org.freedesktop.secrets" = "*"; #< TODO: restrict to a subset of secrets
|
||||
sandbox.whitelistDbus.user.call."org.mobian_project.CallAudio" = "*";
|
||||
sandbox.whitelistDbus.user.call."org.sigxcpu.Feedback" = "*";
|
||||
sandbox.whitelistDbus.user.call."org.gnome.evolution.dataserver.*" = "*"; #< TODO: reduce; only needs address book and maybe sources
|
||||
sandbox.whitelistDbus.user.own = [ "org.gnome.Calls" ];
|
||||
sandbox.whitelistSendNotifications = true; # for missed calls
|
||||
sandbox.whitelistWayland = true;
|
||||
|
||||
persist.byStore.private = [
|
||||
|
@@ -1,7 +1,7 @@
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
sane.programs.captree = {
|
||||
packageUnwrapped = pkgs.linkBinIntoOwnPackage pkgs.libcap-with-captree "captree";
|
||||
packageUnwrapped = pkgs.linkBinIntoOwnPackage pkgs.libcap "captree";
|
||||
sandbox.keepPidsAndProc = true;
|
||||
};
|
||||
}
|
||||
|
16
hosts/common/programs/cargo.nix
Normal file
16
hosts/common/programs/cargo.nix
Normal file
@@ -0,0 +1,16 @@
|
||||
{ ... }:
|
||||
{
|
||||
sane.programs.cargo = {
|
||||
#v XXX(2025-02-23): normal `cargo` fails to build for cross (temporarily?). use prebuilt instead.
|
||||
# NOT easy to debug/fix. git bisect pins this between ceba2c6c3b (good) and 62a28e5a3d (bad)
|
||||
# packageUnwrapped = pkgs.rust.packages.prebuilt.cargo;
|
||||
|
||||
buildCost = 1; # 2.5 GiB closure
|
||||
|
||||
persist.byStore.plaintext = [ ".cargo" ];
|
||||
# probably this sandboxing is too restrictive; i'm sandboxing it for rust-analyzer / neovim LSP
|
||||
sandbox.whitelistPwd = true;
|
||||
sandbox.net = "all";
|
||||
sandbox.extraHomePaths = [ "dev" "ref" ];
|
||||
};
|
||||
}
|
28
hosts/common/programs/cassini.nix
Normal file
28
hosts/common/programs/cassini.nix
Normal file
@@ -0,0 +1,28 @@
|
||||
{ config, lib, pkgs, ...}:
|
||||
let
|
||||
cfg = config.sane.programs.cassini;
|
||||
in
|
||||
{
|
||||
sane.programs.cassini = {
|
||||
sandbox.method = null; #< TODO: sandbox
|
||||
};
|
||||
|
||||
# inspired by SSDP firewall code.
|
||||
# Elegoo printers use their own SSDP-like discovery method, but on port 3000 instead of 1900 and 255.255.255.255 instead of 239.255.255.250:
|
||||
# 1. i send a broadcast packet to 255.255.255.255 port 3000;
|
||||
# 2. printers respond with a packet that originates from their port 3000, addressed to whichever port i sent from.
|
||||
#
|
||||
# TODO: can i generalize the SSDP rule from <hosts/common/net/upnp.nix> to be generic over port?
|
||||
networking.firewall.extraCommands = with pkgs; lib.mkIf cfg.enabled ''
|
||||
# originally for SSDP: <https://serverfault.com/a/911286>
|
||||
# ipset -! means "don't fail if set already exists"
|
||||
${ipset}/bin/ipset create -! upnp hash:ip,port timeout 10
|
||||
${iptables}/bin/iptables -A OUTPUT -d 255.255.255.255/32 -p udp -m udp --dport 3000 -j SET --add-set upnp src,src --exist
|
||||
${iptables}/bin/iptables -A INPUT -p udp -m set --match-set upnp dst,dst -j ACCEPT
|
||||
|
||||
# IPv6 ruleset. ff02::/16 means *any* link-local multicast group (so this is probably more broad than it needs to be)
|
||||
${ipset}/bin/ipset create -! upnp6 hash:ip,port timeout 10 family inet6
|
||||
${iptables}/bin/ip6tables -A OUTPUT -d ff02::/16 -p udp -m udp --dport 3000 -j SET --add-set upnp6 src,src --exist
|
||||
${iptables}/bin/ip6tables -A INPUT -p udp -m set --match-set upnp6 dst,dst -j ACCEPT
|
||||
'';
|
||||
}
|
@@ -14,5 +14,6 @@
|
||||
# save data, controls map
|
||||
".local/share/Celeste64"
|
||||
];
|
||||
sandbox.mesaCacheDir = ".cache/Celeste64/mesa";
|
||||
};
|
||||
}
|
||||
|
19
hosts/common/programs/confy.nix
Normal file
19
hosts/common/programs/confy.nix
Normal file
@@ -0,0 +1,19 @@
|
||||
{ ... }:
|
||||
{
|
||||
sane.programs.confy = {
|
||||
sandbox.net = "all";
|
||||
sandbox.whitelistDri = true;
|
||||
sandbox.whitelistWayland = true;
|
||||
sandbox.mesaCacheDir = ".cache/net.kirgroup.confy/mesa";
|
||||
sandbox.whitelistDbus.user.own = [ "net.kirgroup.confy" ];
|
||||
sandbox.whitelistPortal = [
|
||||
"NetworkMonitor"
|
||||
"OpenURI"
|
||||
];
|
||||
|
||||
persist.byStore.private = [
|
||||
".cache/net.kirgroup.confy"
|
||||
# ".local/share/net.kirgroup.confy" #< empty
|
||||
];
|
||||
};
|
||||
}
|
@@ -11,6 +11,7 @@
|
||||
|
||||
conky.config = {
|
||||
out_to_wayland = true,
|
||||
out_to_x = false,
|
||||
update_interval = 10,
|
||||
|
||||
alignment = 'middle_middle',
|
||||
|
@@ -9,7 +9,6 @@
|
||||
# "/sys/devices/system"
|
||||
];
|
||||
sandbox.whitelistWayland = true;
|
||||
sandbox.mesaCacheDir = null; # doesn't use mesa even though it uses wayland
|
||||
|
||||
suggestedPrograms = [
|
||||
"sane-sysload"
|
||||
|
@@ -16,7 +16,7 @@
|
||||
buildCost = 1;
|
||||
|
||||
sandbox.whitelistAudio = true;
|
||||
sandbox.whitelistDbus = [ "user" ]; # mpris
|
||||
sandbox.whitelistDbus.user = true; #< TODO: reduce # mpris
|
||||
sandbox.whitelistWayland = true;
|
||||
sandbox.extraHomePaths = [
|
||||
"Books/Audiobooks"
|
||||
|
@@ -11,11 +11,12 @@ let
|
||||
in
|
||||
{
|
||||
sane.programs.cups = {
|
||||
sandbox.method = null; #< TODO: sandbox
|
||||
suggestedPrograms = [
|
||||
"system-config-printer"
|
||||
];
|
||||
};
|
||||
sane.programs.system-config-printer = {};
|
||||
sane.programs.system-config-printer.sandbox.method = null; #< TODO: sandbox
|
||||
|
||||
services.printing = lib.mkIf cfg.enabled {
|
||||
enable = true;
|
||||
|
@@ -30,7 +30,7 @@ in
|
||||
{
|
||||
sane.programs.dconf = {
|
||||
packageUnwrapped = pkgs.rmDbusServicesInPlace pkgs.dconf;
|
||||
sandbox.whitelistDbus = [ "user" ];
|
||||
sandbox.whitelistDbus.user = true; #< TODO: reduce
|
||||
persist.byStore.private = [
|
||||
".config/dconf"
|
||||
];
|
||||
|
@@ -5,6 +5,7 @@
|
||||
./abaddon.nix
|
||||
./aerc.nix
|
||||
./alacritty.nix
|
||||
./alpaca.nix
|
||||
./alsa-ucm-conf
|
||||
./animatch.nix
|
||||
./assorted.nix
|
||||
@@ -13,6 +14,9 @@
|
||||
./avahi.nix
|
||||
./bemenu.nix
|
||||
./bitcoin-cli.nix
|
||||
./blanket.nix
|
||||
./blueberry.nix
|
||||
./blueman.nix
|
||||
./bonsai.nix
|
||||
./brave.nix
|
||||
./brightnessctl.nix
|
||||
@@ -24,9 +28,12 @@
|
||||
./cantata.nix
|
||||
./capsh.nix
|
||||
./captree.nix
|
||||
./cargo.nix
|
||||
./cassini.nix
|
||||
./catt.nix
|
||||
./celeste64.nix
|
||||
./chatty.nix
|
||||
./confy.nix
|
||||
./conky
|
||||
./cozy.nix
|
||||
./cups.nix
|
||||
@@ -52,6 +59,7 @@
|
||||
./evince.nix
|
||||
./evolution-data-server.nix
|
||||
./exiftool.nix
|
||||
./expect.nix
|
||||
./fcitx5.nix
|
||||
./feedbackd.nix
|
||||
./fftest.nix
|
||||
@@ -75,12 +83,14 @@
|
||||
./gnome-clocks.nix
|
||||
./gnome-contacts.nix
|
||||
./gnome-feeds.nix
|
||||
./gnome-frog.nix
|
||||
./gnome-keyring
|
||||
./gnome-maps.nix
|
||||
./gnome-sound-recorder.nix
|
||||
./gnome-weather.nix
|
||||
./go2tv.nix
|
||||
./gocryptfs.nix
|
||||
./gpodder.nix
|
||||
./gpodder
|
||||
./gpsd.nix
|
||||
./gps-share.nix
|
||||
./grimshot.nix
|
||||
@@ -93,15 +103,18 @@
|
||||
./haredoc.nix
|
||||
./helix.nix
|
||||
./htop
|
||||
./htpasswd.nix
|
||||
./iio-sensor-proxy.nix
|
||||
./imagemagick.nix
|
||||
./inkscape.nix
|
||||
./itgmania.nix
|
||||
./jellyfin-media-player.nix
|
||||
./kdenlive.nix
|
||||
./keymapp.nix
|
||||
./komikku.nix
|
||||
./koreader
|
||||
./krita.nix
|
||||
./lddtree.nix
|
||||
./less.nix
|
||||
./lftp.nix
|
||||
./lgtrombetta-compass.nix
|
||||
@@ -114,6 +127,7 @@
|
||||
./megapixels.nix
|
||||
./megapixels-next.nix
|
||||
./mepo.nix
|
||||
./mercurial
|
||||
./mimeo
|
||||
./mimetype.nix
|
||||
./mmcli.nix
|
||||
@@ -124,6 +138,7 @@
|
||||
./nautilus.nix
|
||||
./neovim
|
||||
./networkmanager_dmenu
|
||||
./newelle.nix
|
||||
./newsflash.nix
|
||||
./nheko.nix
|
||||
./nicotine-plus.nix
|
||||
@@ -132,6 +147,7 @@
|
||||
./nmcli.nix
|
||||
./notejot.nix
|
||||
./ntfy-sh.nix
|
||||
./nvimpager.nix
|
||||
./nwg-panel
|
||||
./objdump.nix
|
||||
./obsidian.nix
|
||||
@@ -149,6 +165,7 @@
|
||||
./playerctl.nix
|
||||
./qmk-udev-rules.nix
|
||||
./radicale.nix
|
||||
./readline.nix
|
||||
./rhythmbox.nix
|
||||
./ripgrep.nix
|
||||
./rofi
|
||||
@@ -168,17 +185,22 @@
|
||||
./sblast
|
||||
./schlock.nix
|
||||
./seatd.nix
|
||||
./see-cat.nix
|
||||
./sfeed.nix
|
||||
./shadow.nix
|
||||
./signal-desktop.nix
|
||||
./slack.nix
|
||||
./sm64coopdx.nix
|
||||
./sm64ex-coop.nix
|
||||
./smartmontools.nix
|
||||
./socat.nix
|
||||
./sops.nix
|
||||
./soundconverter.nix
|
||||
./splatmoji.nix
|
||||
./spot.nix
|
||||
./spotify.nix
|
||||
./steam.nix
|
||||
./ssh.nix
|
||||
./stepmania.nix
|
||||
./strings.nix
|
||||
./sublime-music.nix
|
||||
@@ -191,9 +213,11 @@
|
||||
./switchboard.nix
|
||||
./syshud.nix
|
||||
./tangram.nix
|
||||
./tcpdump.nix
|
||||
./tor-browser.nix
|
||||
./tuba.nix
|
||||
./unl0kr
|
||||
./uptime.nix
|
||||
./v4l-utils.nix
|
||||
./via.nix
|
||||
./video-trimmer.nix
|
||||
@@ -222,6 +246,8 @@
|
||||
./zathura.nix
|
||||
./zeal.nix
|
||||
./zecwallet-lite.nix
|
||||
./zelda64recomp.nix
|
||||
./zoom-us.nix
|
||||
./zulip.nix
|
||||
./zsa-udev-rules.nix
|
||||
./zfs-tools.nix
|
||||
|
@@ -1,20 +1,13 @@
|
||||
{ pkgs, ... }:
|
||||
{ ... }:
|
||||
{
|
||||
sane.programs.dialect = {
|
||||
packageUnwrapped = pkgs.dialect.overrideAttrs (upstream: {
|
||||
# TODO: send upstream
|
||||
# TODO: figure out how to get audio working
|
||||
# TODO: move to runtimeDependencies?
|
||||
buildInputs = upstream.buildInputs ++ [
|
||||
pkgs.glib-networking # for TLS
|
||||
];
|
||||
});
|
||||
|
||||
buildCost = 1;
|
||||
|
||||
sandbox.wrapperType = "inplace"; # share/search_providers/ calls back into the binary, weird wrap semantics
|
||||
sandbox.whitelistWayland = true;
|
||||
sandbox.net = "clearnet";
|
||||
# gsettingsPersist = [ "app/drey/Dialect" ];
|
||||
|
||||
sandbox.mesaCacheDir = ".cache/dialect/mesa"; # TODO: is this the correct app-dir?
|
||||
};
|
||||
}
|
||||
|
@@ -50,22 +50,31 @@ in
|
||||
};
|
||||
};
|
||||
|
||||
packageUnwrapped = pkgs.dino.override {
|
||||
# XXX(2024/04/24): build without echo cancelation (i.e. force WITH_VOICE_PROCESSOR to be undefined).
|
||||
# this means that if the other end of the call is on speaker phone, i'm liable to hear my own voice
|
||||
# leave their speaker, enter their mic, and then return to me.
|
||||
# the benefit is a >50% reduction in CPU use. insignificant on any modern PC; make-or-break on a low-power Pinephone.
|
||||
webrtc-audio-processing = null;
|
||||
};
|
||||
# packageUnwrapped = pkgs.dino.override {
|
||||
# # XXX(2024/04/24): build without echo cancelation (i.e. force WITH_VOICE_PROCESSOR to be undefined).
|
||||
# # this means that if the other end of the call is on speaker phone, i'm liable to hear my own voice
|
||||
# # leave their speaker, enter their mic, and then return to me.
|
||||
# # the benefit is a >50% reduction in CPU use. insignificant on any modern PC; make-or-break on a low-power Pinephone.
|
||||
# # XXX(2025/05/16): this appears to no longer be optional
|
||||
# # webrtc-audio-processing_1 = null;
|
||||
# };
|
||||
|
||||
suggestedPrograms = [
|
||||
"gnome-keyring"
|
||||
];
|
||||
# suggestedPrograms = [
|
||||
# "gnome-keyring"
|
||||
# ];
|
||||
|
||||
sandbox.net = "clearnet";
|
||||
sandbox.whitelistAudio = true;
|
||||
sandbox.whitelistDbus = [ "user" ]; # notifications
|
||||
# sandbox.whitelistDbus.user.call."org.freedesktop.secrets" = "*"; #< apparently not needed?
|
||||
sandbox.whitelistDbus.user.own = [ "im.dino.Dino" ];
|
||||
sandbox.whitelistDri = true; #< not strictly necessary, but we need all the perf we can get on moby
|
||||
sandbox.whitelistSendNotifications = true;
|
||||
sandbox.whitelistPortal = [
|
||||
# "FileChooser"
|
||||
# "NetworkMonitor" #< stderr message if omitted, but non-fatal
|
||||
"OpenURI"
|
||||
"ProxyResolver" #< REQUIRED, else all peers will appear offline & messages can't be sent/received
|
||||
];
|
||||
sandbox.whitelistWayland = true;
|
||||
sandbox.extraHomePaths = [
|
||||
"Music"
|
||||
@@ -84,6 +93,7 @@ in
|
||||
# ".cache/gstreamer-1.0" # 1.3 MB #< TODO: place the gst cache in ~/.cache/dino/gstreamer-1.0
|
||||
# ];
|
||||
persist.byStore.private = [ ".local/share/dino" ];
|
||||
sandbox.mesaCacheDir = ".cache/dino/mesa";
|
||||
|
||||
services.dino = {
|
||||
description = "dino XMPP client";
|
||||
|
@@ -6,11 +6,16 @@
|
||||
installPhase = lib.replaceStrings [ "NIXOS_OZONE_WL" ] [ "WAYLAND_DISPLAY" ] base.installPhase;
|
||||
});
|
||||
|
||||
sandbox.mesaCacheDir = ".cache/discord/mesa";
|
||||
# creds, but also 200 MB of node modules, etc
|
||||
persist.byStore.private = [ ".config/discord" ];
|
||||
sandbox.wrapperType = "inplace"; #< package contains broken symlinks that my wrapper can't handle
|
||||
sandbox.whitelistAudio = true;
|
||||
sandbox.whitelistDbus = [ "user" ]; # needed for xdg-open
|
||||
# sandbox.whitelistDbus.user.own = [ ":*" ]; #< does not own any well-known name
|
||||
sandbox.whitelistPortal = [
|
||||
# "FileChooser" #< does not use file chooser
|
||||
"OpenURI"
|
||||
];
|
||||
sandbox.whitelistDri = true; #< required for even basic graphics (e.g. rendering a window)
|
||||
sandbox.whitelistWayland = true;
|
||||
sandbox.net = "clearnet";
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user