Compare commits
1517 Commits
wip-vulkan
...
wip/less-d
| Author | SHA1 | Date | |
|---|---|---|---|
| 2f2c666b0b | |||
| 8760621440 | |||
| 0596b02f22 | |||
| a5841192a2 | |||
| f085c1d691 | |||
| 396d094520 | |||
| 12f3fc333d | |||
| 4d96a1ed45 | |||
| 9aedb133bb | |||
| 5a15b76b61 | |||
| 5c17de6e83 | |||
| 8db4498ae8 | |||
| 001a5fc252 | |||
| 6f64e5d469 | |||
| b1e9d8db80 | |||
| 5b39baf2db | |||
| 4e8ca1a30d | |||
| 1db3a29dac | |||
| 61ba1802ee | |||
| 059c4e9964 | |||
| a09736e60b | |||
| bdfdcfd164 | |||
| 7579d4b2c5 | |||
| e90a8b7b6e | |||
| 50cec94164 | |||
| 5bb31aa5da | |||
| 2aef1c30bd | |||
| 471ef03289 | |||
| bdcdba6a6d | |||
| bf64948cc1 | |||
| 4331df28d2 | |||
| 2a148c1543 | |||
| adf72fc9d4 | |||
| 96a66abcd5 | |||
| 8f40bdc9c0 | |||
| 3e782a5e73 | |||
| f1b47e5de9 | |||
| 3c6c466d87 | |||
| 16bf03d8be | |||
| ca1594a354 | |||
| 2e120f613f | |||
| 2c6f667a7e | |||
| 8e7586b902 | |||
| 7a0eed4ec3 | |||
| ca1015d579 | |||
| f89837f3aa | |||
| 2a1d6e1faa | |||
| 7918403d1b | |||
| 3fb76e720f | |||
| a899cf6c9f | |||
| 40b26fc57e | |||
| 1be7119b73 | |||
| 4b41aa3718 | |||
| 71d6fe44a1 | |||
| c5c1378f59 | |||
| 8fc57c4249 | |||
| 39eb1e3d07 | |||
| e386406bc1 | |||
| 0cf4c3ff80 | |||
| 06e699a72b | |||
| 0c32f807e6 | |||
| f6d3c102fa | |||
| 3e1a2243c7 | |||
| 4fe6f2aab3 | |||
| dc1cd7a9a5 | |||
| ead9fd87d7 | |||
| 4ac5c5f469 | |||
| f3151320a3 | |||
| 403b177a80 | |||
| f714235717 | |||
| 3ec01ba971 | |||
| a51f8d45b3 | |||
| cd375a9a05 | |||
| 0486c7f787 | |||
| 190571e565 | |||
| 94c31c4e8e | |||
| e13af1c1c8 | |||
| 77587389c4 | |||
| 70d2d97525 | |||
| 65ed2afb23 | |||
| b2419da057 | |||
| 243d38333d | |||
| 7ad75cacb9 | |||
| 6e9cd15517 | |||
| 9d052a62b4 | |||
| 862667648c | |||
| 2591314fdb | |||
| dcd622bc1d | |||
| e5cdcc4500 | |||
| cb4ca7d26a | |||
| 9f5d1c0111 | |||
| 6fe29529b2 | |||
| eae8ef11c8 | |||
| edf21e6837 | |||
| 0ecc08b49d | |||
| 6eb8191514 | |||
| 3c6da51f84 | |||
| 6c10c14a32 | |||
| 8ae4be341a | |||
| c94ed9d519 | |||
| 99373dcd83 | |||
| 98739bb061 | |||
| 46dabcd33f | |||
| 68d72eab16 | |||
| f933581b0c | |||
| 1a639b320d | |||
| c9ac005548 | |||
| 9a73293bd4 | |||
| 99e2ac1dbb | |||
| a56b31cdac | |||
| df9716e244 | |||
| 45f3d5a117 | |||
| 97a1b5732b | |||
| 59e4c84800 | |||
| 16e84cae9d | |||
| d725dfb7f1 | |||
| 79b6c119ee | |||
| be1d8c5d97 | |||
| 454e02c8ec | |||
| 3b37286e65 | |||
| 77388f35f6 | |||
| a6c91db11b | |||
| a96d0e9630 | |||
| 43f39674d6 | |||
| d7fd7d7368 | |||
| 386c712a23 | |||
| 9d09a323be | |||
| 9beb6b52e5 | |||
| f96f2ec960 | |||
| fd080393f8 | |||
| 408cfc08a1 | |||
| d34a03e060 | |||
| 8230389b21 | |||
| 6a735cc0bc | |||
| fbc79d2527 | |||
| 76963d6aaf | |||
| 7f74951fb3 | |||
| d698c7ca70 | |||
| 8e865999f8 | |||
| f7b5423338 | |||
| 1ec3e1fb1c | |||
| 8346d21d42 | |||
| 3ed8e0cb44 | |||
| 583fcbce6e | |||
| 4a7513ba23 | |||
| b51b01ff02 | |||
| f9ceb7d8fd | |||
| 1a1bef5948 | |||
| 0625eb1bf8 | |||
| b722a4bcc8 | |||
| c744b976d0 | |||
| 8352d3aa8f | |||
| dfebedbd6c | |||
| 3caa072d00 | |||
| 4ee31d075a | |||
| d973cb939c | |||
| 78ab7b0b80 | |||
| 2fcb0ebfd0 | |||
| 7445adbea0 | |||
| 706cf3bac2 | |||
| 4b722a6c30 | |||
| 8350386ea8 | |||
| 0ee0b3c3bb | |||
| 8ce1fae67b | |||
| f27202056e | |||
| 7f38cd7535 | |||
| b56507d4c2 | |||
| aab2a9cd26 | |||
| b7c2dfea19 | |||
| f1709c0355 | |||
| 7a67f3ed0f | |||
| 91054159d3 | |||
| 0eedcd0114 | |||
| 9305566330 | |||
| 0abbd006fc | |||
| 9d31a462a8 | |||
| 1c8659d145 | |||
| 503f097272 | |||
| a55e8847ec | |||
| 2937cbc67a | |||
| c92e67bda1 | |||
| 652e4ca93b | |||
| 07d3f60f26 | |||
| cb20b4a56b | |||
| 0da3edfa52 | |||
| 9477160a2d | |||
| b77bde5417 | |||
| d2a3bec605 | |||
| b519de1d6f | |||
| 1c867c5160 | |||
| f8ab8b290e | |||
| c8a8fe73ca | |||
| 03d7cf65a4 | |||
| 8ddfa91125 | |||
| 415a2e1a67 | |||
| f4a1ede7d4 | |||
| 478002766e | |||
| 290a15e517 | |||
| e923636181 | |||
| 017aa335b1 | |||
| 58b219546b | |||
| 499078e0f8 | |||
| 82d3e9686d | |||
| 02df87fc51 | |||
| 33ff993981 | |||
| 976f48268d | |||
| ec26f11db4 | |||
| 15755a8a71 | |||
| 02067db774 | |||
| e69734250e | |||
| f78a02700f | |||
| d776c4618a | |||
| 50812e5678 | |||
| 86293377d7 | |||
| 14922a40b2 | |||
| e6a6d35adf | |||
| 5777e1a6e4 | |||
| 635a4b958b | |||
| 99c4fedbdc | |||
| e70e8e144b | |||
| aad572a058 | |||
| 4a886b9e9b | |||
| ce60270821 | |||
| 8929311732 | |||
| fdec1817c4 | |||
| 6cbeccf51f | |||
| 7491114915 | |||
| 5715795d1f | |||
| bffe39b6b5 | |||
| 8b2a7d5fb4 | |||
| 251297b62e | |||
| 0e70f516b7 | |||
| 8ecdaa0a64 | |||
| af5c0d0648 | |||
| 87ec775ddb | |||
| 71028911e3 | |||
| 5de54acd90 | |||
| d54d1b9295 | |||
| b740af17cd | |||
| 40e7d8a689 | |||
| 2f16e802d8 | |||
| b048b47d54 | |||
| bcfd8e1725 | |||
| e0a6f8ea4a | |||
| 80f3d0472b | |||
| b6685c9e6c | |||
| 0c2d8af448 | |||
| 7ce0c34f43 | |||
| f2e8be3bd1 | |||
| 9b2e7b02cc | |||
| 1b3e0b95be | |||
| f78968c73a | |||
| d5d755a4b2 | |||
| e08281c380 | |||
| afb006f6ec | |||
| a76cf03232 | |||
| 9c24f24306 | |||
| 736999eea6 | |||
| 979ed38506 | |||
| 46285852d0 | |||
| 0e756d5064 | |||
| a52ead5aec | |||
| c0377ff1a0 | |||
| 062ef20d05 | |||
| a0861edc5f | |||
| eae075acb5 | |||
| ef2ba01141 | |||
| 2756e15bab | |||
| 940aac3a22 | |||
| 5f24e029af | |||
| 98b542332b | |||
| 70b62e9f76 | |||
| 7c81df00df | |||
| f288f34d1e | |||
| 854977c3aa | |||
| 3653776399 | |||
| e4bff9b5ef | |||
| ec22c128e0 | |||
| 77cc560052 | |||
| c1f3fc502d | |||
| 4d3248d315 | |||
| 45a1c07210 | |||
| a1a711190f | |||
| ee9a2b320d | |||
| 870afec07e | |||
| 5f8154e6ce | |||
| 0bc3b78a52 | |||
| 5288be1822 | |||
| 5b1113929a | |||
| 216c812f7b | |||
| 39effa15ad | |||
| f66de76b76 | |||
| 427ee669c5 | |||
| 8e81b5827c | |||
| cb3e7623ae | |||
| a9cf619a14 | |||
| 02100ed1a2 | |||
| ae22865099 | |||
| 6c85c6ecd8 | |||
| 161bbc1159 | |||
| b94d0672cc | |||
| 768bc35940 | |||
| 9aca00c186 | |||
| 443100daa4 | |||
| ac25909a10 | |||
| ed70e045cb | |||
| e9172fe731 | |||
| fd19802e91 | |||
| d84846e293 | |||
| b46ccb9bc2 | |||
| 1958c1f36b | |||
| 67299ebfd7 | |||
| adecfbaea4 | |||
| fa4a576703 | |||
| abb0a3c94e | |||
| 32612e6acb | |||
| e0a3979b65 | |||
| 4d84ca0878 | |||
| 1ae8ab2550 | |||
| ed1380ba70 | |||
| e1b8d3ccc3 | |||
| 392ad7c674 | |||
| 4026334e51 | |||
| 2269016736 | |||
| f2c61d64b7 | |||
| 840c2feba5 | |||
| 4603f0fd8e | |||
| 64704d361b | |||
| 7df18686e0 | |||
| aee928dac0 | |||
| 76c0c3dc6a | |||
| 796988bdeb | |||
| 31d28ccf23 | |||
| a298678622 | |||
| 32eb3b1998 | |||
| 7a726b8d08 | |||
| 3edbb1c873 | |||
| d94687e8cc | |||
| 641ffc3452 | |||
| fa8016db67 | |||
| 0c9cc87728 | |||
| 5236da2383 | |||
| aa24eebf40 | |||
| 3cc0d7ec40 | |||
| 42c2d93306 | |||
| f6f8d0e19d | |||
| 8ad4d8a4f9 | |||
| d419e10f10 | |||
| c56734e00e | |||
| e095149797 | |||
| 6006b84f9e | |||
| b3b914bc2e | |||
| d6f87c7ee7 | |||
| 028d78437b | |||
| 0539bb8fd5 | |||
| 95cc42f057 | |||
| 54cfde0e30 | |||
| b358cbe02a | |||
| 64cd562824 | |||
| 749f59a4af | |||
| 77d5ff623e | |||
| 6386abb8c6 | |||
| 28f8434c53 | |||
| 30fafb4837 | |||
| c7205ed668 | |||
| c69c6612fe | |||
| 6951b277ad | |||
| 1167c9bd0c | |||
| 8537fe411b | |||
| 1fb2ddbecc | |||
| 27608cb8c7 | |||
| 33ee59e80d | |||
| edacc28e4a | |||
| 99780e30bc | |||
| 140dd05bd1 | |||
| c35bc92ac9 | |||
| 16b92f98e7 | |||
| 576b63da9c | |||
| e434add20d | |||
| d288086aa2 | |||
| e9c0f692d8 | |||
| 5a75d0f56b | |||
| a222cf18a3 | |||
| 45b9ee763b | |||
| 50a2196495 | |||
| e4419ffad4 | |||
| ae3ba64fc3 | |||
| 948b2489d3 | |||
| abe491b563 | |||
| 9911593a63 | |||
| 798ba7f7e3 | |||
| f72e901f57 | |||
| 2047222233 | |||
| 5d33cb66d6 | |||
| 6fded1f256 | |||
| 1d1c528abc | |||
| 35fdd2788f | |||
| 77cb951545 | |||
| 1909e0fbe8 | |||
| 33d7819619 | |||
| 0846abb6bf | |||
| f3568462c2 | |||
| ed9291a443 | |||
| 9eac7f7c02 | |||
| f5eaa635a5 | |||
| 47db6f0dd4 | |||
| bba7efc535 | |||
| 358b673344 | |||
| d9c101689d | |||
| ccbb573681 | |||
| f5c270233f | |||
| bf92bb48be | |||
| 2037b425d6 | |||
| 026746a76f | |||
| de74c4e7d5 | |||
| 34a5f3f49b | |||
| ee93141c07 | |||
| f2d22231a3 | |||
| d5334e65ad | |||
| 17cdfff286 | |||
| 8d4ff6d4e6 | |||
| 5d78bc6704 | |||
| 4da19a6d34 | |||
| 2f75925678 | |||
| 55a1856e87 | |||
| 2ee0f4efe2 | |||
| b0c5a5907f | |||
| 9af157b294 | |||
| c36fed8547 | |||
| a653311f04 | |||
| f4d6ecb1cf | |||
| c2e5a0a2fc | |||
| c316e51344 | |||
| f4f0c1bdd6 | |||
| 6a2374e046 | |||
| 708cb841fe | |||
| 094b7223c7 | |||
| f6dfc9cf29 | |||
| 7c2ab92302 | |||
| 7c18d77046 | |||
| 02f316f7f8 | |||
| df848b3262 | |||
| 1e67b5c97e | |||
| a3a7b6c563 | |||
| e527beb9d0 | |||
| 2e942e2dd4 | |||
| f46e3fdf01 | |||
| 038a9034d7 | |||
| 5a232eb832 | |||
| 9301b95dbb | |||
| d13bcc49ab | |||
| 35e28041cd | |||
| 58a5a8b56d | |||
| e6d4ff3c6a | |||
| be29ad8bd8 | |||
| 0fb8e2c867 | |||
| 580c1b74cb | |||
| f8595f1ed6 | |||
| 1deda148bb | |||
| 5bbef18130 | |||
| 6967c331e2 | |||
| 9202345beb | |||
| 17a8cabc09 | |||
| bc190f90bd | |||
| bb983a5328 | |||
| 0e8fc29b01 | |||
| 4e14f063fc | |||
| 10d69fb0a4 | |||
| 7aac965e32 | |||
| 98ae1a8513 | |||
| 72a2ab78f3 | |||
| 18c98feb34 | |||
| 487af9b492 | |||
| 472d25c056 | |||
| 9eafacad12 | |||
| 0eb46a3179 | |||
| ddb184b5ff | |||
| 194a6b6cf4 | |||
| 016384aa2b | |||
| b4e19c037e | |||
| bd504f6c83 | |||
| bdd309eb15 | |||
| eedc1170ec | |||
| 5a586c6e3c | |||
| 371bcad650 | |||
| 926decbea5 | |||
| c0f76ea8d8 | |||
| 40fc37930f | |||
| 30e7eb9ab6 | |||
| 2e03f47edc | |||
| 4d552e3f0f | |||
| 176a98879d | |||
| fc70889c34 | |||
| 49b4c57826 | |||
| 5111d095ac | |||
| fe15cdd705 | |||
| 638420ea0d | |||
| d55dd5ace6 | |||
| 45695aed6b | |||
| d6e79c4d07 | |||
| 380ceaf625 | |||
| 942c581107 | |||
| b6d94c2e08 | |||
| fd7acc8fc8 | |||
| db670fc172 | |||
| 6438971c8c | |||
| e439d398b6 | |||
| 0f25cba331 | |||
| 39959e912d | |||
| 62e649743d | |||
| b1741a18e1 | |||
| a829a8e027 | |||
| d742ae83bd | |||
| 110ab1a794 | |||
| 7d5a81e542 | |||
| 1af2a3f329 | |||
| 3fa9e910a9 | |||
| 6befc40700 | |||
| 29db2d8dc5 | |||
| 36d8052982 | |||
| 48115231a3 | |||
| 8b56ddd1ca | |||
| c1457f5bfb | |||
| 7dfaf77a71 | |||
| 72dc7029e6 | |||
| 95f3215b00 | |||
| baac8df8c2 | |||
| dc6a08a12b | |||
| 2413e2eb5f | |||
| 7327128493 | |||
| ed8059f4c4 | |||
| 3a72295610 | |||
| e6d9edf27d | |||
| 78782d5f7e | |||
| 91275f3723 | |||
| 8115edea8d | |||
| 4c475bbf9c | |||
| 7040e1f07c | |||
| aafa64942c | |||
| a44a99e371 | |||
| a7ff90c843 | |||
| d4996d6f31 | |||
| bd5209c655 | |||
| 9588108fd5 | |||
| 942e302afb | |||
| 2bd98e6764 | |||
| 7b9910f287 | |||
| 917afe209e | |||
| cc5cf9b6f4 | |||
| 57d95dd298 | |||
| 0b78df53be | |||
| c8dcb4ac59 | |||
| 241f4ae58f | |||
| 965d7eedbb | |||
| cdc881e887 | |||
| 33967554a5 | |||
| 5af55ecdbf | |||
| 6ca3e7086e | |||
| ca62f1b62f | |||
| eef66df36d | |||
| 9ca6a1c907 | |||
| dbb78088f4 | |||
| f17ae1ca7b | |||
| b2774a4004 | |||
| 0ae548d47c | |||
| 760505db20 | |||
| 71fc1a2fd7 | |||
| a457fc1416 | |||
| 2c0b0f6947 | |||
| f10de6c2c4 | |||
| a6be200a82 | |||
| fb57e9aa5b | |||
| f5acbbd830 | |||
| af77417531 | |||
| eea80b575d | |||
| 6a209d27fd | |||
| e8f778fecd | |||
| 488036beb3 | |||
| 00b681eca5 | |||
| 72d589cb2d | |||
| ea5552daa7 | |||
| fb7d94209c | |||
| 8f5b92685b | |||
| 32a4cb19fd | |||
| 031cfa2bcd | |||
| e93fbea1e6 | |||
| 85a2fbc38a | |||
| 9e902c8eb2 | |||
| dc15091ea7 | |||
| c063ecd047 | |||
| 70a43c770d | |||
| cc9e2d8e15 | |||
| bb41fb95fe | |||
| d852adf806 | |||
| 5443542cba | |||
| 81effb01a3 | |||
| 83f416999f | |||
| dd34883246 | |||
| e47f9e38ce | |||
| 0f0b728911 | |||
| 1839f87a4e | |||
| 53edf4e6af | |||
| fb6e0ddb34 | |||
| 0a48d79174 | |||
| b6208e1a19 | |||
| e46ab4ec14 | |||
| 19c254c266 | |||
| 1d0cadce85 | |||
| e8342b8044 | |||
| 40e642bfc3 | |||
| f008565e22 | |||
| 4ea2835d9d | |||
| 493d317bb1 | |||
| e446bfba58 | |||
| a7bac5de18 | |||
| b0950e90f4 | |||
| d8cd0e1f57 | |||
| fd7d67ee05 | |||
| 1a712b4d47 | |||
| 4520e1d1f5 | |||
| 841a2a3bcb | |||
| fe816e9110 | |||
| 426e0c3ae2 | |||
| a95b91a556 | |||
| 837e5438c3 | |||
| 8217b22c86 | |||
| 0b35ce4dec | |||
| 413f9a171b | |||
| 43a46af43b | |||
| 1a0f05bfd6 | |||
| c18dd9636d | |||
| 0977721af5 | |||
| 122d3cd7e4 | |||
| cd5f8054c0 | |||
| 3db388b105 | |||
| 2ba6116f10 | |||
| 592d17b725 | |||
| 4d9c15f9b8 | |||
| abced7dd0d | |||
| 5c42365912 | |||
| 247ad326b2 | |||
| 170008f345 | |||
| 2c48e61854 | |||
| f89f756489 | |||
| c0da19951b | |||
| 5fb67306e4 | |||
| 5533b586d7 | |||
| 68c2eb7363 | |||
| fd79026366 | |||
| a76471cb1f | |||
| c94b8299a6 | |||
| 175bc0709f | |||
| 7b02477486 | |||
| d7c8638fea | |||
| 9d7d1acc80 | |||
| 787857d27f | |||
| 9c248a8a31 | |||
| 829680fb00 | |||
| a9ee26388c | |||
| 2960b895b6 | |||
| 933063115b | |||
| afe684ca2c | |||
| 93f1411522 | |||
| 01e44c1f7f | |||
| 618e9bd2fa | |||
| fbc39d0584 | |||
| 2d7b3750cd | |||
| e6ccd2e4f7 | |||
| d4bf491e9c | |||
| 5a2bbcce3b | |||
| 327e6b536f | |||
| bace7403e7 | |||
| 57f5521ef3 | |||
| 9e32211c12 | |||
| edf6bd4455 | |||
| a9a14786f9 | |||
| eade5fe16e | |||
| be222c1d70 | |||
| 88a33dd5de | |||
| 875e923197 | |||
| 54dd643cf0 | |||
| 3c726f148b | |||
| e225e2e704 | |||
| cf0bf8190e | |||
| b8f7f68d4c | |||
| 7a3aae8c97 | |||
| 89e519810d | |||
| 0e920230ba | |||
| 6ffae00e17 | |||
| be19985440 | |||
| f7e3e7294a | |||
| d745e3c1ee | |||
| c1890ce82b | |||
| 53a0b621d8 | |||
| aeb2f63d65 | |||
| 528ffdb58e | |||
| b6887b305e | |||
| 08dfc80c98 | |||
| 5a273213f6 | |||
| 0a6d88dfc1 | |||
| 50dfd482cf | |||
| 9743aee79d | |||
| 0819899102 | |||
| d3ff68217e | |||
| 1a96859994 | |||
| af92a2250e | |||
| d00f9b15d7 | |||
| aa1c1f40cb | |||
| 530b2d6385 | |||
| e6919dd16f | |||
| 760f2ac66d | |||
| 8e5ca11259 | |||
| 121936620a | |||
| f5b49e014c | |||
| 4bdb34775d | |||
| f5fbc206f5 | |||
| a9096f3312 | |||
| 67cddecab4 | |||
| 9a002c99eb | |||
| a0ac7fa98d | |||
| b03043e513 | |||
| 0713e3bad1 | |||
| d3a3f39756 | |||
| a7d9e5cc54 | |||
| 13f3b322b0 | |||
| 5c25330891 | |||
| dc6dc2e475 | |||
| c4352fa9bb | |||
| 2c6629a658 | |||
| c0496b25b5 | |||
| 9e0346c329 | |||
| 364a598324 | |||
| c6850aff23 | |||
| 730ef272d1 | |||
| 16fa1e0eda | |||
| 51a96525d9 | |||
| 7b01822ee7 | |||
| f9aa36a620 | |||
| 9b75d8705b | |||
| 217ecec250 | |||
| 6c7ca7630a | |||
| 1f99d44288 | |||
| f1aa685a03 | |||
| 2b31fc8776 | |||
| 0c35e2b3c1 | |||
| 77b8d0ddc0 | |||
| 84f23c602e | |||
| ea5fbc63cf | |||
| 69361ee9a2 | |||
| 1808d153b2 | |||
| b3ad0f8f1f | |||
| c745612cfd | |||
| 278cc98c6d | |||
| fac661af15 | |||
| 65777c70ad | |||
| 09c524a5b1 | |||
| 0db7f0857a | |||
| 38befe502c | |||
| 55e09c2dbf | |||
| bd699c887c | |||
| 2de6f7d364 | |||
| d60e5264f3 | |||
| c66699b697 | |||
| 97044bf70e | |||
| 3122334a41 | |||
| 0b2faef989 | |||
| 8acd6ca4f1 | |||
| 8169f7c6b2 | |||
| cd1aa0b376 | |||
| 72b627100c | |||
| 567c08460a | |||
| 9b66aecf1b | |||
| 16cb3b83a2 | |||
| 970438be8a | |||
| 51da29555e | |||
| 8a745a9b8a | |||
| 3505f3b9f3 | |||
| 444595e847 | |||
| 3e1407c30b | |||
| 0a744117a4 | |||
| a2935cedaa | |||
| 22e46d52c2 | |||
| 1e0c213adf | |||
| 3e1340ed61 | |||
| 341dd3f2b2 | |||
| 1c9caa40bd | |||
| 3be15c6d05 | |||
| 8e8168ec28 | |||
| 28397807fc | |||
| 42ebb9a155 | |||
| a8a4b8e739 | |||
| 2550601179 | |||
| 199a49755a | |||
| 8c7700688f | |||
| 8fe304d6c1 | |||
| 700fef7df3 | |||
| 01db7e1f23 | |||
| df6e8f1562 | |||
| 1f0a40c81f | |||
| 995b41d1e8 | |||
| 7674735d42 | |||
| 329693c9ce | |||
| 5ae3bb2f6c | |||
| e0b1aef127 | |||
| 9b8363dfb4 | |||
| 58ad87df8e | |||
| 5fc894cda9 | |||
| 07e6ec2533 | |||
| 005a79e680 | |||
| 0f5279bbca | |||
| e9b3b7ebab | |||
| 7a83c1d6df | |||
| 46788fe565 | |||
| a473ef6db3 | |||
| 3627d47f12 | |||
| 115f8d7054 | |||
| ac44b04d99 | |||
| afff0aff19 | |||
| f0086dc5bd | |||
| acabd34f28 | |||
| d0e6b82739 | |||
| dc09b7b9b2 | |||
| 38c5b82a08 | |||
| 89def1a073 | |||
| ad2ed370d9 | |||
| 3e8f7a9ba2 | |||
| 028ecfe93f | |||
| c5ac792c13 | |||
| bd1624bef9 | |||
| 3ae53d7f32 | |||
| e7f2d41b1f | |||
| 3394a79e2b | |||
| b01501663d | |||
| cbd5ccd1c8 | |||
| cf857eaf9f | |||
| 3a7eb294c7 | |||
| 2ccb470adc | |||
| 0a2a929507 | |||
| 2014d5ce77 | |||
| 041adb7092 | |||
| a979521a98 | |||
| 77881be955 | |||
| 0450b4d9a6 | |||
| edea64a41c | |||
| 90e479592f | |||
| 62d83d94f2 | |||
| 52bbe4e9f4 | |||
| ab176b8d4b | |||
| 62df4492a3 | |||
| f4ed194abc | |||
| 6420c9fd16 | |||
| 86245b460b | |||
| bf1ba786b3 | |||
| 35a896a3e2 | |||
| b4314bd919 | |||
| 4696209822 | |||
| c3957d81c2 | |||
| 8a5be00c93 | |||
| c2db9fe28e | |||
| ccaac901f7 | |||
| 7f285a8254 | |||
| b0b82a3d88 | |||
| b0664d81ab | |||
| 8ba52bb9cd | |||
| 20f0a19e25 | |||
| 9dc17a3874 | |||
| 2992644901 | |||
| d5d89a10b9 | |||
| f7d9fdfe04 | |||
| c42aa2847b | |||
| 768c5c910f | |||
| 8790a7d9fd | |||
| 7c36a0d522 | |||
| 977a80d59e | |||
| 63c92a44ed | |||
| bf838ea203 | |||
| e8a7a1dc75 | |||
| 992efc1093 | |||
| d320fa39f3 | |||
| e40156ed9a | |||
| 656837c810 | |||
| 0533ea1cc2 | |||
| a1911f3001 | |||
| 24967c53a7 | |||
| 8b9c18aee1 | |||
| 8d3acb104a | |||
| 69eacf6c4d | |||
| d7ad414a9c | |||
| 533b0a91bd | |||
| 56d87da650 | |||
| 3f33b2cb76 | |||
| f8a1df790f | |||
| e94186e9c9 | |||
| 82d11a7ae1 | |||
| 0253774622 | |||
| 2f45c57310 | |||
| 5d1e8f5f60 | |||
| ff9c26b03d | |||
| b9533d7ee3 | |||
| 103f7b1b2c | |||
| 16327fd323 | |||
| abcfa2dbea | |||
| 27403fa36d | |||
| 96b3ac26dd | |||
| 1accf264cf | |||
| 3772a428da | |||
| a56f2008d3 | |||
| 04ea55499a | |||
| 59244fa50c | |||
| c2a2b27002 | |||
| 7bd6015a9f | |||
| 2a010f7882 | |||
| b566910da0 | |||
| ca43811c16 | |||
| 7284452aa5 | |||
| f772300d88 | |||
| eccb5ff3d6 | |||
| 0c6b949a72 | |||
| 9a6c83776d | |||
| e408e77026 | |||
| e0612ccfa8 | |||
| a0e85ff31b | |||
| 1d448a4114 | |||
| ed52b5f251 | |||
| dc21b0d68c | |||
| 18ec4f9b4d | |||
| 84a17f4599 | |||
| 43fa7fdd9f | |||
| 8fc6b05c07 | |||
| 439c7d9ef2 | |||
| 9633c4f012 | |||
| b869617b09 | |||
| ce323ffcf9 | |||
| ac153aecd3 | |||
| 353d97b661 | |||
| 1150ee4b50 | |||
| 9e51eafff0 | |||
| afaa6343ab | |||
| 67dff6069c | |||
| dea7ca9474 | |||
| ad7ae94501 | |||
| 1a0bd16b44 | |||
| 56f89bb3f7 | |||
| 92a67253c3 | |||
| 8d0ded0ea1 | |||
| de820e32b7 | |||
| be286cd190 | |||
| 7cacbd9580 | |||
| c84f10e060 | |||
| fd8f660ee0 | |||
| 205b6a9afb | |||
| 6b7a544df3 | |||
| c3eacf7126 | |||
| 3b6f638f98 | |||
| 6057a2e665 | |||
| f45b032e48 | |||
| 1c810dc1b8 | |||
| fdd9833b01 | |||
| 25854d3135 | |||
| 45f8cc3894 | |||
| fc4138327a | |||
| 889c47e884 | |||
| f6f500c592 | |||
| 6fa9fb740a | |||
| 10a665d11c | |||
| 77baf03496 | |||
| 26f920e119 | |||
| 88fba6f496 | |||
| 9f43444f0c | |||
| b68fd881e4 | |||
| 5cca6ede0d | |||
| 3b4e394ce8 | |||
| d9b3fccdfa | |||
| 94366d4bf6 | |||
| 12b5e68b25 | |||
| a0d332766a | |||
| cdd9672654 | |||
| 887a431956 | |||
| 502ebafb0a | |||
| 57ada6af4f | |||
| d1d64b7376 | |||
| f2188be9f2 | |||
| 6d52c0e8ab | |||
| 14b334ff55 | |||
| 730fa8ba4b | |||
| 8817f661ac | |||
| 3b0f505864 | |||
| b559d334c3 | |||
| f6e4c0058c | |||
| 775fc979fc | |||
| ad6daa4e5b | |||
| 3ecfea158a | |||
| 5ff47b3719 | |||
| 03ea7e7fa5 | |||
| ca93518dda | |||
| 7f7041351b | |||
| 1c62bcd50c | |||
| bad4fe0e76 | |||
| 8b473ff88f | |||
| ad54b9c5fb | |||
| b805a101ba | |||
| 69a3aaa086 | |||
| 9acf2dfde1 | |||
| 4b5accac88 | |||
| cb00ae4f92 | |||
| 7c38c1dbe9 | |||
| b3b45ec0f2 | |||
| 34d77542e7 | |||
| 6236c14def | |||
| 0c0f8c44bd | |||
| 7f97786a88 | |||
| db2e156f15 | |||
| 43efec495e | |||
| 279f9ce614 | |||
| 7d02652e08 | |||
| 10e224be0d | |||
| e25c92794f | |||
| a8d2b7196d | |||
| a6cbecbc74 | |||
| 518d2f60c0 | |||
| 70e5ccc968 | |||
| c44cad9c16 | |||
| e3bf585382 | |||
| 1fea9618ba | |||
| 8d89f828b6 | |||
| e2985ef018 | |||
| d54b595e45 | |||
| ad75ed352c | |||
| 306836042c | |||
| 965181c8b0 | |||
| b344c38bfb | |||
| 174bc539bc | |||
| 9ef457c0dd | |||
| 939278b970 | |||
| 3d0bd0fbf4 | |||
| 36d8a711ac | |||
| 4c4b73f693 | |||
| 9151f58b37 | |||
| b2c55ed98a | |||
| 1721546410 | |||
| c833c68d83 | |||
| 9a4c2613c1 | |||
| 8de5b0a79d | |||
| ced64e63ef | |||
| 8dd267db30 | |||
| 10541698a7 | |||
| b658b93c64 | |||
| f68bc342e8 | |||
| e3221bf8b9 | |||
| 3cfe236e90 | |||
| 2b14648587 | |||
| 0753aa59e9 | |||
| 55cbce17c2 | |||
| ebf3152ced | |||
| 8345375bc4 | |||
| cc63cacf28 | |||
| 8f61ba6085 | |||
| b43103a024 | |||
| 187a52527b | |||
| b26e826b3b | |||
| 3851136398 | |||
| 635fee1bda | |||
| 5048ee1ce5 | |||
| e787dc29c6 | |||
| 7cc44f9455 | |||
| 419ababe6f | |||
| e4c0a0d468 | |||
| 0e63cd4e11 | |||
| 9328e5ff32 | |||
| 87dda0ad11 | |||
| 46783cd0e2 | |||
| f7d3b8128e | |||
| 9119f0b092 | |||
| 17189b22e9 | |||
| 7db3816511 | |||
| 8c20017544 | |||
| 4c1f68f82f | |||
| 289745f41a | |||
| d9caf70c6c | |||
| cf95a6e321 | |||
| 155c095be8 | |||
| bafe7aa3c7 | |||
| c9d57f2995 | |||
| a8227bbcbc | |||
| 1623367b13 | |||
| 90b0535c56 | |||
| 760d69efc0 | |||
| f8157961c8 | |||
| 25df2ebc28 | |||
| 33110dc1d9 | |||
| 0fa602f1dd | |||
| 48ff8e9ca7 | |||
| 366e28e199 | |||
| 06dcd8883a | |||
| ed03f7f929 | |||
| f3bec7bf0a | |||
| e6adfe95fa | |||
| 70d1e14cf8 | |||
| 4752371b43 | |||
| 3e7c112548 | |||
| a2856a3601 | |||
| 53d8bdc0ea | |||
| 94a6ca82f3 | |||
| 10e9daa085 | |||
| e11f903aec | |||
| 98c2ac21fe | |||
| 52fe0c7523 | |||
| 825b3e4067 | |||
| 674f852393 | |||
| fdb77ac588 | |||
| 05cb85fd9b | |||
| 8f0a270154 | |||
| fae87d3fbc | |||
| 75ae16aaab | |||
| 8a1ea79f1f | |||
| b25f270f48 | |||
| e023f48c52 | |||
| 3d7a63e4f9 | |||
| d296475e64 | |||
| f031e489a3 | |||
| 699204c5f5 | |||
| b25528ecd7 | |||
| 130dd3f895 | |||
| fcf60bae35 | |||
| 5b5187bd03 | |||
| 43123e78cb | |||
| 9305d44fde | |||
| ac0d7cc1e5 | |||
| 711778a975 | |||
| 590c81c5db | |||
| e858afea72 | |||
| 4abac0162f | |||
| 8fa591229f | |||
| a118e17b32 | |||
| 8afe0c0be5 | |||
| aa6153aa56 | |||
| 69a7e2fae1 | |||
| eec4e288f3 | |||
| f84e451a9e | |||
| dacbfa0493 | |||
| fbd8a70102 | |||
| 17b6dc56bd | |||
| f464a80541 | |||
| f663243ad4 | |||
| 94d9348b73 | |||
| 6a44432d3f | |||
| 9047aec7e9 | |||
| b702031ddf | |||
| d5686426bf | |||
| 85e249913a | |||
| d50b8c1315 | |||
| 336301258f | |||
| 645ca3764b | |||
| 22602283c9 | |||
| 39b963e87b | |||
| 1a5f1260e2 | |||
| c18e8eddcc | |||
| 874c352987 | |||
| 0395c5b8ee | |||
| f64c44716e | |||
| b2b61d2889 | |||
| 4f05a00e4a | |||
| c71346e9b8 | |||
| f5576c3667 | |||
| b437ddacd9 | |||
| 68bda8aea7 | |||
| d840f947b3 | |||
| d4261c45e6 | |||
| 6e01c59d08 | |||
| 9052291b31 | |||
| a95884d635 | |||
| 0e9993923d | |||
| cc12b87d0e | |||
| a5393c3c84 | |||
| e1cd1be48d | |||
| 37b931418d | |||
| a3db626a00 | |||
| ca239ca3e6 | |||
| 6c38500e52 | |||
| 0c4dd28bc8 | |||
| 47f378e7fc | |||
| 0648825765 | |||
| 5f277f8653 | |||
| 5929286397 | |||
| 8847147a9d | |||
| 5682a3e5f1 | |||
| 6bc9337b3a | |||
| 5058694c5b | |||
| 94e03467ab | |||
| 2ff9cc9d6c | |||
| a38d66073d | |||
| f486fa9eda | |||
| e3faabfad7 | |||
| 7d4a7df2dd | |||
| 93177fffb3 | |||
| bc482a2621 | |||
| 381d41e3b4 | |||
| 469aa50b64 | |||
| 6dbd107a07 | |||
| ffcc1ab49a | |||
| f78b06bc88 | |||
| b88a20b0f4 | |||
| 56f484f460 | |||
| 151fdad014 | |||
| 16371a37b9 | |||
| 034f29a897 | |||
| ef2d58a5a2 | |||
| b109bc5586 | |||
| 434b299eca | |||
| 40e7a12ea3 | |||
| 77579733c6 | |||
| 861defcc6e | |||
| 7d62212c24 | |||
| 120bb23f3c | |||
| ccb442c875 | |||
| aa5fc023a9 | |||
| 487dfd3378 | |||
| 2180361eaf | |||
| d6e34c6e98 | |||
| 10c7a8d779 | |||
| 3184c6cfb6 | |||
| 26c8d2d2d4 | |||
| 13531744d3 | |||
| 4fd9650ee6 | |||
| 529e47a5fa | |||
| 83b27526cb | |||
| 570619b097 | |||
| ae8d708018 | |||
| b5cab38348 | |||
| bb7e2ee70a | |||
| ae220ab2e1 | |||
| 050c8d15de | |||
| af5834c3fc | |||
| 30ef2b651a | |||
| 8d185f1bbc | |||
| b1a4fb9ccb | |||
| 8df4415218 | |||
| 9a6e0b4451 | |||
| 90fb89390e | |||
| fbc747fc22 | |||
| ad8da9dfa6 | |||
| 32036ec45e | |||
| 90107c024e | |||
| d466c0b942 | |||
| 8a6460e1b0 | |||
| 370ae917b9 | |||
| b223a3a20e | |||
| f70a62def5 | |||
| 7863d12263 | |||
| 2703bda28c | |||
| 68982b7f2a | |||
| 5ed7888710 | |||
| eb02b8aa23 | |||
| 29d3a6f9b2 | |||
| e381b1d2dd | |||
| 592b96e436 | |||
| beda2b5238 | |||
| f40dfdee0c | |||
| 7a153903b1 | |||
| c5d2549ee4 | |||
| d8b2b73463 | |||
| 0c304e18eb | |||
| 38f55661c2 | |||
| 863f6a8c7b | |||
| b3a4a95e28 | |||
| 554bb5a84f | |||
| 12308f00f1 | |||
| 34b013f82a | |||
| 2456317004 | |||
| 2316b4a3ce | |||
| 5558da55d5 | |||
| 09e8510d0e | |||
| 4b3b71bb84 | |||
| bee4fb4ea3 | |||
| 20872d3733 | |||
| 7be0a33522 | |||
| 5f8268cecd | |||
| 00c22c1ca7 | |||
| 8e63857794 | |||
| cdbfa2d177 | |||
| e66692eecd | |||
| 18ca147b67 | |||
| 8f231cde33 | |||
| f9c8563506 | |||
| 3669a05db5 | |||
| 618b7b934e | |||
| fe2c0b47bc | |||
| 3b02fb5f48 | |||
| 355a982cf0 | |||
| 8ff7e22ac8 | |||
| cb0c122080 | |||
| d84600cfcf | |||
| dc44d8098e | |||
| 58c6c1dd7d | |||
| 933996d34e | |||
| 2a1932d602 | |||
| a6fd6a0a6d | |||
| b42b6e7ce2 | |||
| e9da458179 | |||
| ee3793ad46 | |||
| b8ab7c1fa9 | |||
| cdbde672d8 | |||
| 08bd619ef9 | |||
| c91948c565 | |||
| f3ba1d488d | |||
| 11a2dbd684 | |||
| 2fb4bae804 | |||
| 61ce0e62e9 | |||
| 315d9b8703 | |||
| c5a69a401f | |||
| b8e42a0ada | |||
| 1fa7724b35 | |||
| 10c6801ccd | |||
| 8d051d319f | |||
| c0a41def22 | |||
| f0334db736 | |||
| cd89ea884b | |||
| 13b937fbb7 | |||
| 877870a522 | |||
| 956545a795 | |||
| cb98ac2a91 | |||
| 85add7c531 | |||
| df379a2a38 | |||
| d49ac8c175 | |||
| 5a4dd3b38d | |||
| ed98b1702a | |||
| 5b5103f660 | |||
| 91d37f2532 | |||
| 66d79329d9 | |||
| c6485a5e42 | |||
| e54af3f571 | |||
| c39170be23 | |||
| a532825761 | |||
| 4faa6d5d5f | |||
| fe09b08be2 | |||
| 9e53053526 | |||
| 56036b13c3 | |||
| 9ed4a13a6f | |||
| 1446f5e8ca | |||
| 118007075f | |||
| 25c75b10bf | |||
| 56637bb649 | |||
| 62d6c4d688 | |||
| b05c256809 | |||
| a30d6fd51f | |||
| da3070479f | |||
| 287547d46c | |||
| 2f0bbef76b | |||
| 2ba1678cd8 | |||
| c162225789 | |||
| f052e2226d | |||
| 48774c8940 | |||
| 7a7e4c9df7 | |||
| de2bb05a04 | |||
| 65a4aa4135 | |||
| 0e611ba3d4 | |||
| c5b132b8c8 | |||
| 8d2c8d44f3 | |||
| 7b311eaf2d | |||
| eecf51d344 | |||
| eaef2f2325 | |||
| fc629082e6 | |||
| bbb384c70a | |||
| e2f6977244 | |||
| 05ab747650 | |||
| 913c9e5fdf | |||
| f0b772d688 | |||
| f328043966 | |||
| 6758440ce3 | |||
| 9e4bfc2fce | |||
| d3193bc051 | |||
| c0b6d46575 | |||
| 808153f939 | |||
| 78dfb03c2b | |||
| b1ae5b0f9c | |||
| 7a6bb04e86 | |||
| 3565e96dc5 | |||
| 54754de6fa | |||
| 281be29b90 | |||
| 465478271a | |||
| 7003f7407e | |||
| 890e1b17e2 | |||
| 34af63fab0 | |||
| 8e8a326dce | |||
| da3c25eff6 | |||
| 43782ae734 | |||
| 2204a54456 | |||
| e80e37ae29 | |||
| 505a5f8b47 | |||
| 216282a345 | |||
| 6f88302430 | |||
| 228f8c0a68 | |||
| a3111d250f | |||
| 9976c82946 | |||
| 42951a1382 | |||
| e5ff11d14b | |||
| 95e7d86cc7 | |||
| 21c9ce21cc | |||
| 65bcaa939e | |||
| 38cd3bdb96 | |||
| 8059477edd | |||
| 46a0e949f9 | |||
| f86c6390a5 | |||
| b60a7ed7d5 | |||
| d29e69e18a | |||
| 042bd9340b | |||
| c6fbbbab66 | |||
| b1205e964b | |||
| 7d39a761cf | |||
| 8a0da17f05 | |||
| de8f658dcd | |||
| 5c2f33a550 | |||
| 0ec48a9145 | |||
| 408e817c39 | |||
| ba6d0b7e3d | |||
| 4d7d96f4a4 | |||
| 1a9dfe22ba | |||
| 8ae0d77938 | |||
| b53d2f945d | |||
| f67ca0bd24 | |||
| d196ce29ac | |||
| f03238daac | |||
| f9ab3b7cf1 | |||
| 40bc4098ad | |||
| 451816f623 | |||
| 9dea707eea | |||
| 0875d5cb52 | |||
| 0de0749fb4 | |||
| ac772e72b8 | |||
| d44db610cb | |||
| 79b3bfc9e7 | |||
| 6608e2bf6d | |||
| 19e0bd4780 | |||
| 18bb89ded0 | |||
| 4aa3e6cf24 | |||
| ee621cd132 | |||
| 641b32b8d0 | |||
| d69db1df37 | |||
| 6d44c93b5a | |||
| 32be025ec6 | |||
| ce5bfc68f5 | |||
| b1773a9b54 | |||
| 3fe67e744f | |||
| ea61d22764 | |||
| d92994bcd2 | |||
| a5d14a643e | |||
| 4c1bc06441 | |||
| 730b4f9d9b | |||
| 59f8191830 | |||
| af4e70c4c5 | |||
| 5595da2c56 | |||
| e52e2c8faa | |||
| 7563090dd5 | |||
| bd44bd4434 | |||
| 430e594285 | |||
| 8f88085eb5 | |||
| 7375a55d4c | |||
| 878f9fbe49 | |||
| 5ec0ee4524 | |||
| 2f3eda1800 | |||
| 8c9c9ca6c9 | |||
| 42117f375b | |||
| ede10dd1c8 | |||
| a380e300bc | |||
| 3773aebac0 | |||
| 8a61be18e1 | |||
| c07c106a68 | |||
| 1a159c8340 | |||
| 6faed74958 | |||
| d4d345ca12 | |||
| a5b3677adc | |||
| 97374fdcf4 | |||
| 1062a610c9 | |||
| 8f37edb402 | |||
| 99d55167f6 | |||
| e2d7d63ebe | |||
| d0b903d50e | |||
| 9d71041530 | |||
| 31e404b04f | |||
| 01a47932f7 | |||
| 5c6f616c97 | |||
| 89447d9fe9 | |||
| 80ac5496be | |||
| ce46b3490a | |||
| 678958f5cf | |||
| 292aa042f2 | |||
| b2bd8d5f89 | |||
| 06989c613f | |||
| c6fbe3574d | |||
| f790147fb0 | |||
| dca68a019b | |||
| fffeb95153 | |||
| 461398143c | |||
| 89aabda1a6 | |||
| 54f6e86e20 | |||
| 39ba149aab | |||
| 01ce23130a | |||
| dc6472f39f | |||
| db6dc8e08c | |||
| 3b0d10f05e | |||
| 978017b4e7 | |||
| 1dd3cab02b | |||
| 8fd42f49c2 | |||
| 7ec1879f90 | |||
| c851f44a40 | |||
| bcfd2cbdb1 | |||
| c58df098d2 | |||
| dfd1536d19 | |||
| 3e774241af | |||
| a100100e79 | |||
| 24fa857ee0 | |||
| 6aa79e9e55 | |||
| 0fa7cdaa76 | |||
| c673e1db92 | |||
| 4d3caf6fde | |||
| 2ceb2637d8 | |||
| eb8cfc682f |
20
.sops.yaml
20
.sops.yaml
@@ -2,11 +2,11 @@ keys:
|
|||||||
- &user_desko_colin age1tnl4jfgacwkargzeqnhzernw29xx8mkv73xh6ufdyde6q7859slsnzf24x
|
- &user_desko_colin age1tnl4jfgacwkargzeqnhzernw29xx8mkv73xh6ufdyde6q7859slsnzf24x
|
||||||
- &user_lappy_colin age1j2pqnl8j0krdzk6npe93s4nnqrzwx978qrc0u570gzlamqpnje9sc8le2g
|
- &user_lappy_colin age1j2pqnl8j0krdzk6npe93s4nnqrzwx978qrc0u570gzlamqpnje9sc8le2g
|
||||||
- &user_servo_colin age1z8fauff34cdecr6sjkre260luzxcca05kpcwvhx988d306tpcejsp63znu
|
- &user_servo_colin age1z8fauff34cdecr6sjkre260luzxcca05kpcwvhx988d306tpcejsp63znu
|
||||||
- &user_moby_colin age1lt739n2tq7dmpglvntjr9j2r7426md7rat7x9w930gagtx4jyvnqwts2al
|
- &user_moby_colin age1zsrsvd7j6l62fjxpfd2qnhqlk8wk4p8r0dtxpe4sdgnh2474095qdu7xj9
|
||||||
- &host_desko age1vnw7lnfpdpjn62l3u5nyv5xt2c965k96p98kc43mcnyzpetrts9q54mc9v
|
- &host_desko age1vnw7lnfpdpjn62l3u5nyv5xt2c965k96p98kc43mcnyzpetrts9q54mc9v
|
||||||
- &host_lappy age1w7mectcjku6x3sd8plm8wkn2qfrhv9n6zhzlf329e2r2uycgke8qkf9dyn
|
- &host_lappy age1w7mectcjku6x3sd8plm8wkn2qfrhv9n6zhzlf329e2r2uycgke8qkf9dyn
|
||||||
- &host_servo age1tzlyex2z6t88tg9h82943e39shxhmqeyr7ywhlwpdjmyqsndv3qq27x0rf
|
- &host_servo age1tzlyex2z6t88tg9h82943e39shxhmqeyr7ywhlwpdjmyqsndv3qq27x0rf
|
||||||
- &host_moby age1t957gf0z865gya0khgc9x59wy76hzps3sgejjqtwcngn2xl273msxsmpe6
|
- &host_moby age18vq5ktwgeaysucvw9t67drqmg5zd5c5k3le34yqxckkfj7wqdqgsd4ejmt
|
||||||
creation_rules:
|
creation_rules:
|
||||||
- path_regex: secrets/universal*
|
- path_regex: secrets/universal*
|
||||||
key_groups:
|
key_groups:
|
||||||
@@ -19,10 +19,11 @@ creation_rules:
|
|||||||
- *host_lappy
|
- *host_lappy
|
||||||
- *host_servo
|
- *host_servo
|
||||||
- *host_moby
|
- *host_moby
|
||||||
- path_regex: secrets/servo.yaml$
|
- path_regex: secrets/servo*
|
||||||
key_groups:
|
key_groups:
|
||||||
- age:
|
- age:
|
||||||
- *user_desko_colin
|
- *user_desko_colin
|
||||||
|
- *user_lappy_colin
|
||||||
- *user_servo_colin
|
- *user_servo_colin
|
||||||
- *host_servo
|
- *host_servo
|
||||||
- path_regex: secrets/desko.yaml$
|
- path_regex: secrets/desko.yaml$
|
||||||
@@ -31,3 +32,16 @@ creation_rules:
|
|||||||
- *user_desko_colin
|
- *user_desko_colin
|
||||||
- *user_lappy_colin
|
- *user_lappy_colin
|
||||||
- *host_desko
|
- *host_desko
|
||||||
|
- path_regex: secrets/lappy.yaml$
|
||||||
|
key_groups:
|
||||||
|
- age:
|
||||||
|
- *user_lappy_colin
|
||||||
|
- *user_desko_colin
|
||||||
|
- *host_lappy
|
||||||
|
- path_regex: secrets/moby.yaml$
|
||||||
|
key_groups:
|
||||||
|
- age:
|
||||||
|
- *user_desko_colin
|
||||||
|
- *user_lappy_colin
|
||||||
|
- *user_moby_colin
|
||||||
|
- *host_moby
|
||||||
|
|||||||
12
TODO.md
12
TODO.md
@@ -1,12 +0,0 @@
|
|||||||
# features/tweaks
|
|
||||||
- iron out video drivers
|
|
||||||
- emoji picker application
|
|
||||||
- find a Masto/Pleroma app which works on mobile
|
|
||||||
|
|
||||||
|
|
||||||
# speed up cross compiling
|
|
||||||
https://nixos.wiki/wiki/Cross_Compiling
|
|
||||||
https://nixos.wiki/wiki/NixOS_on_ARM
|
|
||||||
overlays = [{ ... }: {
|
|
||||||
nixpkgs.crossSystem.system = "aarch64-linux";
|
|
||||||
}];
|
|
||||||
167
flake.lock
generated
167
flake.lock
generated
@@ -1,49 +1,28 @@
|
|||||||
{
|
{
|
||||||
"nodes": {
|
"nodes": {
|
||||||
"home-manager": {
|
"flake-utils": {
|
||||||
"inputs": {
|
|
||||||
"nixpkgs": [
|
|
||||||
"nixpkgs"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1656169755,
|
"lastModified": 1678901627,
|
||||||
"narHash": "sha256-Nlnm4jeQWEGjYrE6hxi/7HYHjBSZ/E0RtjCYifnNsWk=",
|
"narHash": "sha256-U02riOqrKKzwjsxc/400XnElV+UtPUQWpANPlyazjH0=",
|
||||||
"owner": "nix-community",
|
"owner": "numtide",
|
||||||
"repo": "home-manager",
|
"repo": "flake-utils",
|
||||||
"rev": "4a3d01fb53f52ac83194081272795aa4612c2381",
|
"rev": "93a2b84fc4b70d9e089d029deacc3583435c2ed6",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "nix-community",
|
"owner": "numtide",
|
||||||
"ref": "release-22.05",
|
"repo": "flake-utils",
|
||||||
"repo": "home-manager",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"impermanence": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1646131459,
|
|
||||||
"narHash": "sha256-GPmgxvUFvQ1GmsGfWHy9+rcxWrczeDhS9XnAIPHi9XQ=",
|
|
||||||
"owner": "nix-community",
|
|
||||||
"repo": "impermanence",
|
|
||||||
"rev": "2f39baeb7d039fda5fc8225111bb79474138e6f4",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "nix-community",
|
|
||||||
"repo": "impermanence",
|
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"mobile-nixos": {
|
"mobile-nixos": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1656299939,
|
"lastModified": 1679516998,
|
||||||
"narHash": "sha256-gODt71CCv0gnMNeU4GYdSBJkxsfmBy0uNv8owQC1oPs=",
|
"narHash": "sha256-w4baQlS84X8Lf0E5RN0nGkx03luDuV1X0+jWMAXm6fs=",
|
||||||
"owner": "nixos",
|
"owner": "nixos",
|
||||||
"repo": "mobile-nixos",
|
"repo": "mobile-nixos",
|
||||||
"rev": "de9a88a70f0ae5fc0839ff94bf29e8a30af399f8",
|
"rev": "7a6e97e3af73c4cca87e12c83abcb4913dac7dbc",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -52,106 +31,93 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"nix-serve": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": "nixpkgs"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1678202930,
|
||||||
|
"narHash": "sha256-SF82/tTnagdazlETJLzXD9kjZ6lyk38agdLbmMx1UZE=",
|
||||||
|
"owner": "edolstra",
|
||||||
|
"repo": "nix-serve",
|
||||||
|
"rev": "3b6d30016d910a43e0e16f94170440a3e0b8fa8d",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "edolstra",
|
||||||
|
"repo": "nix-serve",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1656679828,
|
"lastModified": 1606086654,
|
||||||
"narHash": "sha256-akGA97pR1BAQew1FrVTCME3p8qvYxJXB2X3a13aBphs=",
|
"narHash": "sha256-VFl+3eGIMqNp7cyOMJ6TjM/+UcsLKtodKoYexrlTJMI=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "915f5a5b3cc4f8ba206afd0b70e52ba4c6a2796b",
|
"rev": "19db3e5ea2777daa874563b5986288151f502e27",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"id": "nixpkgs",
|
"id": "nixpkgs",
|
||||||
"ref": "nixos-22.05",
|
"ref": "nixos-20.09",
|
||||||
"type": "indirect"
|
"type": "indirect"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"nixpkgs-21_11": {
|
"nixpkgs-stable": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1656198488,
|
"lastModified": 1680390120,
|
||||||
"narHash": "sha256-xe81o3Kin6a0jXA3mTxcR+jeA1jLKw3TCar5LUo/B5c=",
|
"narHash": "sha256-RyDJcG/7mfimadlo8vO0QjW22mvYH1+cCqMuigUntr8=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "46af3303651699dc58cfc251d9b18c0f59d857da",
|
"rev": "c1e2efaca8d8a3db6a36f652765d6c6ba7bb8fae",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"ref": "release-21.11",
|
"ref": "release-22.11",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"nixpkgs-22_05": {
|
"nixpkgs-unpatched": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1656199498,
|
"lastModified": 1680415272,
|
||||||
"narHash": "sha256-/BCpM7j7y1G4het6Z3idlnv9A87/s0O1glVmH7fnWvk=",
|
"narHash": "sha256-S2J9n+sSeAAdXWHrz/s9pyS5fhbQilfNqYrs6RCUyN8=",
|
||||||
"owner": "NixOS",
|
"owner": "nixos",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "72a1f167077060a1a7b6e0104863245d0483fa7f",
|
"rev": "66f60deb8aa348ca81d60d0639ae420c667ff92a",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "NixOS",
|
"owner": "nixos",
|
||||||
"ref": "release-22.05",
|
"ref": "staging-next",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"nixpkgs_2": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1656130826,
|
|
||||||
"narHash": "sha256-g5Wo75ddDQmWnL70rJCMm+JJlvHbzPFUePUpuMNn5qk=",
|
|
||||||
"owner": "NixOS",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"rev": "72d1b0d0fac131df1ea254b65413c85609bdd2ee",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "NixOS",
|
|
||||||
"ref": "nixpkgs-unstable",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nurpkgs": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1656786319,
|
|
||||||
"narHash": "sha256-MpdBL2+csFfnMu+2eUNkkACkrPt7UhUdpvXnhrLim0E=",
|
|
||||||
"owner": "nix-community",
|
|
||||||
"repo": "NUR",
|
|
||||||
"rev": "433704dc83b1491725e616bbb898ccd17fbe3d0e",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "nix-community",
|
|
||||||
"repo": "NUR",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"root": {
|
"root": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"home-manager": "home-manager",
|
|
||||||
"impermanence": "impermanence",
|
|
||||||
"mobile-nixos": "mobile-nixos",
|
"mobile-nixos": "mobile-nixos",
|
||||||
"nixpkgs": "nixpkgs",
|
"nix-serve": "nix-serve",
|
||||||
"nurpkgs": "nurpkgs",
|
"nixpkgs-unpatched": "nixpkgs-unpatched",
|
||||||
"sops-nix": "sops-nix"
|
"sops-nix": "sops-nix",
|
||||||
|
"uninsane-dot-org": "uninsane-dot-org"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"sops-nix": {
|
"sops-nix": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"nixpkgs": "nixpkgs_2",
|
"nixpkgs": [
|
||||||
"nixpkgs-21_11": "nixpkgs-21_11",
|
"nixpkgs-unpatched"
|
||||||
"nixpkgs-22_05": "nixpkgs-22_05"
|
],
|
||||||
|
"nixpkgs-stable": "nixpkgs-stable"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1656399028,
|
"lastModified": 1680404136,
|
||||||
"narHash": "sha256-re66+rVHGR3y+0QsaDAwoAHCfoi3BlGV24t2EqRZsAE=",
|
"narHash": "sha256-06D8HJmRv4DdpEQGblMhx2Vm81SBWM61XBBIx7QQfo0=",
|
||||||
"owner": "Mic92",
|
"owner": "Mic92",
|
||||||
"repo": "sops-nix",
|
"repo": "sops-nix",
|
||||||
"rev": "d26947f2d6252e2aae5ffddfe9b38b7c4b94e8f9",
|
"rev": "b93eb910f768f9788737bfed596a598557e5625d",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -159,6 +125,27 @@
|
|||||||
"repo": "sops-nix",
|
"repo": "sops-nix",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"uninsane-dot-org": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-utils": "flake-utils",
|
||||||
|
"nixpkgs": [
|
||||||
|
"nixpkgs-unpatched"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1680086409,
|
||||||
|
"narHash": "sha256-Q2QcVgKvTj/LLuZX9dP8ImySWD5sTn8DDI5+EggRn2c=",
|
||||||
|
"ref": "refs/heads/master",
|
||||||
|
"rev": "068f176a64f0e26dc8c1f0eccf28cbd05be4909b",
|
||||||
|
"revCount": 182,
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://git.uninsane.org/colin/uninsane"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://git.uninsane.org/colin/uninsane"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"root": "root",
|
"root": "root",
|
||||||
|
|||||||
321
flake.nix
321
flake.nix
@@ -1,83 +1,284 @@
|
|||||||
# docs:
|
# FLAKE FEEDBACK:
|
||||||
# https://nixos.wiki/wiki/Flakes
|
# - if flake inputs are meant to be human-readable, a human should be able to easily track them down given the URL.
|
||||||
# https://serokell.io/blog/practical-nix-flakes
|
# - this is not the case with registry URLs, like `nixpkgs/nixos-22.11`.
|
||||||
|
# - this is marginally the case with schemes like `github:nixos/nixpkgs`.
|
||||||
|
# - given the *existing* `git+https://` scheme, i propose expressing github URLs similarly:
|
||||||
|
# - `github+https://github.com/nixos/nixpkgs/tree/nixos-22.11`
|
||||||
|
# - need some way to apply local patches to inputs.
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# DEVELOPMENT DOCS:
|
||||||
|
# - Flake docs: <https://nixos.wiki/wiki/Flakes>
|
||||||
|
# - Flake RFC: <https://github.com/tweag/rfcs/blob/flakes/rfcs/0049-flakes.md>
|
||||||
|
# - Discussion: <https://github.com/NixOS/rfcs/pull/49>
|
||||||
|
# - <https://serokell.io/blog/practical-nix-flakes>
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# COMMON OPERATIONS:
|
||||||
|
# - update a specific flake input:
|
||||||
|
# - `nix flake lock --update-input nixpkgs`
|
||||||
|
|
||||||
{
|
{
|
||||||
|
# XXX: use the `github:` scheme instead of the more readable git+https: because it's *way* more efficient
|
||||||
|
# preferably, i would rewrite the human-readable https URLs to nix-specific github: URLs with a helper,
|
||||||
|
# but `inputs` is required to be a strict attrset: not an expression.
|
||||||
inputs = {
|
inputs = {
|
||||||
nixpkgs.url = "nixpkgs/nixos-22.05";
|
# <https://github.com/nixos/nixpkgs/tree/nixos-22.11>
|
||||||
# pkgs-telegram.url = "nixpkgs/33775ec9a2173a08e46edf9f46c9febadbf743e8";# 2022/04/18; telegram 3.7.3. fails: nix log /nix/store/y5kv47hnv55qknb6cnmpcyraicay79fx-telegram-desktop-3.7.3.drv: g++: fatal error: cannot execute '/nix/store/njk5sbd21305bhr7gwibxbbvgbx5lxvn-gcc-9.3.0/libexec/gcc/aarch64-unknown-linux-gnu/9.3.0/cc1plus': execv: No such file or directory
|
# nixpkgs-stable.url = "github:nixos/nixpkgs?ref=nixos-22.11";
|
||||||
|
|
||||||
|
# <https://github.com/nixos/nixpkgs/tree/nixos-unstable>
|
||||||
|
# nixpkgs-unpatched.url = "github:nixos/nixpkgs?ref=nixos-unstable";
|
||||||
|
nixpkgs-unpatched.url = "github:nixos/nixpkgs?ref=staging-next";
|
||||||
|
|
||||||
|
# nixpkgs = {
|
||||||
|
# url = "./nixpatches";
|
||||||
|
# inputs.nixpkgs.follows = "nixpkgs-unpatched";
|
||||||
|
# };
|
||||||
|
|
||||||
mobile-nixos = {
|
mobile-nixos = {
|
||||||
|
# <https://github.com/nixos/mobile-nixos>
|
||||||
url = "github:nixos/mobile-nixos";
|
url = "github:nixos/mobile-nixos";
|
||||||
flake = false;
|
flake = false;
|
||||||
};
|
};
|
||||||
home-manager = {
|
sops-nix = {
|
||||||
url = "github:nix-community/home-manager/release-22.05";
|
# <https://github.com/Mic92/sops-nix>
|
||||||
inputs.nixpkgs.follows = "nixpkgs";
|
url = "github:Mic92/sops-nix";
|
||||||
|
# inputs.nixpkgs.follows = "nixpkgs";
|
||||||
|
inputs.nixpkgs.follows = "nixpkgs-unpatched";
|
||||||
|
};
|
||||||
|
uninsane-dot-org = {
|
||||||
|
url = "git+https://git.uninsane.org/colin/uninsane";
|
||||||
|
# inputs.nixpkgs.follows = "nixpkgs";
|
||||||
|
inputs.nixpkgs.follows = "nixpkgs-unpatched";
|
||||||
|
};
|
||||||
|
nix-serve = {
|
||||||
|
# <https://github.com/edolstra/nix-serve>
|
||||||
|
url = "github:edolstra/nix-serve";
|
||||||
};
|
};
|
||||||
nurpkgs.url = "github:nix-community/NUR";
|
|
||||||
sops-nix.url = "github:Mic92/sops-nix";
|
|
||||||
impermanence.url = "github:nix-community/impermanence";
|
|
||||||
};
|
};
|
||||||
|
|
||||||
outputs = { self, nixpkgs, mobile-nixos, home-manager, nurpkgs, sops-nix, impermanence }:
|
outputs = {
|
||||||
let
|
self,
|
||||||
patchedPkgs = system: nixpkgs.legacyPackages.${system}.applyPatches {
|
nixpkgs-unpatched,
|
||||||
name = "nixpkgs-patched-uninsane";
|
mobile-nixos,
|
||||||
src = nixpkgs;
|
sops-nix,
|
||||||
patches = import ./nixpatches/list.nix nixpkgs.legacyPackages.${system}.fetchpatch;
|
uninsane-dot-org,
|
||||||
};
|
nix-serve,
|
||||||
# return something which behaves like `pkgs`, for the provided system
|
...
|
||||||
nixpkgsFor = system: import (patchedPkgs system) { inherit system; };
|
}@inputs:
|
||||||
# evaluate ONLY our overlay, for the provided system
|
|
||||||
customPackagesFor = system: import ./pkgs/overlay.nix (nixpkgsFor system) (nixpkgsFor system);
|
|
||||||
decl-machine = { name, system }:
|
|
||||||
let
|
let
|
||||||
nixosSystem = import ((patchedPkgs system) + "/nixos/lib/eval-config.nix");
|
inherit (builtins) attrNames elem listToAttrs map mapAttrs;
|
||||||
in (nixosSystem {
|
mapAttrs' = f: set:
|
||||||
inherit system;
|
listToAttrs (map (attr: f attr set.${attr}) (attrNames set));
|
||||||
specialArgs = { inherit nixpkgs mobile-nixos home-manager nurpkgs impermanence; };
|
# mapAttrs but without the `name` argument
|
||||||
modules = [
|
mapAttrValues = f: mapAttrs (_: f);
|
||||||
./modules
|
# rather than apply our nixpkgs patches as a flake input, do that here instead.
|
||||||
./machines/${name}
|
# this (temporarily?) resolves the bad UX wherein a subflake residing in the same git
|
||||||
(import ./helpers/set-hostname.nix name)
|
# repo as the main flake causes the main flake to have an unstable hash.
|
||||||
sops-nix.nixosModules.sops
|
nixpkgs = (import ./nixpatches/flake.nix).outputs {
|
||||||
{
|
self = nixpkgs;
|
||||||
nixpkgs.config.allowUnfree = true;
|
nixpkgs = nixpkgs-unpatched;
|
||||||
nixpkgs.overlays = [
|
};
|
||||||
nurpkgs.overlay
|
|
||||||
(import "${mobile-nixos}/overlay/overlay.nix")
|
|
||||||
(import ./pkgs/overlay.nix)
|
|
||||||
];
|
|
||||||
}
|
|
||||||
];
|
|
||||||
});
|
|
||||||
|
|
||||||
decl-bootable-machine = { name, system }: rec {
|
nixpkgsCompiledBy = local: nixpkgs.legacyPackages."${local}";
|
||||||
nixosConfiguration = decl-machine { inherit name system; };
|
|
||||||
|
evalHost = { name, local, target }:
|
||||||
|
let
|
||||||
|
# XXX: we'd prefer to use `nixosSystem = (nixpkgsCompiledBy target).nixos`
|
||||||
|
# but it doesn't propagate config to the underlying pkgs, meaning it doesn't let you use
|
||||||
|
# non-free packages even after setting nixpkgs.allowUnfree.
|
||||||
|
# XXX: patch using the target -- not local -- otherwise the target will
|
||||||
|
# need to emulate the host in order to rebuild!
|
||||||
|
nixosSystem = import ((nixpkgsCompiledBy target).path + "/nixos/lib/eval-config.nix");
|
||||||
|
in
|
||||||
|
(nixosSystem {
|
||||||
|
modules = [
|
||||||
|
(import ./hosts/instantiate.nix { localSystem = local; hostName = name; })
|
||||||
|
self.nixosModules.default
|
||||||
|
self.nixosModules.passthru
|
||||||
|
{
|
||||||
|
nixpkgs.overlays = [
|
||||||
|
self.overlays.disable-flakey-tests
|
||||||
|
self.overlays.passthru
|
||||||
|
self.overlays.pins
|
||||||
|
self.overlays.pkgs
|
||||||
|
# self.overlays.optimizations
|
||||||
|
];
|
||||||
|
nixpkgs.hostPlatform = target;
|
||||||
|
# nixpkgs.buildPlatform = local; # set by instantiate.nix instead
|
||||||
|
# nixpkgs.config.replaceStdenv = { pkgs }: pkgs.ccacheStdenv;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
});
|
||||||
|
in {
|
||||||
|
nixosConfigurations =
|
||||||
|
let
|
||||||
|
hosts = {
|
||||||
|
servo = { name = "servo"; local = "x86_64-linux"; target = "x86_64-linux"; };
|
||||||
|
desko = { name = "desko"; local = "x86_64-linux"; target = "x86_64-linux"; };
|
||||||
|
lappy = { name = "lappy"; local = "x86_64-linux"; target = "x86_64-linux"; };
|
||||||
|
moby = { name = "moby"; local = "x86_64-linux"; target = "aarch64-linux"; };
|
||||||
|
rescue = { name = "rescue"; local = "x86_64-linux"; target = "x86_64-linux"; };
|
||||||
|
};
|
||||||
|
# cross-compiled builds: instead of emulating the host, build using a cross-compiler.
|
||||||
|
# - these are faster to *build* than the emulated variants (useful when tweaking packages),
|
||||||
|
# - but fewer of their packages can be found in upstream caches.
|
||||||
|
cross = mapAttrValues evalHost hosts;
|
||||||
|
emulated = mapAttrValues
|
||||||
|
({name, local, target}: evalHost {
|
||||||
|
inherit name target;
|
||||||
|
local = null;
|
||||||
|
})
|
||||||
|
hosts;
|
||||||
|
prefixAttrs = prefix: attrs: mapAttrs'
|
||||||
|
(name: value: {
|
||||||
|
name = prefix + name;
|
||||||
|
inherit value;
|
||||||
|
})
|
||||||
|
attrs;
|
||||||
|
in
|
||||||
|
(prefixAttrs "cross-" cross) //
|
||||||
|
(prefixAttrs "emulated-" emulated) // {
|
||||||
|
# prefer native builds for these machines:
|
||||||
|
inherit (emulated) servo desko lappy rescue;
|
||||||
|
# prefer cross-compiled builds for these machines:
|
||||||
|
inherit (cross) moby;
|
||||||
|
};
|
||||||
|
|
||||||
|
# unofficial output
|
||||||
# this produces a EFI-bootable .img file (GPT with a /boot partition and a system (/ or /nix) partition).
|
# this produces a EFI-bootable .img file (GPT with a /boot partition and a system (/ or /nix) partition).
|
||||||
# after building this:
|
# after building this:
|
||||||
# - flash it to a bootable medium (SD card, flash drive, HDD)
|
# - flash it to a bootable medium (SD card, flash drive, HDD)
|
||||||
# - resize the root partition (use cfdisk)
|
# - resize the root partition (use cfdisk)
|
||||||
# - mount the part
|
# - mount the part
|
||||||
# chown root:nixblkd <part>/nix/store
|
# - chown root:nixbld <part>/nix/store
|
||||||
# chmod 775 <part>/nix/store
|
# - chown root:root -R <part>/nix/store/*
|
||||||
# chown root:root -R <part>/nix/store/*
|
# - chown root:root -R <part>/persist # if using impermanence
|
||||||
# populate any important things (persist/, home/colin/.ssh, etc)
|
# - populate any important things (persist/, home/colin/.ssh, etc)
|
||||||
# - boot
|
# - boot
|
||||||
# - if fs wasn't resized automatically, then `sudo btrfs filesystem resize max /`
|
# - if fs wasn't resized automatically, then `sudo btrfs filesystem resize max /`
|
||||||
# - checkout this flake into /etc/nixos AND UPDATE THE FS UUIDS.
|
# - checkout this flake into /etc/nixos AND UPDATE THE FS UUIDS.
|
||||||
# - `nixos-rebuild --flake './#<machine>' switch`
|
# - `nixos-rebuild --flake './#<host>' switch`
|
||||||
img = nixosConfiguration.config.system.build.img;
|
imgs = mapAttrValues (host: host.config.system.build.img) self.nixosConfigurations;
|
||||||
|
|
||||||
|
# unofficial output
|
||||||
|
host-pkgs = mapAttrValues (host: host.config.system.build.pkgs) self.nixosConfigurations;
|
||||||
|
|
||||||
|
overlays = {
|
||||||
|
# N.B.: `nix flake check` requires every overlay to take `final: prev:` at defn site,
|
||||||
|
# hence the weird redundancy.
|
||||||
|
default = final: prev: self.overlays.pkgs final prev;
|
||||||
|
disable-flakey-tests = final: prev: import ./overlays/disable-flakey-tests.nix final prev;
|
||||||
|
pkgs = final: prev: import ./overlays/pkgs.nix final prev;
|
||||||
|
pins = final: prev: import ./overlays/pins.nix final prev;
|
||||||
|
optimizations = final: prev: import ./overlays/optimizations.nix final prev;
|
||||||
|
passthru = final: prev:
|
||||||
|
let
|
||||||
|
stable =
|
||||||
|
if inputs ? "nixpkgs-stable" then (
|
||||||
|
final': prev': {
|
||||||
|
stable = inputs.nixpkgs-stable.legacyPackages."${prev'.stdenv.hostPlatform.system}";
|
||||||
|
}
|
||||||
|
) else (final': prev': {});
|
||||||
|
mobile = (import "${mobile-nixos}/overlay/overlay.nix");
|
||||||
|
uninsane = uninsane-dot-org.overlay;
|
||||||
|
# nix-serve' = nix-serve.overlay;
|
||||||
|
nix-serve' = next: prev: {
|
||||||
|
# XXX(2023/03/02): upstream isn't compatible with modern `nix`. probably the perl bindings.
|
||||||
|
# - we use the package built against `nixpkgs` specified in its flake rather than use its overlay,
|
||||||
|
# to get around this.
|
||||||
|
inherit (nix-serve.packages."${next.system}") nix-serve;
|
||||||
|
};
|
||||||
|
in
|
||||||
|
(stable final prev)
|
||||||
|
// (mobile final prev)
|
||||||
|
// (uninsane final prev)
|
||||||
|
// (nix-serve' final prev)
|
||||||
|
;
|
||||||
|
};
|
||||||
|
|
||||||
|
nixosModules = rec {
|
||||||
|
default = sane;
|
||||||
|
sane = import ./modules;
|
||||||
|
passthru = { ... }: {
|
||||||
|
imports = [
|
||||||
|
sops-nix.nixosModules.sops
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# this includes both our native packages and all the nixpkgs packages.
|
||||||
|
legacyPackages =
|
||||||
|
let
|
||||||
|
allPkgsFor = sys: (nixpkgsCompiledBy sys).appendOverlays [
|
||||||
|
self.overlays.passthru self.overlays.pkgs
|
||||||
|
];
|
||||||
|
in {
|
||||||
|
x86_64-linux = allPkgsFor "x86_64-linux";
|
||||||
|
aarch64-linux = allPkgsFor "aarch64-linux";
|
||||||
|
};
|
||||||
|
|
||||||
|
# extract only our own packages from the full set.
|
||||||
|
# because of `nix flake check`, we flatten the package set and only surface x86_64-linux packages.
|
||||||
|
packages = mapAttrs
|
||||||
|
(system: allPkgs:
|
||||||
|
allPkgs.lib.filterAttrs (name: pkg:
|
||||||
|
# keep only packages which will pass `nix flake check`, i.e. keep only:
|
||||||
|
# - derivations (not package sets)
|
||||||
|
# - packages that build for the given platform
|
||||||
|
(! elem name [ "feeds" "pythonPackagesExtensions" ])
|
||||||
|
&& (allPkgs.lib.meta.availableOn allPkgs.stdenv.hostPlatform pkg)
|
||||||
|
)
|
||||||
|
(allPkgs.sane // {
|
||||||
|
inherit (allPkgs) uninsane-dot-org;
|
||||||
|
})
|
||||||
|
)
|
||||||
|
# self.legacyPackages;
|
||||||
|
{ inherit (self.legacyPackages) x86_64-linux; }
|
||||||
|
;
|
||||||
|
|
||||||
|
apps."x86_64-linux" =
|
||||||
|
let
|
||||||
|
pkgs = self.legacyPackages."x86_64-linux";
|
||||||
|
deployScript = action: pkgs.writeShellScript "deploy-moby" ''
|
||||||
|
nixos-rebuild --flake '.#cross-moby' build
|
||||||
|
sudo nix sign-paths -r -k /run/secrets/nix_serve_privkey $(readlink ./result)
|
||||||
|
nixos-rebuild --flake '.#cross-moby' ${action} --target-host colin@moby --use-remote-sudo
|
||||||
|
'';
|
||||||
|
in {
|
||||||
|
update-feeds = {
|
||||||
|
type = "app";
|
||||||
|
program = "${pkgs.feeds.passthru.updateScript}";
|
||||||
|
};
|
||||||
|
|
||||||
|
init-feed = {
|
||||||
|
# use like `nix run '.#init-feed' uninsane.org`
|
||||||
|
type = "app";
|
||||||
|
program = "${pkgs.feeds.passthru.initFeedScript}";
|
||||||
|
};
|
||||||
|
|
||||||
|
deploy-moby-test = {
|
||||||
|
# `nix run '.#deploy-moby-test'`
|
||||||
|
type = "app";
|
||||||
|
program = ''${deployScript "test"}'';
|
||||||
|
};
|
||||||
|
deploy-moby-switch = {
|
||||||
|
# `nix run '.#deploy-moby-switch'`
|
||||||
|
type = "app";
|
||||||
|
program = ''${deployScript "switch"}'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
templates = {
|
||||||
|
python-data = {
|
||||||
|
# initialize with:
|
||||||
|
# - `nix flake init -t '/home/colin/dev/nixos/#python-data'`
|
||||||
|
# then enter with:
|
||||||
|
# - `nix develop`
|
||||||
|
path = ./templates/python-data;
|
||||||
|
description = "python environment for data processing";
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
machines.servo = decl-bootable-machine { name = "servo"; system = "aarch64-linux"; };
|
|
||||||
machines.desko = decl-bootable-machine { name = "desko"; system = "x86_64-linux"; };
|
|
||||||
machines.lappy = decl-bootable-machine { name = "lappy"; system = "x86_64-linux"; };
|
|
||||||
machines.moby = decl-bootable-machine { name = "moby"; system = "aarch64-linux"; };
|
|
||||||
in {
|
|
||||||
nixosConfigurations = builtins.mapAttrs (name: value: value.nixosConfiguration) machines;
|
|
||||||
imgs = builtins.mapAttrs (name: value: value.img) machines;
|
|
||||||
packages.x86_64-linux = customPackagesFor "x86_64-linux";
|
|
||||||
packages.aarch64-linux = customPackagesFor "aarch64-linux";
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
hostName: { ... }:
|
|
||||||
{
|
|
||||||
networking.hostName = hostName;
|
|
||||||
}
|
|
||||||
64
hosts/by-name/desko/default.nix
Normal file
64
hosts/by-name/desko/default.nix
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
{ config, pkgs, ... }:
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
./fs.nix
|
||||||
|
];
|
||||||
|
|
||||||
|
sane.roles.build-machine.enable = true;
|
||||||
|
sane.roles.client = true;
|
||||||
|
sane.services.wg-home.enable = true;
|
||||||
|
sane.services.wg-home.ip = config.sane.hosts.by-name."desko".wg-home.ip;
|
||||||
|
sane.services.duplicity.enable = true;
|
||||||
|
sane.services.nixserve.sopsFile = ../../../secrets/desko.yaml;
|
||||||
|
|
||||||
|
sane.gui.sway.enable = true;
|
||||||
|
sane.programs.iphoneUtils.enableFor.user.colin = true;
|
||||||
|
|
||||||
|
sane.programs.guiApps.suggestedPrograms = [ "desktopGuiApps" ];
|
||||||
|
|
||||||
|
boot.loader.efi.canTouchEfiVariables = false;
|
||||||
|
sane.image.extraBootFiles = [ pkgs.bootpart-uefi-x86_64 ];
|
||||||
|
|
||||||
|
# needed to use libimobiledevice/ifuse, for iphone sync
|
||||||
|
services.usbmuxd.enable = true;
|
||||||
|
|
||||||
|
sops.secrets.colin-passwd = {
|
||||||
|
sopsFile = ../../../secrets/desko.yaml;
|
||||||
|
neededForUsers = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
# don't enable wifi by default: it messes with connectivity.
|
||||||
|
systemd.services.iwd.enable = false;
|
||||||
|
|
||||||
|
# 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.
|
||||||
|
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`
|
||||||
|
extraConfig = ''
|
||||||
|
ALLOW_USERS = "colin";
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
sops.secrets.duplicity_passphrase = {
|
||||||
|
sopsFile = ../../../secrets/desko.yaml;
|
||||||
|
};
|
||||||
|
|
||||||
|
programs.steam = {
|
||||||
|
enable = true;
|
||||||
|
# not sure if needed: stole this whole snippet from the wiki
|
||||||
|
remotePlay.openFirewall = true; # Open ports in the firewall for Steam Remote Play
|
||||||
|
dedicatedServer.openFirewall = true; # Open ports in the firewall for Source Dedicated Server
|
||||||
|
};
|
||||||
|
sane.user.persist.plaintext = [
|
||||||
|
".steam"
|
||||||
|
".local/share/Steam"
|
||||||
|
];
|
||||||
|
|
||||||
|
# docs: https://nixos.org/manual/nixos/stable/options.html#opt-system.stateVersion
|
||||||
|
system.stateVersion = "21.05";
|
||||||
|
}
|
||||||
@@ -1,22 +1,15 @@
|
|||||||
{ ... }:
|
{ ... }:
|
||||||
|
|
||||||
{
|
{
|
||||||
# root is a tmpfs so that we have an ephemeral system ("impermanence" handles the state)
|
sane.persist.root-on-tmpfs = true;
|
||||||
fileSystems."/" = {
|
# we need a /tmp for building large nix things.
|
||||||
device = "none";
|
# a cross-compiled kernel, particularly, will easily use 30+GB of tmp
|
||||||
fsType = "tmpfs";
|
|
||||||
options = [
|
|
||||||
"mode=755"
|
|
||||||
"size=1G"
|
|
||||||
"defaults"
|
|
||||||
];
|
|
||||||
};
|
|
||||||
# we need a /tmp of default size (half RAM) for building large nix things
|
|
||||||
fileSystems."/tmp" = {
|
fileSystems."/tmp" = {
|
||||||
device = "none";
|
device = "none";
|
||||||
fsType = "tmpfs";
|
fsType = "tmpfs";
|
||||||
options = [
|
options = [
|
||||||
"mode=777"
|
"mode=777"
|
||||||
|
"size=64G"
|
||||||
"defaults"
|
"defaults"
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
@@ -1,22 +1,30 @@
|
|||||||
{ pkgs, ... }:
|
{ config, pkgs, ... }:
|
||||||
{
|
{
|
||||||
imports = [
|
imports = [
|
||||||
./fs.nix
|
./fs.nix
|
||||||
];
|
];
|
||||||
|
|
||||||
colinsane.gui.sway.enable = true;
|
sane.yggdrasil.enable = true;
|
||||||
colinsane.impermanence.enable = true;
|
|
||||||
boot.loader.generic-extlinux-compatible.enable = true;
|
|
||||||
boot.loader.efi.canTouchEfiVariables = false;
|
|
||||||
colinsane.image.extraBootFiles = [ pkgs.bootpart-uefi-x86_64 ];
|
|
||||||
|
|
||||||
hardware.opengl.extraPackages = with pkgs; [
|
sane.roles.client = true;
|
||||||
intel-compute-runtime
|
sane.services.wg-home.enable = true;
|
||||||
intel-media-driver # new
|
sane.services.wg-home.ip = config.sane.hosts.by-name."lappy".wg-home.ip;
|
||||||
libvdpau-va-gl # new
|
|
||||||
vaapiIntel
|
# sane.guest.enable = true;
|
||||||
|
sane.gui.sway.enable = true;
|
||||||
|
boot.loader.efi.canTouchEfiVariables = false;
|
||||||
|
sane.image.extraBootFiles = [ pkgs.bootpart-uefi-x86_64 ];
|
||||||
|
|
||||||
|
sane.programs.guiApps.suggestedPrograms = [
|
||||||
|
"desktopGuiApps"
|
||||||
|
"stepmania"
|
||||||
];
|
];
|
||||||
|
|
||||||
|
sops.secrets.colin-passwd = {
|
||||||
|
sopsFile = ../../../secrets/lappy.yaml;
|
||||||
|
neededForUsers = true;
|
||||||
|
};
|
||||||
|
|
||||||
# default config: https://man.archlinux.org/man/snapper-configs.5
|
# default config: https://man.archlinux.org/man/snapper-configs.5
|
||||||
# defaults to something like:
|
# defaults to something like:
|
||||||
# - hourly snapshots
|
# - hourly snapshots
|
||||||
@@ -1,16 +1,7 @@
|
|||||||
{ ... }:
|
{ ... }:
|
||||||
|
|
||||||
{
|
{
|
||||||
# root is a tmpfs so that we have an ephemeral system ("impermanence" handles the state)
|
sane.persist.root-on-tmpfs = true;
|
||||||
fileSystems."/" = {
|
|
||||||
device = "none";
|
|
||||||
fsType = "tmpfs";
|
|
||||||
options = [
|
|
||||||
"mode=755"
|
|
||||||
"size=1G"
|
|
||||||
"defaults"
|
|
||||||
];
|
|
||||||
};
|
|
||||||
# we need a /tmp of default size (half RAM) for building large nix things
|
# we need a /tmp of default size (half RAM) for building large nix things
|
||||||
fileSystems."/tmp" = {
|
fileSystems."/tmp" = {
|
||||||
device = "none";
|
device = "none";
|
||||||
91
hosts/by-name/moby/default.nix
Normal file
91
hosts/by-name/moby/default.nix
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
{ config, pkgs, lib, ... }:
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
./firmware.nix
|
||||||
|
./fs.nix
|
||||||
|
./kernel.nix
|
||||||
|
];
|
||||||
|
|
||||||
|
sane.roles.client = true;
|
||||||
|
sane.services.wg-home.enable = true;
|
||||||
|
sane.services.wg-home.ip = config.sane.hosts.by-name."moby".wg-home.ip;
|
||||||
|
|
||||||
|
# XXX colin: phosh doesn't work well with passwordless login,
|
||||||
|
# so set this more reliable default password should anything go wrong
|
||||||
|
users.users.colin.initialPassword = "147147";
|
||||||
|
services.getty.autologinUser = "root"; # allows for emergency maintenance?
|
||||||
|
|
||||||
|
sops.secrets.colin-passwd = {
|
||||||
|
sopsFile = ../../../secrets/moby.yaml;
|
||||||
|
neededForUsers = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
sane.web-browser = {
|
||||||
|
# compromise impermanence for the sake of usability
|
||||||
|
persistCache = "private";
|
||||||
|
persistData = "private";
|
||||||
|
|
||||||
|
# i don't do crypto stuff on moby
|
||||||
|
addons.ether-metamask.enable = false;
|
||||||
|
# addons.sideberry.enable = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
sane.user.persist.plaintext = [
|
||||||
|
".config/pulse" # persist pulseaudio volume
|
||||||
|
];
|
||||||
|
|
||||||
|
sane.gui.phosh.enable = true;
|
||||||
|
# sane.programs.consoleUtils.enableFor.user.colin = false;
|
||||||
|
# sane.programs.guiApps.enableFor.user.colin = false;
|
||||||
|
sane.programs.sequoia.enableFor.user.colin = false;
|
||||||
|
sane.programs.tuiApps.enableFor.user.colin = false; # visidata, others, don't compile well
|
||||||
|
|
||||||
|
boot.loader.efi.canTouchEfiVariables = false;
|
||||||
|
# /boot space is at a premium. default was 20.
|
||||||
|
# even 10 can be too much
|
||||||
|
# TODO: compress moby kernels!
|
||||||
|
boot.loader.generic-extlinux-compatible.configurationLimit = 8;
|
||||||
|
# mobile.bootloader.enable = false;
|
||||||
|
# mobile.boot.stage-1.enable = false;
|
||||||
|
# boot.initrd.systemd.enable = false;
|
||||||
|
# boot.initrd.services.swraid.enable = false; # attempt to fix dm_mod stuff
|
||||||
|
# disable proximity sensor.
|
||||||
|
# the filtering/calibration is bad that it causes the screen to go fully dark at times.
|
||||||
|
boot.blacklistedKernelModules = [ "stk3310" ];
|
||||||
|
|
||||||
|
# without this some GUI apps fail: `DRM_IOCTL_MODE_CREATE_DUMB failed: Cannot allocate memory`
|
||||||
|
# this is because they can't allocate enough video ram.
|
||||||
|
# the default CMA seems to be 32M.
|
||||||
|
# i was running fine with 256MB from 2022/07-ish through 2022/12-ish, but then the phone quit reliably coming back from sleep: maybe a memory leak?
|
||||||
|
# `cat /proc/meminfo` to see CmaTotal/CmaFree if interested in tuning this.
|
||||||
|
boot.kernelParams = [ "cma=512M" ];
|
||||||
|
|
||||||
|
# mobile-nixos' /lib/firmware includes:
|
||||||
|
# rtl_bt (bluetooth)
|
||||||
|
# anx7688-fw.bin (USB-C -> HDMI bridge)
|
||||||
|
# ov5640_af.bin (camera module)
|
||||||
|
# hardware.firmware = [ config.mobile.device.firmware ];
|
||||||
|
hardware.firmware = [ pkgs.rtl8723cs-firmware ];
|
||||||
|
|
||||||
|
system.stateVersion = "21.11";
|
||||||
|
|
||||||
|
# defined: https://www.freedesktop.org/software/systemd/man/machine-info.html
|
||||||
|
# XXX colin: not sure which, if any, software makes use of this
|
||||||
|
environment.etc."machine-info".text = ''
|
||||||
|
CHASSIS="handset"
|
||||||
|
'';
|
||||||
|
|
||||||
|
# enable rotation sensor
|
||||||
|
hardware.sensor.iio.enable = true;
|
||||||
|
|
||||||
|
# from https://gitlab.manjaro.org/manjaro-arm/packages/community/phosh/alsa-ucm-pinephone
|
||||||
|
# mobile-nixos does this same thing, with *slightly different settings*.
|
||||||
|
# i trust manjaro more because the guy maintaining that is actively trying to upstream into alsa-ucm-conf.
|
||||||
|
# an alternative may be to build a custom alsa with the PinePhone config patch applied:
|
||||||
|
# - <https://github.com/alsa-project/alsa-ucm-conf/pull/134>
|
||||||
|
# that would make this be not device-specific
|
||||||
|
environment.variables.ALSA_CONFIG_UCM2 = "${./ucm2}";
|
||||||
|
systemd.services.pulseaudio.environment.ALSA_CONFIG_UCM2 = "${./ucm2}";
|
||||||
|
|
||||||
|
hardware.opengl.driSupport = true;
|
||||||
|
}
|
||||||
@@ -2,9 +2,9 @@
|
|||||||
{
|
{
|
||||||
# we need space in the GPT header to place tow-boot.
|
# we need space in the GPT header to place tow-boot.
|
||||||
# only actually need 1 MB, but better to over-allocate than under-allocate
|
# only actually need 1 MB, but better to over-allocate than under-allocate
|
||||||
colinsane.image.extraGPTPadding = 16 * 1024 * 1024;
|
sane.image.extraGPTPadding = 16 * 1024 * 1024;
|
||||||
colinsane.image.firstPartGap = 0;
|
sane.image.firstPartGap = 0;
|
||||||
system.build.img = pkgs.runCommandNoCC "nixos_full-disk-image.img" {} ''
|
system.build.img = pkgs.runCommand "nixos_full-disk-image.img" {} ''
|
||||||
cp -v ${config.system.build.img-without-firmware}/nixos.img $out
|
cp -v ${config.system.build.img-without-firmware}/nixos.img $out
|
||||||
chmod +w $out
|
chmod +w $out
|
||||||
dd if=${pkgs.tow-boot-pinephone}/Tow-Boot.noenv.bin of=$out bs=1024 seek=8 conv=notrunc
|
dd if=${pkgs.tow-boot-pinephone}/Tow-Boot.noenv.bin of=$out bs=1024 seek=8 conv=notrunc
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
{ ... }:
|
{ ... }:
|
||||||
|
|
||||||
{
|
{
|
||||||
fileSystems."/" = {
|
sane.persist.root-on-tmpfs = true;
|
||||||
|
fileSystems."/nix" = {
|
||||||
device = "/dev/disk/by-uuid/1f1271f8-53ce-4081-8a29-60a4a6b5d6f9";
|
device = "/dev/disk/by-uuid/1f1271f8-53ce-4081-8a29-60a4a6b5d6f9";
|
||||||
fsType = "btrfs";
|
fsType = "btrfs";
|
||||||
options = [
|
options = [
|
||||||
146
hosts/by-name/moby/kernel.nix
Normal file
146
hosts/by-name/moby/kernel.nix
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
{ lib, pkgs, ... }:
|
||||||
|
let
|
||||||
|
# use the last commit on the 5.18 branch (5.18.14)
|
||||||
|
# manjaro's changes between kernel patch versions tend to be minimal if any.
|
||||||
|
manjaroBase = "https://gitlab.manjaro.org/manjaro-arm/packages/core/linux/-/raw/25bd828cd47b1c6e09fcbcf394a649b89d2876dd";
|
||||||
|
manjaroPatch = name: sha256: {
|
||||||
|
inherit name;
|
||||||
|
patch = pkgs.fetchpatch {
|
||||||
|
inherit name;
|
||||||
|
url = "${manjaroBase}/${name}?inline=false";
|
||||||
|
inherit sha256;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# the idea for patching off Manjaro's kernel comes from jakewaksbaum:
|
||||||
|
# - https://git.sr.ht/~jakewaksbaum/pi/tree/af20aae5653545d6e67a459b59ee3e1ca8a680b0/item/kernel/default.nix
|
||||||
|
# - he later abandoned this, i think because he's using the Pinephone Pro which received mainline support.
|
||||||
|
manjaroPatches = [
|
||||||
|
(manjaroPatch
|
||||||
|
"1001-arm64-dts-allwinner-add-hdmi-sound-to-pine-devices.patch"
|
||||||
|
"sha256-DApd791A+AxB28Ven/MVAyuyVphdo8KQDx8O7oxVPnc="
|
||||||
|
)
|
||||||
|
# these patches below are critical to enable wifi (RTL8723CS)
|
||||||
|
# - the alternative is a wholly forked kernel by megi/megous:
|
||||||
|
# - https://xnux.eu/howtos/build-pinephone-kernel.html#toc-how-to-build-megi-s-pinehpone-kernel
|
||||||
|
# - i don't know if these patches are based on megi's or original
|
||||||
|
(manjaroPatch
|
||||||
|
"2001-Bluetooth-Add-new-quirk-for-broken-local-ext-features.patch"
|
||||||
|
"sha256-CExhJuUWivegxPdnzKINEsKrMFx/m/1kOZFmlZ2SEOc="
|
||||||
|
)
|
||||||
|
(manjaroPatch
|
||||||
|
"2002-Bluetooth-btrtl-add-support-for-the-RTL8723CS.patch"
|
||||||
|
"sha256-dDdvOphTcP/Aog93HyH+L9m55laTgtjndPSE4/rnzUA="
|
||||||
|
)
|
||||||
|
(manjaroPatch
|
||||||
|
"2004-arm64-dts-allwinner-enable-bluetooth-pinetab-pinepho.patch"
|
||||||
|
"sha256-o43P3WzXyHK1PF+Kdter4asuyGAEKO6wf5ixcco2kCQ="
|
||||||
|
)
|
||||||
|
# XXX: this one has a Makefile, which hardcodes /sbin/depmod:
|
||||||
|
# - drivers/staging/rtl8723cs/Makefile
|
||||||
|
# - not sure if this is problematic?
|
||||||
|
(manjaroPatch
|
||||||
|
"2005-staging-add-rtl8723cs-driver.patch"
|
||||||
|
"sha256-6ywm3dQQ5JYl60CLKarxlSUukwi4QzqctCj3tVgzFbo="
|
||||||
|
)
|
||||||
|
];
|
||||||
|
|
||||||
|
# pinephone uses the linux dtb at arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi
|
||||||
|
# - this includes sun50i-a64.dtsi
|
||||||
|
# - and sun50i-a64-cpu-opp.dtsi
|
||||||
|
# - no need to touch the allwinner-h6 stuff: that's the SBC pine product
|
||||||
|
# - i think it's safe to ignore sun9i stuff, but i don't know what it is
|
||||||
|
kernelConfig = with lib.kernel; {
|
||||||
|
# NB: nix adds the CONFIG_ prefix to each of these.
|
||||||
|
# if you add the prefix yourself nix will IGNORE YOUR CONFIG.
|
||||||
|
RTL8723CS = module;
|
||||||
|
BT_HCIUART_3WIRE = yes;
|
||||||
|
BT_HCIUART_RTL = yes;
|
||||||
|
RTL8XXXU_UNTESTED = yes;
|
||||||
|
BT_BNEP_MC_FILTER = yes;
|
||||||
|
BT_BNEP_PROTO_FILTER = yes;
|
||||||
|
BT_HS = yes;
|
||||||
|
BT_LE = yes;
|
||||||
|
# relevant configs inherited from nixos defaults (or above additions):
|
||||||
|
# CONFIG_BT=m
|
||||||
|
# CONFIG_BT_BREDR=y
|
||||||
|
# CONFIG_BT_RFCOMM=m
|
||||||
|
# CONFIG_BT_RFCOMM_TTY=y
|
||||||
|
# CONFIG_BT_BNEP=m
|
||||||
|
# CONFIG_BT_HIDP=m
|
||||||
|
# CONFIG_BT_RTL=m
|
||||||
|
# CONFIG_BT_HCIBTUSB=m
|
||||||
|
# CONFIG_BT_HCIBTUSB_BCM=y
|
||||||
|
# CONFIG_BT_HCIBTUSB_RTL=y
|
||||||
|
# CONFIG_BT_HCIUART=m
|
||||||
|
# CONFIG_BT_HCIUART_SERDEV=y
|
||||||
|
# CONFIG_BT_HCIUART_H4=y
|
||||||
|
# CONFIG_BT_HCIUART_LL=y
|
||||||
|
# CONFIG_RTL_CARDS=m
|
||||||
|
# CONFIG_RTLWIFI=m
|
||||||
|
# CONFIG_RTLWIFI_PCI=m
|
||||||
|
# CONFIG_RTLWIFI_USB=m
|
||||||
|
# CONFIG_RTLWIFI_DEBUG=y
|
||||||
|
# CONFIG_RTL8723_COMMON=m
|
||||||
|
# CONFIG_RTLBTCOEXIST=m
|
||||||
|
# CONFIG_RTL8XXXU=m
|
||||||
|
# CONFIG_RTLLIB=m
|
||||||
|
# consider adding (from mobile-nixos):
|
||||||
|
# maybe: CONFIG_BT_HCIUART_3WIRE=y
|
||||||
|
# maybe: CONFIG_BT_HCIUART_RTL=y
|
||||||
|
# maybe: CONFIG_RTL8XXXU_UNTESTED=y
|
||||||
|
# consider adding (from manjaro):
|
||||||
|
# CONFIG_BT_6LOWPAN=m (not listed as option in nixos kernel)
|
||||||
|
# these are referenced in the rtl8723 source, but not known to config (and not in mobile-nixos config
|
||||||
|
# maybe: CONFIG_RTL_ODM_WLAN_DRIVER
|
||||||
|
# maybe: CONFIG_RTL_TRIBAND_SUPPORT
|
||||||
|
# maybe: CONFIG_SDIO_HCI
|
||||||
|
# maybe: CONFIG_USB_HCI
|
||||||
|
};
|
||||||
|
|
||||||
|
# create a kernelPatch which overrides nixos' defconfig with extra options
|
||||||
|
patchDefconfig = config: {
|
||||||
|
# defconfig options. this method comes from here:
|
||||||
|
# - https://discourse.nixos.org/t/the-correct-way-to-override-the-latest-kernel-config/533/9
|
||||||
|
name = "sane-moby-defconfig";
|
||||||
|
patch = null;
|
||||||
|
extraStructuredConfig = config;
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
# use Megi's kernel:
|
||||||
|
# even with the Manjaro patches, stock 5.18 has a few issues on Pinephone:
|
||||||
|
# - no battery charging
|
||||||
|
# - phone rotation sensor is off by 90 degrees
|
||||||
|
# - ambient light sensor causes screen brightness to be shakey
|
||||||
|
# - phosh greeter may not appear after wake from sleep
|
||||||
|
boot.kernelPackages = pkgs.linuxPackagesFor pkgs.linux-megous;
|
||||||
|
|
||||||
|
boot.kernelPatches = [
|
||||||
|
(patchDefconfig (kernelConfig //
|
||||||
|
(with lib.kernel; {
|
||||||
|
# disabling the sun5i_eink driver avoids this compilation error:
|
||||||
|
# CC [M] drivers/video/fbdev/sun5i-eink-neon.o
|
||||||
|
# aarch64-unknown-linux-gnu-gcc: error: unrecognized command line option '-mfloat-abi=softfp'
|
||||||
|
# aarch64-unknown-linux-gnu-gcc: error: unrecognized command line option '-mfpu=neon'
|
||||||
|
# make[3]: *** [../scripts/Makefile.build:289: drivers/video/fbdev/sun5i-eink-neon.o] Error 1
|
||||||
|
FB_SUN5I_EINK = no;
|
||||||
|
# used by the pinephone pro, but fails to compile with:
|
||||||
|
# ../drivers/media/i2c/ov8858.c:1834:27: error: implicit declaration of function 'compat_ptr'
|
||||||
|
VIDEO_OV8858 = no;
|
||||||
|
})
|
||||||
|
))
|
||||||
|
];
|
||||||
|
|
||||||
|
# alternatively, use nixos' kernel and add the stuff we want:
|
||||||
|
# # cross-compilation optimization:
|
||||||
|
# boot.kernelPackages =
|
||||||
|
# let p = (import nixpkgs { localSystem = "x86_64-linux"; });
|
||||||
|
# in p.pkgsCross.aarch64-multiplatform.linuxPackages_5_18;
|
||||||
|
# # non-cross:
|
||||||
|
# # boot.kernelPackages = pkgs.linuxPackages_5_18;
|
||||||
|
|
||||||
|
# boot.kernelPatches = manjaroPatches ++ [
|
||||||
|
# (patchDefconfig kernelConfig)
|
||||||
|
# ];
|
||||||
|
}
|
||||||
148
hosts/by-name/moby/ucm2/PinePhone/HiFi.conf
Normal file
148
hosts/by-name/moby/ucm2/PinePhone/HiFi.conf
Normal file
@@ -0,0 +1,148 @@
|
|||||||
|
SectionVerb {
|
||||||
|
EnableSequence [
|
||||||
|
cset "name='Headphone Playback Switch' off"
|
||||||
|
cset "name='Headphone Source Playback Route' DAC"
|
||||||
|
cset "name='Line In Playback Switch' off"
|
||||||
|
cset "name='Line Out Playback Switch' off"
|
||||||
|
cset "name='Line Out Source Playback Route' Mono Differential"
|
||||||
|
cset "name='Mic1 Playback Switch' off"
|
||||||
|
cset "name='Mic2 Playback Switch' off"
|
||||||
|
cset "name='AIF1 DA0 Playback Volume' 160"
|
||||||
|
cset "name='AIF3 ADC Source Capture Route' None"
|
||||||
|
cset "name='AIF2 DAC Source Playback Route' AIF2"
|
||||||
|
cset "name='DAC Playback Switch' on"
|
||||||
|
cset "name='DAC Playback Volume' 160"
|
||||||
|
cset "name='ADC Digital DAC Playback Switch' off"
|
||||||
|
cset "name='AIF1 Slot 0 Digital DAC Playback Switch' on"
|
||||||
|
cset "name='AIF2 Digital DAC Playback Switch' off"
|
||||||
|
cset "name='DAC Reversed Playback Switch' off"
|
||||||
|
cset "name='Earpiece Playback Switch' off"
|
||||||
|
cset "name='Earpiece Source Playback Route' DACL"
|
||||||
|
|
||||||
|
cset "name='Line In Capture Switch' off"
|
||||||
|
cset "name='Mic1 Capture Switch' off"
|
||||||
|
cset "name='Mic1 Boost Volume' 7"
|
||||||
|
cset "name='Mic2 Capture Switch' off"
|
||||||
|
cset "name='Mic2 Boost Volume' 7"
|
||||||
|
cset "name='Mixer Capture Switch' off"
|
||||||
|
cset "name='Mixer Reversed Capture Switch' off"
|
||||||
|
cset "name='ADC Capture Volume' 160"
|
||||||
|
cset "name='ADC Gain Capture Volume' 7"
|
||||||
|
cset "name='AIF1 AD0 Capture Volume' 160"
|
||||||
|
cset "name='AIF1 Data Digital ADC Capture Switch' on"
|
||||||
|
cset "name='AIF2 ADC Mixer ADC Capture Switch' off"
|
||||||
|
cset "name='AIF2 ADC Mixer AIF1 DA0 Capture Switch' off"
|
||||||
|
cset "name='AIF2 ADC Mixer AIF2 DAC Rev Capture Switch' off"
|
||||||
|
cset "name='AIF2 ADC Mixer AIF1 DA0 Capture Switch' off"
|
||||||
|
cset "name='AIF2 ADC Mixer AIF1 DA0 Capture Switch' off"
|
||||||
|
]
|
||||||
|
|
||||||
|
DisableSequence [
|
||||||
|
]
|
||||||
|
|
||||||
|
Value {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SectionDevice."Speaker" {
|
||||||
|
Comment "Internal speaker"
|
||||||
|
EnableSequence [
|
||||||
|
cset "name='AIF1 DA0 Stereo Playback Route' Mix Mono"
|
||||||
|
cset "name='Line Out Playback Switch' on"
|
||||||
|
cset "name='Line Out Playback Volume' 100%"
|
||||||
|
]
|
||||||
|
|
||||||
|
DisableSequence [
|
||||||
|
cset "name='Line Out Playback Switch' off"
|
||||||
|
]
|
||||||
|
|
||||||
|
Value {
|
||||||
|
PlaybackVolume "Line Out Playback Volume"
|
||||||
|
PlaybackSwitch "Line Out Playback Switch"
|
||||||
|
PlaybackChannels 2
|
||||||
|
PlaybackPriority 300
|
||||||
|
PlaybackPCM "hw:${CardId},0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SectionDevice."Earpiece" {
|
||||||
|
Comment "Internal Earpiece"
|
||||||
|
EnableSequence [
|
||||||
|
cset "name='AIF1 DA0 Stereo Playback Route' Mix Mono"
|
||||||
|
cset "name='Earpiece Playback Switch' on"
|
||||||
|
cset "name='Earpiece Playback Volume' 100%"
|
||||||
|
]
|
||||||
|
|
||||||
|
DisableSequence [
|
||||||
|
cset "name='Earpiece Playback Switch' off"
|
||||||
|
]
|
||||||
|
|
||||||
|
Value {
|
||||||
|
PlaybackVolume "Earpiece Playback Volume"
|
||||||
|
PlaybackSwitch "Earpiece Playback Switch"
|
||||||
|
PlaybackChannels 2
|
||||||
|
PlaybackPriority 200
|
||||||
|
PlaybackPCM "hw:${CardId},0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SectionDevice."Mic" {
|
||||||
|
Comment "Internal Microphone"
|
||||||
|
ConflictingDevice [
|
||||||
|
"Headset"
|
||||||
|
]
|
||||||
|
EnableSequence [
|
||||||
|
cset "name='Mic1 Capture Switch' on"
|
||||||
|
]
|
||||||
|
DisableSequence [
|
||||||
|
cset "name='Mic1 Capture Switch' off"
|
||||||
|
]
|
||||||
|
Value {
|
||||||
|
CapturePriority 100
|
||||||
|
CapturePCM "hw:${CardId},0"
|
||||||
|
CaptureChannels 2
|
||||||
|
CaptureMixerElem "ADC"
|
||||||
|
CaptureVolume "ADC Capture Volume"
|
||||||
|
CaptureSwitch "Mic1 Capture Switch"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SectionDevice."Headset" {
|
||||||
|
Comment "Headset Microphone"
|
||||||
|
ConflictingDevice [
|
||||||
|
"Mic"
|
||||||
|
]
|
||||||
|
EnableSequence [
|
||||||
|
cset "name='Mic2 Capture Switch' on"
|
||||||
|
]
|
||||||
|
DisableSequence [
|
||||||
|
cset "name='Mic2 Capture Switch' off"
|
||||||
|
]
|
||||||
|
Value {
|
||||||
|
CapturePriority 500
|
||||||
|
CapturePCM "hw:${CardId},0"
|
||||||
|
CaptureChannels 2
|
||||||
|
CaptureMixerElem "ADC"
|
||||||
|
CaptureVolume "ADC Capture Volume"
|
||||||
|
CaptureSwitch "Mic2 Capture Switch"
|
||||||
|
JackControl "Headset Microphone Jack"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SectionDevice."Headphones" {
|
||||||
|
Comment "Headphones"
|
||||||
|
EnableSequence [
|
||||||
|
cset "name='AIF1 DA0 Stereo Playback Route' Stereo"
|
||||||
|
cset "name='Headphone Playback Switch' on"
|
||||||
|
cset "name='Headphone Playback Volume' 70%"
|
||||||
|
]
|
||||||
|
|
||||||
|
DisableSequence [
|
||||||
|
cset "name='Headphone Playback Switch' off"
|
||||||
|
]
|
||||||
|
|
||||||
|
Value {
|
||||||
|
PlaybackVolume "Headphone Playback Volume"
|
||||||
|
PlaybackSwitch "Headphone Playback Switch"
|
||||||
|
PlaybackChannels 2
|
||||||
|
PlaybackPriority 500
|
||||||
|
PlaybackPCM "hw:${CardId},0"
|
||||||
|
JackControl "Headphone Jack"
|
||||||
|
}
|
||||||
|
}
|
||||||
11
hosts/by-name/moby/ucm2/PinePhone/PinePhone.conf
Normal file
11
hosts/by-name/moby/ucm2/PinePhone/PinePhone.conf
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
Syntax 2
|
||||||
|
|
||||||
|
SectionUseCase."HiFi" {
|
||||||
|
File "HiFi.conf"
|
||||||
|
Comment "Default"
|
||||||
|
}
|
||||||
|
|
||||||
|
SectionUseCase."Voice Call" {
|
||||||
|
File "VoiceCall.conf"
|
||||||
|
Comment "Phone call"
|
||||||
|
}
|
||||||
153
hosts/by-name/moby/ucm2/PinePhone/VoiceCall.conf
Normal file
153
hosts/by-name/moby/ucm2/PinePhone/VoiceCall.conf
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
SectionVerb {
|
||||||
|
EnableSequence [
|
||||||
|
cset "name='Headphone Playback Switch' off"
|
||||||
|
cset "name='Headphone Source Playback Route' DAC"
|
||||||
|
cset "name='Line In Playback Switch' off"
|
||||||
|
cset "name='Line Out Playback Switch' off"
|
||||||
|
cset "name='Line Out Source Playback Route' Mono Differential"
|
||||||
|
cset "name='Mic1 Playback Switch' off"
|
||||||
|
cset "name='Mic2 Playback Switch' off"
|
||||||
|
cset "name='AIF1 DA0 Playback Volume' 160"
|
||||||
|
cset "name='AIF2 DAC Playback Volume' 160"
|
||||||
|
cset "name='AIF3 ADC Source Capture Route' None"
|
||||||
|
cset "name='AIF2 DAC Source Playback Route' AIF2"
|
||||||
|
cset "name='DAC Playback Switch' on"
|
||||||
|
cset "name='DAC Playback Volume' 160"
|
||||||
|
cset "name='ADC Digital DAC Playback Switch' off"
|
||||||
|
cset "name='AIF1 Slot 0 Digital DAC Playback Switch' on"
|
||||||
|
cset "name='AIF2 Digital DAC Playback Switch' on"
|
||||||
|
cset "name='DAC Reversed Playback Switch' off"
|
||||||
|
cset "name='Earpiece Playback Switch' off"
|
||||||
|
cset "name='Earpiece Source Playback Route' DACL"
|
||||||
|
|
||||||
|
cset "name='Line In Capture Switch' off"
|
||||||
|
cset "name='Mic1 Capture Switch' off"
|
||||||
|
cset "name='Mic1 Boost Volume' 0"
|
||||||
|
cset "name='Mic1 Playback Volume' 7"
|
||||||
|
cset "name='Mic2 Capture Switch' off"
|
||||||
|
cset "name='Mic2 Boost Volume' 0"
|
||||||
|
cset "name='Mic2 Playback Volume' 7"
|
||||||
|
cset "name='Mixer Capture Switch' off"
|
||||||
|
cset "name='Mixer Reversed Capture Switch' off"
|
||||||
|
cset "name='ADC Capture Volume' 160"
|
||||||
|
cset "name='ADC Gain Capture Volume' 7"
|
||||||
|
cset "name='AIF1 AD0 Capture Volume' 160"
|
||||||
|
cset "name='AIF1 Data Digital ADC Capture Switch' on"
|
||||||
|
cset "name='AIF2 ADC Capture Volume' 160"
|
||||||
|
cset "name='AIF2 ADC Mixer ADC Capture Switch' on"
|
||||||
|
cset "name='AIF2 ADC Mixer AIF1 DA0 Capture Switch' off"
|
||||||
|
cset "name='AIF2 ADC Mixer AIF2 DAC Rev Capture Switch' off"
|
||||||
|
cset "name='AIF2 ADC Mixer AIF1 DA0 Capture Switch' off"
|
||||||
|
cset "name='AIF2 ADC Mixer AIF1 DA0 Capture Switch' off"
|
||||||
|
]
|
||||||
|
|
||||||
|
DisableSequence [
|
||||||
|
]
|
||||||
|
|
||||||
|
Value {
|
||||||
|
PlaybackRate 8000
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SectionDevice."Speaker" {
|
||||||
|
Comment "Internal speaker"
|
||||||
|
EnableSequence [
|
||||||
|
cset "name='AIF1 DA0 Stereo Playback Route' Mix Mono"
|
||||||
|
cset "name='Line Out Playback Switch' on"
|
||||||
|
cset "name='Line Out Playback Volume' 100%"
|
||||||
|
]
|
||||||
|
|
||||||
|
DisableSequence [
|
||||||
|
cset "name='Line Out Playback Switch' off"
|
||||||
|
]
|
||||||
|
|
||||||
|
Value {
|
||||||
|
PlaybackVolume "Line Out Playback Volume"
|
||||||
|
PlaybackSwitch "Line Out Playback Switch"
|
||||||
|
PlaybackChannels 2
|
||||||
|
PlaybackPriority 300
|
||||||
|
PlaybackPCM "hw:${CardId},0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SectionDevice."Earpiece" {
|
||||||
|
Comment "Internal Earpiece"
|
||||||
|
EnableSequence [
|
||||||
|
cset "name='AIF1 DA0 Stereo Playback Route' Mix Mono"
|
||||||
|
cset "name='Earpiece Playback Switch' on"
|
||||||
|
cset "name='Earpiece Playback Volume' 100%"
|
||||||
|
]
|
||||||
|
|
||||||
|
DisableSequence [
|
||||||
|
cset "name='Earpiece Playback Switch' off"
|
||||||
|
]
|
||||||
|
|
||||||
|
Value {
|
||||||
|
PlaybackVolume "Earpiece Playback Volume"
|
||||||
|
PlaybackSwitch "Earpiece Playback Switch"
|
||||||
|
PlaybackChannels 2
|
||||||
|
PlaybackPriority 500
|
||||||
|
PlaybackPCM "hw:${CardId},0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SectionDevice."Mic" {
|
||||||
|
Comment "Internal Microphone"
|
||||||
|
ConflictingDevice [
|
||||||
|
"Headset"
|
||||||
|
]
|
||||||
|
EnableSequence [
|
||||||
|
cset "name='Mic1 Capture Switch' on"
|
||||||
|
]
|
||||||
|
DisableSequence [
|
||||||
|
cset "name='Mic1 Capture Switch' off"
|
||||||
|
]
|
||||||
|
Value {
|
||||||
|
CapturePriority 200
|
||||||
|
CapturePCM "hw:${CardId},0"
|
||||||
|
CaptureMixerElem "ADC"
|
||||||
|
CaptureVolume "ADC Capture Volume"
|
||||||
|
CaptureSwitch "Mic1 Capture Switch"
|
||||||
|
CaptureChannels 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SectionDevice."Headset" {
|
||||||
|
Comment "Headset Microphone"
|
||||||
|
ConflictingDevice [
|
||||||
|
"Mic"
|
||||||
|
]
|
||||||
|
EnableSequence [
|
||||||
|
cset "name='Mic2 Capture Switch' on"
|
||||||
|
]
|
||||||
|
DisableSequence [
|
||||||
|
cset "name='Mic2 Capture Switch' off"
|
||||||
|
]
|
||||||
|
Value {
|
||||||
|
CapturePriority 500
|
||||||
|
CapturePCM "hw:${CardId},0"
|
||||||
|
CaptureChannels 2
|
||||||
|
CaptureMixerElem "ADC"
|
||||||
|
CaptureVolume "ADC Capture Volume"
|
||||||
|
CaptureSwitch "Mic2 Capture Switch"
|
||||||
|
JackControl "Headset Microphone Jack"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SectionDevice."Headphones" {
|
||||||
|
Comment "Headphones"
|
||||||
|
EnableSequence [
|
||||||
|
cset "name='AIF1 DA0 Stereo Playback Route' Stereo"
|
||||||
|
cset "name='Headphone Playback Switch' on"
|
||||||
|
cset "name='Headphone Playback Volume' 100%"
|
||||||
|
]
|
||||||
|
|
||||||
|
DisableSequence [
|
||||||
|
cset "name='Headphone Playback Switch' off"
|
||||||
|
]
|
||||||
|
|
||||||
|
Value {
|
||||||
|
PlaybackVolume "Headphone Playback Volume"
|
||||||
|
PlaybackSwitch "Headphone Playback Switch"
|
||||||
|
PlaybackChannels 2
|
||||||
|
PlaybackPriority 500
|
||||||
|
PlaybackPCM "hw:${CardId},0"
|
||||||
|
JackControl "Headphone Jack"
|
||||||
|
}
|
||||||
|
}
|
||||||
8
hosts/by-name/moby/ucm2/ucm.conf
Normal file
8
hosts/by-name/moby/ucm2/ucm.conf
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
Syntax 3
|
||||||
|
|
||||||
|
UseCasePath {
|
||||||
|
legacy {
|
||||||
|
Directory "PinePhone"
|
||||||
|
File "PinePhone.conf"
|
||||||
|
}
|
||||||
|
}
|
||||||
15
hosts/by-name/rescue/default.nix
Normal file
15
hosts/by-name/rescue/default.nix
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
{ pkgs, ... }:
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
./fs.nix
|
||||||
|
];
|
||||||
|
|
||||||
|
boot.loader.generic-extlinux-compatible.enable = true;
|
||||||
|
boot.loader.efi.canTouchEfiVariables = false;
|
||||||
|
sane.image.extraBootFiles = [ pkgs.bootpart-uefi-x86_64 ];
|
||||||
|
# sane.persist.enable = false; # TODO: disable (but run `nix flake check` to ensure it works!)
|
||||||
|
sane.nixcache.enable = false; # don't want to be calling out to dead machines that we're *trying* to rescue
|
||||||
|
|
||||||
|
# docs: https://nixos.org/manual/nixos/stable/options.html#opt-system.stateVersion
|
||||||
|
system.stateVersion = "21.05";
|
||||||
|
}
|
||||||
12
hosts/by-name/rescue/fs.nix
Normal file
12
hosts/by-name/rescue/fs.nix
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
{ ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
fileSystems."/" = {
|
||||||
|
device = "/dev/disk/by-uuid/44445555-6666-7777-8888-999900001111";
|
||||||
|
fsType = "ext4";
|
||||||
|
};
|
||||||
|
fileSystems."/boot" = {
|
||||||
|
device = "/dev/disk/by-uuid/2222-3333";
|
||||||
|
fsType = "vfat";
|
||||||
|
};
|
||||||
|
}
|
||||||
47
hosts/by-name/servo/default.nix
Normal file
47
hosts/by-name/servo/default.nix
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
{ config, pkgs, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
./fs.nix
|
||||||
|
./net.nix
|
||||||
|
./secrets.nix
|
||||||
|
./services
|
||||||
|
];
|
||||||
|
|
||||||
|
sane.programs = {
|
||||||
|
# for administering services
|
||||||
|
freshrss.enableFor.user.colin = true;
|
||||||
|
matrix-synapse.enableFor.user.colin = true;
|
||||||
|
signaldctl.enableFor.user.colin = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
sane.roles.build-machine.enable = true;
|
||||||
|
sane.roles.build-machine.emulation = false;
|
||||||
|
sane.zsh.showDeadlines = false; # ~/knowledge doesn't always exist
|
||||||
|
sane.services.dyn-dns.enable = true;
|
||||||
|
sane.services.wg-home.enable = true;
|
||||||
|
sane.services.wg-home.ip = config.sane.hosts.by-name."servo".wg-home.ip;
|
||||||
|
# sane.services.duplicity.enable = true; # TODO: re-enable after HW upgrade
|
||||||
|
|
||||||
|
# automatically log in at the virtual consoles.
|
||||||
|
# using root here makes sure we always have an escape hatch
|
||||||
|
services.getty.autologinUser = "root";
|
||||||
|
|
||||||
|
boot.loader.efi.canTouchEfiVariables = false;
|
||||||
|
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 = {
|
||||||
|
"net.core.rmem_max" = 4194304; # 4MB
|
||||||
|
};
|
||||||
|
|
||||||
|
# This value determines the NixOS release from which the default
|
||||||
|
# settings for stateful data, like file locations and database versions
|
||||||
|
# on your system were taken. It‘s perfectly fine and recommended to leave
|
||||||
|
# this value at the release version of the first install of this system.
|
||||||
|
# Before changing this value read the documentation for this option
|
||||||
|
# (e.g. man configuration.nix or on https://nixos.org/nixos/options.html).
|
||||||
|
system.stateVersion = "21.11";
|
||||||
|
}
|
||||||
|
|
||||||
93
hosts/by-name/servo/fs.nix
Normal file
93
hosts/by-name/servo/fs.nix
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
{ ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
sane.persist.root-on-tmpfs = true;
|
||||||
|
# we need a /tmp for building large nix things
|
||||||
|
fileSystems."/tmp" = {
|
||||||
|
device = "none";
|
||||||
|
fsType = "tmpfs";
|
||||||
|
options = [
|
||||||
|
"mode=777"
|
||||||
|
"defaults"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
fileSystems."/nix" = {
|
||||||
|
device = "/dev/disk/by-uuid/cc81cca0-3cc7-4d82-a00c-6243af3e7776";
|
||||||
|
fsType = "btrfs";
|
||||||
|
options = [
|
||||||
|
"compress=zstd"
|
||||||
|
"defaults"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
fileSystems."/boot" = {
|
||||||
|
device = "/dev/disk/by-uuid/6EE3-4171";
|
||||||
|
fsType = "vfat";
|
||||||
|
};
|
||||||
|
|
||||||
|
# slow, external storage (for archiving, etc)
|
||||||
|
fileSystems."/mnt/persist/ext" = {
|
||||||
|
device = "/dev/disk/by-uuid/aa272cff-0fcc-498e-a4cb-0d95fb60631b";
|
||||||
|
fsType = "btrfs";
|
||||||
|
options = [
|
||||||
|
"compress=zstd"
|
||||||
|
"defaults"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
sane.persist.stores."ext" = {
|
||||||
|
origin = "/mnt/persist/ext/persist";
|
||||||
|
storeDescription = "external HDD storage";
|
||||||
|
};
|
||||||
|
sane.fs."/mnt/persist/ext".mount = {};
|
||||||
|
|
||||||
|
sane.persist.sys.plaintext = [
|
||||||
|
# TODO: this is overly broad; only need media and share directories to be persisted
|
||||||
|
{ user = "colin"; group = "users"; directory = "/var/lib/uninsane"; }
|
||||||
|
];
|
||||||
|
# make sure large media is stored to the HDD
|
||||||
|
sane.persist.sys.ext = [
|
||||||
|
{
|
||||||
|
user = "colin";
|
||||||
|
group = "users";
|
||||||
|
mode = "0777";
|
||||||
|
directory = "/var/lib/uninsane/media/Videos";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
user = "colin";
|
||||||
|
group = "users";
|
||||||
|
mode = "0777";
|
||||||
|
directory = "/var/lib/uninsane/media/freeleech";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
# in-memory compressed RAM (seems to be dynamically sized)
|
||||||
|
# zramSwap = {
|
||||||
|
# enable = true;
|
||||||
|
# };
|
||||||
|
|
||||||
|
# btrfs doesn't easily support swapfiles
|
||||||
|
# swapDevices = [
|
||||||
|
# { device = "/nix/persist/swapfile"; size = 4096; }
|
||||||
|
# ];
|
||||||
|
|
||||||
|
# this can be a partition. create with:
|
||||||
|
# fdisk <dev>
|
||||||
|
# n
|
||||||
|
# <default partno>
|
||||||
|
# <start>
|
||||||
|
# <end>
|
||||||
|
# t
|
||||||
|
# <partno>
|
||||||
|
# 19 # set part type to Linux swap
|
||||||
|
# w # write changes
|
||||||
|
# mkswap -L swap <part>
|
||||||
|
# swapDevices = [
|
||||||
|
# {
|
||||||
|
# label = "swap";
|
||||||
|
# # TODO: randomEncryption.enable = true;
|
||||||
|
# }
|
||||||
|
# ];
|
||||||
|
}
|
||||||
|
|
||||||
209
hosts/by-name/servo/net.nix
Normal file
209
hosts/by-name/servo/net.nix
Normal file
@@ -0,0 +1,209 @@
|
|||||||
|
{ config, pkgs, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
networking.domain = "uninsane.org";
|
||||||
|
|
||||||
|
# The global useDHCP flag is deprecated, therefore explicitly set to false here.
|
||||||
|
# Per-interface useDHCP will be mandatory in the future, so this generated config
|
||||||
|
# replicates the default behaviour.
|
||||||
|
networking.useDHCP = false;
|
||||||
|
networking.interfaces.eth0.useDHCP = true;
|
||||||
|
# XXX colin: probably don't need this. wlan0 won't be populated unless i touch a value in networking.interfaces.wlan0
|
||||||
|
networking.wireless.enable = false;
|
||||||
|
|
||||||
|
# networking.firewall.enable = false;
|
||||||
|
networking.firewall.enable = true;
|
||||||
|
|
||||||
|
# this is needed to forward packets from the VPN to the host
|
||||||
|
boot.kernel.sysctl."net.ipv4.ip_forward" = 1;
|
||||||
|
|
||||||
|
# unless we add interface-specific settings for each VPN, we have to define nameservers globally.
|
||||||
|
# networking.nameservers = [
|
||||||
|
# "1.1.1.1"
|
||||||
|
# "9.9.9.9"
|
||||||
|
# ];
|
||||||
|
|
||||||
|
# use systemd's stub resolver.
|
||||||
|
# /etc/resolv.conf isn't sophisticated enough to use different servers per net namespace (or link).
|
||||||
|
# instead, running the stub resolver on a known address in the root ns lets us rewrite packets
|
||||||
|
# in the ovnps namespace to use the provider's DNS resolvers.
|
||||||
|
# a weakness is we can only query 1 NS at a time (unless we were to clone the packets?)
|
||||||
|
# there also seems to be some cache somewhere that's shared between the two namespaces.
|
||||||
|
# i think this is a libc thing. might need to leverage proper cgroups to _really_ kill it.
|
||||||
|
# - getent ahostsv4 www.google.com
|
||||||
|
# - try fix: <https://serverfault.com/questions/765989/connect-to-3rd-party-vpn-server-but-dont-use-it-as-the-default-route/766290#766290>
|
||||||
|
services.resolved.enable = true;
|
||||||
|
networking.nameservers = [
|
||||||
|
# use systemd-resolved resolver
|
||||||
|
# full resolver (which understands /etc/hosts) lives on 127.0.0.53
|
||||||
|
# stub resolver (just forwards upstream) lives on 127.0.0.54
|
||||||
|
"127.0.0.53"
|
||||||
|
];
|
||||||
|
|
||||||
|
# nscd -- the Name Service Caching Daemon -- caches DNS query responses
|
||||||
|
# in a way that's unaware of my VPN routing, so routes are frequently poor against
|
||||||
|
# services which advertise different IPs based on geolocation.
|
||||||
|
# nscd claims to be usable without a cache, but in practice i can't get it to not cache!
|
||||||
|
# nsncd is the Name Service NON-Caching Daemon. it's a drop-in that doesn't cache;
|
||||||
|
# this is OK on the host -- because systemd-resolved caches. it's probably sub-optimal
|
||||||
|
# in the netns and we query upstream DNS more often than needed. hm.
|
||||||
|
# TODO: run a separate recursive resolver in each namespace.
|
||||||
|
services.nscd.enableNsncd = true;
|
||||||
|
|
||||||
|
# services.resolved.extraConfig = ''
|
||||||
|
# # docs: `man resolved.conf`
|
||||||
|
# # DNS servers to use via the `wg-ovpns` interface.
|
||||||
|
# # i hope that from the root ns, these aren't visible.
|
||||||
|
# DNS=46.227.67.134%wg-ovpns 192.165.9.158%wg-ovpns
|
||||||
|
# FallbackDNS=1.1.1.1 9.9.9.9
|
||||||
|
# '';
|
||||||
|
|
||||||
|
# OVPN CONFIG (https://www.ovpn.com):
|
||||||
|
# DOCS: https://nixos.wiki/wiki/WireGuard
|
||||||
|
# if you `systemctl restart wireguard-wg-ovpns`, make sure to also restart any other services in `NetworkNamespacePath = .../ovpns`.
|
||||||
|
# TODO: why not create the namespace as a seperate operation (nix config for that?)
|
||||||
|
networking.wireguard.enable = true;
|
||||||
|
networking.wireguard.interfaces.wg-ovpns = let
|
||||||
|
ip = "${pkgs.iproute2}/bin/ip";
|
||||||
|
in-ns = "${ip} netns exec ovpns";
|
||||||
|
iptables = "${pkgs.iptables}/bin/iptables";
|
||||||
|
veth-host-ip = "10.0.1.5";
|
||||||
|
veth-local-ip = "10.0.1.6";
|
||||||
|
vpn-ip = "185.157.162.178";
|
||||||
|
# DNS = 46.227.67.134, 192.165.9.158, 2a07:a880:4601:10f0:cd45::1, 2001:67c:750:1:cafe:cd45::1
|
||||||
|
vpn-dns = "46.227.67.134";
|
||||||
|
in {
|
||||||
|
privateKeyFile = config.sops.secrets.wg_ovpns_privkey.path;
|
||||||
|
# wg is active only in this namespace.
|
||||||
|
# run e.g. ip netns exec ovpns <some command like ping/curl/etc, it'll go through wg>
|
||||||
|
# sudo ip netns exec ovpns ping www.google.com
|
||||||
|
interfaceNamespace = "ovpns";
|
||||||
|
ips = [
|
||||||
|
"185.157.162.178/32"
|
||||||
|
];
|
||||||
|
peers = [
|
||||||
|
{
|
||||||
|
publicKey = "SkkEZDCBde22KTs/Hc7FWvDBfdOCQA4YtBEuC3n5KGs=";
|
||||||
|
endpoint = "185.157.162.10:9930";
|
||||||
|
# alternatively: use hostname, but that presents bootstrapping issues (e.g. if host net flakes)
|
||||||
|
# endpoint = "vpn36.prd.amsterdam.ovpn.com:9930";
|
||||||
|
allowedIPs = [ "0.0.0.0/0" ];
|
||||||
|
# nixOS says this is important for keeping NATs active
|
||||||
|
persistentKeepalive = 25;
|
||||||
|
# re-executes wg this often. docs hint that this might help wg notice DNS/hostname changes.
|
||||||
|
# so, maybe that helps if we specify endpoint as a domain name
|
||||||
|
# dynamicEndpointRefreshSeconds = 30;
|
||||||
|
# when refresh fails, try it again after this period instead.
|
||||||
|
# TODO: not avail until nixpkgs upgrade
|
||||||
|
# dynamicEndpointRefreshRestartSeconds = 5;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
preSetup = "" + ''
|
||||||
|
${ip} netns add ovpns || echo "ovpns already exists"
|
||||||
|
'';
|
||||||
|
postShutdown = "" + ''
|
||||||
|
${in-ns} ip link del ovpns-veth-b || echo "couldn't delete ovpns-veth-b"
|
||||||
|
${ip} link del ovpns-veth-a || echo "couldn't delete ovpns-veth-a"
|
||||||
|
${ip} netns delete ovpns || echo "couldn't delete ovpns"
|
||||||
|
# restore rules/routes
|
||||||
|
${ip} rule del from ${veth-host-ip} lookup ovpns pref 50 || echo "couldn't delete init -> ovpns rule"
|
||||||
|
${ip} route del default via ${veth-local-ip} dev ovpns-veth-a proto kernel src ${veth-host-ip} metric 1002 table ovpns || echo "couldn't delete init -> ovpns route"
|
||||||
|
${ip} rule add from all lookup local pref 0
|
||||||
|
${ip} rule del from all lookup local pref 100
|
||||||
|
'';
|
||||||
|
postSetup = "" + ''
|
||||||
|
# DOCS:
|
||||||
|
# - some of this approach is described here: <https://josephmuia.ca/2018-05-16-net-namespaces-veth-nat/>
|
||||||
|
# - iptables primer: <https://danielmiessler.com/study/iptables/>
|
||||||
|
# create veth pair
|
||||||
|
${ip} link add ovpns-veth-a type veth peer name ovpns-veth-b
|
||||||
|
${ip} addr add ${veth-host-ip}/24 dev ovpns-veth-a
|
||||||
|
${ip} link set ovpns-veth-a up
|
||||||
|
|
||||||
|
# mv veth-b into the ovpns namespace
|
||||||
|
${ip} link set ovpns-veth-b netns ovpns
|
||||||
|
${in-ns} ip addr add ${veth-local-ip}/24 dev ovpns-veth-b
|
||||||
|
${in-ns} ip link set ovpns-veth-b up
|
||||||
|
|
||||||
|
# make it so traffic originating from the host side of the veth
|
||||||
|
# is sent over the veth no matter its destination.
|
||||||
|
${ip} rule add from ${veth-host-ip} lookup ovpns pref 50
|
||||||
|
# for traffic originating at the host veth to the WAN, use the veth as our gateway
|
||||||
|
# not sure if the metric 1002 matters.
|
||||||
|
${ip} route add default via ${veth-local-ip} dev ovpns-veth-a proto kernel src ${veth-host-ip} metric 1002 table ovpns
|
||||||
|
# give the default route lower priority
|
||||||
|
${ip} rule add from all lookup local pref 100
|
||||||
|
${ip} rule del from all lookup local pref 0
|
||||||
|
|
||||||
|
# bridge HTTP traffic:
|
||||||
|
# any external port-80 request sent to the VPN addr will be forwarded to the rootns.
|
||||||
|
# this exists so LetsEncrypt can procure a cert for the MX over http.
|
||||||
|
# TODO: we could use _acme_challence.mx.uninsane.org CNAME to avoid this forwarding
|
||||||
|
# - <https://community.letsencrypt.org/t/where-does-letsencrypt-resolve-dns-from/37607/8>
|
||||||
|
${in-ns} ${iptables} -A PREROUTING -t nat -p tcp --dport 80 -m iprange --dst-range ${vpn-ip} \
|
||||||
|
-j DNAT --to-destination ${veth-host-ip}:80
|
||||||
|
|
||||||
|
# we also bridge DNS traffic
|
||||||
|
${in-ns} ${iptables} -A PREROUTING -t nat -p udp --dport 53 -m iprange --dst-range ${vpn-ip} \
|
||||||
|
-j DNAT --to-destination ${veth-host-ip}:53
|
||||||
|
${in-ns} ${iptables} -A PREROUTING -t nat -p tcp --dport 53 -m iprange --dst-range ${vpn-ip} \
|
||||||
|
-j DNAT --to-destination ${veth-host-ip}:53
|
||||||
|
|
||||||
|
# in order to access DNS in this netns, we need to route it to the VPN's nameservers
|
||||||
|
# - alternatively, we could fix DNS servers like 1.1.1.1.
|
||||||
|
${in-ns} ${iptables} -A OUTPUT -t nat -p udp --dport 53 -m iprange --dst-range 127.0.0.53 \
|
||||||
|
-j DNAT --to-destination ${vpn-dns}:53
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
# create a new routing table that we can use to proxy traffic out of the root namespace
|
||||||
|
# through the ovpns namespace, and to the WAN via VPN.
|
||||||
|
networking.iproute2.rttablesExtraConfig = ''
|
||||||
|
5 ovpns
|
||||||
|
'';
|
||||||
|
networking.iproute2.enable = true;
|
||||||
|
|
||||||
|
|
||||||
|
# HURRICANE ELECTRIC CONFIG:
|
||||||
|
# networking.sits = {
|
||||||
|
# hurricane = {
|
||||||
|
# remote = "216.218.226.238";
|
||||||
|
# local = "192.168.0.5";
|
||||||
|
# # local = "10.0.0.5";
|
||||||
|
# # remote = "10.0.0.1";
|
||||||
|
# # local = "10.0.0.22";
|
||||||
|
# dev = "eth0";
|
||||||
|
# ttl = 255;
|
||||||
|
# };
|
||||||
|
# };
|
||||||
|
# networking.interfaces."hurricane".ipv6 = {
|
||||||
|
# addresses = [
|
||||||
|
# # mx.uninsane.org (publically routed /64)
|
||||||
|
# {
|
||||||
|
# address = "2001:470:b:465::1";
|
||||||
|
# prefixLength = 128;
|
||||||
|
# }
|
||||||
|
# # client addr
|
||||||
|
# # {
|
||||||
|
# # address = "2001:470:a:466::2";
|
||||||
|
# # prefixLength = 64;
|
||||||
|
# # }
|
||||||
|
# ];
|
||||||
|
# routes = [
|
||||||
|
# {
|
||||||
|
# address = "::";
|
||||||
|
# prefixLength = 0;
|
||||||
|
# # via = "2001:470:a:466::1";
|
||||||
|
# }
|
||||||
|
# ];
|
||||||
|
# };
|
||||||
|
|
||||||
|
# # after configuration, we want the hurricane device to look like this:
|
||||||
|
# # hurricane: flags=209<UP,POINTOPOINT,RUNNING,NOARP> mtu 1480
|
||||||
|
# # inet6 2001:470:a:450::2 prefixlen 64 scopeid 0x0<global>
|
||||||
|
# # inet6 fe80::c0a8:16 prefixlen 64 scopeid 0x20<link>
|
||||||
|
# # sit txqueuelen 1000 (IPv6-in-IPv4)
|
||||||
|
# # test with:
|
||||||
|
# # curl --interface hurricane http://[2607:f8b0:400a:80b::2004]
|
||||||
|
# # ping 2607:f8b0:400a:80b::2004
|
||||||
|
}
|
||||||
42
hosts/by-name/servo/secrets.nix
Normal file
42
hosts/by-name/servo/secrets.nix
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
{ ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
sops.secrets."ddns_afraid" = {
|
||||||
|
sopsFile = ../../../secrets/servo.yaml;
|
||||||
|
};
|
||||||
|
sops.secrets."ddns_he" = {
|
||||||
|
sopsFile = ../../../secrets/servo.yaml;
|
||||||
|
};
|
||||||
|
|
||||||
|
sops.secrets."dovecot_passwd" = {
|
||||||
|
sopsFile = ../../../secrets/servo.yaml;
|
||||||
|
};
|
||||||
|
|
||||||
|
sops.secrets."duplicity_passphrase" = {
|
||||||
|
sopsFile = ../../../secrets/servo.yaml;
|
||||||
|
};
|
||||||
|
|
||||||
|
sops.secrets."freshrss_passwd" = {
|
||||||
|
sopsFile = ../../../secrets/servo.yaml;
|
||||||
|
};
|
||||||
|
|
||||||
|
sops.secrets."matrix_synapse_secrets" = {
|
||||||
|
sopsFile = ../../../secrets/servo.yaml;
|
||||||
|
};
|
||||||
|
sops.secrets."mautrix_signal_env" = {
|
||||||
|
sopsFile = ../../../secrets/servo/mautrix_signal_env.bin;
|
||||||
|
format = "binary";
|
||||||
|
};
|
||||||
|
|
||||||
|
sops.secrets."mediawiki_pw" = {
|
||||||
|
sopsFile = ../../../secrets/servo.yaml;
|
||||||
|
};
|
||||||
|
|
||||||
|
sops.secrets."pleroma_secrets" = {
|
||||||
|
sopsFile = ../../../secrets/servo.yaml;
|
||||||
|
};
|
||||||
|
|
||||||
|
sops.secrets."wg_ovpns_privkey" = {
|
||||||
|
sopsFile = ../../../secrets/servo.yaml;
|
||||||
|
};
|
||||||
|
}
|
||||||
27
hosts/by-name/servo/services/ddns-afraid.nix
Normal file
27
hosts/by-name/servo/services/ddns-afraid.nix
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
# using manual ddns now
|
||||||
|
lib.mkIf false
|
||||||
|
{
|
||||||
|
systemd.services.ddns-afraid = {
|
||||||
|
description = "update dynamic DNS entries for freedns.afraid.org";
|
||||||
|
serviceConfig = {
|
||||||
|
EnvironmentFile = config.sops.secrets.ddns_afraid.path;
|
||||||
|
# TODO: ProtectSystem = "strict";
|
||||||
|
# TODO: ProtectHome = "full";
|
||||||
|
# TODO: PrivateTmp = true;
|
||||||
|
};
|
||||||
|
script = let
|
||||||
|
curl = "${pkgs.curl}/bin/curl -4";
|
||||||
|
in ''
|
||||||
|
${curl} "https://freedns.afraid.org/dynamic/update.php?$AFRAID_KEY"
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
systemd.timers.ddns-afraid = {
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
timerConfig = {
|
||||||
|
OnStartupSec = "2min";
|
||||||
|
OnUnitActiveSec = "10min";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
{ config, pkgs, ... }:
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
# we use manual DDNS now
|
||||||
|
lib.mkIf false
|
||||||
{
|
{
|
||||||
systemd.services.ddns-he = {
|
systemd.services.ddns-he = {
|
||||||
description = "update dynamic DNS entries for HurricaneElectric";
|
description = "update dynamic DNS entries for HurricaneElectric";
|
||||||
@@ -25,8 +27,4 @@
|
|||||||
OnUnitActiveSec = "10min";
|
OnUnitActiveSec = "10min";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
sops.secrets."ddns_he" = {
|
|
||||||
sopsFile = ../../../secrets/servo.yaml;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
26
hosts/by-name/servo/services/default.nix
Normal file
26
hosts/by-name/servo/services/default.nix
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
{ ... }:
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
./ddns-afraid.nix
|
||||||
|
./ddns-he.nix
|
||||||
|
./ejabberd.nix
|
||||||
|
./freshrss.nix
|
||||||
|
./gitea.nix
|
||||||
|
./goaccess.nix
|
||||||
|
./ipfs.nix
|
||||||
|
./jackett.nix
|
||||||
|
./jellyfin.nix
|
||||||
|
./kiwix-serve.nix
|
||||||
|
./matrix
|
||||||
|
./navidrome.nix
|
||||||
|
./nixserve.nix
|
||||||
|
./nginx.nix
|
||||||
|
./pleroma.nix
|
||||||
|
./postfix.nix
|
||||||
|
./postgres.nix
|
||||||
|
./prosody.nix
|
||||||
|
./transmission.nix
|
||||||
|
./trust-dns.nix
|
||||||
|
./wikipedia.nix
|
||||||
|
];
|
||||||
|
}
|
||||||
395
hosts/by-name/servo/services/ejabberd.nix
Normal file
395
hosts/by-name/servo/services/ejabberd.nix
Normal file
@@ -0,0 +1,395 @@
|
|||||||
|
# docs:
|
||||||
|
# - <https://docs.ejabberd.im/admin/configuration/basic>
|
||||||
|
# example configs:
|
||||||
|
# - <https://github.com/vkleen/machines/blob/138a2586ce185d7cf201d4e1fe898c83c4af52eb/hosts/europium/ejabberd.nix>
|
||||||
|
# - <https://github.com/Mic92/stockholm/blob/675ef0088624c9de1cb531f318446316884a9d3d/tv/3modules/ejabberd/default.nix>
|
||||||
|
# - <https://github.com/buffet/tararice/blob/master/programs/ejabberd.nix>
|
||||||
|
# - enables STUN and TURN
|
||||||
|
# - only over UDP 3478, not firewall-forwarding any TURN port range
|
||||||
|
# - uses stun_disco module (but with no options)
|
||||||
|
# - <https://github.com/leo60228/dotfiles/blob/39b3abba3009bdc31413d4757ca2f882a33eec8b/files/ejabberd.yml>
|
||||||
|
# - <https://github.com/Mic92/dotfiles/blob/ddf0f4821f554f7667fc803344657367c55fb9e6/nixos/eve/modules/ejabberd.nix>
|
||||||
|
# - <nixpkgs:nixos/tests/xmpp/ejabberd.nix>
|
||||||
|
# - 2013: <https://github.com/processone/ejabberd/blob/master/ejabberd.yml.example>
|
||||||
|
#
|
||||||
|
# compliance tests:
|
||||||
|
# - <https://compliance.conversations.im/server/uninsane.org/#xep0352>
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
# XXX: avatar support works in MUCs but not DMs
|
||||||
|
# lib.mkIf false
|
||||||
|
{
|
||||||
|
sane.persist.sys.plaintext = [
|
||||||
|
{ user = "ejabberd"; group = "ejabberd"; directory = "/var/lib/ejabberd"; }
|
||||||
|
];
|
||||||
|
networking.firewall.allowedTCPPorts = [
|
||||||
|
3478 # STUN/TURN
|
||||||
|
5222 # XMPP client -> server
|
||||||
|
5223 # XMPPS client -> server (XMPP over TLS)
|
||||||
|
5269 # XMPP server -> server
|
||||||
|
5270 # XMPPS server -> server (XMPP over TLS)
|
||||||
|
5280 # bosh
|
||||||
|
5281 # bosh (https) ??
|
||||||
|
5349 # STUN/TURN (TLS)
|
||||||
|
5443 # web services (file uploads, websockets, admin)
|
||||||
|
];
|
||||||
|
networking.firewall.allowedUDPPorts = [
|
||||||
|
3478 # STUN/TURN
|
||||||
|
];
|
||||||
|
networking.firewall.allowedTCPPortRanges = [{
|
||||||
|
from = 49152; # TURN
|
||||||
|
to = 49408;
|
||||||
|
}];
|
||||||
|
networking.firewall.allowedUDPPortRanges = [{
|
||||||
|
from = 49152; # TURN
|
||||||
|
to = 49408;
|
||||||
|
}];
|
||||||
|
|
||||||
|
# provide access to certs
|
||||||
|
# TODO: this should just be `acme`. then we also add nginx to the `acme` group.
|
||||||
|
# why is /var/lib/acme/* owned by `nginx` group??
|
||||||
|
users.users.ejabberd.extraGroups = [ "nginx" ];
|
||||||
|
|
||||||
|
security.acme.certs."uninsane.org".extraDomainNames = [
|
||||||
|
"xmpp.uninsane.org"
|
||||||
|
"muc.xmpp.uninsane.org"
|
||||||
|
"pubsub.xmpp.uninsane.org"
|
||||||
|
"upload.xmpp.uninsane.org"
|
||||||
|
"vjid.xmpp.uninsane.org"
|
||||||
|
];
|
||||||
|
|
||||||
|
# exists so the XMPP server's cert can obtain altNames for all its resources
|
||||||
|
services.nginx.virtualHosts."xmpp.uninsane.org" = {
|
||||||
|
useACMEHost = "uninsane.org";
|
||||||
|
};
|
||||||
|
services.nginx.virtualHosts."muc.xmpp.uninsane.org" = {
|
||||||
|
useACMEHost = "uninsane.org";
|
||||||
|
};
|
||||||
|
services.nginx.virtualHosts."pubsub.xmpp.uninsane.org" = {
|
||||||
|
useACMEHost = "uninsane.org";
|
||||||
|
};
|
||||||
|
services.nginx.virtualHosts."upload.xmpp.uninsane.org" = {
|
||||||
|
useACMEHost = "uninsane.org";
|
||||||
|
};
|
||||||
|
services.nginx.virtualHosts."vjid.xmpp.uninsane.org" = {
|
||||||
|
useACMEHost = "uninsane.org";
|
||||||
|
};
|
||||||
|
|
||||||
|
sane.services.trust-dns.zones."uninsane.org".inet = {
|
||||||
|
# XXX: SRV records have to point to something with a A/AAAA record; no CNAMEs
|
||||||
|
A."xmpp" = "%NATIVE%";
|
||||||
|
CNAME."muc.xmpp" = "xmpp";
|
||||||
|
CNAME."pubsub.xmpp" = "xmpp";
|
||||||
|
CNAME."upload.xmpp" = "xmpp";
|
||||||
|
CNAME."vjid.xmpp" = "xmpp";
|
||||||
|
|
||||||
|
# _Service._Proto.Name TTL Class SRV Priority Weight Port Target
|
||||||
|
# - <https://xmpp.org/extensions/xep-0368.html>
|
||||||
|
# something's requesting the SRV records for muc.xmpp, so let's include it
|
||||||
|
# nothing seems to request XMPP SRVs for the other records (except @)
|
||||||
|
# lower numerical priority field tells clients to prefer this method
|
||||||
|
SRV."_xmpps-client._tcp.muc.xmpp" = "3 50 5223 xmpp";
|
||||||
|
SRV."_xmpps-server._tcp.muc.xmpp" = "3 50 5270 xmpp";
|
||||||
|
SRV."_xmpp-client._tcp.muc.xmpp" = "5 50 5222 xmpp";
|
||||||
|
SRV."_xmpp-server._tcp.muc.xmpp" = "5 50 5269 xmpp";
|
||||||
|
|
||||||
|
SRV."_xmpps-client._tcp" = "3 50 5223 xmpp";
|
||||||
|
SRV."_xmpps-server._tcp" = "3 50 5270 xmpp";
|
||||||
|
SRV."_xmpp-client._tcp" = "5 50 5222 xmpp";
|
||||||
|
SRV."_xmpp-server._tcp" = "5 50 5269 xmpp";
|
||||||
|
|
||||||
|
SRV."_stun._udp" = "5 50 3478 xmpp";
|
||||||
|
SRV."_stun._tcp" = "5 50 3478 xmpp";
|
||||||
|
SRV."_stuns._tcp" = "5 50 5349 xmpp";
|
||||||
|
SRV."_turn._udp" = "5 50 3478 xmpp";
|
||||||
|
SRV."_turn._tcp" = "5 50 3478 xmpp";
|
||||||
|
SRV."_turns._tcp" = "5 50 5349 xmpp";
|
||||||
|
};
|
||||||
|
|
||||||
|
# TODO: allocate UIDs/GIDs ?
|
||||||
|
services.ejabberd.enable = true;
|
||||||
|
services.ejabberd.configFile = "/var/lib/ejabberd/ejabberd.yaml";
|
||||||
|
systemd.services.ejabberd.preStart = let
|
||||||
|
config-in = pkgs.writeTextFile {
|
||||||
|
name = "ejabberd.yaml.in";
|
||||||
|
text = ''
|
||||||
|
hosts:
|
||||||
|
- uninsane.org
|
||||||
|
|
||||||
|
# none | emergency | alert | critical | error | warning | notice | info | debug
|
||||||
|
loglevel: debug
|
||||||
|
# loglevel: info
|
||||||
|
# loglevel: notice
|
||||||
|
|
||||||
|
acme:
|
||||||
|
auto: false
|
||||||
|
certfiles:
|
||||||
|
- /var/lib/acme/uninsane.org/full.pem
|
||||||
|
# ca_file: ${pkgs.cacert.unbundled}/etc/ssl/certs/
|
||||||
|
# ca_file: ${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt
|
||||||
|
|
||||||
|
pam_userinfotype: jid
|
||||||
|
|
||||||
|
acl:
|
||||||
|
admin:
|
||||||
|
user:
|
||||||
|
- "colin@uninsane.org"
|
||||||
|
local:
|
||||||
|
user_regexp: ""
|
||||||
|
loopback:
|
||||||
|
ip:
|
||||||
|
- 127.0.0.0/8
|
||||||
|
- ::1/128
|
||||||
|
|
||||||
|
access_rules:
|
||||||
|
local:
|
||||||
|
allow: local
|
||||||
|
c2s_access:
|
||||||
|
allow: all
|
||||||
|
announce:
|
||||||
|
allow: admin
|
||||||
|
configure:
|
||||||
|
allow: admin
|
||||||
|
muc_create:
|
||||||
|
allow: local
|
||||||
|
pubsub_createnode_access:
|
||||||
|
allow: all
|
||||||
|
trusted_network:
|
||||||
|
allow: loopback
|
||||||
|
|
||||||
|
# docs: <https://docs.ejabberd.im/admin/configuration/basic/#shaper-rules>
|
||||||
|
shaper_rules:
|
||||||
|
# setting this to above 1 may break outgoing messages
|
||||||
|
# - maybe some servers rate limit? or just don't understand simultaneous connections?
|
||||||
|
max_s2s_connections: 1
|
||||||
|
max_user_sessions: 10
|
||||||
|
max_user_offline_messages: 5000
|
||||||
|
c2s_shaper:
|
||||||
|
fast: all
|
||||||
|
s2s_shaper:
|
||||||
|
med: all
|
||||||
|
|
||||||
|
# docs: <https://docs.ejabberd.im/admin/configuration/basic/#shapers>
|
||||||
|
# this limits the bytes/sec.
|
||||||
|
# for example, burst: 3_000_000 and rate: 100_000 means:
|
||||||
|
# - each client has a BW budget that accumulates 100kB/sec and is capped at 3 MB
|
||||||
|
shaper:
|
||||||
|
fast: 1000000
|
||||||
|
med: 500000
|
||||||
|
# fast:
|
||||||
|
# - rate: 1000000
|
||||||
|
# - burst_size: 10000000
|
||||||
|
# med:
|
||||||
|
# - rate: 500000
|
||||||
|
# - burst_size: 5000000
|
||||||
|
|
||||||
|
# see: <https://docs.ejabberd.im/admin/configuration/listen/>
|
||||||
|
# s2s_use_starttls: true
|
||||||
|
s2s_use_starttls: optional
|
||||||
|
# lessens 504: remote-server-timeout errors
|
||||||
|
# see: <https://github.com/processone/ejabberd/issues/3105#issuecomment-562182967>
|
||||||
|
negotiation_timeout: 60
|
||||||
|
|
||||||
|
listen:
|
||||||
|
-
|
||||||
|
port: 5222
|
||||||
|
module: ejabberd_c2s
|
||||||
|
shaper: c2s_shaper
|
||||||
|
starttls: true
|
||||||
|
access: c2s_access
|
||||||
|
-
|
||||||
|
port: 5223
|
||||||
|
module: ejabberd_c2s
|
||||||
|
shaper: c2s_shaper
|
||||||
|
tls: true
|
||||||
|
access: c2s_access
|
||||||
|
-
|
||||||
|
port: 5269
|
||||||
|
module: ejabberd_s2s_in
|
||||||
|
shaper: s2s_shaper
|
||||||
|
-
|
||||||
|
port: 5270
|
||||||
|
module: ejabberd_s2s_in
|
||||||
|
shaper: s2s_shaper
|
||||||
|
tls: true
|
||||||
|
-
|
||||||
|
port: 5443
|
||||||
|
module: ejabberd_http
|
||||||
|
tls: true
|
||||||
|
request_handlers:
|
||||||
|
/admin: ejabberd_web_admin # TODO: ensure this actually works
|
||||||
|
/api: mod_http_api # ejabberd API endpoint (to control server)
|
||||||
|
/bosh: mod_bosh
|
||||||
|
/upload: mod_http_upload
|
||||||
|
/ws: ejabberd_http_ws
|
||||||
|
# /.well-known/host-meta: mod_host_meta
|
||||||
|
# /.well-known/host-meta.json: mod_host_meta
|
||||||
|
-
|
||||||
|
# STUN+TURN TCP
|
||||||
|
# note that the full port range should be forwarded ("not NAT'd")
|
||||||
|
# `use_turn=true` enables both TURN *and* STUN
|
||||||
|
port: 3478
|
||||||
|
module: ejabberd_stun
|
||||||
|
transport: tcp
|
||||||
|
use_turn: true
|
||||||
|
turn_min_port: 49152
|
||||||
|
turn_max_port: 65535
|
||||||
|
turn_ipv4_address: %NATIVE%
|
||||||
|
-
|
||||||
|
# STUN+TURN UDP
|
||||||
|
port: 3478
|
||||||
|
module: ejabberd_stun
|
||||||
|
transport: udp
|
||||||
|
use_turn: true
|
||||||
|
turn_min_port: 49152
|
||||||
|
turn_max_port: 65535
|
||||||
|
turn_ipv4_address: %NATIVE%
|
||||||
|
-
|
||||||
|
# STUN+TURN TLS over TCP
|
||||||
|
port: 5349
|
||||||
|
module: ejabberd_stun
|
||||||
|
transport: tcp
|
||||||
|
tls: true
|
||||||
|
certfile: /var/lib/acme/uninsane.org/full.pem
|
||||||
|
use_turn: true
|
||||||
|
turn_min_port: 49152
|
||||||
|
turn_max_port: 65535
|
||||||
|
turn_ipv4_address: %NATIVE%
|
||||||
|
|
||||||
|
# TODO: enable mod_fail2ban
|
||||||
|
# TODO(low): look into mod_http_fileserver for serving macros?
|
||||||
|
modules:
|
||||||
|
# mod_adhoc: {}
|
||||||
|
# mod_announce:
|
||||||
|
# access: admin
|
||||||
|
# allows users to set avatars in vCard
|
||||||
|
# - <https://docs.ejabberd.im/admin/configuration/modules/#mod-avatar>
|
||||||
|
mod_avatar: {}
|
||||||
|
mod_caps: {} # for mod_pubsub
|
||||||
|
mod_carboncopy: {} # allows multiple clients to receive a user's message
|
||||||
|
# queues messages when recipient is offline, including PEP and presence messages.
|
||||||
|
# compliance test suggests this be enabled
|
||||||
|
mod_client_state: {}
|
||||||
|
# mod_conversejs: TODO: enable once on 21.12
|
||||||
|
# allows clients like Dino to discover where to upload files
|
||||||
|
mod_disco:
|
||||||
|
server_info:
|
||||||
|
-
|
||||||
|
modules: all
|
||||||
|
name: abuse-addresses
|
||||||
|
urls:
|
||||||
|
- "mailto:admin.xmpp@uninsane.org"
|
||||||
|
- "xmpp:colin@uninsane.org"
|
||||||
|
-
|
||||||
|
modules: all
|
||||||
|
name: admin-addresses
|
||||||
|
urls:
|
||||||
|
- "mailto:admin.xmpp@uninsane.org"
|
||||||
|
- "xmpp:colin@uninsane.org"
|
||||||
|
mod_http_upload:
|
||||||
|
host: upload.xmpp.uninsane.org
|
||||||
|
hosts:
|
||||||
|
- upload.xmpp.uninsane.org
|
||||||
|
put_url: "https://@HOST@:5443/upload"
|
||||||
|
dir_mode: "0750"
|
||||||
|
file_mode: "0750"
|
||||||
|
rm_on_unregister: false
|
||||||
|
# allow discoverability of BOSH and websocket endpoints
|
||||||
|
# TODO: enable once on ejabberd 22.05 (presently 21.04)
|
||||||
|
# mod_host_meta: {}
|
||||||
|
mod_jidprep: {} # probably not needed: lets clients normalize jids
|
||||||
|
mod_last: {} # allow other users to know when i was last online
|
||||||
|
mod_mam:
|
||||||
|
# Mnesia is limited to 2GB, better to use an SQL backend
|
||||||
|
# For small servers SQLite is a good fit and is very easy
|
||||||
|
# to configure. Uncomment this when you have SQL configured:
|
||||||
|
# db_type: sql
|
||||||
|
assume_mam_usage: true
|
||||||
|
default: always
|
||||||
|
mod_muc:
|
||||||
|
access:
|
||||||
|
- allow
|
||||||
|
access_admin:
|
||||||
|
- allow: admin
|
||||||
|
access_create: muc_create
|
||||||
|
access_persistent: muc_create
|
||||||
|
access_mam:
|
||||||
|
- allow
|
||||||
|
history_size: 100 # messages to show new participants
|
||||||
|
host: muc.xmpp.uninsane.org
|
||||||
|
hosts:
|
||||||
|
- muc.xmpp.uninsane.org
|
||||||
|
default_room_options:
|
||||||
|
anonymous: false
|
||||||
|
lang: en
|
||||||
|
persistent: true
|
||||||
|
mam: true
|
||||||
|
mod_muc_admin: {}
|
||||||
|
mod_offline: # store messages for a user when they're offline (TODO: understand multi-client workflow?)
|
||||||
|
access_max_user_messages: max_user_offline_messages
|
||||||
|
store_groupchat: true
|
||||||
|
mod_ping: {}
|
||||||
|
mod_privacy: {} # deprecated, but required for `ejabberctl export_piefxis`
|
||||||
|
mod_private: {} # allow local clients to persist arbitrary data on my server
|
||||||
|
# push notifications to services integrated with e.g. Apple/Android.
|
||||||
|
# default is for a maximum amount of PII to be withheld, since these push notifs
|
||||||
|
# generally traverse 3rd party services. can opt to include message body, etc, though.
|
||||||
|
mod_push: {}
|
||||||
|
# i don't fully understand what this does, but it seems aimed at making push notifs more reliable.
|
||||||
|
mod_push_keepalive: {}
|
||||||
|
mod_roster:
|
||||||
|
versioning: true
|
||||||
|
# docs: <https://docs.ejabberd.im/admin/configuration/modules/#mod-s2s-dialback>
|
||||||
|
# s2s dialback to verify inbound messages
|
||||||
|
# unclear to what degree the XMPP network requires this
|
||||||
|
mod_s2s_dialback: {}
|
||||||
|
mod_shared_roster: {} # creates groups for @all, @online, and anything manually administered?
|
||||||
|
mod_stream_mgmt:
|
||||||
|
resend_on_timeout: if_offline # resend undelivered messages if the origin client is offline
|
||||||
|
# fallback for when DNS-based STUN discovery is unsupported.
|
||||||
|
# - see: <https://xmpp.org/extensions/xep-0215.html>
|
||||||
|
# docs: <https://docs.ejabberd.im/admin/configuration/modules/#mod-stun-disco>
|
||||||
|
# people say to just keep this defaulted (i guess ejabberd knows to return its `host` option of uninsane.org?)
|
||||||
|
mod_stun_disco: {}
|
||||||
|
# docs: <https://docs.ejabberd.im/admin/configuration/modules/#mod-vcard>
|
||||||
|
mod_vcard:
|
||||||
|
allow_return_all: true # all users are discoverable (?)
|
||||||
|
host: vjid.xmpp.uninsane.org
|
||||||
|
hosts:
|
||||||
|
- vjid.xmpp.uninsane.org
|
||||||
|
search: true
|
||||||
|
mod_vcard_xupdate: {} # needed for avatars
|
||||||
|
# docs: <https://docs.ejabberd.im/admin/configuration/modules/#mod-pubsub>
|
||||||
|
mod_pubsub: # needed for avatars
|
||||||
|
access_createnode: pubsub_createnode_access
|
||||||
|
host: pubsub.xmpp.uninsane.org
|
||||||
|
hosts:
|
||||||
|
- pubsub.xmpp.uninsane.org
|
||||||
|
ignore_pep_from_offline: false
|
||||||
|
last_item_cache: true
|
||||||
|
plugins:
|
||||||
|
- pep
|
||||||
|
- flat
|
||||||
|
force_node_config:
|
||||||
|
# ensure client bookmarks are private
|
||||||
|
storage:bookmarks:
|
||||||
|
access_model: whitelist
|
||||||
|
urn:xmpp:avatar:data:
|
||||||
|
access_model: open
|
||||||
|
urn:xmpp:avatar:metadata:
|
||||||
|
access_model: open
|
||||||
|
mod_version: {}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
sed = "${pkgs.gnused}/bin/sed";
|
||||||
|
in ''
|
||||||
|
ip=$(cat '${config.sane.services.dyn-dns.ipPath}')
|
||||||
|
# config is 444 (not 644), so we want to write out-of-place and then atomically move
|
||||||
|
# TODO: factor this out into `sane-woop` helper?
|
||||||
|
rm -f /var/lib/ejabberd/ejabberd.yaml.new
|
||||||
|
${sed} "s/%NATIVE%/$ip/" ${config-in} > /var/lib/ejabberd/ejabberd.yaml.new
|
||||||
|
mv /var/lib/ejabberd/ejabberd.yaml{.new,}
|
||||||
|
'';
|
||||||
|
|
||||||
|
sane.services.dyn-dns.restartOnChange = [ "ejabberd.service" ];
|
||||||
|
}
|
||||||
63
hosts/by-name/servo/services/freshrss.nix
Normal file
63
hosts/by-name/servo/services/freshrss.nix
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
# import feeds with e.g.
|
||||||
|
# ```console
|
||||||
|
# $ nix build '.#nixpkgs.freshrss'
|
||||||
|
# $ sudo -u freshrss -g freshrss FRESHRSS_DATA_PATH=/var/lib/freshrss ./result/cli/import-for-user.php --user admin --filename /home/colin/.config/newsflashFeeds.opml
|
||||||
|
# ```
|
||||||
|
#
|
||||||
|
# export feeds with
|
||||||
|
# ```console
|
||||||
|
# $ sudo -u freshrss -g freshrss FRESHRSS_DATA_PATH=/var/lib/freshrss ./result/cli/export-opml-for-user.php --user admin
|
||||||
|
# ```
|
||||||
|
|
||||||
|
{ config, lib, pkgs, sane-lib, ... }:
|
||||||
|
{
|
||||||
|
sops.secrets."freshrss_passwd" = {
|
||||||
|
owner = config.users.users.freshrss.name;
|
||||||
|
mode = "0400";
|
||||||
|
};
|
||||||
|
sane.persist.sys.plaintext = [
|
||||||
|
{ user = "freshrss"; group = "freshrss"; directory = "/var/lib/freshrss"; }
|
||||||
|
];
|
||||||
|
|
||||||
|
services.freshrss.enable = true;
|
||||||
|
services.freshrss.baseUrl = "https://rss.uninsane.org";
|
||||||
|
services.freshrss.virtualHost = "rss.uninsane.org";
|
||||||
|
services.freshrss.passwordFile = config.sops.secrets.freshrss_passwd.path;
|
||||||
|
|
||||||
|
systemd.services.freshrss-import-feeds =
|
||||||
|
let
|
||||||
|
feeds = sane-lib.feeds;
|
||||||
|
fresh = config.systemd.services.freshrss-config;
|
||||||
|
all-feeds = config.sane.feeds;
|
||||||
|
wanted-feeds = feeds.filterByFormat ["text" "image"] all-feeds;
|
||||||
|
opml = pkgs.writeText "sane-freshrss.opml" (feeds.feedsToOpml wanted-feeds);
|
||||||
|
in {
|
||||||
|
inherit (fresh) wantedBy environment;
|
||||||
|
serviceConfig = {
|
||||||
|
inherit (fresh.serviceConfig) Type User Group StateDirectory WorkingDirectory
|
||||||
|
# hardening options
|
||||||
|
CapabilityBoundingSet DeviceAllow LockPersonality NoNewPrivileges PrivateDevices PrivateTmp PrivateUsers ProcSubset ProtectClock ProtectControlGroups ProtectHome ProtectHostname ProtectKernelLogs ProtectKernelModules ProtectKernelTunables ProtectProc ProtectSystem RemoveIPC RestrictNamespaces RestrictRealtime RestrictSUIDSGID SystemCallArchitectures SystemCallFilter UMask;
|
||||||
|
};
|
||||||
|
description = "import sane RSS feed list";
|
||||||
|
after = [ "freshrss-config.service" ];
|
||||||
|
script = ''
|
||||||
|
# easiest way to preserve feeds: delete the user, recreate it, import feeds
|
||||||
|
${pkgs.freshrss}/cli/delete-user.php --user colin || true
|
||||||
|
${pkgs.freshrss}/cli/create-user.php --user colin --password "$(cat ${config.services.freshrss.passwordFile})" || true
|
||||||
|
${pkgs.freshrss}/cli/import-for-user.php --user colin --filename ${opml}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
# the default ("*:0/5") is to run every 5 minutes.
|
||||||
|
# `systemctl list-timers` to show
|
||||||
|
systemd.services.freshrss-updater.startAt = lib.mkForce "*:3/30";
|
||||||
|
|
||||||
|
services.nginx.virtualHosts."rss.uninsane.org" = {
|
||||||
|
addSSL = true;
|
||||||
|
enableACME = true;
|
||||||
|
# inherit kTLS;
|
||||||
|
# the routing is handled by services.freshrss.virtualHost
|
||||||
|
};
|
||||||
|
|
||||||
|
sane.services.trust-dns.zones."uninsane.org".inet.CNAME."rss" = "native";
|
||||||
|
}
|
||||||
@@ -1,6 +1,10 @@
|
|||||||
{ pkgs, lib, ... }:
|
{ config, pkgs, lib, ... }:
|
||||||
|
|
||||||
{
|
{
|
||||||
|
sane.persist.sys.plaintext = [
|
||||||
|
# TODO: mode? could be more granular
|
||||||
|
{ user = "git"; group = "gitea"; directory = "/var/lib/gitea"; }
|
||||||
|
];
|
||||||
services.gitea.enable = true;
|
services.gitea.enable = true;
|
||||||
services.gitea.user = "git"; # default is 'gitea'
|
services.gitea.user = "git"; # default is 'gitea'
|
||||||
services.gitea.database.type = "postgres";
|
services.gitea.database.type = "postgres";
|
||||||
@@ -8,9 +12,20 @@
|
|||||||
services.gitea.appName = "Perfectly Sane Git";
|
services.gitea.appName = "Perfectly Sane Git";
|
||||||
services.gitea.domain = "git.uninsane.org";
|
services.gitea.domain = "git.uninsane.org";
|
||||||
services.gitea.rootUrl = "https://git.uninsane.org/";
|
services.gitea.rootUrl = "https://git.uninsane.org/";
|
||||||
services.gitea.cookieSecure = true;
|
services.gitea.settings.session.COOKIE_SECURE = true;
|
||||||
# services.gitea.disableRegistration = true;
|
# services.gitea.disableRegistration = true;
|
||||||
|
|
||||||
|
# gitea doesn't create the git user
|
||||||
|
users.users.git = {
|
||||||
|
description = "Gitea Service";
|
||||||
|
home = "/var/lib/gitea";
|
||||||
|
useDefaultShell = true;
|
||||||
|
group = "gitea";
|
||||||
|
isSystemUser = true;
|
||||||
|
# sendmail access (not 100% sure if this is necessary)
|
||||||
|
extraGroups = [ "postdrop" ];
|
||||||
|
};
|
||||||
|
|
||||||
services.gitea.settings = {
|
services.gitea.settings = {
|
||||||
server = {
|
server = {
|
||||||
# options: "home", "explore", "organizations", "login" or URL fragment (or full URL)
|
# options: "home", "explore", "organizations", "login" or URL fragment (or full URL)
|
||||||
@@ -55,7 +70,7 @@
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
# options: "Trace", "Debug", "Info", "Warn", "Error", "Critical"
|
# options: "Trace", "Debug", "Info", "Warn", "Error", "Critical"
|
||||||
services.gitea.log.level = "Info";
|
services.gitea.settings.log.LEVEL = "Warn";
|
||||||
|
|
||||||
systemd.services.gitea.serviceConfig = {
|
systemd.services.gitea.serviceConfig = {
|
||||||
# nix default is AF_UNIX AF_INET AF_INET6.
|
# nix default is AF_UNIX AF_INET AF_INET6.
|
||||||
@@ -67,4 +82,18 @@
|
|||||||
"/var/lib/gitea"
|
"/var/lib/gitea"
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# hosted git (web view and for `git <cmd>` use
|
||||||
|
# TODO: enable publog?
|
||||||
|
services.nginx.virtualHosts."git.uninsane.org" = {
|
||||||
|
forceSSL = true; # gitea complains if served over a different protocol than its config file says
|
||||||
|
enableACME = true;
|
||||||
|
# inherit kTLS;
|
||||||
|
|
||||||
|
locations."/" = {
|
||||||
|
proxyPass = "http://127.0.0.1:3000";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
sane.services.trust-dns.zones."uninsane.org".inet.CNAME."git" = "native";
|
||||||
}
|
}
|
||||||
68
hosts/by-name/servo/services/goaccess.nix
Normal file
68
hosts/by-name/servo/services/goaccess.nix
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
{ pkgs, ... }:
|
||||||
|
{
|
||||||
|
# based on <https://bytes.fyi/real-time-goaccess-reports-with-nginx/>
|
||||||
|
# log-format setting can be derived with this tool if custom:
|
||||||
|
# - <https://github.com/stockrt/nginx2goaccess>
|
||||||
|
# config options:
|
||||||
|
# - <https://github.com/allinurl/goaccess/blob/master/config/goaccess.conf>
|
||||||
|
|
||||||
|
systemd.services.goaccess = {
|
||||||
|
description = "GoAccess server monitoring";
|
||||||
|
serviceConfig = {
|
||||||
|
ExecStart = ''
|
||||||
|
${pkgs.goaccess}/bin/goaccess \
|
||||||
|
-f /var/log/nginx/public.log \
|
||||||
|
--log-format=VCOMBINED \
|
||||||
|
--real-time-html \
|
||||||
|
--html-refresh=30 \
|
||||||
|
--no-query-string \
|
||||||
|
--anonymize-ip \
|
||||||
|
--ignore-panel=HOSTS \
|
||||||
|
--ws-url=wss://sink.uninsane.org:443/ws \
|
||||||
|
--port=7890 \
|
||||||
|
-o /var/lib/uninsane/sink/index.html
|
||||||
|
'';
|
||||||
|
ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
|
||||||
|
Type = "simple";
|
||||||
|
Restart = "on-failure";
|
||||||
|
RestartSec = "10s";
|
||||||
|
|
||||||
|
# hardening
|
||||||
|
WorkingDirectory = "/tmp";
|
||||||
|
NoNewPrivileges = true;
|
||||||
|
PrivateTmp = true;
|
||||||
|
ProtectHome = "read-only";
|
||||||
|
ProtectSystem = "strict";
|
||||||
|
SystemCallFilter = "~@clock @cpu-emulation @debug @keyring @memlock @module @mount @obsolete @privileged @reboot @resources @setuid @swap @raw-io";
|
||||||
|
ReadOnlyPaths = "/";
|
||||||
|
ReadWritePaths = [ "/proc/self" "/var/lib/uninsane/sink" ];
|
||||||
|
PrivateDevices = "yes";
|
||||||
|
ProtectKernelModules = "yes";
|
||||||
|
ProtectKernelTunables = "yes";
|
||||||
|
};
|
||||||
|
after = [ "network.target" ];
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
# server statistics
|
||||||
|
services.nginx.virtualHosts."sink.uninsane.org" = {
|
||||||
|
addSSL = true;
|
||||||
|
enableACME = true;
|
||||||
|
# inherit kTLS;
|
||||||
|
root = "/var/lib/uninsane/sink";
|
||||||
|
|
||||||
|
locations."/ws" = {
|
||||||
|
proxyPass = "http://127.0.0.1:7890";
|
||||||
|
# XXX not sure how much of this is necessary
|
||||||
|
extraConfig = ''
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection $connection_upgrade;
|
||||||
|
proxy_buffering off;
|
||||||
|
proxy_read_timeout 7d;
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
sane.services.trust-dns.zones."uninsane.org".inet.CNAME."sink" = "native";
|
||||||
|
}
|
||||||
93
hosts/by-name/servo/services/ipfs.nix
Normal file
93
hosts/by-name/servo/services/ipfs.nix
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
# admin:
|
||||||
|
# - view stats:
|
||||||
|
# - sudo -u ipfs -g ipfs ipfs -c /var/lib/ipfs/ stats bw
|
||||||
|
# - sudo -u ipfs -g ipfs ipfs -c /var/lib/ipfs/ stats dht
|
||||||
|
# - sudo -u ipfs -g ipfs ipfs -c /var/lib/ipfs/ bitswap stat
|
||||||
|
# - number of open peer connections:
|
||||||
|
# - sudo -u ipfs -g ipfs ipfs -c /var/lib/ipfs/ swarm peers | wc -l
|
||||||
|
|
||||||
|
{ lib, ... }:
|
||||||
|
|
||||||
|
lib.mkIf false # i don't actively use ipfs anymore
|
||||||
|
{
|
||||||
|
sane.persist.sys.plaintext = [
|
||||||
|
# TODO: mode? could be more granular
|
||||||
|
{ user = "261"; group = "261"; directory = "/var/lib/ipfs"; }
|
||||||
|
];
|
||||||
|
|
||||||
|
networking.firewall.allowedTCPPorts = [ 4001 ];
|
||||||
|
networking.firewall.allowedUDPPorts = [ 4001 ];
|
||||||
|
|
||||||
|
services.nginx.virtualHosts."ipfs.uninsane.org" = {
|
||||||
|
# don't default to ssl upgrades, since this may be dnslink'd from a different domain.
|
||||||
|
# ideally we'd disable ssl entirely, but some places assume it?
|
||||||
|
addSSL = true;
|
||||||
|
enableACME = true;
|
||||||
|
# inherit kTLS;
|
||||||
|
|
||||||
|
locations."/" = {
|
||||||
|
proxyPass = "http://127.0.0.1:8080";
|
||||||
|
extraConfig = ''
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Ipfs-Gateway-Prefix "";
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
sane.services.trust-dns.zones."uninsane.org".inet.CNAME."ipfs" = "native";
|
||||||
|
|
||||||
|
# services.ipfs.enable = true;
|
||||||
|
services.kubo.localDiscovery = true;
|
||||||
|
services.kubo.settings = {
|
||||||
|
Addresses = {
|
||||||
|
Announce = [
|
||||||
|
# "/dns4/ipfs.uninsane.org/tcp/4001"
|
||||||
|
"/dns4/ipfs.uninsane.org/udp/4001/quic"
|
||||||
|
];
|
||||||
|
Swarm = [
|
||||||
|
# "/dns4/ipfs.uninsane.org/tcp/4001"
|
||||||
|
# "/ip4/0.0.0.0/tcp/4001"
|
||||||
|
"/dns4/ipfs.uninsane.org/udp/4001/quic"
|
||||||
|
"/ip4/0.0.0.0/udp/4001/quic"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
Gateway = {
|
||||||
|
# the gateway can only be used to serve content already replicated on this host
|
||||||
|
NoFetch = true;
|
||||||
|
};
|
||||||
|
Swarm = {
|
||||||
|
ConnMgr = {
|
||||||
|
# maintain between LowWater and HighWater peer connections
|
||||||
|
# taken from: https://github.com/ipfs/ipfs-desktop/pull/2055
|
||||||
|
# defaults are 600-900: https://github.com/ipfs/kubo/blob/master/docs/config.md#swarmconnmgr
|
||||||
|
LowWater = 20;
|
||||||
|
HighWater = 40;
|
||||||
|
# default is 20s. i guess more grace period = less churn
|
||||||
|
GracePeriod = "1m";
|
||||||
|
};
|
||||||
|
ResourceMgr = {
|
||||||
|
# docs: https://github.com/libp2p/go-libp2p-resource-manager#resource-scopes
|
||||||
|
Enabled = true;
|
||||||
|
Limits = {
|
||||||
|
System = {
|
||||||
|
Conns = 196;
|
||||||
|
ConnsInbound = 128;
|
||||||
|
ConnsOutbound = 128;
|
||||||
|
FD = 512;
|
||||||
|
Memory = 1073741824; # 1GiB
|
||||||
|
Streams = 1536;
|
||||||
|
StreamsInbound = 1024;
|
||||||
|
StreamsOutbound = 1024;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
Transports = {
|
||||||
|
Network = {
|
||||||
|
# disable TCP, force QUIC, for lighter resources
|
||||||
|
TCP = false;
|
||||||
|
QUIC = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
32
hosts/by-name/servo/services/jackett.nix
Normal file
32
hosts/by-name/servo/services/jackett.nix
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
{ ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
sane.persist.sys.plaintext = [
|
||||||
|
# TODO: mode? we only need this to save Indexer creds ==> migrate to config?
|
||||||
|
{ user = "root"; group = "root"; directory = "/var/lib/jackett"; }
|
||||||
|
];
|
||||||
|
services.jackett.enable = true;
|
||||||
|
|
||||||
|
systemd.services.jackett.after = [ "wireguard-wg-ovpns.service" ];
|
||||||
|
systemd.services.jackett.partOf = [ "wireguard-wg-ovpns.service" ];
|
||||||
|
systemd.services.jackett.serviceConfig = {
|
||||||
|
# run this behind the OVPN static VPN
|
||||||
|
NetworkNamespacePath = "/run/netns/ovpns";
|
||||||
|
# patch jackett to listen on the public interfaces
|
||||||
|
# ExecStart = lib.mkForce "${pkgs.jackett}/bin/Jackett --NoUpdates --DataFolder /var/lib/jackett/.config/Jackett --ListenPublic";
|
||||||
|
};
|
||||||
|
|
||||||
|
# jackett torrent search
|
||||||
|
services.nginx.virtualHosts."jackett.uninsane.org" = {
|
||||||
|
forceSSL = true;
|
||||||
|
enableACME = true;
|
||||||
|
# inherit kTLS;
|
||||||
|
locations."/" = {
|
||||||
|
# proxyPass = "http://ovpns.uninsane.org:9117";
|
||||||
|
proxyPass = "http://10.0.1.6:9117";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
sane.services.trust-dns.zones."uninsane.org".inet.CNAME."jackett" = "native";
|
||||||
|
}
|
||||||
|
|
||||||
114
hosts/by-name/servo/services/jellyfin.nix
Normal file
114
hosts/by-name/servo/services/jellyfin.nix
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
# configuration options (today i don't store my config in nix):
|
||||||
|
#
|
||||||
|
# - jellyfin-web can be statically configured (result/share/jellyfin-web/config.json)
|
||||||
|
# - <https://jellyfin.org/docs/general/clients/web-config>
|
||||||
|
# - configure server list, plugins, "menuLinks", colors
|
||||||
|
#
|
||||||
|
# - jellfyin server is configured in /var/lib/jellfin/
|
||||||
|
# - root/default/<LibraryType>/
|
||||||
|
# - <LibraryName>.mblink: contains the directory name where this library lives
|
||||||
|
# - options.xml: contains preferences which were defined in the web UI during import
|
||||||
|
# - e.g. `EnablePhotos`, `EnableChapterImageExtraction`, etc.
|
||||||
|
# - config/encoding.xml: transcoder settings
|
||||||
|
# - config/system.xml: misc preferences like log file duration, audiobook resume settings, etc.
|
||||||
|
# - data/jellyfin.db: maybe account definitions? internal state?
|
||||||
|
|
||||||
|
{ config, lib, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
# identical to:
|
||||||
|
# services.jellyfin.openFirewall = true;
|
||||||
|
networking.firewall.allowedUDPPorts = [
|
||||||
|
# https://jellyfin.org/docs/general/networking/index.html
|
||||||
|
1900 # UPnP service discovery
|
||||||
|
7359 # Jellyfin-specific (?) client discovery
|
||||||
|
];
|
||||||
|
networking.firewall.allowedTCPPorts = [
|
||||||
|
8096 # HTTP (for the LAN)
|
||||||
|
8920 # HTTPS (for the LAN)
|
||||||
|
];
|
||||||
|
sane.persist.sys.plaintext = [
|
||||||
|
{ user = "jellyfin"; group = "jellyfin"; mode = "0700"; directory = "/var/lib/jellyfin"; }
|
||||||
|
];
|
||||||
|
sane.fs."/var/lib/jellyfin/config/logging.json" = {
|
||||||
|
# "Emby.Dlna" logging: <https://jellyfin.org/docs/general/networking/dlna>
|
||||||
|
symlink.text = ''
|
||||||
|
{
|
||||||
|
"Serilog": {
|
||||||
|
"MinimumLevel": {
|
||||||
|
"Default": "Information",
|
||||||
|
"Override": {
|
||||||
|
"Microsoft": "Warning",
|
||||||
|
"System": "Warning",
|
||||||
|
"Emby.Dlna": "Debug",
|
||||||
|
"Emby.Dlna.Eventing": "Debug"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"WriteTo": [
|
||||||
|
{
|
||||||
|
"Name": "Console",
|
||||||
|
"Args": {
|
||||||
|
"outputTemplate": "[{Timestamp:HH:mm:ss}] [{Level:u3}] [{ThreadId}] {SourceContext}: {Message:lj}{NewLine}{Exception}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Enrich": [ "FromLogContext", "WithThreadId" ]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
wantedBeforeBy = [ "jellyfin.service" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
# Jellyfin multimedia server
|
||||||
|
# this is mostly taken from the official jellfin.org docs
|
||||||
|
services.nginx.virtualHosts."jelly.uninsane.org" = {
|
||||||
|
addSSL = true;
|
||||||
|
enableACME = true;
|
||||||
|
# inherit kTLS;
|
||||||
|
|
||||||
|
locations."/" = {
|
||||||
|
proxyPass = "http://127.0.0.1:8096";
|
||||||
|
extraConfig = ''
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
proxy_set_header X-Forwarded-Protocol $scheme;
|
||||||
|
proxy_set_header X-Forwarded-Host $http_host;
|
||||||
|
|
||||||
|
# Disable buffering when the nginx proxy gets very resource heavy upon streaming
|
||||||
|
proxy_buffering off;
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
# locations."/web/" = {
|
||||||
|
# proxyPass = "http://127.0.0.1:8096/web/index.html";
|
||||||
|
# extraConfig = ''
|
||||||
|
# proxy_set_header Host $host;
|
||||||
|
# proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
# proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
# proxy_set_header X-Forwarded-Protocol $scheme;
|
||||||
|
# proxy_set_header X-Forwarded-Host $http_host;
|
||||||
|
# '';
|
||||||
|
# };
|
||||||
|
locations."/socket" = {
|
||||||
|
proxyPass = "http://127.0.0.1:8096";
|
||||||
|
extraConfig = ''
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection "upgrade";
|
||||||
|
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
proxy_set_header X-Forwarded-Protocol $scheme;
|
||||||
|
proxy_set_header X-Forwarded-Host $http_host;
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
sane.services.trust-dns.zones."uninsane.org".inet.CNAME."jelly" = "native";
|
||||||
|
|
||||||
|
services.jellyfin.enable = true;
|
||||||
|
}
|
||||||
17
hosts/by-name/servo/services/kiwix-serve.nix
Normal file
17
hosts/by-name/servo/services/kiwix-serve.nix
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
{ ... }:
|
||||||
|
{
|
||||||
|
sane.services.kiwix-serve = {
|
||||||
|
enable = true;
|
||||||
|
port = 8013;
|
||||||
|
zimPaths = [ "/var/lib/uninsane/www-archive/wikipedia_en_all_maxi_2022-05.zim" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
services.nginx.virtualHosts."w.uninsane.org" = {
|
||||||
|
forceSSL = true;
|
||||||
|
enableACME = true;
|
||||||
|
# inherit kTLS;
|
||||||
|
locations."/".proxyPass = "http://127.0.0.1:8013";
|
||||||
|
};
|
||||||
|
|
||||||
|
sane.services.trust-dns.zones."uninsane.org".inet.CNAME."w" = "native";
|
||||||
|
}
|
||||||
137
hosts/by-name/servo/services/matrix/default.nix
Normal file
137
hosts/by-name/servo/services/matrix/default.nix
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
# docs: https://nixos.wiki/wiki/Matrix
|
||||||
|
# docs: https://nixos.org/manual/nixos/stable/index.html#module-services-matrix-synapse
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
./discord-puppet.nix
|
||||||
|
# ./irc.nix
|
||||||
|
# TODO(2023/03/10): disabled because it's not bridging and mautrix_signal is hogging CPU
|
||||||
|
# ./signal.nix
|
||||||
|
];
|
||||||
|
|
||||||
|
sane.persist.sys.plaintext = [
|
||||||
|
{ user = "matrix-synapse"; group = "matrix-synapse"; directory = "/var/lib/matrix-synapse"; }
|
||||||
|
];
|
||||||
|
services.matrix-synapse.enable = true;
|
||||||
|
# this changes the default log level from INFO to WARN.
|
||||||
|
# maybe there's an easier way?
|
||||||
|
services.matrix-synapse.settings.log_config = ./synapse-log_level.yaml;
|
||||||
|
services.matrix-synapse.settings.server_name = "uninsane.org";
|
||||||
|
|
||||||
|
# services.matrix-synapse.enable_registration_captcha = true;
|
||||||
|
# services.matrix-synapse.enable_registration_without_verification = true;
|
||||||
|
services.matrix-synapse.settings.enable_registration = true;
|
||||||
|
# services.matrix-synapse.registration_shared_secret = "<shared key goes here>";
|
||||||
|
|
||||||
|
# default for listeners is port = 8448, tls = true, x_forwarded = false.
|
||||||
|
# we change this because the server is situated behind nginx.
|
||||||
|
services.matrix-synapse.settings.listeners = [
|
||||||
|
{
|
||||||
|
port = 8008;
|
||||||
|
bind_addresses = [ "127.0.0.1" ];
|
||||||
|
type = "http";
|
||||||
|
tls = false;
|
||||||
|
x_forwarded = true;
|
||||||
|
resources = [
|
||||||
|
{
|
||||||
|
names = [ "client" "federation" ];
|
||||||
|
compress = false;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
services.matrix-synapse.settings.admin_contact = "admin.matrix@uninsane.org";
|
||||||
|
services.matrix-synapse.settings.registrations_require_3pid = [ "email" ];
|
||||||
|
|
||||||
|
services.matrix-synapse.extraConfigFiles = [
|
||||||
|
config.sops.secrets.matrix_synapse_secrets.path
|
||||||
|
];
|
||||||
|
|
||||||
|
# services.matrix-synapse.extraConfigFiles = [builtins.toFile "matrix-synapse-extra-config" ''
|
||||||
|
# admin_contact: "admin.matrix@uninsane.org"
|
||||||
|
# registrations_require_3pid:
|
||||||
|
# - email
|
||||||
|
# email:
|
||||||
|
# smtp_host: "mx.uninsane.org"
|
||||||
|
# smtp_port: 587
|
||||||
|
# smtp_user: "matrix-synapse"
|
||||||
|
# smtp_pass: "${secrets.matrix-synapse.smtp_pass}"
|
||||||
|
# require_transport_security: true
|
||||||
|
# enable_tls: true
|
||||||
|
# notif_from: "%(app)s <notify.matrix@uninsane.org>"
|
||||||
|
# app_name: "Uninsane Matrix"
|
||||||
|
# enable_notifs: true
|
||||||
|
# validation_token_lifetime: 96h
|
||||||
|
# invite_client_location: "https://web.matrix.uninsane.org"
|
||||||
|
# subjects:
|
||||||
|
# email_validation: "[%(server_name)s] Validate your email"
|
||||||
|
# ''];
|
||||||
|
|
||||||
|
# new users may be registered on the CLI:
|
||||||
|
# register_new_matrix_user -c /nix/store/8n6kcka37jhmi4qpd2r03aj71pkyh21s-homeserver.yaml http://localhost:8008
|
||||||
|
#
|
||||||
|
# or provide an registration token then can use to register through the client.
|
||||||
|
# docs: https://github.com/matrix-org/synapse/blob/develop/docs/usage/administration/admin_api/registration_tokens.md
|
||||||
|
# first, grab your own user's access token (Help & About section in Element). then:
|
||||||
|
# curl --header "Authorization: Bearer <my_token>" localhost:8008/_synapse/admin/v1/registration_tokens
|
||||||
|
# create a token with unlimited uses:
|
||||||
|
# curl -d '{}' --header "Authorization: Bearer <my_token>" localhost:8008/_synapse/admin/v1/registration_tokens/new
|
||||||
|
# create a token with limited uses:
|
||||||
|
# curl -d '{ "uses_allowed": 1 }' --header "Authorization: Bearer <my_token>" localhost:8008/_synapse/admin/v1/registration_tokens/new
|
||||||
|
|
||||||
|
# matrix chat server
|
||||||
|
# TODO: was `publog`
|
||||||
|
services.nginx.virtualHosts."matrix.uninsane.org" = {
|
||||||
|
addSSL = true;
|
||||||
|
enableACME = true;
|
||||||
|
# inherit kTLS;
|
||||||
|
|
||||||
|
# TODO colin: replace this with something helpful to the viewer
|
||||||
|
# locations."/".extraConfig = ''
|
||||||
|
# return 404;
|
||||||
|
# '';
|
||||||
|
|
||||||
|
locations."/" = {
|
||||||
|
proxyPass = "http://127.0.0.1:8008";
|
||||||
|
};
|
||||||
|
# redirect browsers to the web client.
|
||||||
|
# i don't think native matrix clients ever fetch the root.
|
||||||
|
# ideally this would be put behind some user-agent test though.
|
||||||
|
locations."= /" = {
|
||||||
|
return = "301 https://web.matrix.uninsane.org";
|
||||||
|
};
|
||||||
|
|
||||||
|
# locations."/_matrix" = {
|
||||||
|
# proxyPass = "http://127.0.0.1:8008";
|
||||||
|
# };
|
||||||
|
};
|
||||||
|
|
||||||
|
# matrix web client
|
||||||
|
# docs: https://nixos.org/manual/nixos/stable/index.html#module-services-matrix-element-web
|
||||||
|
services.nginx.virtualHosts."web.matrix.uninsane.org" = {
|
||||||
|
forceSSL = true;
|
||||||
|
enableACME = true;
|
||||||
|
# inherit kTLS;
|
||||||
|
|
||||||
|
root = pkgs.element-web.override {
|
||||||
|
conf = {
|
||||||
|
default_server_config."m.homeserver" = {
|
||||||
|
"base_url" = "https://matrix.uninsane.org";
|
||||||
|
"server_name" = "uninsane.org";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
sane.services.trust-dns.zones."uninsane.org".inet = {
|
||||||
|
CNAME."matrix" = "native";
|
||||||
|
CNAME."web.matrix" = "native";
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
sops.secrets."matrix_synapse_secrets" = {
|
||||||
|
owner = config.users.users.matrix-synapse.name;
|
||||||
|
};
|
||||||
|
}
|
||||||
53
hosts/by-name/servo/services/matrix/discord-puppet.nix
Normal file
53
hosts/by-name/servo/services/matrix/discord-puppet.nix
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
{ lib, ... }:
|
||||||
|
{
|
||||||
|
sane.persist.sys.plaintext = [
|
||||||
|
{ user = "matrix-synapse"; group = "matrix-synapse"; directory = "/var/lib/mx-puppet-discord"; }
|
||||||
|
];
|
||||||
|
|
||||||
|
services.matrix-synapse.settings.app_service_config_files = [
|
||||||
|
# auto-created by mx-puppet-discord service
|
||||||
|
"/var/lib/mx-puppet-discord/discord-registration.yaml"
|
||||||
|
];
|
||||||
|
|
||||||
|
services.mx-puppet-discord.enable = true;
|
||||||
|
# schema/example: <https://gitlab.com/mx-puppet/discord/mx-puppet-discord/-/blob/main/sample.config.yaml>
|
||||||
|
services.mx-puppet-discord.settings = {
|
||||||
|
bridge = {
|
||||||
|
# port = 8434
|
||||||
|
bindAddress = "127.0.0.1";
|
||||||
|
domain = "uninsane.org";
|
||||||
|
homeserverUrl = "http://127.0.0.1:8008";
|
||||||
|
# displayName = "mx-discord-puppet"; # matrix name for the bot
|
||||||
|
# matrix "groups" were an earlier version of spaces.
|
||||||
|
# maybe the puppet understands this, maybe not?
|
||||||
|
enableGroupSync = false;
|
||||||
|
};
|
||||||
|
presence = {
|
||||||
|
enabled = false;
|
||||||
|
interval = 30000;
|
||||||
|
};
|
||||||
|
provisioning = {
|
||||||
|
# allow these users to control the puppet
|
||||||
|
whitelist = [ "@colin:uninsane\\.org" ];
|
||||||
|
};
|
||||||
|
relay = {
|
||||||
|
whitelist = [ "@colin:uninsane\\.org" ];
|
||||||
|
};
|
||||||
|
selfService = {
|
||||||
|
# who's allowed to use plumbed rooms (idk what that means)
|
||||||
|
whitelist = [ "@colin:uninsane\\.org" ];
|
||||||
|
};
|
||||||
|
logging = {
|
||||||
|
# silly, debug, verbose, info, warn, error
|
||||||
|
console = "debug";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# TODO: should use a dedicated user
|
||||||
|
systemd.services.mx-puppet-discord.serviceConfig = {
|
||||||
|
# fix up to not use /var/lib/private, but just /var/lib
|
||||||
|
DynamicUser = lib.mkForce false;
|
||||||
|
User = "matrix-synapse";
|
||||||
|
Group = "matrix-synapse";
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,80 +1,19 @@
|
|||||||
# docs: https://nixos.wiki/wiki/Matrix
|
{ config, lib, ... }:
|
||||||
# docs: https://nixos.org/manual/nixos/stable/index.html#module-services-matrix-synapse
|
|
||||||
{ config, ... }:
|
|
||||||
|
|
||||||
{
|
{
|
||||||
services.matrix-synapse.enable = true;
|
sane.persist.sys.plaintext = [
|
||||||
services.matrix-synapse.settings.server_name = "uninsane.org";
|
# TODO: mode?
|
||||||
|
# user and group are both "matrix-appservice-irc"
|
||||||
# services.matrix-synapse.enable_registration_captcha = true;
|
{ user = "993"; group = "992"; directory = "/var/lib/matrix-appservice-irc"; }
|
||||||
# services.matrix-synapse.enable_registration_without_verification = true;
|
|
||||||
services.matrix-synapse.settings.enable_registration = true;
|
|
||||||
# services.matrix-synapse.registration_shared_secret = "<shared key goes here>";
|
|
||||||
|
|
||||||
# default for listeners is port = 8448, tls = true, x_forwarded = false.
|
|
||||||
# we change this because the server is situated behind nginx.
|
|
||||||
services.matrix-synapse.settings.listeners = [
|
|
||||||
{
|
|
||||||
port = 8008;
|
|
||||||
bind_addresses = [ "127.0.0.1" ];
|
|
||||||
type = "http";
|
|
||||||
tls = false;
|
|
||||||
x_forwarded = true;
|
|
||||||
resources = [
|
|
||||||
{
|
|
||||||
names = [ "client" "federation" ];
|
|
||||||
compress = false;
|
|
||||||
}
|
|
||||||
];
|
|
||||||
}
|
|
||||||
];
|
];
|
||||||
|
|
||||||
services.matrix-synapse.settings.admin_contact = "admin.matrix@uninsane.org";
|
|
||||||
services.matrix-synapse.settings.registrations_require_3pid = [ "email" ];
|
|
||||||
|
|
||||||
services.matrix-synapse.extraConfigFiles = [
|
|
||||||
config.sops.secrets.matrix_synapse_secrets.path
|
|
||||||
];
|
|
||||||
|
|
||||||
# services.matrix-synapse.extraConfigFiles = [builtins.toFile "matrix-synapse-extra-config" ''
|
|
||||||
# admin_contact: "admin.matrix@uninsane.org"
|
|
||||||
# registrations_require_3pid:
|
|
||||||
# - email
|
|
||||||
# email:
|
|
||||||
# smtp_host: "mx.uninsane.org"
|
|
||||||
# smtp_port: 587
|
|
||||||
# smtp_user: "matrix-synapse"
|
|
||||||
# smtp_pass: "${secrets.matrix-synapse.smtp_pass}"
|
|
||||||
# require_transport_security: true
|
|
||||||
# enable_tls: true
|
|
||||||
# notif_from: "%(app)s <notify.matrix@uninsane.org>"
|
|
||||||
# app_name: "Uninsane Matrix"
|
|
||||||
# enable_notifs: true
|
|
||||||
# validation_token_lifetime: 96h
|
|
||||||
# invite_client_location: "https://web.matrix.uninsane.org"
|
|
||||||
# subjects:
|
|
||||||
# email_validation: "[%(server_name)s] Validate your email"
|
|
||||||
# ''];
|
|
||||||
services.matrix-synapse.settings.app_service_config_files = [
|
services.matrix-synapse.settings.app_service_config_files = [
|
||||||
"/var/lib/matrix-appservice-irc/registration.yml" # auto-created by irc appservice
|
"/var/lib/matrix-appservice-irc/registration.yml" # auto-created by irc appservice
|
||||||
];
|
];
|
||||||
|
|
||||||
# new users may be registered on the CLI:
|
|
||||||
# register_new_matrix_user -c /nix/store/8n6kcka37jhmi4qpd2r03aj71pkyh21s-homeserver.yaml http://localhost:8008
|
|
||||||
#
|
|
||||||
# or provide an registration token then can use to register through the client.
|
|
||||||
# docs: https://github.com/matrix-org/synapse/blob/develop/docs/usage/administration/admin_api/registration_tokens.md
|
|
||||||
# first, grab your own user's access token (Help & About section in Element). then:
|
|
||||||
# curl --header "Authorization: Bearer <my_token>" localhost:8008/_synapse/admin/v1/registration_tokens
|
|
||||||
# create a token with unlimited uses:
|
|
||||||
# curl -d '{}' --header "Authorization: Bearer <my_token>" localhost:8008/_synapse/admin/v1/registration_tokens/new
|
|
||||||
# create a token with limited uses:
|
|
||||||
# curl -d '{ "uses_allowed": 1 }' --header "Authorization: Bearer <my_token>" localhost:8008/_synapse/admin/v1/registration_tokens/new
|
|
||||||
|
|
||||||
# IRC bridging
|
|
||||||
# note: Rizon allows only FOUR simultaneous IRC connections per IP: https://wiki.rizon.net/index.php?title=Connection/Session_Limit_Exemptions
|
# note: Rizon allows only FOUR simultaneous IRC connections per IP: https://wiki.rizon.net/index.php?title=Connection/Session_Limit_Exemptions
|
||||||
# Rizon supports CertFP for auth: https://wiki.rizon.net/index.php?title=CertFP
|
# Rizon supports CertFP for auth: https://wiki.rizon.net/index.php?title=CertFP
|
||||||
# services.matrix-appservice-irc.enable = true;
|
services.matrix-appservice-irc.enable = true;
|
||||||
services.matrix-appservice-irc.registrationUrl = "http://127.0.0.1:8009";
|
services.matrix-appservice-irc.registrationUrl = "http://127.0.0.1:8009";
|
||||||
# settings documented here: https://github.com/matrix-org/matrix-appservice-irc/blob/develop/config.sample.yaml
|
# settings documented here: https://github.com/matrix-org/matrix-appservice-irc/blob/develop/config.sample.yaml
|
||||||
services.matrix-appservice-irc.settings = {
|
services.matrix-appservice-irc.settings = {
|
||||||
@@ -155,9 +94,4 @@
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
sops.secrets.matrix_synapse_secrets = {
|
|
||||||
sopsFile = ../../../secrets/servo.yaml;
|
|
||||||
owner = config.users.users.matrix-synapse.name;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
37
hosts/by-name/servo/services/matrix/signal.nix
Normal file
37
hosts/by-name/servo/services/matrix/signal.nix
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
# config options:
|
||||||
|
# - <https://github.com/mautrix/signal/blob/master/mautrix_signal/example-config.yaml>
|
||||||
|
{ config, pkgs, ... }:
|
||||||
|
{
|
||||||
|
sane.persist.sys.plaintext = [
|
||||||
|
{ user = "mautrix-signal"; group = "mautrix-signal"; directory = "/var/lib/mautrix-signal"; }
|
||||||
|
{ user = "signald"; group = "signald"; directory = "/var/lib/signald"; }
|
||||||
|
];
|
||||||
|
|
||||||
|
# allow synapse to read the registration file
|
||||||
|
users.users.matrix-synapse.extraGroups = [ "mautrix-signal" ];
|
||||||
|
|
||||||
|
services.signald.enable = true;
|
||||||
|
services.mautrix-signal.enable = true;
|
||||||
|
services.mautrix-signal.environmentFile =
|
||||||
|
config.sops.secrets.mautrix_signal_env.path;
|
||||||
|
|
||||||
|
services.mautrix-signal.settings.signal.socket_path = "/run/signald/signald.sock";
|
||||||
|
services.mautrix-signal.settings.homeserver.domain = "uninsane.org";
|
||||||
|
services.mautrix-signal.settings.bridge.permissions."@colin:uninsane.org" = "admin";
|
||||||
|
services.matrix-synapse.settings.app_service_config_files = [
|
||||||
|
# auto-created by mautrix-signal service
|
||||||
|
"/var/lib/mautrix-signal/signal-registration.yaml"
|
||||||
|
];
|
||||||
|
|
||||||
|
systemd.services.mautrix-signal.serviceConfig = {
|
||||||
|
# allow communication to signald
|
||||||
|
SupplementaryGroups = [ "signald" ];
|
||||||
|
ReadWritePaths = [ "/run/signald" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
sops.secrets."mautrix_signal_env" = {
|
||||||
|
mode = "0440";
|
||||||
|
owner = config.users.users.mautrix-signal.name;
|
||||||
|
group = config.users.users.matrix-synapse.name;
|
||||||
|
};
|
||||||
|
}
|
||||||
27
hosts/by-name/servo/services/matrix/synapse-log_level.yaml
Normal file
27
hosts/by-name/servo/services/matrix/synapse-log_level.yaml
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
version: 1
|
||||||
|
|
||||||
|
# In systemd's journal, loglevel is implicitly stored, so let's omit it
|
||||||
|
# from the message text.
|
||||||
|
formatters:
|
||||||
|
journal_fmt:
|
||||||
|
format: '%(name)s: [%(request)s] %(message)s'
|
||||||
|
|
||||||
|
filters:
|
||||||
|
context:
|
||||||
|
(): synapse.util.logcontext.LoggingContextFilter
|
||||||
|
request: ""
|
||||||
|
|
||||||
|
handlers:
|
||||||
|
journal:
|
||||||
|
class: systemd.journal.JournalHandler
|
||||||
|
formatter: journal_fmt
|
||||||
|
filters: [context]
|
||||||
|
SYSLOG_IDENTIFIER: synapse
|
||||||
|
|
||||||
|
# default log level: INFO
|
||||||
|
root:
|
||||||
|
level: WARN
|
||||||
|
handlers: [journal]
|
||||||
|
|
||||||
|
disable_existing_loggers: False
|
||||||
|
|
||||||
40
hosts/by-name/servo/services/navidrome.nix
Normal file
40
hosts/by-name/servo/services/navidrome.nix
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
{ lib, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
sane.persist.sys.plaintext = [
|
||||||
|
{ user = "navidrome"; group = "navidrome"; directory = "/var/lib/navidrome"; }
|
||||||
|
];
|
||||||
|
services.navidrome.enable = true;
|
||||||
|
services.navidrome.settings = {
|
||||||
|
# docs: https://www.navidrome.org/docs/usage/configuration-options/
|
||||||
|
Address = "127.0.0.1";
|
||||||
|
Port = 4533;
|
||||||
|
MusicFolder = "/var/lib/uninsane/media/Music";
|
||||||
|
CovertArtPriority = "*.jpg, *.JPG, *.png, *.PNG, embedded";
|
||||||
|
AutoImportPlaylists = false;
|
||||||
|
ScanSchedule = "@every 1h";
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.services.navidrome.serviceConfig = {
|
||||||
|
# fix to use a normal user so we can configure perms correctly
|
||||||
|
DynamicUser = lib.mkForce false;
|
||||||
|
User = "navidrome";
|
||||||
|
Group = "navidrome";
|
||||||
|
};
|
||||||
|
|
||||||
|
users.groups.navidrome = {};
|
||||||
|
|
||||||
|
users.users.navidrome = {
|
||||||
|
group = "navidrome";
|
||||||
|
isSystemUser = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
services.nginx.virtualHosts."music.uninsane.org" = {
|
||||||
|
forceSSL = true;
|
||||||
|
enableACME = true;
|
||||||
|
# inherit kTLS;
|
||||||
|
locations."/".proxyPass = "http://127.0.0.1:4533";
|
||||||
|
};
|
||||||
|
|
||||||
|
sane.services.trust-dns.zones."uninsane.org".inet.CNAME."music" = "native";
|
||||||
|
}
|
||||||
166
hosts/by-name/servo/services/nginx.nix
Normal file
166
hosts/by-name/servo/services/nginx.nix
Normal file
@@ -0,0 +1,166 @@
|
|||||||
|
# docs: https://nixos.wiki/wiki/Nginx
|
||||||
|
{ 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
|
||||||
|
{
|
||||||
|
|
||||||
|
networking.firewall.allowedTCPPorts = [ 80 443 ];
|
||||||
|
|
||||||
|
services.nginx.enable = true;
|
||||||
|
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;
|
||||||
|
'';
|
||||||
|
# sets gzip_comp_level = 5
|
||||||
|
services.nginx.recommendedGzipSettings = 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
|
||||||
|
services.nginx.virtualHosts."uninsane.org" = publog {
|
||||||
|
root = "${pkgs.uninsane-dot-org}/share/uninsane-dot-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;
|
||||||
|
# inherit kTLS;
|
||||||
|
# for OCSP stapling
|
||||||
|
sslTrustedCertificate = "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt";
|
||||||
|
|
||||||
|
# uninsane.org/share/foo => /var/lib/uninsane/root/share/foo.
|
||||||
|
# yes, nginx does not strip the prefix when evaluating against the root.
|
||||||
|
locations."/share".root = "/var/lib/uninsane/root";
|
||||||
|
|
||||||
|
# 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
|
||||||
|
# TODO: waiting on https://git.pleroma.social/pleroma/pleroma/-/merge_requests/3361/
|
||||||
|
# locations."/.well-known/nodeinfo" = {
|
||||||
|
# proxyPass = "http://127.0.0.1:4000";
|
||||||
|
# extraConfig = pleromaExtraConfig;
|
||||||
|
# };
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
# 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.plaintext = [
|
||||||
|
# TODO: mode?
|
||||||
|
{ user = "acme"; group = "acme"; directory = "/var/lib/acme"; }
|
||||||
|
{ user = "colin"; group = "users"; directory = "/var/www/sites"; }
|
||||||
|
];
|
||||||
|
|
||||||
|
# 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 || ${pkgs.openssl}/bin/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
|
||||||
|
'';
|
||||||
|
}
|
||||||
21
hosts/by-name/servo/services/nixserve.nix
Normal file
21
hosts/by-name/servo/services/nixserve.nix
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
{ config, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
services.nginx.virtualHosts."nixcache.uninsane.org" = {
|
||||||
|
addSSL = true;
|
||||||
|
enableACME = true;
|
||||||
|
# inherit kTLS;
|
||||||
|
# serverAliases = [ "nixcache" ];
|
||||||
|
locations."/".extraConfig = ''
|
||||||
|
proxy_pass http://localhost:${toString config.services.nix-serve.port};
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
sane.services.trust-dns.zones."uninsane.org".inet.CNAME."nixcache" = "native";
|
||||||
|
|
||||||
|
sane.services.nixserve.enable = true;
|
||||||
|
sane.services.nixserve.sopsFile = ../../../../secrets/servo.yaml;
|
||||||
|
}
|
||||||
@@ -1,21 +1,27 @@
|
|||||||
# docs: https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/services/networking/pleroma.nix
|
# docs:
|
||||||
|
# - https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/services/networking/pleroma.nix
|
||||||
|
# - https://docs.pleroma.social/backend/configuration/cheatsheet/
|
||||||
#
|
#
|
||||||
# to run it in a oci-container: https://github.com/barrucadu/nixfiles/blob/master/services/pleroma.nix
|
# to run it in a oci-container: https://github.com/barrucadu/nixfiles/blob/master/services/pleroma.nix
|
||||||
{ config, pkgs, ... }:
|
{ config, pkgs, ... }:
|
||||||
|
|
||||||
{
|
{
|
||||||
|
sane.persist.sys.plaintext = [
|
||||||
|
# TODO: mode? could be more granular
|
||||||
|
{ user = "pleroma"; group = "pleroma"; directory = "/var/lib/pleroma"; }
|
||||||
|
];
|
||||||
services.pleroma.enable = true;
|
services.pleroma.enable = true;
|
||||||
services.pleroma.secretConfigFile = config.sops.secrets.pleroma_secrets.path;
|
services.pleroma.secretConfigFile = config.sops.secrets.pleroma_secrets.path;
|
||||||
services.pleroma.configs = [
|
services.pleroma.configs = [
|
||||||
''
|
''
|
||||||
import Config
|
import Config
|
||||||
|
|
||||||
config :pleroma, Pleroma.Web.Endpoint,
|
config :pleroma, Pleroma.Web.Endpoint,
|
||||||
url: [host: "fed.uninsane.org", scheme: "https", port: 443],
|
url: [host: "fed.uninsane.org", scheme: "https", port: 443],
|
||||||
http: [ip: {127, 0, 0, 1}, port: 4000]
|
http: [ip: {127, 0, 0, 1}, port: 4000]
|
||||||
# secret_key_base: "{secrets.pleroma.secret_key_base}",
|
# secret_key_base: "{secrets.pleroma.secret_key_base}",
|
||||||
# signing_salt: "{secrets.pleroma.signing_salt}"
|
# signing_salt: "{secrets.pleroma.signing_salt}"
|
||||||
|
|
||||||
config :pleroma, :instance,
|
config :pleroma, :instance,
|
||||||
name: "Perfectly Sane",
|
name: "Perfectly Sane",
|
||||||
description: "Single-user Pleroma instance",
|
description: "Single-user Pleroma instance",
|
||||||
@@ -41,17 +47,20 @@
|
|||||||
enabled: false,
|
enabled: false,
|
||||||
redirect_on_failure: true
|
redirect_on_failure: true
|
||||||
#base_url: "https://cache.pleroma.social"
|
#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,
|
config :pleroma, Pleroma.Repo,
|
||||||
adapter: Ecto.Adapters.Postgres,
|
adapter: Ecto.Adapters.Postgres,
|
||||||
username: "pleroma",
|
username: "pleroma",
|
||||||
database: "pleroma",
|
database: "pleroma",
|
||||||
hostname: "localhost",
|
hostname: "localhost",
|
||||||
pool_size: 10,
|
pool_size: 10,
|
||||||
prepare: :named,
|
|
||||||
parameters: [
|
parameters: [
|
||||||
plan_cache_mode: "force_custom_plan"
|
plan_cache_mode: "force_custom_plan"
|
||||||
]
|
]
|
||||||
|
# XXX: prepare: :named is needed only for PG <= 12
|
||||||
|
# prepare: :named,
|
||||||
# password: "{secrets.pleroma.db_password}",
|
# password: "{secrets.pleroma.db_password}",
|
||||||
|
|
||||||
# Configure web push notifications
|
# Configure web push notifications
|
||||||
@@ -61,16 +70,17 @@
|
|||||||
# private_key: "{secrets.pleroma.vapid_private_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, :database, rum_enabled: false
|
||||||
config :pleroma, :instance, static_dir: "/var/lib/pleroma/instance/static"
|
config :pleroma, :instance, static_dir: "/var/lib/pleroma/instance/static"
|
||||||
config :pleroma, Pleroma.Uploaders.Local, uploads: "/var/lib/pleroma/uploads"
|
config :pleroma, Pleroma.Uploaders.Local, uploads: "/var/lib/pleroma/uploads"
|
||||||
config :pleroma, configurable_from_database: false
|
config :pleroma, configurable_from_database: false
|
||||||
|
|
||||||
# strip metadata from uploaded images
|
# strip metadata from uploaded images
|
||||||
config :pleroma, Pleroma.Upload, filters: [Pleroma.Upload.Filter.Exiftool]
|
config :pleroma, Pleroma.Upload, filters: [Pleroma.Upload.Filter.Exiftool.StripLocation]
|
||||||
|
|
||||||
# TODO: GET /api/pleroma/captcha is broken
|
# TODO: GET /api/pleroma/captcha is broken
|
||||||
|
# there was a nixpkgs PR to fix this around 2022/10 though.
|
||||||
config :pleroma, Pleroma.Captcha,
|
config :pleroma, Pleroma.Captcha,
|
||||||
enabled: false,
|
enabled: false,
|
||||||
method: Pleroma.Captcha.Native
|
method: Pleroma.Captcha.Native
|
||||||
@@ -80,11 +90,11 @@
|
|||||||
# Enable Strict-Transport-Security once SSL is working:
|
# Enable Strict-Transport-Security once SSL is working:
|
||||||
config :pleroma, :http_security,
|
config :pleroma, :http_security,
|
||||||
sts: true
|
sts: true
|
||||||
|
|
||||||
# docs: https://docs.pleroma.social/backend/configuration/cheatsheet/#logger
|
# docs: https://docs.pleroma.social/backend/configuration/cheatsheet/#logger
|
||||||
config :logger,
|
config :logger,
|
||||||
backends: [{ExSyslogger, :ex_syslogger}]
|
backends: [{ExSyslogger, :ex_syslogger}]
|
||||||
|
|
||||||
config :logger, :ex_syslogger,
|
config :logger, :ex_syslogger,
|
||||||
level: :warn
|
level: :warn
|
||||||
# level: :debug
|
# level: :debug
|
||||||
@@ -101,11 +111,11 @@
|
|||||||
''
|
''
|
||||||
];
|
];
|
||||||
|
|
||||||
systemd.services.pleroma.path = [
|
systemd.services.pleroma.path = [
|
||||||
# something inside pleroma invokes `sh` w/o specifying it by path, so this is needed to allow pleroma to start
|
# something inside pleroma invokes `sh` w/o specifying it by path, so this is needed to allow pleroma to start
|
||||||
pkgs.bash
|
pkgs.bash
|
||||||
# used by Pleroma to strip geo tags from uploads
|
# used by Pleroma to strip geo tags from uploads
|
||||||
pkgs.exiftool
|
pkgs.exiftool
|
||||||
# i saw some errors when pleroma was shutting down about it not being able to find `awk`. probably not critical
|
# i saw some errors when pleroma was shutting down about it not being able to find `awk`. probably not critical
|
||||||
pkgs.gawk
|
pkgs.gawk
|
||||||
# needed for email operations like password reset
|
# needed for email operations like password reset
|
||||||
@@ -115,6 +125,7 @@
|
|||||||
systemd.services.pleroma.serviceConfig = {
|
systemd.services.pleroma.serviceConfig = {
|
||||||
# postgres can be slow to service early requests, preventing pleroma from starting on the first try
|
# postgres can be slow to service early requests, preventing pleroma from starting on the first try
|
||||||
Restart = "on-failure";
|
Restart = "on-failure";
|
||||||
|
RestartSec = "10s";
|
||||||
};
|
};
|
||||||
|
|
||||||
# systemd.services.pleroma.serviceConfig = {
|
# systemd.services.pleroma.serviceConfig = {
|
||||||
@@ -124,8 +135,56 @@
|
|||||||
# CapabilityBoundingSet = lib.mkForce "~";
|
# CapabilityBoundingSet = lib.mkForce "~";
|
||||||
# };
|
# };
|
||||||
|
|
||||||
sops.secrets.pleroma_secrets = {
|
# this is required to allow pleroma to send email.
|
||||||
sopsFile = ../../../secrets/servo.yaml;
|
# 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:4000";
|
||||||
|
# documented: https://git.pleroma.social/pleroma/pleroma/-/blob/develop/installation/pleroma.nginx
|
||||||
|
extraConfig = ''
|
||||||
|
# XXX colin: this block is in the nixos examples: i don't understand all of it
|
||||||
|
add_header 'Access-Control-Allow-Origin' '*' always;
|
||||||
|
add_header 'Access-Control-Allow-Methods' 'POST, PUT, DELETE, GET, PATCH, OPTIONS' always;
|
||||||
|
add_header 'Access-Control-Allow-Headers' 'Authorization, Content-Type, Idempotency-Key' always;
|
||||||
|
add_header 'Access-Control-Expose-Headers' 'Link, X-RateLimit-Reset, X-RateLimit-Limit, X-RateLimit-Remaining, X-Request-Id' always;
|
||||||
|
if ($request_method = OPTIONS) {
|
||||||
|
return 204;
|
||||||
|
}
|
||||||
|
|
||||||
|
add_header X-XSS-Protection "1; mode=block";
|
||||||
|
add_header X-Permitted-Cross-Domain-Policies none;
|
||||||
|
add_header X-Frame-Options DENY;
|
||||||
|
add_header X-Content-Type-Options nosniff;
|
||||||
|
add_header Referrer-Policy same-origin;
|
||||||
|
add_header X-Download-Options noopen;
|
||||||
|
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection "upgrade";
|
||||||
|
# proxy_set_header Host $http_host;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
|
||||||
|
# colin: added this due to Pleroma complaining in its logs
|
||||||
|
# proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
# proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
|
||||||
|
client_max_body_size 16m;
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
sane.services.trust-dns.zones."uninsane.org".inet.CNAME."fed" = "native";
|
||||||
|
|
||||||
|
sops.secrets."pleroma_secrets" = {
|
||||||
owner = config.users.users.pleroma.name;
|
owner = config.users.users.pleroma.name;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -1,3 +1,6 @@
|
|||||||
|
# DOCS:
|
||||||
|
# - dovecot config: <https://doc.dovecot.org/configuration_manual/>
|
||||||
|
|
||||||
{ config, lib, ... }:
|
{ config, lib, ... }:
|
||||||
|
|
||||||
let
|
let
|
||||||
@@ -16,6 +19,73 @@ let
|
|||||||
};
|
};
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
|
sane.persist.sys.plaintext = [
|
||||||
|
# TODO: mode? could be more granular
|
||||||
|
{ user = "opendkim"; group = "opendkim"; directory = "/var/lib/opendkim"; }
|
||||||
|
{ user = "root"; group = "root"; directory = "/var/lib/postfix"; }
|
||||||
|
{ user = "root"; group = "root"; directory = "/var/spool/mail"; }
|
||||||
|
# *probably* don't need these dirs:
|
||||||
|
# "/var/lib/dhparams" # https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/security/dhparams.nix
|
||||||
|
# "/var/lib/dovecot"
|
||||||
|
];
|
||||||
|
|
||||||
|
networking.firewall.allowedTCPPorts = [
|
||||||
|
# exposed over non-vpn imap.uninsane.org
|
||||||
|
143 # IMAP
|
||||||
|
993 # IMAPS
|
||||||
|
|
||||||
|
# exposed over vpn mx.uninsane.org
|
||||||
|
25 # SMTP
|
||||||
|
465 # SMTPS
|
||||||
|
587 # SMTPS/submission
|
||||||
|
];
|
||||||
|
|
||||||
|
# exists only to manage certs for dovecot
|
||||||
|
services.nginx.virtualHosts."imap.uninsane.org" = {
|
||||||
|
enableACME = true;
|
||||||
|
};
|
||||||
|
# exists only to manage certs for Postfix
|
||||||
|
services.nginx.virtualHosts."mx.uninsane.org" = {
|
||||||
|
enableACME = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
sane.services.trust-dns.zones."uninsane.org".inet = {
|
||||||
|
MX."@" = "10 mx.uninsane.org.";
|
||||||
|
# XXX: RFC's specify that the MX record CANNOT BE A CNAME
|
||||||
|
A."mx" = "185.157.162.178";
|
||||||
|
CNAME."imap" = "native";
|
||||||
|
|
||||||
|
# Sender Policy Framework:
|
||||||
|
# +mx => mail passes if it originated from the MX
|
||||||
|
# +a => mail passes if it originated from the A address of this domain
|
||||||
|
# +ip4:.. => mail passes if it originated from this IP
|
||||||
|
# -all => mail fails if none of these conditions were met
|
||||||
|
TXT."@" = "v=spf1 a mx -all";
|
||||||
|
|
||||||
|
# DKIM public key:
|
||||||
|
TXT."mx._domainkey" =
|
||||||
|
"v=DKIM1;k=rsa;p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCkSyMufc2KrRx3j17e/LyB+3eYSBRuEFT8PUka8EDX04QzCwDPdkwgnj3GNDvnB5Ktb05Cf2SJ/S1OLqNsINxJRWtkVfZd/C339KNh9wrukMKRKNELL9HLUw0bczOI4gKKFqyrRE9qm+4csCMAR79Te9FCjGV/jVnrkLdPT0GtFwIDAQAB"
|
||||||
|
;
|
||||||
|
|
||||||
|
# DMARC fields <https://datatracker.ietf.org/doc/html/rfc7489>:
|
||||||
|
# p=none|quarantine|reject: what to do with failures
|
||||||
|
# sp = p but for subdomains
|
||||||
|
# rua = where to send aggregrate reports
|
||||||
|
# ruf = where to send individual failure reports
|
||||||
|
# fo=0|1|d|s controls WHEN to send failure reports
|
||||||
|
# (1=on bad alignment; d=on DKIM failure; s=on SPF failure);
|
||||||
|
# Additionally:
|
||||||
|
# adkim=r|s (is DKIM relaxed [default] or strict)
|
||||||
|
# aspf=r|s (is SPF relaxed [default] or strict)
|
||||||
|
# pct = sampling ratio for punishing failures (default 100 for 100%)
|
||||||
|
# rf = report format
|
||||||
|
# ri = report interval
|
||||||
|
TXT."_dmarc" =
|
||||||
|
"v=DMARC1;p=quarantine;sp=reject;rua=mailto:admin+mail@uninsane.org;ruf=mailto:admin+mail@uninsane.org;fo=1:d:s"
|
||||||
|
;
|
||||||
|
};
|
||||||
|
|
||||||
services.postfix.enable = true;
|
services.postfix.enable = true;
|
||||||
services.postfix.hostname = "mx.uninsane.org";
|
services.postfix.hostname = "mx.uninsane.org";
|
||||||
services.postfix.origin = "uninsane.org";
|
services.postfix.origin = "uninsane.org";
|
||||||
@@ -46,7 +116,8 @@ in
|
|||||||
services.postfix.enableSubmissions = true;
|
services.postfix.enableSubmissions = true;
|
||||||
services.postfix.submissionsOptions = submissionOptions;
|
services.postfix.submissionsOptions = submissionOptions;
|
||||||
|
|
||||||
systemd.services.postfix.after = [ "wg0veth.service" ];
|
systemd.services.postfix.after = [ "wireguard-wg-ovpns.service" ];
|
||||||
|
systemd.services.postfix.partOf = [ "wireguard-wg-ovpns.service" ];
|
||||||
systemd.services.postfix.serviceConfig = {
|
systemd.services.postfix.serviceConfig = {
|
||||||
# run this behind the OVPN static VPN
|
# run this behind the OVPN static VPN
|
||||||
NetworkNamespacePath = "/run/netns/ovpns";
|
NetworkNamespacePath = "/run/netns/ovpns";
|
||||||
@@ -67,7 +138,8 @@ in
|
|||||||
# keeping this the same as the hostname seems simplest
|
# keeping this the same as the hostname seems simplest
|
||||||
services.opendkim.selector = "mx";
|
services.opendkim.selector = "mx";
|
||||||
|
|
||||||
systemd.services.opendkim.after = [ "wg0veth.service" ];
|
systemd.services.opendkim.after = [ "wireguard-wg-ovpns.service" ];
|
||||||
|
systemd.services.opendkim.partOf = [ "wireguard-wg-ovpns.service" ];
|
||||||
systemd.services.opendkim.serviceConfig = {
|
systemd.services.opendkim.serviceConfig = {
|
||||||
# run this behind the OVPN static VPN
|
# run this behind the OVPN static VPN
|
||||||
NetworkNamespacePath = "/run/netns/ovpns";
|
NetworkNamespacePath = "/run/netns/ovpns";
|
||||||
@@ -77,6 +149,25 @@ in
|
|||||||
|
|
||||||
# inspired by https://gitlab.com/simple-nixos-mailserver/nixos-mailserver/
|
# inspired by https://gitlab.com/simple-nixos-mailserver/nixos-mailserver/
|
||||||
services.dovecot2.enable = true;
|
services.dovecot2.enable = true;
|
||||||
|
services.dovecot2.mailboxes = {
|
||||||
|
# special-purpose mailboxes: "All" "Archive" "Drafts" "Flagged" "Junk" "Sent" "Trash"
|
||||||
|
# RFC6154 describes these special mailboxes: https://www.ietf.org/rfc/rfc6154.html
|
||||||
|
# how these boxes are treated is 100% up to the client and server to decide.
|
||||||
|
# client behavior:
|
||||||
|
# iOS
|
||||||
|
# - Drafts: ?
|
||||||
|
# - Sent: works
|
||||||
|
# - Trash: works
|
||||||
|
# aerc
|
||||||
|
# - Drafts: works
|
||||||
|
# - Sent: works
|
||||||
|
# - Trash: no; deleted messages are actually deleted
|
||||||
|
# use `:move trash` instead
|
||||||
|
# Sent mailbox: all sent messages are copied to it. unclear if this happens server-side or client-side.
|
||||||
|
Drafts = { specialUse = "Drafts"; auto = "create"; };
|
||||||
|
Sent = { specialUse = "Sent"; auto = "create"; };
|
||||||
|
Trash = { specialUse = "Trash"; auto = "create"; };
|
||||||
|
};
|
||||||
services.dovecot2.sslServerCert = "/var/lib/acme/imap.uninsane.org/fullchain.pem";
|
services.dovecot2.sslServerCert = "/var/lib/acme/imap.uninsane.org/fullchain.pem";
|
||||||
services.dovecot2.sslServerKey = "/var/lib/acme/imap.uninsane.org/key.pem";
|
services.dovecot2.sslServerKey = "/var/lib/acme/imap.uninsane.org/key.pem";
|
||||||
services.dovecot2.enablePAM = false;
|
services.dovecot2.enablePAM = false;
|
||||||
@@ -131,8 +222,7 @@ in
|
|||||||
# }
|
# }
|
||||||
];
|
];
|
||||||
|
|
||||||
sops.secrets.dovecot_passwd = {
|
sops.secrets."dovecot_passwd" = {
|
||||||
sopsFile = ../../../secrets/servo.yaml;
|
|
||||||
owner = config.users.users.dovecot2.name;
|
owner = config.users.users.dovecot2.name;
|
||||||
# TODO: debug why mail can't be sent without this being world-readable
|
# TODO: debug why mail can't be sent without this being world-readable
|
||||||
mode = "0444";
|
mode = "0444";
|
||||||
@@ -1,6 +1,10 @@
|
|||||||
{ ... }:
|
{ ... }:
|
||||||
|
|
||||||
{
|
{
|
||||||
|
sane.persist.sys.plaintext = [
|
||||||
|
# TODO: mode?
|
||||||
|
{ user = "postgres"; group = "postgres"; directory = "/var/lib/postgresql"; }
|
||||||
|
];
|
||||||
services.postgresql.enable = true;
|
services.postgresql.enable = true;
|
||||||
# services.postgresql.dataDir = "/opt/postgresql/13";
|
# services.postgresql.dataDir = "/opt/postgresql/13";
|
||||||
# XXX colin: for a proper deploy, we'd want to include something for Pleroma here too.
|
# XXX colin: for a proper deploy, we'd want to include something for Pleroma here too.
|
||||||
@@ -13,6 +17,11 @@
|
|||||||
# LC_CTYPE = "C";
|
# LC_CTYPE = "C";
|
||||||
# '';
|
# '';
|
||||||
|
|
||||||
|
# TODO: 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 = { ... }
|
||||||
|
|
||||||
# daily backups to /var/backup
|
# daily backups to /var/backup
|
||||||
services.postgresqlBackup.enable = true;
|
services.postgresqlBackup.enable = true;
|
||||||
|
|
||||||
64
hosts/by-name/servo/services/prosody.nix
Normal file
64
hosts/by-name/servo/services/prosody.nix
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
# example configs:
|
||||||
|
# - <https://github.com/kittywitch/nixfiles/blob/main/services/prosody.nix>
|
||||||
|
# create users with:
|
||||||
|
# - `sudo -u prosody prosodyctl adduser colin@uninsane.org`
|
||||||
|
|
||||||
|
{ lib, ... }:
|
||||||
|
|
||||||
|
# XXX disabled: doesn't send messages to nixnet.social (only receives them).
|
||||||
|
# nixnet runs ejabberd, so revisiting that.
|
||||||
|
lib.mkIf false
|
||||||
|
{
|
||||||
|
sane.persist.sys.plaintext = [
|
||||||
|
{ user = "prosody"; group = "prosody"; directory = "/var/lib/prosody"; }
|
||||||
|
];
|
||||||
|
networking.firewall.allowedTCPPorts = [
|
||||||
|
5222 # XMPP client -> server
|
||||||
|
5269 # XMPP server -> server
|
||||||
|
5280 # bosh
|
||||||
|
5281 # Prosody HTTPS port (necessary?)
|
||||||
|
];
|
||||||
|
|
||||||
|
# provide access to certs
|
||||||
|
users.users.prosody.extraGroups = [ "nginx" ];
|
||||||
|
|
||||||
|
security.acme.certs."uninsane.org".extraDomainNames = [
|
||||||
|
"conference.xmpp.uninsane.org"
|
||||||
|
"upload.xmpp.uninsane.org"
|
||||||
|
];
|
||||||
|
|
||||||
|
services.prosody = {
|
||||||
|
enable = true;
|
||||||
|
admins = [ "colin@uninsane.org" ];
|
||||||
|
# allowRegistration = false;
|
||||||
|
# extraConfig = ''
|
||||||
|
# s2s_require_encryption = true
|
||||||
|
# c2s_require_encryption = true
|
||||||
|
# '';
|
||||||
|
|
||||||
|
extraModules = [ "private" "vcard" "privacy" "compression" "component" "muc" "pep" "adhoc" "lastactivity" "admin_adhoc" "blocklist"];
|
||||||
|
|
||||||
|
ssl.cert = "/var/lib/acme/uninsane.org/fullchain.pem";
|
||||||
|
ssl.key = "/var/lib/acme/uninsane.org/key.pem";
|
||||||
|
|
||||||
|
muc = [
|
||||||
|
{
|
||||||
|
domain = "conference.xmpp.uninsane.org";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
uploadHttp.domain = "upload.xmpp.uninsane.org";
|
||||||
|
|
||||||
|
virtualHosts = {
|
||||||
|
localhost = {
|
||||||
|
domain = "localhost";
|
||||||
|
enabled = true;
|
||||||
|
};
|
||||||
|
"xmpp.uninsane.org" = {
|
||||||
|
domain = "uninsane.org";
|
||||||
|
enabled = true;
|
||||||
|
ssl.cert = "/var/lib/acme/uninsane.org/fullchain.pem";
|
||||||
|
ssl.key = "/var/lib/acme/uninsane.org/key.pem";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
80
hosts/by-name/servo/services/transmission.nix
Normal file
80
hosts/by-name/servo/services/transmission.nix
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
{ pkgs, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
sane.persist.sys.plaintext = [
|
||||||
|
# TODO: mode? we need this specifically for the stats tracking in .config/
|
||||||
|
{ user = "transmission"; group = "transmission"; directory = "/var/lib/transmission"; }
|
||||||
|
];
|
||||||
|
services.transmission.enable = true;
|
||||||
|
services.transmission.settings = {
|
||||||
|
rpc-bind-address = "0.0.0.0";
|
||||||
|
#rpc-host-whitelist = "bt.uninsane.org";
|
||||||
|
#rpc-whitelist = "*.*.*.*";
|
||||||
|
rpc-authentication-required = true;
|
||||||
|
rpc-username = "colin";
|
||||||
|
# salted pw. to regenerate, set this plaintext, run nixos-rebuild, and then find the salted pw in:
|
||||||
|
# /var/lib/transmission/.config/transmission-daemon/settings.json
|
||||||
|
rpc-password = "{503fc8928344f495efb8e1f955111ca5c862ce0656SzQnQ5";
|
||||||
|
rpc-whitelist-enabled = false;
|
||||||
|
|
||||||
|
# download-dir = "/opt/uninsane/media/";
|
||||||
|
# hopefully, make the downloads world-readable
|
||||||
|
umask = 0;
|
||||||
|
|
||||||
|
# force peer connections to be encrypted
|
||||||
|
encryption = 2;
|
||||||
|
|
||||||
|
# units in kBps
|
||||||
|
speed-limit-down = 3000;
|
||||||
|
speed-limit-down-enabled = true;
|
||||||
|
speed-limit-up = 300;
|
||||||
|
speed-limit-up-enabled = true;
|
||||||
|
|
||||||
|
# see: https://git.zknt.org/mirror/transmission/commit/cfce6e2e3a9b9d31a9dafedd0bdc8bf2cdb6e876?lang=bg-BG
|
||||||
|
anti-brute-force-enabled = false;
|
||||||
|
|
||||||
|
download-dir = "/var/lib/uninsane/media";
|
||||||
|
incomplete-dir = "/var/lib/uninsane/media/incomplete";
|
||||||
|
|
||||||
|
};
|
||||||
|
# transmission will by default not allow the world to read its files.
|
||||||
|
services.transmission.downloadDirPermissions = "775";
|
||||||
|
|
||||||
|
systemd.services.transmission.after = [ "wireguard-wg-ovpns.service" ];
|
||||||
|
systemd.services.transmission.partOf = [ "wireguard-wg-ovpns.service" ];
|
||||||
|
systemd.services.transmission.serviceConfig = {
|
||||||
|
# run this behind the OVPN static VPN
|
||||||
|
NetworkNamespacePath = "/run/netns/ovpns";
|
||||||
|
LogLevelMax = "warning";
|
||||||
|
};
|
||||||
|
|
||||||
|
# service to automatically backup torrents i add to transmission
|
||||||
|
systemd.services.backup-torrents = {
|
||||||
|
description = "archive torrents to storage not owned by transmission";
|
||||||
|
script = ''
|
||||||
|
${pkgs.rsync}/bin/rsync -arv /var/lib/transmission/.config/transmission-daemon/torrents/ /var/backup/torrents/
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
systemd.timers.backup-torrents = {
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
timerConfig = {
|
||||||
|
OnStartupSec = "11min";
|
||||||
|
OnUnitActiveSec = "240min";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# transmission web client
|
||||||
|
services.nginx.virtualHosts."bt.uninsane.org" = {
|
||||||
|
# basicAuth is literally cleartext user/pw, so FORCE this to happen over SSL
|
||||||
|
forceSSL = true;
|
||||||
|
enableACME = true;
|
||||||
|
# inherit kTLS;
|
||||||
|
locations."/" = {
|
||||||
|
# proxyPass = "http://ovpns.uninsane.org:9091";
|
||||||
|
proxyPass = "http://10.0.1.6:9091";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
sane.services.trust-dns.zones."uninsane.org".inet.CNAME."bt" = "native";
|
||||||
|
}
|
||||||
|
|
||||||
67
hosts/by-name/servo/services/trust-dns.nix
Normal file
67
hosts/by-name/servo/services/trust-dns.nix
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
{ config, pkgs, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
sane.services.trust-dns.enable = true;
|
||||||
|
|
||||||
|
sane.services.trust-dns.listenAddrsIPv4 = [
|
||||||
|
# specify each address explicitly, instead of using "*".
|
||||||
|
# this ensures responses are sent from the address at which the request was received.
|
||||||
|
config.sane.hosts.by-name."servo".lan-ip
|
||||||
|
"10.0.1.5"
|
||||||
|
];
|
||||||
|
sane.services.trust-dns.quiet = true;
|
||||||
|
|
||||||
|
sane.services.trust-dns.zones."uninsane.org".TTL = 900;
|
||||||
|
|
||||||
|
# SOA record structure: <https://en.wikipedia.org/wiki/SOA_record#Structure>
|
||||||
|
# SOA MNAME RNAME (... rest)
|
||||||
|
# MNAME = Master name server for this zone. this is where update requests should be sent.
|
||||||
|
# RNAME = admin contact (encoded email address)
|
||||||
|
# Serial = YYYYMMDDNN, where N is incremented every time this file changes, to trigger secondary NS to re-fetch it.
|
||||||
|
# Refresh = how frequently secondary NS should query master
|
||||||
|
# Retry = how long secondary NS should wait until re-querying master after a failure (must be < Refresh)
|
||||||
|
# Expire = how long secondary NS should continue to reply to queries after master fails (> Refresh + Retry)
|
||||||
|
sane.services.trust-dns.zones."uninsane.org".inet = {
|
||||||
|
SOA."@" = ''
|
||||||
|
ns1.uninsane.org. admin-dns.uninsane.org. (
|
||||||
|
2022122101 ; Serial
|
||||||
|
4h ; Refresh
|
||||||
|
30m ; Retry
|
||||||
|
7d ; Expire
|
||||||
|
5m) ; Negative response TTL
|
||||||
|
'';
|
||||||
|
TXT."rev" = "2022122101";
|
||||||
|
|
||||||
|
# XXX NS records must also not be CNAME
|
||||||
|
# it's best that we keep this identical, or a superset of, what org. lists as our NS.
|
||||||
|
# so, org. can specify ns2/ns3 as being to the VPN, with no mention of ns1. we provide ns1 here.
|
||||||
|
A."ns1" = "%NATIVE%";
|
||||||
|
A."ns2" = "185.157.162.178";
|
||||||
|
A."ns3" = "185.157.162.178";
|
||||||
|
A."ovpns" = "185.157.162.178";
|
||||||
|
A."native" = "%NATIVE%";
|
||||||
|
A."@" = "%NATIVE%";
|
||||||
|
NS."@" = [
|
||||||
|
"ns1.uninsane.org."
|
||||||
|
"ns2.uninsane.org."
|
||||||
|
"ns3.uninsane.org."
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
sane.services.trust-dns.zones."uninsane.org".file =
|
||||||
|
"/var/lib/trust-dns/uninsane.org.zone";
|
||||||
|
|
||||||
|
systemd.services.trust-dns.preStart = let
|
||||||
|
sed = "${pkgs.gnused}/bin/sed";
|
||||||
|
zone-dir = "/var/lib/trust-dns";
|
||||||
|
zone-out = "${zone-dir}/uninsane.org.zone";
|
||||||
|
zone-template = pkgs.writeText "uninsane.org.zone.in" config.sane.services.trust-dns.generatedZones."uninsane.org";
|
||||||
|
in ''
|
||||||
|
# make WAN records available to trust-dns
|
||||||
|
mkdir -p ${zone-dir}
|
||||||
|
ip=$(cat '${config.sane.services.dyn-dns.ipPath}')
|
||||||
|
${sed} s/%NATIVE%/$ip/ ${zone-template} > ${zone-out}
|
||||||
|
'';
|
||||||
|
|
||||||
|
sane.services.dyn-dns.restartOnChange = [ "trust-dns.service" ];
|
||||||
|
}
|
||||||
30
hosts/by-name/servo/services/wikipedia.nix
Normal file
30
hosts/by-name/servo/services/wikipedia.nix
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
# docs: <https://nixos.wiki/wiki/MediaWiki>
|
||||||
|
{ config, lib, ... }:
|
||||||
|
|
||||||
|
# XXX: working to host wikipedia with kiwix instead of mediawiki
|
||||||
|
# mediawiki does more than i need and isn't obviously superior in any way
|
||||||
|
# except that the dumps are more frequent/up-to-date.
|
||||||
|
lib.mkIf false
|
||||||
|
{
|
||||||
|
sops.secrets."mediawiki_pw" = {
|
||||||
|
owner = config.users.users.mediawiki.name;
|
||||||
|
};
|
||||||
|
|
||||||
|
services.mediawiki.enable = true;
|
||||||
|
services.mediawiki.name = "Uninsane Wiki";
|
||||||
|
services.mediawiki.passwordFile = config.sops.secrets.mediawiki_pw.path;
|
||||||
|
services.mediawiki.extraConfig = ''
|
||||||
|
# Disable anonymous editing
|
||||||
|
$wgGroupPermissions['*']['edit'] = false;
|
||||||
|
'';
|
||||||
|
services.mediawiki.virtualHost.listen = [
|
||||||
|
{
|
||||||
|
ip = "127.0.0.1";
|
||||||
|
port = 8013;
|
||||||
|
ssl = false;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
services.mediawiki.virtualHost.hostName = "w.uninsane.org";
|
||||||
|
services.mediawiki.virtualHost.adminAddr = "admin+mediawiki@uninsane.org";
|
||||||
|
# services.mediawiki.extensions = TODO: wikipedia sync extension?
|
||||||
|
}
|
||||||
1611
hosts/common/cross/default.nix
Normal file
1611
hosts/common/cross/default.nix
Normal file
File diff suppressed because it is too large
Load Diff
22
hosts/common/cross/kitty-no-docs.patch
Normal file
22
hosts/common/cross/kitty-no-docs.patch
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
diff --git a/setup.py b/setup.py
|
||||||
|
index 2b9d240e..770bc5e7 100755
|
||||||
|
--- a/setup.py
|
||||||
|
+++ b/setup.py
|
||||||
|
@@ -1092,11 +1092,12 @@ def c(base_path: str, **kw: object) -> None:
|
||||||
|
|
||||||
|
|
||||||
|
def create_linux_bundle_gunk(ddir: str, libdir_name: str) -> None:
|
||||||
|
- if not os.path.exists('docs/_build/html'):
|
||||||
|
- make = 'gmake' if is_freebsd else 'make'
|
||||||
|
- run_tool([make, 'docs'])
|
||||||
|
- copy_man_pages(ddir)
|
||||||
|
- copy_html_docs(ddir)
|
||||||
|
+ if not os.getenv('KITTY_NO_DOCS'):
|
||||||
|
+ if not os.path.exists('docs/_build/html'):
|
||||||
|
+ make = 'gmake' if is_freebsd else 'make'
|
||||||
|
+ run_tool([make, 'docs'])
|
||||||
|
+ copy_man_pages(ddir)
|
||||||
|
+ copy_html_docs(ddir)
|
||||||
|
for (icdir, ext) in {'256x256': 'png', 'scalable': 'svg'}.items():
|
||||||
|
icdir = os.path.join(ddir, 'share', 'icons', 'hicolor', icdir, 'apps')
|
||||||
|
safe_makedirs(icdir)
|
||||||
109
hosts/common/default.nix
Normal file
109
hosts/common/default.nix
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
{ lib, pkgs, ... }:
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
./cross
|
||||||
|
./feeds.nix
|
||||||
|
./fs.nix
|
||||||
|
./hardware.nix
|
||||||
|
./home
|
||||||
|
./i2p.nix
|
||||||
|
./ids.nix
|
||||||
|
./machine-id.nix
|
||||||
|
./net.nix
|
||||||
|
./persist.nix
|
||||||
|
./programs.nix
|
||||||
|
./secrets.nix
|
||||||
|
./ssh.nix
|
||||||
|
./users.nix
|
||||||
|
./vpn.nix
|
||||||
|
];
|
||||||
|
|
||||||
|
sane.nixcache.enable-trusted-keys = true;
|
||||||
|
sane.nixcache.enable = lib.mkDefault true;
|
||||||
|
sane.persist.enable = lib.mkDefault true;
|
||||||
|
sane.programs.sysadminUtils.enableFor.system = lib.mkDefault true;
|
||||||
|
sane.programs.consoleUtils.enableFor.user.colin = lib.mkDefault true;
|
||||||
|
|
||||||
|
# some services which use private directories error if the parent (/var/lib/private) isn't 700.
|
||||||
|
sane.fs."/var/lib/private".dir.acl.mode = "0700";
|
||||||
|
|
||||||
|
nixpkgs.config.allowUnfree = true;
|
||||||
|
|
||||||
|
# time.timeZone = "America/Los_Angeles";
|
||||||
|
time.timeZone = "Etc/UTC"; # DST is too confusing for me => use a stable timezone
|
||||||
|
|
||||||
|
# allow `nix flake ...` command
|
||||||
|
# TODO: is this still required?
|
||||||
|
nix.extraOptions = ''
|
||||||
|
experimental-features = nix-command flakes
|
||||||
|
'';
|
||||||
|
# allow `nix-shell` (and probably nix-index?) to locate our patched and custom packages
|
||||||
|
nix.nixPath = [
|
||||||
|
"nixpkgs=${pkgs.path}"
|
||||||
|
"nixpkgs-overlays=${../..}/overlays"
|
||||||
|
];
|
||||||
|
# hardlinks identical files in the nix store to save 25-35% disk space.
|
||||||
|
# unclear _when_ this occurs. it's not a service.
|
||||||
|
# does the daemon continually scan the nix store?
|
||||||
|
# does the builder use some content-addressed db to efficiently dedupe?
|
||||||
|
nix.settings.auto-optimise-store = true;
|
||||||
|
|
||||||
|
fonts = {
|
||||||
|
enableDefaultFonts = true;
|
||||||
|
fonts = with pkgs; [ font-awesome noto-fonts-emoji hack-font ];
|
||||||
|
fontconfig.enable = true;
|
||||||
|
fontconfig.defaultFonts = {
|
||||||
|
emoji = [ "Font Awesome 6 Free" "Noto Color Emoji" ];
|
||||||
|
monospace = [ "Hack" ];
|
||||||
|
serif = [ "DejaVu Serif" ];
|
||||||
|
sansSerif = [ "DejaVu Sans" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# XXX: twitter-color-emoji doesn't cross-compile; but not-fonts-emoji does
|
||||||
|
# fonts = {
|
||||||
|
# enableDefaultFonts = true;
|
||||||
|
# fonts = with pkgs; [ font-awesome twitter-color-emoji hack-font ];
|
||||||
|
# fontconfig.enable = true;
|
||||||
|
# fontconfig.defaultFonts = {
|
||||||
|
# emoji = [ "Font Awesome 6 Free" "Twitter Color Emoji" ];
|
||||||
|
# monospace = [ "Hack" ];
|
||||||
|
# serif = [ "DejaVu Serif" ];
|
||||||
|
# sansSerif = [ "DejaVu Sans" ];
|
||||||
|
# };
|
||||||
|
# };
|
||||||
|
|
||||||
|
# disable non-required packages like nano, perl, rsync, strace
|
||||||
|
environment.defaultPackages = [];
|
||||||
|
|
||||||
|
# programs.vim.defaultEditor = true;
|
||||||
|
environment.variables = {
|
||||||
|
EDITOR = "vim";
|
||||||
|
# git claims it should use EDITOR, but it doesn't!
|
||||||
|
GIT_EDITOR = "vim";
|
||||||
|
# TODO: these should be moved to `home.sessionVariables` (home-manager)
|
||||||
|
# Electron apps should use native wayland backend:
|
||||||
|
# https://nixos.wiki/wiki/Slack#Wayland
|
||||||
|
# Discord under sway crashes with this.
|
||||||
|
# NIXOS_OZONE_WL = "1";
|
||||||
|
# LIBGL_ALWAYS_SOFTWARE = "1";
|
||||||
|
};
|
||||||
|
|
||||||
|
# dconf docs: <https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/desktop_migration_and_administration_guide/profiles>
|
||||||
|
# find keys/values with `dconf dump /`
|
||||||
|
programs.dconf.enable = true;
|
||||||
|
programs.dconf.packages = [
|
||||||
|
(pkgs.writeTextFile {
|
||||||
|
name = "dconf-user-profile";
|
||||||
|
destination = "/etc/dconf/profile/user";
|
||||||
|
text = ''
|
||||||
|
user-db:user
|
||||||
|
system-db:site
|
||||||
|
'';
|
||||||
|
})
|
||||||
|
];
|
||||||
|
|
||||||
|
# link debug symbols into /run/current-system/sw/lib/debug
|
||||||
|
# hopefully picked up by gdb automatically?
|
||||||
|
environment.enableDebugInfo = true;
|
||||||
|
}
|
||||||
234
hosts/common/feeds.nix
Normal file
234
hosts/common/feeds.nix
Normal file
@@ -0,0 +1,234 @@
|
|||||||
|
# candidates:
|
||||||
|
# - The Nonlinear Library (podcast): <https://forum.effectivealtruism.org/posts/JTZTBienqWEAjGDRv/listen-to-more-ea-content-with-the-nonlinear-library>
|
||||||
|
# - has ~10 posts per day, text-to-speech; i would need better tagging before adding this
|
||||||
|
# - <https://www.metaculus.com/questions/11102/introducing-the-metaculus-journal-podcast/>
|
||||||
|
# - dead since 2022/10 - 2023/03
|
||||||
|
|
||||||
|
{ lib, sane-data, ... }:
|
||||||
|
let
|
||||||
|
hourly = { freq = "hourly"; };
|
||||||
|
daily = { freq = "daily"; };
|
||||||
|
weekly = { freq = "weekly"; };
|
||||||
|
infrequent = { freq = "infrequent"; };
|
||||||
|
|
||||||
|
art = { cat = "art"; };
|
||||||
|
humor = { cat = "humor"; };
|
||||||
|
pol = { cat = "pol"; }; # or maybe just "social"
|
||||||
|
rat = { cat = "rat"; };
|
||||||
|
tech = { cat = "tech"; };
|
||||||
|
uncat = { cat = "uncat"; };
|
||||||
|
|
||||||
|
text = { format = "text"; };
|
||||||
|
img = { format = "image"; };
|
||||||
|
|
||||||
|
mkRss = format: url: { inherit url format; } // uncat // infrequent;
|
||||||
|
# format-specific helpers
|
||||||
|
mkText = mkRss "text";
|
||||||
|
mkImg = mkRss "image";
|
||||||
|
mkPod = mkRss "podcast";
|
||||||
|
|
||||||
|
# host-specific helpers
|
||||||
|
mkSubstack = subdomain: { substack = subdomain; };
|
||||||
|
|
||||||
|
fromDb = name:
|
||||||
|
let
|
||||||
|
raw = sane-data.feeds."${name}";
|
||||||
|
in {
|
||||||
|
url = raw.url;
|
||||||
|
# not sure the exact mapping with velocity here: entries per day?
|
||||||
|
freq = lib.mkIf (raw.velocity or 0 != 0) (lib.mkDefault (
|
||||||
|
if raw.velocity > 2 then
|
||||||
|
"hourly"
|
||||||
|
else if raw.velocity > 0.5 then
|
||||||
|
"daily"
|
||||||
|
else if raw.velocity > 0.1 then
|
||||||
|
"weekly"
|
||||||
|
else
|
||||||
|
"infrequent"
|
||||||
|
));
|
||||||
|
} // lib.optionalAttrs (raw.is_podcast or false) {
|
||||||
|
format = "podcast";
|
||||||
|
} // lib.optionalAttrs (raw.title or "" != "") {
|
||||||
|
title = lib.mkDefault raw.title;
|
||||||
|
};
|
||||||
|
|
||||||
|
podcasts = [
|
||||||
|
(fromDb "lexfridman.com/podcast" // rat)
|
||||||
|
## Astral Codex Ten
|
||||||
|
(fromDb "sscpodcast.libsyn.com" // rat)
|
||||||
|
## Less Wrong Curated
|
||||||
|
(fromDb "feeds.libsyn.com/421877" // rat)
|
||||||
|
## Econ Talk
|
||||||
|
(fromDb "feeds.simplecast.com/wgl4xEgL" // rat)
|
||||||
|
## Cory Doctorow -- both podcast & text entries
|
||||||
|
(fromDb "craphound.com" // pol)
|
||||||
|
## Maggie Killjoy -- referenced by Cory Doctorow
|
||||||
|
(fromDb "omny.fm/shows/cool-people-who-did-cool-stuff" // pol)
|
||||||
|
(fromDb "congressionaldish.libsyn.com" // pol)
|
||||||
|
(mkPod "https://podcasts.la.utexas.edu/this-is-democracy/feed/podcast/" // pol // weekly)
|
||||||
|
## Civboot -- https://anchor.fm/civboot
|
||||||
|
(fromDb "anchor.fm/s/34c7232c/podcast/rss" // tech)
|
||||||
|
## Emerge: making sense of what's next -- <https://www.whatisemerging.com/emergepodcast>
|
||||||
|
(mkPod "https://anchor.fm/s/21bc734/podcast/rss" // pol // infrequent)
|
||||||
|
(fromDb "feeds.feedburner.com/80000HoursPodcast" // rat)
|
||||||
|
## Daniel Huberman on sleep
|
||||||
|
(fromDb "feeds.megaphone.fm/hubermanlab" // uncat)
|
||||||
|
## Multidisciplinary Association for Psychedelic Studies
|
||||||
|
(fromDb "mapspodcast.libsyn.com" // uncat)
|
||||||
|
(fromDb "allinchamathjason.libsyn.com" // pol)
|
||||||
|
(fromDb "acquired.libsyn.com" // tech)
|
||||||
|
## ACQ2 - more "Acquired" episodes
|
||||||
|
(fromDb "acquiredlpbonussecretsecret.libsyn.com" // tech)
|
||||||
|
# The Intercept - Deconstructed; also available: <rss.acast.com/deconstructed>
|
||||||
|
(fromDb "rss.prod.firstlook.media/deconstructed/podcast.rss" // pol)
|
||||||
|
## The Daily
|
||||||
|
(mkPod "https://feeds.simplecast.com/54nAGcIl" // pol // daily)
|
||||||
|
# The Intercept - Intercepted; also available: <https://rss.acast.com/intercepted-with-jeremy-scahill>
|
||||||
|
(fromDb "rss.prod.firstlook.media/intercepted/podcast.rss" // pol)
|
||||||
|
(fromDb "podcast.posttv.com/itunes/post-reports.xml" // pol)
|
||||||
|
## Eric Weinstein
|
||||||
|
(fromDb "rss.art19.com/the-portal" // rat)
|
||||||
|
(fromDb "darknetdiaries.com" // tech)
|
||||||
|
## Radiolab -- also available here, but ONLY OVER HTTP: <http://feeds.wnyc.org/radiolab>
|
||||||
|
(fromDb "feeds.feedburner.com/radiolab" // pol)
|
||||||
|
## Sam Harris
|
||||||
|
(fromDb "wakingup.libsyn.com" // pol)
|
||||||
|
## 99% Invisible -- also available here: <https://feeds.simplecast.com/BqbsxVfO>
|
||||||
|
(fromDb "feeds.99percentinvisible.org/99percentinvisible" // pol)
|
||||||
|
(fromDb "rss.acast.com/ft-tech-tonic" // tech)
|
||||||
|
(fromDb "feeds.feedburner.com/dancarlin/history" // rat)
|
||||||
|
(fromDb "rss.art19.com/60-minutes" // pol)
|
||||||
|
## The Verge - Decoder
|
||||||
|
(fromDb "feeds.megaphone.fm/recodedecode" // tech)
|
||||||
|
## Matrix (chat) Live
|
||||||
|
(fromDb "feed.podbean.com/matrixlive/feed.xml" // tech)
|
||||||
|
## Michael Malice - Your Welcome -- also available here: <https://origin.podcastone.com/podcast?categoryID2=2232>
|
||||||
|
(fromDb "rss.art19.com/your-welcome" // pol)
|
||||||
|
(fromDb "seattlenice.buzzsprout.com" // pol)
|
||||||
|
## Sci-Fi? has Peter Watts; author of No Moods, Ads or Cutesy Fucking Icons (rifters.com)
|
||||||
|
(fromDb "talesfromthebridge.buzzsprout.com" // tech)
|
||||||
|
## UnNamed Reverse Engineering Podcast
|
||||||
|
(fromDb "reverseengineering.libsyn.com/rss" // tech)
|
||||||
|
];
|
||||||
|
|
||||||
|
texts = [
|
||||||
|
# AGGREGATORS (> 1 post/day)
|
||||||
|
(fromDb "lwn.net" // tech)
|
||||||
|
(fromDb "lesswrong.com" // rat)
|
||||||
|
(fromDb "econlib.org" // pol)
|
||||||
|
|
||||||
|
# AGGREGATORS (< 1 post/day)
|
||||||
|
(fromDb "palladiummag.com" // uncat)
|
||||||
|
(fromDb "profectusmag.com" // uncat)
|
||||||
|
(fromDb "semiaccurate.com" // tech)
|
||||||
|
(mkText "https://linuxphoneapps.org/blog/atom.xml" // tech // infrequent)
|
||||||
|
(fromDb "spectrum.ieee.org" // tech)
|
||||||
|
(fromDb "thisweek.gnome.org" // tech)
|
||||||
|
# more nixos stuff here, but unclear how to subscribe: <https://nixos.org/blog/categories.html>
|
||||||
|
(mkText "https://nixos.org/blog/announcements-rss.xml" // tech // infrequent)
|
||||||
|
(mkText "https://nixos.org/blog/stories-rss.xml" // tech // weekly)
|
||||||
|
## n.b.: quality RSS list here: <https://forum.merveilles.town/thread/57/share-your-rss-feeds%21-6/>
|
||||||
|
(mkText "https://forum.merveilles.town/rss.xml" // pol // infrequent)
|
||||||
|
|
||||||
|
## No Moods, Ads or Cutesy Fucking Icons
|
||||||
|
(fromDb "rifters.com/crawl" // uncat)
|
||||||
|
|
||||||
|
# DEVELOPERS
|
||||||
|
(fromDb "uninsane.org" // tech)
|
||||||
|
(fromDb "ascii.textfiles.com" // tech) # Jason Scott
|
||||||
|
(fromDb "xn--gckvb8fzb.com" // tech)
|
||||||
|
(fromDb "mg.lol" // tech)
|
||||||
|
(fromDb "drewdevault.com" // tech)
|
||||||
|
## Ken Shirriff
|
||||||
|
(fromDb "righto.com" // tech)
|
||||||
|
## shared blog by a few NixOS devs, notably onny
|
||||||
|
(fromDb "project-insanity.org" // tech)
|
||||||
|
## Vitalik Buterin
|
||||||
|
(fromDb "vitalik.ca" // tech)
|
||||||
|
## ian (Sanctuary)
|
||||||
|
(fromDb "sagacioussuricata.com" // tech)
|
||||||
|
## Bunnie Juang
|
||||||
|
(fromDb "bunniestudios.com" // tech)
|
||||||
|
(fromDb "blog.danieljanus.pl" // tech)
|
||||||
|
(fromDb "ianthehenry.com" // tech)
|
||||||
|
(fromDb "bitbashing.io" // tech)
|
||||||
|
(fromDb "idiomdrottning.org" // uncat)
|
||||||
|
(mkText "https://anish.lakhwara.com/home.html" // tech // weekly)
|
||||||
|
(fromDb "jefftk.com" // tech)
|
||||||
|
(fromDb "pomeroyb.com" // tech)
|
||||||
|
(mkText "https://til.simonwillison.net/tils/feed.atom" // tech // weekly)
|
||||||
|
|
||||||
|
# TECH PROJECTS
|
||||||
|
(fromDb "blog.rust-lang.org" // tech)
|
||||||
|
|
||||||
|
# (TECH; POL) COMMENTATORS
|
||||||
|
## Matt Webb -- engineering-ish, but dreamy
|
||||||
|
(fromDb "interconnected.org/home/feed" // rat)
|
||||||
|
(fromDb "edwardsnowden.substack.com" // pol // text)
|
||||||
|
## Julia Evans
|
||||||
|
(mkText "https://jvns.ca/atom.xml" // tech // weekly)
|
||||||
|
(mkText "http://benjaminrosshoffman.com/feed" // pol // weekly)
|
||||||
|
## Ben Thompson
|
||||||
|
(mkText "https://www.stratechery.com/rss" // pol // weekly)
|
||||||
|
## Balaji
|
||||||
|
(fromDb "balajis.com" // pol)
|
||||||
|
(fromDb "ben-evans.com/benedictevans" // pol)
|
||||||
|
(fromDb "lynalden.com" // pol)
|
||||||
|
(fromDb "austinvernon.site" // tech)
|
||||||
|
(mkSubstack "oversharing" // pol // daily)
|
||||||
|
(mkSubstack "byrnehobart" // pol // infrequent)
|
||||||
|
# (mkSubstack "doomberg" // tech // weekly) # articles are all pay-walled
|
||||||
|
## David Rosenthal
|
||||||
|
(fromDb "blog.dshr.org" // pol)
|
||||||
|
## Matt Levine
|
||||||
|
(mkText "https://www.bloomberg.com/opinion/authors/ARbTQlRLRjE/matthew-s-levine.rss" // pol // weekly)
|
||||||
|
(fromDb "stpeter.im/atom.xml" // pol)
|
||||||
|
## Peter Saint-Andre -- side project of stpeter.im
|
||||||
|
(fromDb "philosopher.coach" // rat)
|
||||||
|
|
||||||
|
# RATIONALITY/PHILOSOPHY/ETC
|
||||||
|
(mkSubstack "samkriss" // humor // infrequent)
|
||||||
|
(fromDb "unintendedconsequenc.es" // rat)
|
||||||
|
(fromDb "applieddivinitystudies.com" // rat)
|
||||||
|
(fromDb "slimemoldtimemold.com" // rat)
|
||||||
|
(fromDb "richardcarrier.info" // rat)
|
||||||
|
(fromDb "gwern.net" // rat)
|
||||||
|
## Jason Crawford
|
||||||
|
(fromDb "rootsofprogress.org" // rat)
|
||||||
|
## Robin Hanson
|
||||||
|
(fromDb "overcomingbias.com" // rat)
|
||||||
|
## Scott Alexander
|
||||||
|
(mkSubstack "astralcodexten" // rat // daily)
|
||||||
|
## Paul Christiano
|
||||||
|
(fromDb "sideways-view.com" // rat)
|
||||||
|
## Sean Carroll
|
||||||
|
(fromDb "preposterousuniverse.com" // rat)
|
||||||
|
|
||||||
|
## mostly dating topics. not advice, or humor, but looking through a social lens
|
||||||
|
(fromDb "putanumonit.com" // rat)
|
||||||
|
|
||||||
|
# CODE
|
||||||
|
# (mkText "https://github.com/Kaiteki-Fedi/Kaiteki/commits/master.atom" // tech // infrequent)
|
||||||
|
];
|
||||||
|
|
||||||
|
images = [
|
||||||
|
(fromDb "smbc-comics.com" // img // humor)
|
||||||
|
(fromDb "xkcd.com" // img // humor)
|
||||||
|
(fromDb "pbfcomics.com" // img // humor)
|
||||||
|
# (mkImg "http://dilbert.com/feed" // humor // daily)
|
||||||
|
(fromDb "poorlydrawnlines.com/feed" // img // humor)
|
||||||
|
|
||||||
|
# ART
|
||||||
|
(fromDb "miniature-calendar.com" // img // art // daily)
|
||||||
|
];
|
||||||
|
in
|
||||||
|
{
|
||||||
|
sane.feeds = texts ++ images ++ podcasts;
|
||||||
|
|
||||||
|
assertions = builtins.map
|
||||||
|
(p: {
|
||||||
|
assertion = p.format or "unknown" == "podcast";
|
||||||
|
message = ''${p.url} is not a podcast: ${p.format or "unknown"}'';
|
||||||
|
})
|
||||||
|
podcasts;
|
||||||
|
}
|
||||||
74
hosts/common/fs.nix
Normal file
74
hosts/common/fs.nix
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
{ pkgs, ... }:
|
||||||
|
|
||||||
|
let sshOpts = rec {
|
||||||
|
fsType = "fuse.sshfs";
|
||||||
|
optionsBase = [
|
||||||
|
"x-systemd.automount"
|
||||||
|
"_netdev"
|
||||||
|
"user"
|
||||||
|
"identityfile=/home/colin/.ssh/id_ed25519"
|
||||||
|
"allow_other"
|
||||||
|
"default_permissions"
|
||||||
|
];
|
||||||
|
optionsColin = optionsBase ++ [
|
||||||
|
"transform_symlinks"
|
||||||
|
"idmap=user"
|
||||||
|
"uid=1000"
|
||||||
|
"gid=100"
|
||||||
|
];
|
||||||
|
|
||||||
|
optionsRoot = optionsBase ++ [
|
||||||
|
# we don't transform_symlinks because that breaks the validity of remote /nix stores
|
||||||
|
"sftp_server=/run/wrappers/bin/sudo\\040/run/current-system/sw/libexec/sftp-server"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
environment.pathsToLink = [
|
||||||
|
# needed to achieve superuser access for user-mounted filesystems (see optionsRoot above)
|
||||||
|
# we can only link whole directories here, even though we're only interested in pkgs.openssh
|
||||||
|
"/libexec"
|
||||||
|
];
|
||||||
|
|
||||||
|
fileSystems."/mnt/servo-media-wan" = {
|
||||||
|
device = "colin@uninsane.org:/var/lib/uninsane/media";
|
||||||
|
inherit (sshOpts) fsType;
|
||||||
|
options = sshOpts.optionsColin;
|
||||||
|
noCheck = true;
|
||||||
|
};
|
||||||
|
fileSystems."/mnt/servo-media-lan" = {
|
||||||
|
device = "colin@servo:/var/lib/uninsane/media";
|
||||||
|
inherit (sshOpts) fsType;
|
||||||
|
options = sshOpts.optionsColin;
|
||||||
|
noCheck = true;
|
||||||
|
};
|
||||||
|
fileSystems."/mnt/servo-root-wan" = {
|
||||||
|
device = "colin@uninsane.org:/";
|
||||||
|
inherit (sshOpts) fsType;
|
||||||
|
options = sshOpts.optionsRoot;
|
||||||
|
noCheck = true;
|
||||||
|
};
|
||||||
|
fileSystems."/mnt/servo-root-lan" = {
|
||||||
|
device = "colin@servo:/";
|
||||||
|
inherit (sshOpts) fsType;
|
||||||
|
options = sshOpts.optionsRoot;
|
||||||
|
noCheck = true;
|
||||||
|
};
|
||||||
|
fileSystems."/mnt/desko-home" = {
|
||||||
|
device = "colin@desko:/home/colin";
|
||||||
|
inherit (sshOpts) fsType;
|
||||||
|
options = sshOpts.optionsColin;
|
||||||
|
noCheck = true;
|
||||||
|
};
|
||||||
|
fileSystems."/mnt/desko-root" = {
|
||||||
|
device = "colin@desko:/";
|
||||||
|
inherit (sshOpts) fsType;
|
||||||
|
options = sshOpts.optionsRoot;
|
||||||
|
noCheck = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
environment.systemPackages = [
|
||||||
|
pkgs.sshfs-fuse
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
40
hosts/common/hardware.nix
Normal file
40
hosts/common/hardware.nix
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
{ lib, pkgs, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
boot.initrd.supportedFilesystems = [ "ext4" "btrfs" "ext2" "ext3" "vfat" ];
|
||||||
|
# useful emergency utils
|
||||||
|
boot.initrd.extraUtilsCommands = ''
|
||||||
|
copy_bin_and_libs ${pkgs.btrfs-progs}/bin/btrfstune
|
||||||
|
'';
|
||||||
|
boot.kernelParams = [ "boot.shell_on_fail" ];
|
||||||
|
# other kernelParams:
|
||||||
|
# "boot.trace"
|
||||||
|
# "systemd.log_level=debug"
|
||||||
|
# "systemd.log_target=console"
|
||||||
|
|
||||||
|
# hack in the `boot.shell_on_fail` arg since that doesn't always seem to work.
|
||||||
|
boot.initrd.preFailCommands = "allowShell=1";
|
||||||
|
|
||||||
|
# default: 4 (warn). 7 is debug
|
||||||
|
boot.consoleLogLevel = 7;
|
||||||
|
|
||||||
|
boot.loader.grub.enable = lib.mkDefault false;
|
||||||
|
boot.loader.generic-extlinux-compatible.enable = lib.mkDefault true;
|
||||||
|
|
||||||
|
# non-free firmware
|
||||||
|
hardware.enableRedistributableFirmware = true;
|
||||||
|
services.fwupd.enable = true;
|
||||||
|
|
||||||
|
# powertop will default to putting USB devices -- including HID -- to sleep after TWO SECONDS
|
||||||
|
powerManagement.powertop.enable = false;
|
||||||
|
|
||||||
|
# services.snapper.configs = {
|
||||||
|
# root = {
|
||||||
|
# subvolume = "/";
|
||||||
|
# extraConfig = {
|
||||||
|
# ALLOW_USERS = "colin";
|
||||||
|
# };
|
||||||
|
# };
|
||||||
|
# };
|
||||||
|
# services.snapper.snapshotInterval = "daily";
|
||||||
|
}
|
||||||
11
hosts/common/home/aerc.nix
Normal file
11
hosts/common/home/aerc.nix
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# Terminal UI mail client
|
||||||
|
{ config, sane-lib, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
sops.secrets."aerc_accounts" = {
|
||||||
|
owner = config.users.users.colin.name;
|
||||||
|
sopsFile = ../../../secrets/universal/aerc_accounts.conf;
|
||||||
|
format = "binary";
|
||||||
|
};
|
||||||
|
sane.user.fs.".config/aerc/accounts.conf" = sane-lib.fs.wantedSymlinkTo config.sops.secrets.aerc_accounts.path;
|
||||||
|
}
|
||||||
25
hosts/common/home/default.nix
Normal file
25
hosts/common/home/default.nix
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
{ ... }:
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
./aerc.nix
|
||||||
|
./firefox.nix
|
||||||
|
./gfeeds.nix
|
||||||
|
./git.nix
|
||||||
|
./gpodder.nix
|
||||||
|
./keyring.nix
|
||||||
|
./kitty
|
||||||
|
./libreoffice.nix
|
||||||
|
./mime.nix
|
||||||
|
./mpv.nix
|
||||||
|
./neovim.nix
|
||||||
|
./newsflash.nix
|
||||||
|
./offlineimap.nix
|
||||||
|
./ripgrep.nix
|
||||||
|
./splatmoji.nix
|
||||||
|
./ssh.nix
|
||||||
|
./sublime-music.nix
|
||||||
|
./vlc.nix
|
||||||
|
./xdg-dirs.nix
|
||||||
|
./zsh
|
||||||
|
];
|
||||||
|
}
|
||||||
203
hosts/common/home/firefox.nix
Normal file
203
hosts/common/home/firefox.nix
Normal file
@@ -0,0 +1,203 @@
|
|||||||
|
# common settings to toggle (at runtime, in about:config):
|
||||||
|
# > security.ssl.require_safe_negotiation
|
||||||
|
|
||||||
|
# librewolf is a forked firefox which patches firefox to allow more things
|
||||||
|
# (like default search engines) to be configurable at runtime.
|
||||||
|
# many of the settings below won't have effect without those patches.
|
||||||
|
# see: https://gitlab.com/librewolf-community/settings/-/blob/master/distribution/policies.json
|
||||||
|
|
||||||
|
{ config, lib, pkgs, sane-lib, ...}:
|
||||||
|
with lib;
|
||||||
|
let
|
||||||
|
cfg = config.sane.web-browser;
|
||||||
|
# allow easy switching between firefox and librewolf with `defaultSettings`, below
|
||||||
|
librewolfSettings = {
|
||||||
|
browser = pkgs.librewolf-unwrapped;
|
||||||
|
# browser = pkgs.librewolf-unwrapped.overrideAttrs (drv: {
|
||||||
|
# # this allows side-loading unsigned addons
|
||||||
|
# MOZ_REQUIRE_SIGNING = false;
|
||||||
|
# });
|
||||||
|
libName = "librewolf";
|
||||||
|
dotDir = ".librewolf";
|
||||||
|
cacheDir = ".cache/librewolf"; # TODO: is it?
|
||||||
|
desktop = "librewolf.desktop";
|
||||||
|
};
|
||||||
|
firefoxSettings = {
|
||||||
|
browser = pkgs.firefox-esr-unwrapped;
|
||||||
|
libName = "firefox";
|
||||||
|
dotDir = ".mozilla/firefox";
|
||||||
|
cacheDir = ".cache/mozilla";
|
||||||
|
desktop = "firefox.desktop";
|
||||||
|
};
|
||||||
|
defaultSettings = firefoxSettings;
|
||||||
|
# defaultSettings = librewolfSettings;
|
||||||
|
|
||||||
|
addon = name: extid: hash: pkgs.fetchFirefoxAddon {
|
||||||
|
inherit name hash;
|
||||||
|
url = "https://addons.mozilla.org/firefox/downloads/latest/${name}/latest.xpi";
|
||||||
|
# extid can be found by unar'ing the above xpi, and copying browser_specific_settings.gecko.id field
|
||||||
|
fixedExtid = extid;
|
||||||
|
};
|
||||||
|
localAddon = pkg: pkgs.fetchFirefoxAddon {
|
||||||
|
inherit (pkg) name;
|
||||||
|
src = "${pkg}/share/mozilla/extensions/\\{ec8030f7-c20a-464f-9b0e-13a3a9e97384\\}/${pkg.extid}.xpi";
|
||||||
|
fixedExtid = pkg.extid;
|
||||||
|
};
|
||||||
|
|
||||||
|
package = pkgs.wrapFirefox cfg.browser.browser {
|
||||||
|
# inherit the default librewolf.cfg
|
||||||
|
# it can be further customized via ~/.librewolf/librewolf.overrides.cfg
|
||||||
|
inherit (pkgs.librewolf-unwrapped) extraPrefsFiles;
|
||||||
|
inherit (cfg.browser) libName;
|
||||||
|
|
||||||
|
extraNativeMessagingHosts = [ pkgs.browserpass ];
|
||||||
|
# extraNativeMessagingHosts = [ pkgs.gopass-native-messaging-host ];
|
||||||
|
|
||||||
|
nixExtensions = concatMap (ext: optional ext.enable ext.package) (attrValues cfg.addons);
|
||||||
|
|
||||||
|
extraPolicies = {
|
||||||
|
NoDefaultBookmarks = true;
|
||||||
|
SearchEngines = {
|
||||||
|
Default = "DuckDuckGo";
|
||||||
|
};
|
||||||
|
AppUpdateURL = "https://localhost";
|
||||||
|
DisableAppUpdate = true;
|
||||||
|
OverrideFirstRunPage = "";
|
||||||
|
OverridePostUpdatePage = "";
|
||||||
|
DisableSystemAddonUpdate = true;
|
||||||
|
DisableFirefoxStudies = true;
|
||||||
|
DisableTelemetry = true;
|
||||||
|
DisableFeedbackCommands = true;
|
||||||
|
DisablePocket = true;
|
||||||
|
DisableSetDesktopBackground = false;
|
||||||
|
|
||||||
|
# remove many default search providers
|
||||||
|
# XXX this seems to prevent the `nixExtensions` from taking effect
|
||||||
|
# Extensions.Uninstall = [
|
||||||
|
# "google@search.mozilla.org"
|
||||||
|
# "bing@search.mozilla.org"
|
||||||
|
# "amazondotcom@search.mozilla.org"
|
||||||
|
# "ebay@search.mozilla.org"
|
||||||
|
# "twitter@search.mozilla.org"
|
||||||
|
# ];
|
||||||
|
# XXX doesn't seem to have any effect...
|
||||||
|
# docs: https://github.com/mozilla/policy-templates#homepage
|
||||||
|
# Homepage = {
|
||||||
|
# HomepageURL = "https://uninsane.org/";
|
||||||
|
# StartPage = "homepage";
|
||||||
|
# };
|
||||||
|
# NewTabPage = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
addonOpts = types.submodule {
|
||||||
|
options = {
|
||||||
|
package = mkOption {
|
||||||
|
type = types.package;
|
||||||
|
};
|
||||||
|
enable = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options = {
|
||||||
|
sane.web-browser.browser = mkOption {
|
||||||
|
default = defaultSettings;
|
||||||
|
type = types.attrs;
|
||||||
|
};
|
||||||
|
sane.web-browser.persistData = mkOption {
|
||||||
|
description = "optional store name to which persist browsing data (like history)";
|
||||||
|
type = types.nullOr types.str;
|
||||||
|
default = null;
|
||||||
|
};
|
||||||
|
sane.web-browser.persistCache = mkOption {
|
||||||
|
description = "optional store name to which persist browser cache";
|
||||||
|
type = types.nullOr types.str;
|
||||||
|
default = "cryptClearOnBoot";
|
||||||
|
};
|
||||||
|
sane.web-browser.addons = mkOption {
|
||||||
|
type = types.attrsOf addonOpts;
|
||||||
|
default = {
|
||||||
|
# get names from:
|
||||||
|
# - ~/ref/nix-community/nur-combined/repos/rycee/pkgs/firefox-addons/generated-firefox-addons.nix
|
||||||
|
# `wget ...xpi`; `unar ...xpi`; `cat */manifest.json | jq '.browser_specific_settings.gecko.id'`
|
||||||
|
# browserpass-ce.package = addon "browserpass-ce" "browserpass@maximbaz.com" "sha256-sXgUBbRvMnRpeIW1MTkmTcoqtW/8RDXAkxAq1evFkpc=";
|
||||||
|
browserpass-extension.package = localAddon pkgs.browserpass-extension;
|
||||||
|
# TODO: build bypass-paywalls from source? it's mysteriously disappeared from the Mozilla store.
|
||||||
|
# bypass-paywalls-clean.package = addon "bypass-paywalls-clean" "{d133e097-46d9-4ecc-9903-fa6a722a6e0e}" "sha256-oUwdqdAwV3DezaTtOMx7A/s4lzIws+t2f08mwk+324k=";
|
||||||
|
ether-metamask.package = addon "ether-metamask" "webextension@metamask.io" "sha256-G+MwJDOcsaxYSUXjahHJmkWnjLeQ0Wven8DU/lGeMzA=";
|
||||||
|
i2p-in-private-browsing.package = addon "i2p-in-private-browsing" "i2ppb@eyedeekay.github.io" "sha256-dJcJ3jxeAeAkRvhODeIVrCflvX+S4E0wT/PyYzQBQWs=";
|
||||||
|
sidebery.package = addon "sidebery" "{3c078156-979c-498b-8990-85f7987dd929}" "sha256-YONfK/rIjlsrTgRHIt3km07Q7KnpIW89Z9r92ZSCc6w=";
|
||||||
|
sponsorblock.package = addon "sponsorblock" "sponsorBlocker@ajay.app" "sha256-hRsvLaAsVm3dALsTrJqHTNgRFAQcU7XSaGhr5G6+mFs=";
|
||||||
|
ublacklist.package = addon "ublacklist" "@ublacklist" "sha256-RqY5iHzbL2qizth7aguyOKWPyINXmrwOlf/OsfqAS48=";
|
||||||
|
ublock-origin.package = addon "ublock-origin" "uBlock0@raymondhill.net" "sha256-eHlQrU/b9X/6sTbHBpGAd+0VsLT7IrVCnd0AQ948lyA=";
|
||||||
|
|
||||||
|
browserpass-extension.enable = lib.mkDefault true;
|
||||||
|
# bypass-paywalls-clean.enable = lib.mkDefault true;
|
||||||
|
ether-metamask.enable = lib.mkDefault true;
|
||||||
|
i2p-in-private-browsing.enable = lib.mkDefault config.services.i2p.enable;
|
||||||
|
sidebery.enable = lib.mkDefault true;
|
||||||
|
sponsorblock.enable = lib.mkDefault true;
|
||||||
|
ublacklist.enable = lib.mkDefault true;
|
||||||
|
ublock-origin.enable = lib.mkDefault true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = {
|
||||||
|
sane.programs.web-browser = {
|
||||||
|
inherit package;
|
||||||
|
# TODO: define the persistence & fs config here
|
||||||
|
};
|
||||||
|
sane.programs.guiApps.suggestedPrograms = [ "web-browser" ];
|
||||||
|
|
||||||
|
# uBlock filter list configuration.
|
||||||
|
# specifically, enable the GDPR cookie prompt blocker.
|
||||||
|
# data.toOverwrite.filterLists is additive (i.e. it supplements the default filters)
|
||||||
|
# this configuration method is documented here:
|
||||||
|
# - <https://github.com/gorhill/uBlock/issues/2986#issuecomment-364035002>
|
||||||
|
# the specific attribute path is found via scraping ublock code here:
|
||||||
|
# - <https://github.com/gorhill/uBlock/blob/master/src/js/storage.js>
|
||||||
|
# - <https://github.com/gorhill/uBlock/blob/master/assets/assets.json>
|
||||||
|
sane.user.fs."${cfg.browser.dotDir}/managed-storage/uBlock0@raymondhill.net.json" = sane-lib.fs.wantedText ''
|
||||||
|
{
|
||||||
|
"name": "uBlock0@raymondhill.net",
|
||||||
|
"description": "ignored",
|
||||||
|
"type": "storage",
|
||||||
|
"data": {
|
||||||
|
"toOverwrite": "{\"filterLists\": [\"fanboy-cookiemonster\"]}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
sane.user.fs."${cfg.browser.dotDir}/${cfg.browser.libName}.overrides.cfg" = sane-lib.fs.wantedText ''
|
||||||
|
// if we can't query the revocation status of a SSL cert because the issuer is offline,
|
||||||
|
// treat it as unrevoked.
|
||||||
|
// see: <https://librewolf.net/docs/faq/#im-getting-sec_error_ocsp_server_error-what-can-i-do>
|
||||||
|
defaultPref("security.OCSP.require", false);
|
||||||
|
'';
|
||||||
|
# flush the cache to disk to avoid it taking up too much tmp
|
||||||
|
sane.user.persist.byPath."${cfg.browser.cacheDir}" = lib.mkIf (cfg.persistCache != null) {
|
||||||
|
store = cfg.persistCache;
|
||||||
|
};
|
||||||
|
|
||||||
|
sane.user.persist.byPath."${cfg.browser.dotDir}/default" = lib.mkIf (cfg.persistData != null) {
|
||||||
|
store = cfg.persistData;
|
||||||
|
};
|
||||||
|
sane.user.fs."${cfg.browser.dotDir}/default" = sane-lib.fs.wantedDir;
|
||||||
|
# instruct Firefox to put the profile in a predictable directory (so we can do things like persist just it).
|
||||||
|
# XXX: the directory *must* exist, even if empty; Firefox will not create the directory itself.
|
||||||
|
sane.user.fs."${cfg.browser.dotDir}/profiles.ini" = sane-lib.fs.wantedText ''
|
||||||
|
[Profile0]
|
||||||
|
Name=default
|
||||||
|
IsRelative=1
|
||||||
|
Path=default
|
||||||
|
Default=1
|
||||||
|
|
||||||
|
[General]
|
||||||
|
StartWithLastProfile=1
|
||||||
|
'';
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
42
hosts/common/home/gfeeds.nix
Normal file
42
hosts/common/home/gfeeds.nix
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
# gnome feeds RSS viewer
|
||||||
|
{ config, lib, sane-lib, ... }:
|
||||||
|
|
||||||
|
let
|
||||||
|
feeds = sane-lib.feeds;
|
||||||
|
all-feeds = config.sane.feeds;
|
||||||
|
wanted-feeds = feeds.filterByFormat ["text" "image"] all-feeds;
|
||||||
|
in {
|
||||||
|
sane.user.fs.".config/org.gabmus.gfeeds.json" = sane-lib.fs.wantedText (
|
||||||
|
builtins.toJSON {
|
||||||
|
# feed format is a map from URL to a dict,
|
||||||
|
# with dict["tags"] a list of string tags.
|
||||||
|
feeds = sane-lib.mapToAttrs (feed: {
|
||||||
|
name = feed.url;
|
||||||
|
value.tags = [ feed.cat feed.freq ];
|
||||||
|
}) wanted-feeds;
|
||||||
|
dark_reader = false;
|
||||||
|
new_first = true;
|
||||||
|
# windowsize = {
|
||||||
|
# width = 350;
|
||||||
|
# height = 650;
|
||||||
|
# };
|
||||||
|
max_article_age_days = 90;
|
||||||
|
enable_js = false;
|
||||||
|
max_refresh_threads = 3;
|
||||||
|
# saved_items = {};
|
||||||
|
# read_items = [];
|
||||||
|
show_read_items = true;
|
||||||
|
full_article_title = true;
|
||||||
|
# views: "webview", "reader", "rsscont"
|
||||||
|
default_view = "rsscont";
|
||||||
|
open_links_externally = true;
|
||||||
|
full_feed_name = false;
|
||||||
|
refresh_on_startup = true;
|
||||||
|
tags = lib.unique (
|
||||||
|
(builtins.catAttrs "cat" wanted-feeds) ++ (builtins.catAttrs "freq" wanted-feeds)
|
||||||
|
);
|
||||||
|
open_youtube_externally = false;
|
||||||
|
media_player = "vlc"; # default: mpv
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
18
hosts/common/home/git.nix
Normal file
18
hosts/common/home/git.nix
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
{ lib, pkgs, sane-lib, ... }:
|
||||||
|
|
||||||
|
let
|
||||||
|
mkCfg = lib.generators.toINI { };
|
||||||
|
in
|
||||||
|
{
|
||||||
|
sane.user.fs.".config/git/config" = sane-lib.fs.wantedText (mkCfg {
|
||||||
|
user.name = "Colin";
|
||||||
|
user.email = "colin@uninsane.org";
|
||||||
|
alias.co = "checkout";
|
||||||
|
# difftastic docs:
|
||||||
|
# - <https://difftastic.wilfred.me.uk/git.html>
|
||||||
|
diff.tool = "difftastic";
|
||||||
|
difftool.prompt = false;
|
||||||
|
"difftool \"difftastic\"".cmd = ''${pkgs.difftastic}/bin/difft "$LOCAL" "$REMOTE"'';
|
||||||
|
# now run `git difftool` to use difftastic git
|
||||||
|
});
|
||||||
|
}
|
||||||
12
hosts/common/home/gpodder.nix
Normal file
12
hosts/common/home/gpodder.nix
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# gnome feeds RSS viewer
|
||||||
|
{ config, sane-lib, ... }:
|
||||||
|
|
||||||
|
let
|
||||||
|
feeds = sane-lib.feeds;
|
||||||
|
all-feeds = config.sane.feeds;
|
||||||
|
wanted-feeds = feeds.filterByFormat ["podcast"] all-feeds;
|
||||||
|
in {
|
||||||
|
sane.user.fs.".config/gpodderFeeds.opml" = sane-lib.fs.wantedText (
|
||||||
|
feeds.feedsToOpml wanted-feeds
|
||||||
|
);
|
||||||
|
}
|
||||||
11
hosts/common/home/keyring.nix
Normal file
11
hosts/common/home/keyring.nix
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
{ config, sane-lib, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
sane.user.persist.private = [ ".local/share/keyrings" ];
|
||||||
|
|
||||||
|
sane.user.fs."private/.local/share/keyrings/default" = {
|
||||||
|
generated.script.script = builtins.readFile ../../../scripts/init-keyring;
|
||||||
|
# TODO: is this `wantedBy` needed? can we inherit it?
|
||||||
|
wantedBy = [ config.sane.fs."/home/colin/private".unit ];
|
||||||
|
};
|
||||||
|
}
|
||||||
47
hosts/common/home/kitty/PaperColor_dark.conf
Normal file
47
hosts/common/home/kitty/PaperColor_dark.conf
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
# vim:ft=kitty
|
||||||
|
|
||||||
|
## name: PaperColor Dark
|
||||||
|
## author: Nikyle Nguyen
|
||||||
|
## license: MIT
|
||||||
|
## blurb: Dark color scheme inspired by Google's Material Design
|
||||||
|
|
||||||
|
# special
|
||||||
|
foreground #d0d0d0
|
||||||
|
background #1c1c1c
|
||||||
|
cursor #d0d0d0
|
||||||
|
cursor_text_color background
|
||||||
|
|
||||||
|
# black
|
||||||
|
color0 #1c1c1c
|
||||||
|
color8 #585858
|
||||||
|
|
||||||
|
# red
|
||||||
|
color1 #af005f
|
||||||
|
color9 #5faf5f
|
||||||
|
|
||||||
|
# green
|
||||||
|
# "color2" is the green color used by ls to indicate executability
|
||||||
|
# both as text color
|
||||||
|
# or as bg color when the text is blue (color4)
|
||||||
|
color2 #246a28
|
||||||
|
color10 #2df200
|
||||||
|
|
||||||
|
# yellow
|
||||||
|
color3 #d7af5f
|
||||||
|
color11 #af87d7
|
||||||
|
|
||||||
|
# blue
|
||||||
|
color4 #78c6ef
|
||||||
|
color12 #ffaf00
|
||||||
|
|
||||||
|
# magenta
|
||||||
|
color5 #808080
|
||||||
|
color13 #ff5faf
|
||||||
|
|
||||||
|
# cyan
|
||||||
|
color6 #d7875f
|
||||||
|
color14 #00afaf
|
||||||
|
|
||||||
|
# white
|
||||||
|
color7 #d0d0d0
|
||||||
|
color15 #5f8787
|
||||||
70
hosts/common/home/kitty/default.nix
Normal file
70
hosts/common/home/kitty/default.nix
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
{ pkgs, sane-lib, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
sane.user.fs.".config/kitty/kitty.conf" = sane-lib.fs.wantedText ''
|
||||||
|
# docs: https://sw.kovidgoyal.net/kitty/conf/
|
||||||
|
# disable terminal bell (when e.g. you backspace too many times)
|
||||||
|
enable_audio_bell no
|
||||||
|
|
||||||
|
map ctrl+n new_os_window_with_cwd
|
||||||
|
include ${./PaperColor_dark.conf}
|
||||||
|
'';
|
||||||
|
|
||||||
|
# include ${pkgs.kitty-themes}/themes/PaperColor_dark.conf
|
||||||
|
|
||||||
|
# THEME CHOICES:
|
||||||
|
# docs: https://github.com/kovidgoyal/kitty-themes
|
||||||
|
# theme = "1984 Light"; # dislike: awful, harsh blues/teals
|
||||||
|
# theme = "Adventure Time"; # dislike: harsh (dark)
|
||||||
|
# theme = "Atom One Light"; # GOOD: light theme. all color combos readable. not a huge fan of the blue.
|
||||||
|
# theme = "Belafonte Day"; # dislike: too low contrast for text colors
|
||||||
|
# theme = "Belafonte Night"; # better: dark theme that's easy on the eyes. all combos readable. low contrast.
|
||||||
|
# theme = "Catppuccin"; # dislike: a bit pale/low-contrast (dark)
|
||||||
|
# theme = "Desert"; # mediocre: colors are harsh
|
||||||
|
# theme = "Earthsong"; # BEST: dark theme. readable, good contrast. unique, but decent colors.
|
||||||
|
# theme = "Espresso Libre"; # better: dark theme. readable, but meh colors
|
||||||
|
# theme = "Forest Night"; # decent: very pastel. it's workable, but unconventional and muted/flat.
|
||||||
|
# theme = "Gruvbox Material Light Hard"; # mediocre light theme.
|
||||||
|
# theme = "kanagawabones"; # better: dark theme. colors are too background-y
|
||||||
|
# theme = "Kaolin Dark"; # dislike: too dark
|
||||||
|
# theme = "Kaolin Breeze"; # mediocre: not-too-harsh light theme, but some parts are poor contrast
|
||||||
|
# theme = "Later This Evening"; # mediocre: not-too-harsh dark theme, but cursor is poor contrast
|
||||||
|
# theme = "Material"; # decent: light theme, few colors.
|
||||||
|
# theme = "Mayukai"; # decent: not-too-harsh dark theme. the teal is a bit straining
|
||||||
|
# theme = "Nord"; # mediocre: pale background, low contrast
|
||||||
|
# theme = "One Half Light"; # better: not-too-harsh light theme. contrast could be better
|
||||||
|
# theme = "PaperColor Dark"; # BEST: dark theme, very readable still the colors are background-y
|
||||||
|
# theme = "Parasio Dark"; # dislike: too low contrast
|
||||||
|
# theme = "Pencil Light"; # better: not-too-harsh light theme. decent contrast.
|
||||||
|
# theme = "Pnevma"; # dislike: too low contrast
|
||||||
|
# theme = "Piatto Light"; # better: readable light theme. pleasing colors. powerline prompt is hard to read.
|
||||||
|
# theme = "Rosé Pine Dawn"; # GOOD: light theme. all color combinations are readable. it is very mild -- may need to manually tweak contrast. tasteful colors
|
||||||
|
# theme = "Rosé Pine Moon"; # GOOD: dark theme. tasteful colors. but background is a bit intense
|
||||||
|
# theme = "Sea Shells"; # mediocre. not all color combos are readable
|
||||||
|
# theme = "Solarized Light"; # mediocre: not-too-harsh light theme; GREAT background; but some colors are low contrast
|
||||||
|
# theme = "Solarized Dark Higher Contrast"; # better: dark theme, decent colors
|
||||||
|
# theme = "Sourcerer"; # mediocre: ugly colors
|
||||||
|
# theme = "Space Gray"; # mediocre: too muted
|
||||||
|
# theme = "Space Gray Eighties"; # better: all readable, decent colors
|
||||||
|
# theme = "Spacemacs"; # mediocre: too muted
|
||||||
|
# theme = "Spring"; # mediocre: readable light theme, but the teal is ugly.
|
||||||
|
# theme = "Srcery"; # better: highly readable. colors are ehhh
|
||||||
|
# theme = "Substrata"; # decent: nice colors, but a bit flat.
|
||||||
|
# theme = "Sundried"; # mediocre: the solar text makes me squint
|
||||||
|
# theme = "Symfonic"; # mediocre: the dark purple has low contrast to the black bg.
|
||||||
|
# theme = "Tango Light"; # dislike: teal is too grating
|
||||||
|
# theme = "Tokyo Night Day"; # medicore: too muted
|
||||||
|
# theme = "Tokyo Night"; # better: tasteful. a bit flat
|
||||||
|
# theme = "Tomorrow"; # GOOD: all color combinations are readable. contrast is slightly better than Rose. on the blander side
|
||||||
|
# theme = "Treehouse"; # dislike: the orange is harsh on my eyes.
|
||||||
|
# theme = "Urple"; # dislike: weird palette
|
||||||
|
# theme = "Warm Neon"; # decent: not-too-harsh dark theme. the green is a bit unattractive
|
||||||
|
# theme = "Wild Cherry"; # GOOD: dark theme: nice colors. a bit flat
|
||||||
|
# theme = "Xcodedark"; # dislike: bad palette
|
||||||
|
# theme = "citylights"; # decent: dark theme. some parts have just a bit low contrast
|
||||||
|
# theme = "neobones_light"; # better light theme. the background is maybe too muted
|
||||||
|
# theme = "vimbones";
|
||||||
|
# theme = "zenbones_dark"; # mediocre: readable, but meh colors
|
||||||
|
# theme = "zenbones_light"; # decent: light theme. all colors are readable. contrast is passable but not excellent. highlight color is BAD
|
||||||
|
# theme = "zenwritten_dark"; # mediocre: looks same as zenbones_dark
|
||||||
|
}
|
||||||
14
hosts/common/home/libreoffice.nix
Normal file
14
hosts/common/home/libreoffice.nix
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
{ sane-lib, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
# libreoffice: disable first-run stuff
|
||||||
|
sane.user.fs.".config/libreoffice/4/user/registrymodifications.xcu" = sane-lib.fs.wantedText ''
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<oor:items xmlns:oor="http://openoffice.org/2001/registry" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||||
|
<item oor:path="/org.openoffice.Office.Common/Misc"><prop oor:name="FirstRun" oor:op="fuse"><value>false</value></prop></item>
|
||||||
|
<item oor:path="/org.openoffice.Office.Common/Misc"><prop oor:name="ShowTipOfTheDay" oor:op="fuse"><value>false</value></prop></item>
|
||||||
|
</oor:items>
|
||||||
|
'';
|
||||||
|
# <item oor:path="/org.openoffice.Setup/Product"><prop oor:name="LastTimeDonateShown" oor:op="fuse"><value>1667693880</value></prop></item>
|
||||||
|
# <item oor:path="/org.openoffice.Setup/Product"><prop oor:name="LastTimeGetInvolvedShown" oor:op="fuse"><value>1667693880</value></prop></item>
|
||||||
|
}
|
||||||
42
hosts/common/home/mime.nix
Normal file
42
hosts/common/home/mime.nix
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
{ config, sane-lib, ...}:
|
||||||
|
|
||||||
|
let
|
||||||
|
www = config.sane.web-browser.browser.desktop;
|
||||||
|
pdf = "org.gnome.Evince.desktop";
|
||||||
|
md = "obsidian.desktop";
|
||||||
|
thumb = "org.gnome.gThumb.desktop";
|
||||||
|
video = "vlc.desktop";
|
||||||
|
# audio = "mpv.desktop";
|
||||||
|
audio = "vlc.desktop";
|
||||||
|
in
|
||||||
|
{
|
||||||
|
|
||||||
|
# the xdg mime type for a file can be found with:
|
||||||
|
# - `xdg-mime query filetype path/to/thing.ext`
|
||||||
|
# we can have single associations or a list of associations.
|
||||||
|
# there's also options to *remove* [non-default] associations from specific apps
|
||||||
|
xdg.mime.enable = true;
|
||||||
|
xdg.mime.defaultApplications = {
|
||||||
|
# AUDIO
|
||||||
|
"audio/flac" = audio;
|
||||||
|
"audio/mpeg" = audio;
|
||||||
|
"audio/x-vorbis+ogg" = audio;
|
||||||
|
# IMAGES
|
||||||
|
"image/heif" = thumb; # apple codec
|
||||||
|
"image/png" = thumb;
|
||||||
|
"image/jpeg" = thumb;
|
||||||
|
# VIDEO
|
||||||
|
"video/mp4" = video;
|
||||||
|
"video/quicktime" = video;
|
||||||
|
"video/x-matroska" = video;
|
||||||
|
# HTML
|
||||||
|
"text/html" = www;
|
||||||
|
"x-scheme-handler/http" = www;
|
||||||
|
"x-scheme-handler/https" = www;
|
||||||
|
"x-scheme-handler/about" = www;
|
||||||
|
"x-scheme-handler/unknown" = www;
|
||||||
|
# RICH-TEXT DOCUMENTS
|
||||||
|
"application/pdf" = pdf;
|
||||||
|
"text/markdown" = md;
|
||||||
|
};
|
||||||
|
}
|
||||||
10
hosts/common/home/mpv.nix
Normal file
10
hosts/common/home/mpv.nix
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
{ sane-lib, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
# format is <key>=%<length>%<value>
|
||||||
|
sane.user.fs.".config/mpv/mpv.conf" = sane-lib.fs.wantedText ''
|
||||||
|
save-position-on-quit=%3%yes
|
||||||
|
keep-open=%3%yes
|
||||||
|
'';
|
||||||
|
}
|
||||||
|
|
||||||
129
hosts/common/home/neovim.nix
Normal file
129
hosts/common/home/neovim.nix
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
{ lib, pkgs, ... }:
|
||||||
|
|
||||||
|
let
|
||||||
|
inherit (builtins) map;
|
||||||
|
inherit (lib) concatMapStrings optionalString;
|
||||||
|
# this structure roughly mirrors home-manager's `programs.neovim.plugins` option
|
||||||
|
plugins = with pkgs.vimPlugins; [
|
||||||
|
# docs: surround-nvim: https://github.com/ur4ltz/surround.nvim/
|
||||||
|
# docs: vim-surround: https://github.com/tpope/vim-surround
|
||||||
|
{ plugin = vim-surround; }
|
||||||
|
# docs: fzf-vim (fuzzy finder): https://github.com/junegunn/fzf.vim
|
||||||
|
{ plugin = fzf-vim; }
|
||||||
|
({
|
||||||
|
# docs: tex-conceal-vim: https://github.com/KeitaNakamura/tex-conceal.vim/
|
||||||
|
plugin = tex-conceal-vim;
|
||||||
|
type = "viml";
|
||||||
|
config = ''
|
||||||
|
" present prettier fractions
|
||||||
|
let g:tex_conceal_frac=1
|
||||||
|
'';
|
||||||
|
})
|
||||||
|
({
|
||||||
|
plugin = vim-SyntaxRange;
|
||||||
|
type = "viml";
|
||||||
|
config = ''
|
||||||
|
" enable markdown-style codeblock highlighting for tex code
|
||||||
|
autocmd BufEnter * call SyntaxRange#Include('```tex', '```', 'tex', 'NonText')
|
||||||
|
" autocmd Syntax tex set conceallevel=2
|
||||||
|
'';
|
||||||
|
})
|
||||||
|
({
|
||||||
|
# treesitter syntax highlighting: https://nixos.wiki/wiki/Tree_sitters
|
||||||
|
# docs: https://github.com/nvim-treesitter/nvim-treesitter
|
||||||
|
# config taken from: https://github.com/i077/system/blob/master/modules/home/neovim/default.nix
|
||||||
|
# this is required for tree-sitter to even highlight
|
||||||
|
plugin = nvim-treesitter.withAllGrammars;
|
||||||
|
type = "lua";
|
||||||
|
config = ''
|
||||||
|
require'nvim-treesitter.configs'.setup {
|
||||||
|
highlight = {
|
||||||
|
enable = true,
|
||||||
|
-- disable treesitter on Rust so that we can use SyntaxRange
|
||||||
|
-- and leverage TeX rendering in rust projects
|
||||||
|
disable = { "rust", "tex", "latex" },
|
||||||
|
-- disable = { "tex", "latex" },
|
||||||
|
-- true to also use builtin vim syntax highlighting when treesitter fails
|
||||||
|
additional_vim_regex_highlighting = false
|
||||||
|
},
|
||||||
|
incremental_selection = {
|
||||||
|
enable = true,
|
||||||
|
keymaps = {
|
||||||
|
init_selection = "gnn",
|
||||||
|
node_incremental = "grn",
|
||||||
|
mcope_incremental = "grc",
|
||||||
|
node_decremental = "grm"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
indent = {
|
||||||
|
enable = true,
|
||||||
|
disable = {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vim.o.foldmethod = 'expr'
|
||||||
|
vim.o.foldexpr = 'nvim_treesitter#foldexpr()'
|
||||||
|
'';
|
||||||
|
})
|
||||||
|
];
|
||||||
|
plugin-packages = map (p: p.plugin) plugins;
|
||||||
|
plugin-config-tex = concatMapStrings (p: optionalString (p.type or "" == "viml") p.config) plugins;
|
||||||
|
plugin-config-lua = concatMapStrings (p: optionalString (p.type or "" == "lua") p.config) plugins;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
# private because there could be sensitive things in the swap
|
||||||
|
sane.user.persist.private = [ ".cache/vim-swap" ];
|
||||||
|
|
||||||
|
programs.neovim = {
|
||||||
|
# neovim: https://github.com/neovim/neovim
|
||||||
|
enable = true;
|
||||||
|
viAlias = true;
|
||||||
|
vimAlias = true;
|
||||||
|
configure = {
|
||||||
|
packages.myVimPackage = {
|
||||||
|
start = plugin-packages;
|
||||||
|
};
|
||||||
|
customRC = ''
|
||||||
|
" let the terminal handle mouse events, that way i get OS-level ctrl+shift+c/etc
|
||||||
|
" this used to be default, until <https://github.com/neovim/neovim/pull/19290>
|
||||||
|
set mouse=
|
||||||
|
|
||||||
|
" copy/paste to system clipboard
|
||||||
|
set clipboard=unnamedplus
|
||||||
|
|
||||||
|
" screw tabs; always expand them into spaces
|
||||||
|
set expandtab
|
||||||
|
|
||||||
|
" at least don't open files with sections folded by default
|
||||||
|
set nofoldenable
|
||||||
|
|
||||||
|
" allow text substitutions for certain glyphs.
|
||||||
|
" higher number = more aggressive substitution (0, 1, 2, 3)
|
||||||
|
" i only make use of this for tex, but it's unclear how to
|
||||||
|
" apply that *just* to tex and retain the SyntaxRange stuff.
|
||||||
|
set conceallevel=2
|
||||||
|
|
||||||
|
" horizontal rule under the active line
|
||||||
|
" set cursorline
|
||||||
|
|
||||||
|
" highlight trailing space & related syntax errors (doesn't seem to work??)
|
||||||
|
" let c_space_errors=1
|
||||||
|
" let python_space_errors=1
|
||||||
|
|
||||||
|
" enable highlighting of leading/trailing spaces,
|
||||||
|
" and especially tabs
|
||||||
|
" source: https://www.reddit.com/r/neovim/comments/chlmfk/highlight_trailing_whitespaces_in_neovim/
|
||||||
|
set list
|
||||||
|
set listchars=tab:▷\·,trail:·,extends:◣,precedes:◢,nbsp:○
|
||||||
|
|
||||||
|
""""" PLUGIN CONFIG (tex)
|
||||||
|
${plugin-config-tex}
|
||||||
|
|
||||||
|
""""" PLUGIN CONFIG (lua)
|
||||||
|
lua <<EOF
|
||||||
|
${plugin-config-lua}
|
||||||
|
EOF
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
12
hosts/common/home/newsflash.nix
Normal file
12
hosts/common/home/newsflash.nix
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# news-flash RSS viewer
|
||||||
|
{ config, sane-lib, ... }:
|
||||||
|
|
||||||
|
let
|
||||||
|
feeds = sane-lib.feeds;
|
||||||
|
all-feeds = config.sane.feeds;
|
||||||
|
wanted-feeds = feeds.filterByFormat ["text" "image"] all-feeds;
|
||||||
|
in {
|
||||||
|
sane.user.fs.".config/newsflashFeeds.opml" = sane-lib.fs.wantedText (
|
||||||
|
feeds.feedsToOpml wanted-feeds
|
||||||
|
);
|
||||||
|
}
|
||||||
17
hosts/common/home/offlineimap.nix
Normal file
17
hosts/common/home/offlineimap.nix
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
# mail archiving/synchronization tool.
|
||||||
|
#
|
||||||
|
# manually download all emails for an account with
|
||||||
|
# - `offlineimap -a <accountname>`
|
||||||
|
#
|
||||||
|
# view account names inside the secrets file, listed below.
|
||||||
|
{ config, sane-lib, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
sops.secrets."offlineimaprc" = {
|
||||||
|
owner = config.users.users.colin.name;
|
||||||
|
sopsFile = ../../../secrets/universal/offlineimaprc.bin;
|
||||||
|
format = "binary";
|
||||||
|
};
|
||||||
|
sane.user.fs.".config/offlineimap/config" = sane-lib.fs.wantedSymlinkTo config.sops.secrets.offlineimaprc.path;
|
||||||
|
}
|
||||||
|
|
||||||
9
hosts/common/home/ripgrep.nix
Normal file
9
hosts/common/home/ripgrep.nix
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
{ sane-lib, ... }:
|
||||||
|
{
|
||||||
|
# .ignore file is read by ripgrep (rg), silver searcher (ag), maybe others.
|
||||||
|
# ignore translation files by default when searching, as they tend to have
|
||||||
|
# a LOT of duplicate text.
|
||||||
|
sane.user.fs.".ignore" = sane-lib.fs.wantedText ''
|
||||||
|
po/
|
||||||
|
'';
|
||||||
|
}
|
||||||
20
hosts/common/home/splatmoji.nix
Normal file
20
hosts/common/home/splatmoji.nix
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
# borrows from:
|
||||||
|
# - default config: <https://github.com/cspeterson/splatmoji/blob/master/splatmoji.config>
|
||||||
|
# - wayland: <https://github.com/cspeterson/splatmoji/issues/32#issuecomment-830862566>
|
||||||
|
{ pkgs, sane-lib, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
sane.user.persist.plaintext = [ ".local/state/splatmoji" ];
|
||||||
|
sane.user.fs.".config/splatmoji/splatmoji.config" = sane-lib.fs.wantedText ''
|
||||||
|
# XXX doesn't seem to understand ~ as shorthand for `$HOME`
|
||||||
|
history_file=/home/colin/.local/state/splatmoji/history
|
||||||
|
history_length=5
|
||||||
|
# TODO: wayland equiv
|
||||||
|
paste_command=xdotool key ctrl+v
|
||||||
|
# rofi_command=${pkgs.wofi}/bin/wofi --dmenu --insensitive --cache-file /dev/null
|
||||||
|
rofi_command=${pkgs.fuzzel}/bin/fuzzel -d -i -w 60
|
||||||
|
xdotool_command=${pkgs.wtype}/bin/wtype
|
||||||
|
# TODO: wayland equiv
|
||||||
|
xsel_command=xsel -b -i
|
||||||
|
'';
|
||||||
|
}
|
||||||
26
hosts/common/home/ssh.nix
Normal file
26
hosts/common/home/ssh.nix
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
{ config, lib, sane-lib, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
let
|
||||||
|
host = config.networking.hostName;
|
||||||
|
user-pubkey-full = config.sane.ssh.pubkeys."colin@${host}" or {};
|
||||||
|
user-pubkey = user-pubkey-full.asUserKey or null;
|
||||||
|
host-keys = filter (k: k.user == "root") (attrValues config.sane.ssh.pubkeys);
|
||||||
|
known-hosts-text = concatStringsSep
|
||||||
|
"\n"
|
||||||
|
(map (k: k.asHostKey) host-keys)
|
||||||
|
;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
# ssh key is stored in private storage
|
||||||
|
sane.user.persist.private = [ ".ssh/id_ed25519" ];
|
||||||
|
sane.user.fs.".ssh/id_ed25519.pub" =
|
||||||
|
mkIf (user-pubkey != null) (sane-lib.fs.wantedText user-pubkey);
|
||||||
|
sane.user.fs.".ssh/known_hosts" = sane-lib.fs.wantedText known-hosts-text;
|
||||||
|
|
||||||
|
users.users.colin.openssh.authorizedKeys.keys =
|
||||||
|
let
|
||||||
|
user-keys = filter (k: k.user == "colin") (attrValues config.sane.ssh.pubkeys);
|
||||||
|
in
|
||||||
|
map (k: k.asUserKey) user-keys;
|
||||||
|
}
|
||||||
11
hosts/common/home/sublime-music.nix
Normal file
11
hosts/common/home/sublime-music.nix
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
{ config, sane-lib, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
# TODO: this should only be shipped on gui platforms
|
||||||
|
sops.secrets."sublime_music_config" = {
|
||||||
|
owner = config.users.users.colin.name;
|
||||||
|
sopsFile = ../../../secrets/universal/sublime_music_config.json.bin;
|
||||||
|
format = "binary";
|
||||||
|
};
|
||||||
|
sane.user.fs.".config/sublime-music/config.json" = sane-lib.fs.wantedSymlinkTo config.sops.secrets.sublime_music_config.path;
|
||||||
|
}
|
||||||
20
hosts/common/home/vlc.nix
Normal file
20
hosts/common/home/vlc.nix
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
{ config, lib, sane-lib, ... }:
|
||||||
|
|
||||||
|
let
|
||||||
|
feeds = sane-lib.feeds;
|
||||||
|
all-feeds = config.sane.feeds;
|
||||||
|
wanted-feeds = feeds.filterByFormat ["podcast"] all-feeds;
|
||||||
|
podcast-urls = lib.concatStringsSep "|" (
|
||||||
|
builtins.map (feed: feed.url) wanted-feeds
|
||||||
|
);
|
||||||
|
in
|
||||||
|
{
|
||||||
|
sane.user.fs.".config/vlc/vlcrc" = sane-lib.fs.wantedText ''
|
||||||
|
[podcast]
|
||||||
|
podcast-urls=${podcast-urls}
|
||||||
|
[core]
|
||||||
|
metadata-network-access=0
|
||||||
|
[qt]
|
||||||
|
qt-privacy-ask=0
|
||||||
|
'';
|
||||||
|
}
|
||||||
20
hosts/common/home/xdg-dirs.nix
Normal file
20
hosts/common/home/xdg-dirs.nix
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
{ lib, sane-lib, ...}:
|
||||||
|
|
||||||
|
{
|
||||||
|
# XDG defines things like ~/Desktop, ~/Downloads, etc.
|
||||||
|
# these clutter the home, so i mostly don't use them.
|
||||||
|
sane.user.fs.".config/user-dirs.dirs" = sane-lib.fs.wantedText ''
|
||||||
|
XDG_DESKTOP_DIR="$HOME/.xdg/Desktop"
|
||||||
|
XDG_DOCUMENTS_DIR="$HOME/dev"
|
||||||
|
XDG_DOWNLOAD_DIR="$HOME/tmp"
|
||||||
|
XDG_MUSIC_DIR="$HOME/Music"
|
||||||
|
XDG_PICTURES_DIR="$HOME/Pictures"
|
||||||
|
XDG_PUBLICSHARE_DIR="$HOME/.xdg/Public"
|
||||||
|
XDG_TEMPLATES_DIR="$HOME/.xdg/Templates"
|
||||||
|
XDG_VIDEOS_DIR="$HOME/Videos"
|
||||||
|
'';
|
||||||
|
|
||||||
|
# prevent `xdg-user-dirs-update` from overriding/updating our config
|
||||||
|
# see <https://manpages.ubuntu.com/manpages/bionic/man5/user-dirs.conf.5.html>
|
||||||
|
sane.user.fs.".config/user-dirs.conf" = sane-lib.fs.wantedText "enabled=False";
|
||||||
|
}
|
||||||
161
hosts/common/home/zsh/default.nix
Normal file
161
hosts/common/home/zsh/default.nix
Normal file
@@ -0,0 +1,161 @@
|
|||||||
|
{ config, lib, pkgs, sane-lib, ... }:
|
||||||
|
|
||||||
|
let
|
||||||
|
inherit (lib) mkOption types;
|
||||||
|
cfg = config.sane.zsh;
|
||||||
|
# powerlevel10k prompt config
|
||||||
|
# p10k.zsh is the auto-generated config, and i overwrite those defaults here, below.
|
||||||
|
p10k-overrides = ''
|
||||||
|
# powerlevel10k launches a gitstatusd daemon to accelerate git prompt queries.
|
||||||
|
# this keeps open file handles for any git repo i touch for 60 minutes (by default).
|
||||||
|
# that prevents unmounting whatever device the git repo is on -- particularly problematic for ~/private.
|
||||||
|
# i can disable gitstatusd and get slower fallback git queries:
|
||||||
|
# - either universally
|
||||||
|
# - or selectively by path
|
||||||
|
# see: <https://github.com/romkatv/powerlevel10k/issues/246>
|
||||||
|
typeset -g POWERLEVEL9K_VCS_DISABLED_DIR_PATTERN='(/home/colin/private/*|/home/colin/knowledge/*)'
|
||||||
|
# typeset -g POWERLEVEL9K_DISABLE_GITSTATUS=true
|
||||||
|
|
||||||
|
# show user@host also when logged into the current machine.
|
||||||
|
# default behavior is to show it only over ssh.
|
||||||
|
typeset -g POWERLEVEL9K_CONTEXT_{DEFAULT,SUDO}_CONTENT_EXPANSION='$P9K_CONTENT'
|
||||||
|
'';
|
||||||
|
|
||||||
|
prezto-init = ''
|
||||||
|
source ${pkgs.zsh-autosuggestions}/share/zsh-autosuggestions/zsh-autosuggestions.zsh
|
||||||
|
source ${pkgs.zsh-syntax-highlighting}/share/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh
|
||||||
|
source ${pkgs.zsh-prezto}/share/zsh-prezto/init.zsh
|
||||||
|
'';
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options = {
|
||||||
|
sane.zsh = {
|
||||||
|
showDeadlines = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = true;
|
||||||
|
description = "show upcoming deadlines (frommy PKM) upon shell init";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = {
|
||||||
|
sane.user.persist.plaintext = [
|
||||||
|
# we don't need to full zsh dir -- just the history file --
|
||||||
|
# but zsh will sometimes backup the history file and we get fewer errors if we do proper mounts instead of symlinks.
|
||||||
|
# TODO: should be private?
|
||||||
|
".local/share/zsh"
|
||||||
|
# cache gitstatus otherwise p10k fetched it from the net EVERY BOOT
|
||||||
|
".cache/gitstatus"
|
||||||
|
];
|
||||||
|
|
||||||
|
# zsh/prezto complains if zshrc doesn't exist; but it does allow an "empty" file.
|
||||||
|
sane.user.fs.".config/zsh/.zshrc" = sane-lib.fs.wantedText "# ";
|
||||||
|
|
||||||
|
# enable zsh completions
|
||||||
|
environment.pathsToLink = [ "/share/zsh" ];
|
||||||
|
|
||||||
|
programs.zsh = {
|
||||||
|
enable = true;
|
||||||
|
histFile = "$HOME/.local/share/zsh/history";
|
||||||
|
shellAliases = {
|
||||||
|
":q" = "exit";
|
||||||
|
# common typos
|
||||||
|
"cd.." = "cd ..";
|
||||||
|
"cd../" = "cd ../";
|
||||||
|
};
|
||||||
|
setOptions = [
|
||||||
|
# defaults:
|
||||||
|
"HIST_IGNORE_DUPS"
|
||||||
|
"SHARE_HISTORY"
|
||||||
|
"HIST_FCNTL_LOCK"
|
||||||
|
# disable `rm *` confirmations
|
||||||
|
"rmstarsilent"
|
||||||
|
];
|
||||||
|
|
||||||
|
# .zshenv config:
|
||||||
|
shellInit = ''
|
||||||
|
ZDOTDIR=$HOME/.config/zsh
|
||||||
|
'';
|
||||||
|
|
||||||
|
# .zshrc config:
|
||||||
|
interactiveShellInit =
|
||||||
|
(builtins.readFile ./p10k.zsh)
|
||||||
|
+ p10k-overrides
|
||||||
|
+ prezto-init
|
||||||
|
+ ''
|
||||||
|
# zmv is a way to do rich moves/renames, with pattern matching/substitution.
|
||||||
|
# see for an example: <https://filipe.kiss.ink/zmv-zsh-rename/>
|
||||||
|
autoload -Uz zmv
|
||||||
|
|
||||||
|
HISTORY_IGNORE='(sane-shutdown *|sane-reboot *|rm *|nixos-rebuild.* switch)'
|
||||||
|
|
||||||
|
# extra aliases
|
||||||
|
# TODO: move to `shellAliases` config?
|
||||||
|
function nd() {
|
||||||
|
mkdir -p "$1";
|
||||||
|
pushd "$1";
|
||||||
|
}
|
||||||
|
''
|
||||||
|
+ lib.optionalString cfg.showDeadlines ''
|
||||||
|
${pkgs.sane-scripts}/bin/sane-deadlines
|
||||||
|
''
|
||||||
|
+ ''
|
||||||
|
# auto-cd into any of these dirs by typing them and pressing 'enter':
|
||||||
|
hash -d 3rd="/home/colin/dev/3rd"
|
||||||
|
hash -d dev="/home/colin/dev"
|
||||||
|
hash -d knowledge="/home/colin/knowledge"
|
||||||
|
hash -d nixos="/home/colin/nixos"
|
||||||
|
hash -d nixpkgs="/home/colin/dev/3rd/nixpkgs"
|
||||||
|
hash -d ref="/home/colin/ref"
|
||||||
|
hash -d secrets="/home/colin/knowledge/secrets"
|
||||||
|
hash -d tmp="/home/colin/tmp"
|
||||||
|
hash -d uninsane="/home/colin/dev/uninsane"
|
||||||
|
hash -d Videos="/home/colin/Videos"
|
||||||
|
'';
|
||||||
|
|
||||||
|
syntaxHighlighting.enable = true;
|
||||||
|
vteIntegration = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
# enable a command-not-found hook to show nix packages that might provide the binary typed.
|
||||||
|
programs.nix-index.enable = true;
|
||||||
|
programs.command-not-found.enable = false; #< mutually exclusive with nix-index
|
||||||
|
|
||||||
|
# prezto = oh-my-zsh fork; controls prompt, auto-completion, etc.
|
||||||
|
# see: https://github.com/sorin-ionescu/prezto
|
||||||
|
# i believe this file is auto-sourced by the prezto init.zsh script.
|
||||||
|
sane.user.fs.".config/zsh/.zpreztorc" = sane-lib.fs.wantedText ''
|
||||||
|
zstyle ':prezto:*:*' color 'yes'
|
||||||
|
|
||||||
|
# modules (they ship with prezto):
|
||||||
|
# ENVIRONMENT: configures jobs to persist after shell exit; other basic niceties
|
||||||
|
# TERMINAL: auto-titles terminal (e.g. based on cwd)
|
||||||
|
# EDITOR: configures shortcuts like Ctrl+U=undo, Ctrl+L=clear
|
||||||
|
# HISTORY: `history-stat` alias, setopts for good history defaults
|
||||||
|
# DIRECTORY: sets AUTO_CD, adds `d` alias to list directory stack, and `1`-`9` to cd that far back the stack
|
||||||
|
# SPECTRUM: helpers for term colors and styling. used by prompts? might be unnecessary
|
||||||
|
# UTILITY: configures aliases like `ll`, `la`, disables globbing for things like rsync
|
||||||
|
# adds aliases like `get` to fetch a file. also adds `http-serve` alias??
|
||||||
|
# COMPLETION: tab completion. requires `utility` module prior to loading
|
||||||
|
# TODO: enable AUTO_PARAM_SLASH
|
||||||
|
zstyle ':prezto:load' pmodule \
|
||||||
|
'environment' \
|
||||||
|
'terminal' \
|
||||||
|
'editor' \
|
||||||
|
'history' \
|
||||||
|
'directory' \
|
||||||
|
'spectrum' \
|
||||||
|
'utility' \
|
||||||
|
'completion' \
|
||||||
|
'prompt'
|
||||||
|
|
||||||
|
# default keymap. try also `vicmd` (vim normal mode, AKA "cmd mode") or `vi`.
|
||||||
|
zstyle ':prezto:module:editor' key-bindings 'emacs'
|
||||||
|
|
||||||
|
zstyle ':prezto:module:prompt' theme 'powerlevel10k'
|
||||||
|
|
||||||
|
# disable `mv` confirmation (and `rm`, too, unfortunately)
|
||||||
|
zstyle ':prezto:module:utility' safe-ops 'no'
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
}
|
||||||
1635
hosts/common/home/zsh/p10k.zsh
Normal file
1635
hosts/common/home/zsh/p10k.zsh
Normal file
File diff suppressed because it is too large
Load Diff
4
hosts/common/i2p.nix
Normal file
4
hosts/common/i2p.nix
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
{ ... }:
|
||||||
|
{
|
||||||
|
services.i2p.enable = true;
|
||||||
|
}
|
||||||
69
hosts/common/ids.nix
Normal file
69
hosts/common/ids.nix
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
# TODO: migrate to nixpkgs `config.ids.uids`
|
||||||
|
# - note that nixpkgs' `config.ids.uids` is strictly a database: it doesn't set anything by default
|
||||||
|
# whereas our impl sets the gid/uid of the user/group specified if they exist.
|
||||||
|
{ ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
# legacy servo users, some are inconvenient to migrate
|
||||||
|
sane.ids.dhcpcd.gid = 991;
|
||||||
|
sane.ids.dhcpcd.uid = 992;
|
||||||
|
sane.ids.gitea.gid = 993;
|
||||||
|
sane.ids.git.uid = 994;
|
||||||
|
sane.ids.jellyfin.gid = 994;
|
||||||
|
sane.ids.pleroma.gid = 995;
|
||||||
|
sane.ids.jellyfin.uid = 996;
|
||||||
|
sane.ids.acme.gid = 996;
|
||||||
|
sane.ids.pleroma.uid = 997;
|
||||||
|
sane.ids.acme.uid = 998;
|
||||||
|
|
||||||
|
# greetd (used by sway)
|
||||||
|
sane.ids.greeter.uid = 999;
|
||||||
|
sane.ids.greeter.gid = 999;
|
||||||
|
|
||||||
|
# new servo users
|
||||||
|
sane.ids.freshrss.uid = 2401;
|
||||||
|
sane.ids.freshrss.gid = 2401;
|
||||||
|
sane.ids.mediawiki.uid = 2402;
|
||||||
|
sane.ids.signald.uid = 2403;
|
||||||
|
sane.ids.signald.gid = 2403;
|
||||||
|
sane.ids.mautrix-signal.uid = 2404;
|
||||||
|
sane.ids.mautrix-signal.gid = 2404;
|
||||||
|
sane.ids.navidrome.uid = 2405;
|
||||||
|
sane.ids.navidrome.gid = 2405;
|
||||||
|
|
||||||
|
sane.ids.colin.uid = 1000;
|
||||||
|
sane.ids.guest.uid = 1100;
|
||||||
|
|
||||||
|
# found on all hosts
|
||||||
|
sane.ids.sshd.uid = 2001; # 997
|
||||||
|
sane.ids.sshd.gid = 2001; # 997
|
||||||
|
sane.ids.polkituser.gid = 2002; # 998
|
||||||
|
sane.ids.systemd-coredump.gid = 2003; # 996 # 2023/02/12-2023/02/28: upstream temporarily specified this as 151
|
||||||
|
sane.ids.nscd.uid = 2004;
|
||||||
|
sane.ids.nscd.gid = 2004;
|
||||||
|
sane.ids.systemd-oom.uid = 2005;
|
||||||
|
sane.ids.systemd-oom.gid = 2005;
|
||||||
|
|
||||||
|
# found on graphical hosts
|
||||||
|
sane.ids.nm-iodine.uid = 2101; # desko/moby/lappy
|
||||||
|
|
||||||
|
# found on desko host
|
||||||
|
# from services.usbmuxd
|
||||||
|
sane.ids.usbmux.uid = 2204;
|
||||||
|
sane.ids.usbmux.gid = 2204;
|
||||||
|
|
||||||
|
|
||||||
|
# originally found on moby host
|
||||||
|
# gnome core-shell
|
||||||
|
sane.ids.avahi.uid = 2304;
|
||||||
|
sane.ids.avahi.gid = 2304;
|
||||||
|
sane.ids.colord.uid = 2305;
|
||||||
|
sane.ids.colord.gid = 2305;
|
||||||
|
sane.ids.geoclue.uid = 2306;
|
||||||
|
sane.ids.geoclue.gid = 2306;
|
||||||
|
# gnome core-os-services
|
||||||
|
sane.ids.rtkit.uid = 2307;
|
||||||
|
sane.ids.rtkit.gid = 2307;
|
||||||
|
# phosh
|
||||||
|
sane.ids.feedbackd.gid = 2308;
|
||||||
|
}
|
||||||
16
hosts/common/machine-id.nix
Normal file
16
hosts/common/machine-id.nix
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
{ ... }:
|
||||||
|
{
|
||||||
|
# /etc/machine-id is a globally unique identifier used for:
|
||||||
|
# - systemd-networkd: DHCP lease renewal (instead of keying by the MAC address)
|
||||||
|
# - systemd-journald: to filter logs by host
|
||||||
|
# - chromium (potentially to track re-installations)
|
||||||
|
# - gdbus; system services that might upgrade to AF_LOCAL if both services can confirm they're on the same machine
|
||||||
|
# because of e.g. the chromium use, we *don't want* to persist this.
|
||||||
|
# however, `journalctl` won't show logs from previous boots unless the machine-ids match.
|
||||||
|
# so for now, generate something unique from the host ssh key.
|
||||||
|
# TODO: move this into modules?
|
||||||
|
system.activationScripts.machine-id = {
|
||||||
|
deps = [ "etc" ];
|
||||||
|
text = "sha256sum /etc/ssh/host_keys/ssh_host_ed25519_key | cut -c 1-32 > /etc/machine-id";
|
||||||
|
};
|
||||||
|
}
|
||||||
23
hosts/common/net.nix
Normal file
23
hosts/common/net.nix
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
# the default backend is "wpa_supplicant".
|
||||||
|
# wpa_supplicant reliably picks weak APs to connect to.
|
||||||
|
# see: <https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/issues/474>
|
||||||
|
# iwd is an alternative that shouldn't have this problem
|
||||||
|
# docs:
|
||||||
|
# - <https://nixos.wiki/wiki/Iwd>
|
||||||
|
# - <https://iwd.wiki.kernel.org/networkmanager>
|
||||||
|
# - `man iwd.config` for global config
|
||||||
|
# - `man iwd.network` for per-SSID config
|
||||||
|
# use `iwctl` to control
|
||||||
|
networking.networkmanager.wifi.backend = "iwd";
|
||||||
|
networking.wireless.iwd.enable = true;
|
||||||
|
networking.wireless.iwd.settings = {
|
||||||
|
# auto-connect to a stronger network if signal drops below this value
|
||||||
|
# bedroom -> bedroom connection is -35 to -40 dBm
|
||||||
|
# bedroom -> living room connection is -60 dBm
|
||||||
|
General.RoamThreshold = "-52"; # default -70
|
||||||
|
General.RoamThreshold5G = "-52"; # default -76
|
||||||
|
};
|
||||||
|
}
|
||||||
18
hosts/common/persist.nix
Normal file
18
hosts/common/persist.nix
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
{ ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
sane.persist.stores.private.origin = "/home/colin/private";
|
||||||
|
# store /home/colin/a/b in /home/private/a/b instead of /home/private/home/colin/a/b
|
||||||
|
sane.persist.stores.private.prefix = "/home/colin";
|
||||||
|
|
||||||
|
sane.persist.sys.plaintext = [
|
||||||
|
"/var/log"
|
||||||
|
"/var/backup" # for e.g. postgres dumps
|
||||||
|
# TODO: move elsewhere
|
||||||
|
"/var/lib/alsa" # preserve output levels, default devices
|
||||||
|
"/var/lib/colord" # preserve color calibrations (?)
|
||||||
|
"/var/lib/machines" # maybe not needed, but would be painful to add a VM and forget.
|
||||||
|
"/var/lib/systemd/backlight" # backlight brightness
|
||||||
|
"/var/lib/systemd/coredump"
|
||||||
|
];
|
||||||
|
}
|
||||||
384
hosts/common/programs.nix
Normal file
384
hosts/common/programs.nix
Normal file
@@ -0,0 +1,384 @@
|
|||||||
|
{ lib, pkgs, ... }:
|
||||||
|
|
||||||
|
let
|
||||||
|
inherit (builtins) attrNames concatLists;
|
||||||
|
inherit (lib) mapAttrs mapAttrsToList mkDefault mkMerge optional;
|
||||||
|
|
||||||
|
flattenedPkgs = pkgs // (with pkgs; {
|
||||||
|
# XXX can't `inherit` a nested attr, so we move them to the toplevel
|
||||||
|
"cacert.unbundled" = pkgs.cacert.unbundled;
|
||||||
|
"gnome.cheese" = gnome.cheese;
|
||||||
|
"gnome.dconf-editor" = gnome.dconf-editor;
|
||||||
|
"gnome.file-roller" = gnome.file-roller;
|
||||||
|
"gnome.gnome-disk-utility" = gnome.gnome-disk-utility;
|
||||||
|
"gnome.gnome-maps" = gnome.gnome-maps;
|
||||||
|
"gnome.nautilus" = gnome.nautilus;
|
||||||
|
"gnome.gnome-system-monitor" = gnome.gnome-system-monitor;
|
||||||
|
"gnome.gnome-terminal" = gnome.gnome-terminal;
|
||||||
|
"gnome.gnome-weather" = gnome.gnome-weather;
|
||||||
|
"gnome.totem" = gnome.totem;
|
||||||
|
"libsForQt5.plasmatube" = libsForQt5.plasmatube;
|
||||||
|
});
|
||||||
|
|
||||||
|
sysadminPkgs = {
|
||||||
|
inherit (flattenedPkgs)
|
||||||
|
btrfs-progs
|
||||||
|
"cacert.unbundled" # some services require unbundled /etc/ssl/certs
|
||||||
|
cryptsetup
|
||||||
|
dig
|
||||||
|
efibootmgr
|
||||||
|
fatresize
|
||||||
|
fd
|
||||||
|
file
|
||||||
|
gawk
|
||||||
|
git
|
||||||
|
gptfdisk
|
||||||
|
hdparm
|
||||||
|
htop
|
||||||
|
iftop
|
||||||
|
inetutils # for telnet
|
||||||
|
iotop
|
||||||
|
iptables
|
||||||
|
jq
|
||||||
|
killall
|
||||||
|
lsof
|
||||||
|
nano
|
||||||
|
netcat
|
||||||
|
nethogs
|
||||||
|
nmap
|
||||||
|
openssl
|
||||||
|
parted
|
||||||
|
pciutils
|
||||||
|
powertop
|
||||||
|
pstree
|
||||||
|
ripgrep
|
||||||
|
screen
|
||||||
|
smartmontools
|
||||||
|
socat
|
||||||
|
strace
|
||||||
|
subversion
|
||||||
|
tcpdump
|
||||||
|
tree
|
||||||
|
usbutils
|
||||||
|
wget
|
||||||
|
;
|
||||||
|
};
|
||||||
|
sysadminExtraPkgs = {
|
||||||
|
# application-specific packages
|
||||||
|
inherit (pkgs)
|
||||||
|
backblaze-b2
|
||||||
|
duplicity
|
||||||
|
sqlite # to debug sqlite3 databases
|
||||||
|
;
|
||||||
|
};
|
||||||
|
|
||||||
|
iphonePkgs = {
|
||||||
|
inherit (pkgs)
|
||||||
|
ifuse
|
||||||
|
ipfs
|
||||||
|
libimobiledevice
|
||||||
|
;
|
||||||
|
};
|
||||||
|
|
||||||
|
tuiPkgs = {
|
||||||
|
inherit (pkgs)
|
||||||
|
aerc # email client
|
||||||
|
offlineimap # email mailox sync
|
||||||
|
visidata # TUI spreadsheet viewer/editor
|
||||||
|
w3m
|
||||||
|
;
|
||||||
|
};
|
||||||
|
|
||||||
|
# TODO: split these into smaller groups.
|
||||||
|
# - transcoders (ffmpeg, imagemagick) only wanted on desko/lappy ("powerutils"?)
|
||||||
|
consolePkgs = {
|
||||||
|
inherit (pkgs)
|
||||||
|
cdrtools
|
||||||
|
dmidecode
|
||||||
|
efivar
|
||||||
|
flashrom
|
||||||
|
fwupd
|
||||||
|
ghostscript # TODO: imagemagick wrapper should add gs to PATH
|
||||||
|
gnupg
|
||||||
|
gocryptfs
|
||||||
|
gopass
|
||||||
|
gopass-jsonapi
|
||||||
|
imagemagick
|
||||||
|
kitty # TODO: move to GUI, but `ssh servo` from kitty sets `TERM=xterm-kitty` in the remove and breaks things
|
||||||
|
libsecret # for managing user keyrings
|
||||||
|
lm_sensors # for sensors-detect
|
||||||
|
lshw
|
||||||
|
ffmpeg
|
||||||
|
memtester
|
||||||
|
# networkmanager
|
||||||
|
nixpkgs-review
|
||||||
|
# nixos-generators
|
||||||
|
# nettools
|
||||||
|
nmon
|
||||||
|
oathToolkit # for oathtool
|
||||||
|
# ponymix
|
||||||
|
pulsemixer
|
||||||
|
python3
|
||||||
|
rsync
|
||||||
|
# python3Packages.eyeD3 # music tagging
|
||||||
|
sane-scripts
|
||||||
|
sequoia
|
||||||
|
snapper
|
||||||
|
sops
|
||||||
|
sox
|
||||||
|
speedtest-cli
|
||||||
|
ssh-to-age
|
||||||
|
sudo
|
||||||
|
# tageditor # music tagging
|
||||||
|
unar
|
||||||
|
wireguard-tools
|
||||||
|
xdg-utils # for xdg-open
|
||||||
|
# youtube-dl
|
||||||
|
yt-dlp
|
||||||
|
;
|
||||||
|
};
|
||||||
|
|
||||||
|
guiPkgs = {
|
||||||
|
inherit (flattenedPkgs)
|
||||||
|
celluloid # mpv frontend
|
||||||
|
clinfo
|
||||||
|
emote
|
||||||
|
evince # works on phosh
|
||||||
|
|
||||||
|
# { pkg = fluffychat-moby; dir = [ ".local/share/chat.fluffy.fluffychat" ]; } # TODO: ship normal fluffychat on non-moby?
|
||||||
|
|
||||||
|
# foliate # e-book reader
|
||||||
|
|
||||||
|
# XXX by default fractal stores its state in ~/.local/share/<UUID>.
|
||||||
|
# after logging in, manually change ~/.local/share/keyrings/... to point it to some predictable subdir.
|
||||||
|
# then reboot (so that libsecret daemon re-loads the keyring...?)
|
||||||
|
# { pkg = fractal-latest; private = [ ".local/share/fractal" ]; }
|
||||||
|
# { pkg = fractal-next; private = [ ".local/share/fractal" ]; }
|
||||||
|
|
||||||
|
# "gnome.cheese"
|
||||||
|
"gnome.dconf-editor"
|
||||||
|
gnome-feeds # RSS reader (with claimed mobile support)
|
||||||
|
"gnome.file-roller"
|
||||||
|
# "gnome.gnome-maps" # works on phosh
|
||||||
|
"gnome.nautilus"
|
||||||
|
# gnome-podcasts
|
||||||
|
"gnome.gnome-system-monitor"
|
||||||
|
# "gnome.gnome-terminal" # works on phosh
|
||||||
|
"gnome.gnome-weather"
|
||||||
|
gpodder-configured
|
||||||
|
gthumb
|
||||||
|
# lollypop
|
||||||
|
mpv
|
||||||
|
networkmanagerapplet
|
||||||
|
# newsflash
|
||||||
|
nheko
|
||||||
|
pavucontrol
|
||||||
|
# picard # music tagging
|
||||||
|
playerctl
|
||||||
|
# "libsForQt5.plasmatube" # Youtube player
|
||||||
|
soundconverter
|
||||||
|
# sublime music persists any downloaded albums here.
|
||||||
|
# it doesn't obey a conventional ~/Music/{Artist}/{Album}/{Track} notation, so no symlinking
|
||||||
|
# config (e.g. server connection details) is persisted in ~/.config/sublime-music/config.json
|
||||||
|
# possible to pass config as a CLI arg (sublime-music -c config.json)
|
||||||
|
# { pkg = sublime-music; dir = [ ".local/share/sublime-music" ]; }
|
||||||
|
sublime-music-mobile
|
||||||
|
# tdesktop # broken on phosh
|
||||||
|
# tokodon
|
||||||
|
vlc
|
||||||
|
# pleroma client (Electron). input is broken on phosh. TODO(2023/02/02): fix electron19 input (insecure)
|
||||||
|
# whalebird
|
||||||
|
xterm # broken on phosh
|
||||||
|
;
|
||||||
|
};
|
||||||
|
desktopGuiPkgs = {
|
||||||
|
inherit (flattenedPkgs)
|
||||||
|
audacity
|
||||||
|
brave # for the integrated wallet -- as a backup
|
||||||
|
chromium
|
||||||
|
dino
|
||||||
|
electrum
|
||||||
|
element-desktop
|
||||||
|
font-manager
|
||||||
|
gajim # XMPP client
|
||||||
|
gimp # broken on phosh
|
||||||
|
"gnome.gnome-disk-utility"
|
||||||
|
# "gnome.totem" # video player, supposedly supports UPnP
|
||||||
|
handbrake
|
||||||
|
hase
|
||||||
|
inkscape
|
||||||
|
jellyfin-media-player # TODO: try on moby!
|
||||||
|
kdenlive
|
||||||
|
kid3 # audio tagging
|
||||||
|
krita
|
||||||
|
libreoffice-fresh # XXX colin: maybe don't want this on mobile
|
||||||
|
mumble
|
||||||
|
obsidian
|
||||||
|
;
|
||||||
|
};
|
||||||
|
x86GuiPkgs = {
|
||||||
|
inherit (pkgs)
|
||||||
|
discord
|
||||||
|
|
||||||
|
# kaiteki # Pleroma client
|
||||||
|
# gnome.zenity # for kaiteki (it will use qarma, kdialog, or zenity)
|
||||||
|
# gpt2tc # XXX: unreliable mirror
|
||||||
|
|
||||||
|
logseq
|
||||||
|
losslesscut-bin
|
||||||
|
makemkv
|
||||||
|
monero-gui
|
||||||
|
signal-desktop
|
||||||
|
spotify
|
||||||
|
tor-browser-bundle-bin
|
||||||
|
zecwallet-lite
|
||||||
|
;
|
||||||
|
};
|
||||||
|
|
||||||
|
# packages not part of any package set
|
||||||
|
otherPkgs = {
|
||||||
|
inherit (pkgs)
|
||||||
|
stepmania
|
||||||
|
;
|
||||||
|
};
|
||||||
|
|
||||||
|
# define -- but don't enable -- the packages in some attrset.
|
||||||
|
# use `mkDefault` for the package here so we can customize some of them further down this file
|
||||||
|
declarePkgs = pkgsAsAttrs: mapAttrs (_n: p: {
|
||||||
|
package = mkDefault p;
|
||||||
|
}) pkgsAsAttrs;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
config = {
|
||||||
|
sane.programs = mkMerge [
|
||||||
|
(declarePkgs consolePkgs)
|
||||||
|
(declarePkgs desktopGuiPkgs)
|
||||||
|
(declarePkgs guiPkgs)
|
||||||
|
(declarePkgs iphonePkgs)
|
||||||
|
(declarePkgs sysadminPkgs)
|
||||||
|
(declarePkgs sysadminExtraPkgs)
|
||||||
|
(declarePkgs tuiPkgs)
|
||||||
|
(declarePkgs x86GuiPkgs)
|
||||||
|
(declarePkgs otherPkgs)
|
||||||
|
{
|
||||||
|
# link the various package sets into their own meta packages
|
||||||
|
consoleUtils = {
|
||||||
|
package = null;
|
||||||
|
suggestedPrograms = attrNames consolePkgs;
|
||||||
|
};
|
||||||
|
desktopGuiApps = {
|
||||||
|
package = null;
|
||||||
|
suggestedPrograms = attrNames desktopGuiPkgs;
|
||||||
|
};
|
||||||
|
guiApps = {
|
||||||
|
package = null;
|
||||||
|
suggestedPrograms = (attrNames guiPkgs)
|
||||||
|
++ [ "tuiApps" ]
|
||||||
|
++ optional (pkgs.system == "x86_64-linux") "x86GuiApps";
|
||||||
|
};
|
||||||
|
iphoneUtils = {
|
||||||
|
package = null;
|
||||||
|
suggestedPrograms = attrNames iphonePkgs;
|
||||||
|
};
|
||||||
|
sysadminUtils = {
|
||||||
|
package = null;
|
||||||
|
suggestedPrograms = attrNames sysadminPkgs;
|
||||||
|
};
|
||||||
|
sysadminExtraUtils = {
|
||||||
|
package = null;
|
||||||
|
suggestedPrograms = attrNames sysadminExtraPkgs;
|
||||||
|
};
|
||||||
|
tuiApps = {
|
||||||
|
package = null;
|
||||||
|
suggestedPrograms = attrNames tuiPkgs;
|
||||||
|
};
|
||||||
|
x86GuiApps = {
|
||||||
|
package = null;
|
||||||
|
suggestedPrograms = attrNames x86GuiPkgs;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
{
|
||||||
|
# nontrivial package definitions
|
||||||
|
imagemagick.package = pkgs.imagemagick.override {
|
||||||
|
ghostscriptSupport = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
dino.private = [ ".local/share/dino" ];
|
||||||
|
|
||||||
|
# creds, but also 200 MB of node modules, etc
|
||||||
|
discord.private = [ ".config/discord" ];
|
||||||
|
|
||||||
|
# creds/session keys, etc
|
||||||
|
element-desktop.private = [ ".config/Element" ];
|
||||||
|
|
||||||
|
# `emote` will show a first-run dialog based on what's in this directory.
|
||||||
|
# mostly, it just keeps a LRU of previously-used emotes to optimize display order.
|
||||||
|
# TODO: package [smile](https://github.com/mijorus/smile) for probably a better mobile experience.
|
||||||
|
emote.dir = [ ".local/share/Emote" ];
|
||||||
|
|
||||||
|
# XXX: we preserve the whole thing because if we only preserve gPodder/Downloads
|
||||||
|
# then startup is SLOW during feed import, and we might end up with zombie eps in the dl dir.
|
||||||
|
gpodder-configured.dir = [ "gPodder" ];
|
||||||
|
|
||||||
|
# jellyfin stores things in a bunch of directories: this one persists auth info.
|
||||||
|
# it *might* be possible to populate this externally (it's Qt stuff), but likely to
|
||||||
|
# be fragile and take an hour+ to figure out.
|
||||||
|
jellyfin-media-player.dir = [ ".local/share/Jellyfin Media Player" ];
|
||||||
|
|
||||||
|
# actual monero blockchain (not wallet/etc; safe to delete, just slow to regenerate)
|
||||||
|
# XXX: is it really safe to persist this? it doesn't have info that could de-anonymize if captured?
|
||||||
|
monero-gui.dir = [ ".bitmonero" ];
|
||||||
|
|
||||||
|
mpv.dir = [ ".config/mpv/watch_later" ];
|
||||||
|
|
||||||
|
mumble.private = [ ".local/share/Mumble" ];
|
||||||
|
|
||||||
|
# not strictly necessary, but allows caching articles; offline use, etc.
|
||||||
|
newsflash.dir = [ ".local/share/news-flash" ];
|
||||||
|
nheko.private = [
|
||||||
|
".config/nheko" # config file (including client token)
|
||||||
|
".cache/nheko" # media cache
|
||||||
|
".local/share/nheko" # per-account state database
|
||||||
|
];
|
||||||
|
|
||||||
|
# settings (electron app)
|
||||||
|
obsidian.dir = [ ".config/obsidian" ];
|
||||||
|
|
||||||
|
# creds, media
|
||||||
|
signal-desktop.private = [ ".config/Signal" ];
|
||||||
|
|
||||||
|
|
||||||
|
# creds, widevine .so download. TODO: could easily manage these statically.
|
||||||
|
spotify.dir = [ ".config/spotify" ];
|
||||||
|
|
||||||
|
# sublime music persists any downloaded albums here.
|
||||||
|
# it doesn't obey a conventional ~/Music/{Artist}/{Album}/{Track} notation, so no symlinking
|
||||||
|
# config (e.g. server connection details) is persisted in ~/.config/sublime-music/config.json
|
||||||
|
# possible to pass config as a CLI arg (sublime-music -c config.json)
|
||||||
|
# { pkg = sublime-music; dir = [ ".local/share/sublime-music" ]; }
|
||||||
|
sublime-music-mobile.dir = [ ".local/share/sublime-music" ];
|
||||||
|
|
||||||
|
tdesktop.private = [ ".local/share/TelegramDesktop" ];
|
||||||
|
|
||||||
|
tokodon.private = [ ".cache/KDE/tokodon" ];
|
||||||
|
|
||||||
|
# hardenedMalloc solves a crash at startup
|
||||||
|
# TODO 2023/02/02: is this safe to remove yet?
|
||||||
|
tor-browser-bundle-bin.package = pkgs.tor-browser-bundle-bin.override {
|
||||||
|
useHardenedMalloc = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
# vlc remembers play position in ~/.config/vlc/vlc-qt-interface.conf
|
||||||
|
vlc.dir = [ ".config/vlc" ];
|
||||||
|
|
||||||
|
whalebird.private = [ ".config/Whalebird" ];
|
||||||
|
|
||||||
|
# zcash coins. safe to delete, just slow to regenerate (10-60 minutes)
|
||||||
|
zecwallet-lite.private = [ ".zcash" ];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
# XXX: this might not be necessary. try removing this and cacert.unbundled (servo)?
|
||||||
|
environment.etc."ssl/certs".source = "${pkgs.cacert.unbundled}/etc/ssl/certs/*";
|
||||||
|
};
|
||||||
|
}
|
||||||
135
hosts/common/secrets.nix
Normal file
135
hosts/common/secrets.nix
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
{ config, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
# SOPS configuration:
|
||||||
|
# docs: https://github.com/Mic92/sops-nix
|
||||||
|
#
|
||||||
|
# for each new user you want to edit sops files:
|
||||||
|
# create a private age key from ssh key:
|
||||||
|
# $ mkdir -p ~/.config/sops/age; ssh-to-age -private-key -i ~/.ssh/id_ed25519 > ~/.config/sops/age/keys.txt; chmod 600 ~/.config/sops/age/keys.txt
|
||||||
|
# if the private key was password protected, then first decrypt it:
|
||||||
|
# $ cp ~/.ssh/id_ed25519 /tmp/id_ed25519
|
||||||
|
# $ ssh-keygen -p -N "" -f /tmp/id_ed25519
|
||||||
|
#
|
||||||
|
# for each user you want to decrypt secrets:
|
||||||
|
# $ cat ~/.ssh/id_ed25519.pub | ssh-to-age
|
||||||
|
# add the result to .sops.yaml
|
||||||
|
# since we specify ssh pubkeys in the nix config, you can just grep for `ssh-ed25519` here and use those instead
|
||||||
|
#
|
||||||
|
# for each host you want to decrypt secrets:
|
||||||
|
# $ cat /etc/ssh/ssh_host_ed25519_key.pub | ssh-to-age
|
||||||
|
# add the result to .sops.yaml
|
||||||
|
# $ sops updatekeys secrets/example.yaml
|
||||||
|
#
|
||||||
|
# to create a new secret:
|
||||||
|
# $ sops secrets/example.yaml
|
||||||
|
# control access below (sops.secret.<x>.owner = ...)
|
||||||
|
#
|
||||||
|
# to read a secret:
|
||||||
|
# $ cat /run/secrets/example_key
|
||||||
|
|
||||||
|
# sops.age.sshKeyPaths = [ "/home/colin/.ssh/id_ed25519_dec" ];
|
||||||
|
# This will add secrets.yaml to the nix store
|
||||||
|
# You can avoid this by adding a string to the full path instead, i.e.
|
||||||
|
# sops.defaultSopsFile = "/root/.sops/secrets/example.yaml";
|
||||||
|
sops.defaultSopsFile = ../../secrets/universal.yaml;
|
||||||
|
sops.gnupg.sshKeyPaths = []; # disable RSA key import
|
||||||
|
# This is using an age key that is expected to already be in the filesystem
|
||||||
|
# sops.age.keyFile = "/home/colin/.ssh/age.pub";
|
||||||
|
# sops.age.keyFile = "/var/lib/sops-nix/key.txt";
|
||||||
|
# This will generate a new key if the key specified above does not exist
|
||||||
|
# sops.age.generateKey = true;
|
||||||
|
# This is the actual specification of the secrets.
|
||||||
|
# sops.secrets.example_key = {
|
||||||
|
# owner = config.users.users.colin.name;
|
||||||
|
# };
|
||||||
|
# sops.secrets."myservice/my_subdir/my_secret" = {};
|
||||||
|
|
||||||
|
## universal secrets
|
||||||
|
# TODO: glob these?
|
||||||
|
|
||||||
|
sops.secrets."jackett_apikey" = {
|
||||||
|
sopsFile = ../../secrets/universal.yaml;
|
||||||
|
owner = config.users.users.colin.name;
|
||||||
|
};
|
||||||
|
sops.secrets."router_passwd" = {
|
||||||
|
sopsFile = ../../secrets/universal.yaml;
|
||||||
|
};
|
||||||
|
sops.secrets."transmission_passwd" = {
|
||||||
|
sopsFile = ../../secrets/universal.yaml;
|
||||||
|
};
|
||||||
|
sops.secrets."wg_ovpnd_us_privkey" = {
|
||||||
|
sopsFile = ../../secrets/universal.yaml;
|
||||||
|
};
|
||||||
|
sops.secrets."wg_ovpnd_us-atl_privkey" = {
|
||||||
|
sopsFile = ../../secrets/universal.yaml;
|
||||||
|
};
|
||||||
|
sops.secrets."wg_ovpnd_us-mi_privkey" = {
|
||||||
|
sopsFile = ../../secrets/universal.yaml;
|
||||||
|
};
|
||||||
|
sops.secrets."wg_ovpnd_ukr_privkey" = {
|
||||||
|
sopsFile = ../../secrets/universal.yaml;
|
||||||
|
};
|
||||||
|
|
||||||
|
sops.secrets."snippets" = {
|
||||||
|
sopsFile = ../../secrets/universal/snippets.bin;
|
||||||
|
format = "binary";
|
||||||
|
owner = config.users.users.colin.name;
|
||||||
|
};
|
||||||
|
|
||||||
|
sops.secrets."bt/car" = {
|
||||||
|
sopsFile = ../../secrets/universal/bt/car.bin;
|
||||||
|
format = "binary";
|
||||||
|
};
|
||||||
|
sops.secrets."bt/earbuds" = {
|
||||||
|
sopsFile = ../../secrets/universal/bt/earbuds.bin;
|
||||||
|
format = "binary";
|
||||||
|
};
|
||||||
|
sops.secrets."bt/portable-speaker" = {
|
||||||
|
sopsFile = ../../secrets/universal/bt/portable-speaker.bin;
|
||||||
|
format = "binary";
|
||||||
|
};
|
||||||
|
|
||||||
|
sops.secrets."iwd/community-university.psk" = {
|
||||||
|
sopsFile = ../../secrets/universal/net/community-university.psk.bin;
|
||||||
|
format = "binary";
|
||||||
|
};
|
||||||
|
sops.secrets."iwd/friend-libertarian-dod.psk" = {
|
||||||
|
sopsFile = ../../secrets/universal/net/friend-libertarian-dod.psk.bin;
|
||||||
|
format = "binary";
|
||||||
|
};
|
||||||
|
sops.secrets."iwd/friend-rationalist-empathist.psk" = {
|
||||||
|
sopsFile = ../../secrets/universal/net/friend-rationalist-empathist.psk.bin;
|
||||||
|
format = "binary";
|
||||||
|
};
|
||||||
|
sops.secrets."iwd/home-shared.psk" = {
|
||||||
|
sopsFile = ../../secrets/universal/net/home-shared.psk.bin;
|
||||||
|
format = "binary";
|
||||||
|
};
|
||||||
|
sops.secrets."iwd/makespace-south.psk" = {
|
||||||
|
sopsFile = ../../secrets/universal/net/makespace-south.psk.bin;
|
||||||
|
format = "binary";
|
||||||
|
};
|
||||||
|
sops.secrets."iwd/archive-2023-02-home-bedroom.psk" = {
|
||||||
|
sopsFile = ../../secrets/universal/net/archive/2023-02-home-bedroom.psk.bin;
|
||||||
|
format = "binary";
|
||||||
|
};
|
||||||
|
sops.secrets."iwd/archive-2023-02-home-shared-24G.psk" = {
|
||||||
|
sopsFile = ../../secrets/universal/net/archive/2023-02-home-shared-24G.psk.bin;
|
||||||
|
format = "binary";
|
||||||
|
};
|
||||||
|
sops.secrets."iwd/archive-2023-02-home-shared.psk" = {
|
||||||
|
sopsFile = ../../secrets/universal/net/archive/2023-02-home-shared.psk.bin;
|
||||||
|
format = "binary";
|
||||||
|
};
|
||||||
|
sops.secrets."iwd/iphone" = {
|
||||||
|
sopsFile = ../../secrets/universal/net/iphone.psk.bin;
|
||||||
|
format = "binary";
|
||||||
|
};
|
||||||
|
sops.secrets."iwd/parents" = {
|
||||||
|
sopsFile = ../../secrets/universal/net/parents.psk.bin;
|
||||||
|
format = "binary";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
33
hosts/common/ssh.nix
Normal file
33
hosts/common/ssh.nix
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
{ config, lib, sane-data, sane-lib, ... }:
|
||||||
|
|
||||||
|
let
|
||||||
|
inherit (builtins) head map mapAttrs tail;
|
||||||
|
inherit (lib) concatStringsSep mkMerge reverseList;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
sane.ssh.pubkeys =
|
||||||
|
let
|
||||||
|
# path is a DNS-style path like [ "org" "uninsane" "root" ]
|
||||||
|
keyNameForPath = path:
|
||||||
|
let
|
||||||
|
rev = reverseList path;
|
||||||
|
name = head rev;
|
||||||
|
host = concatStringsSep "." (tail rev);
|
||||||
|
in
|
||||||
|
"${name}@${host}";
|
||||||
|
|
||||||
|
# [{ path :: [String], value :: String }] for the keys we want to install
|
||||||
|
globalKeys = sane-lib.flattenAttrs sane-data.keys;
|
||||||
|
domainKeys = sane-lib.flattenAttrs (
|
||||||
|
mapAttrs (host: cfg: {
|
||||||
|
colin = cfg.ssh.user_pubkey;
|
||||||
|
root = cfg.ssh.host_pubkey;
|
||||||
|
}) config.sane.hosts.by-name
|
||||||
|
);
|
||||||
|
in mkMerge (map
|
||||||
|
({ path, value }: {
|
||||||
|
"${keyNameForPath path}" = lib.mkIf (value != null) value;
|
||||||
|
})
|
||||||
|
(globalKeys ++ domainKeys)
|
||||||
|
);
|
||||||
|
}
|
||||||
137
hosts/common/users.nix
Normal file
137
hosts/common/users.nix
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
{ config, pkgs, lib, sane-lib, ... }:
|
||||||
|
|
||||||
|
# installer docs: https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/profiles/installation-device.nix
|
||||||
|
with lib;
|
||||||
|
let
|
||||||
|
cfg = config.sane.guest;
|
||||||
|
fs = sane-lib.fs;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options = {
|
||||||
|
sane.guest.enable = mkOption {
|
||||||
|
default = false;
|
||||||
|
type = types.bool;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = {
|
||||||
|
# Users are exactly these specified here;
|
||||||
|
# old ones will be deleted (from /etc/passwd, etc) upon upgrade.
|
||||||
|
users.mutableUsers = false;
|
||||||
|
|
||||||
|
# docs: https://nixpkgs-manual-sphinx-markedown-example.netlify.app/generated/options-db.xml.html#users-users
|
||||||
|
users.users.colin = {
|
||||||
|
# sets group to "users" (?)
|
||||||
|
isNormalUser = true;
|
||||||
|
home = "/home/colin";
|
||||||
|
createHome = true;
|
||||||
|
homeMode = "0700";
|
||||||
|
# i don't get exactly what this is, but nixos defaults to this non-deterministically
|
||||||
|
# in /var/lib/nixos/auto-subuid-map and i don't want that.
|
||||||
|
subUidRanges = [
|
||||||
|
{ startUid=100000; count=1; }
|
||||||
|
];
|
||||||
|
group = "users";
|
||||||
|
extraGroups = [
|
||||||
|
"wheel"
|
||||||
|
"nixbuild"
|
||||||
|
"networkmanager"
|
||||||
|
# phosh/mobile. XXX colin: unsure if necessary
|
||||||
|
"video"
|
||||||
|
"feedbackd"
|
||||||
|
"dialout" # required for modem access
|
||||||
|
];
|
||||||
|
|
||||||
|
# initial password is empty, in case anything goes wrong.
|
||||||
|
# if `colin-passwd` (a password hash) is successfully found/decrypted, that becomes the password at boot.
|
||||||
|
initialPassword = lib.mkDefault "";
|
||||||
|
passwordFile = lib.mkIf (config.sops.secrets ? "colin-passwd") config.sops.secrets.colin-passwd.path;
|
||||||
|
|
||||||
|
shell = pkgs.zsh;
|
||||||
|
|
||||||
|
# mount encrypted stuff at login
|
||||||
|
# some other nix pam users:
|
||||||
|
# - <https://github.com/g00pix/nixconf/blob/32c04f6fa843fed97639dd3f09e157668d3eea1f/profiles/sshfs.nix>
|
||||||
|
# - <https://github.com/lourkeur/distro/blob/11173454c6bb50f7ccab28cc2c757dca21446d1d/nixos/profiles/users/louis-full.nix>
|
||||||
|
# - <https://github.com/dnr/sample-nix-code/blob/03494480c1fae550c033aa54fd96aeb3827761c5/nixos/laptop.nix>
|
||||||
|
pamMount = let
|
||||||
|
priv = config.fileSystems."/home/colin/private";
|
||||||
|
in {
|
||||||
|
fstype = priv.fsType;
|
||||||
|
path = priv.device;
|
||||||
|
mountpoint = priv.mountPoint;
|
||||||
|
options = builtins.concatStringsSep "," priv.options;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
security.pam.mount.enable = true;
|
||||||
|
|
||||||
|
sane.users.colin.default = true;
|
||||||
|
# ensure ~ perms are known to sane.fs module.
|
||||||
|
# TODO: this is generic enough to be lifted up into sane.fs itself.
|
||||||
|
sane.fs."/home/colin".dir.acl = {
|
||||||
|
user = "colin";
|
||||||
|
group = config.users.users.colin.group;
|
||||||
|
mode = config.users.users.colin.homeMode;
|
||||||
|
};
|
||||||
|
|
||||||
|
sane.user.persist.plaintext = [
|
||||||
|
"archive"
|
||||||
|
"dev"
|
||||||
|
# TODO: records should be private
|
||||||
|
"records"
|
||||||
|
"ref"
|
||||||
|
"tmp"
|
||||||
|
"use"
|
||||||
|
"Music"
|
||||||
|
"Pictures"
|
||||||
|
"Videos"
|
||||||
|
|
||||||
|
".cache/nix"
|
||||||
|
".cache/nix-index"
|
||||||
|
|
||||||
|
# ".cargo"
|
||||||
|
# ".rustup"
|
||||||
|
];
|
||||||
|
|
||||||
|
# convenience
|
||||||
|
sane.user.fs."knowledge" = fs.wantedSymlinkTo "private/knowledge";
|
||||||
|
sane.user.fs."nixos" = fs.wantedSymlinkTo "dev/nixos";
|
||||||
|
sane.user.fs."Books/servo" = fs.wantedSymlinkTo "/mnt/servo-media/Books";
|
||||||
|
sane.user.fs."Videos/servo" = fs.wantedSymlinkTo "/mnt/servo-media/Videos";
|
||||||
|
sane.user.fs."Videos/servo-incomplete" = fs.wantedSymlinkTo "/mnt/servo-media/incomplete";
|
||||||
|
sane.user.fs."Music/servo" = fs.wantedSymlinkTo "/mnt/servo-media/Music";
|
||||||
|
|
||||||
|
# used by password managers, e.g. unix `pass`
|
||||||
|
sane.user.fs.".password-store" = fs.wantedSymlinkTo "knowledge/secrets/accounts";
|
||||||
|
|
||||||
|
sane.persist.sys.plaintext = mkIf cfg.enable [
|
||||||
|
# intentionally allow other users to write to the guest folder
|
||||||
|
{ directory = "/home/guest"; user = "guest"; group = "users"; mode = "0775"; }
|
||||||
|
];
|
||||||
|
users.users.guest = mkIf cfg.enable {
|
||||||
|
isNormalUser = true;
|
||||||
|
home = "/home/guest";
|
||||||
|
subUidRanges = [
|
||||||
|
{ startUid=200000; count=1; }
|
||||||
|
];
|
||||||
|
group = "users";
|
||||||
|
initialPassword = lib.mkDefault "";
|
||||||
|
shell = pkgs.zsh;
|
||||||
|
openssh.authorizedKeys.keys = [
|
||||||
|
# TODO: insert pubkeys that should be allowed in
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
security.sudo = {
|
||||||
|
enable = true;
|
||||||
|
wheelNeedsPassword = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
services.openssh = {
|
||||||
|
enable = true;
|
||||||
|
settings.PermitRootLogin = "no";
|
||||||
|
settings.PasswordAuthentication = false;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
66
hosts/common/vpn.nix
Normal file
66
hosts/common/vpn.nix
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
{ config, lib, ... }:
|
||||||
|
|
||||||
|
# to add a new OVPN VPN:
|
||||||
|
# - generate a privkey `wg genkey`
|
||||||
|
# - add this key to `sops secrets/universal.yaml`
|
||||||
|
# - upload pubkey to OVPN.com
|
||||||
|
# - generate config @ OVPN.com
|
||||||
|
# - copy the Address, PublicKey, Endpoint from OVPN's config
|
||||||
|
# N.B.: maximum interface name in Linux is 15 characters.
|
||||||
|
let
|
||||||
|
def-ovpn = name: { endpoint, publicKey, address }: {
|
||||||
|
networking.wg-quick.interfaces."ovpnd-${name}" = {
|
||||||
|
inherit address;
|
||||||
|
privateKeyFile = config.sops.secrets."wg_ovpnd_${name}_privkey".path;
|
||||||
|
dns = [
|
||||||
|
"46.227.67.134"
|
||||||
|
"192.165.9.158"
|
||||||
|
];
|
||||||
|
peers = [
|
||||||
|
{
|
||||||
|
allowedIPs = [
|
||||||
|
"0.0.0.0/0"
|
||||||
|
"::/0"
|
||||||
|
];
|
||||||
|
inherit endpoint publicKey;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
# to start: `systemctl start wg-quick-ovpnd-${name}`
|
||||||
|
autostart = false;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
in lib.mkMerge [
|
||||||
|
(def-ovpn "us" {
|
||||||
|
endpoint = "vpn31.prd.losangeles.ovpn.com:9929";
|
||||||
|
publicKey = "VW6bEWMOlOneta1bf6YFE25N/oMGh1E1UFBCfyggd0k=";
|
||||||
|
address = [
|
||||||
|
"172.27.237.218/32"
|
||||||
|
"fd00:0000:1337:cafe:1111:1111:ab00:4c8f/128"
|
||||||
|
];
|
||||||
|
})
|
||||||
|
# NB: us-* share the same wg key and link-local addrs, but distinct public addresses
|
||||||
|
(def-ovpn "us-atl" {
|
||||||
|
endpoint = "vpn18.prd.atlanta.ovpn.com:9929";
|
||||||
|
publicKey = "Dpg/4v5s9u0YbrXukfrMpkA+XQqKIFpf8ZFgyw0IkE0=";
|
||||||
|
address = [
|
||||||
|
"172.21.182.178/32"
|
||||||
|
"fd00:0000:1337:cafe:1111:1111:cfcb:27e3/128"
|
||||||
|
];
|
||||||
|
})
|
||||||
|
(def-ovpn "us-mi" {
|
||||||
|
endpoint = "vpn34.prd.miami.ovpn.com:9929";
|
||||||
|
publicKey = "VtJz2irbu8mdkIQvzlsYhU+k9d55or9mx4A2a14t0V0=";
|
||||||
|
address = [
|
||||||
|
"172.21.182.178/32"
|
||||||
|
"fd00:0000:1337:cafe:1111:1111:cfcb:27e3/128"
|
||||||
|
];
|
||||||
|
})
|
||||||
|
(def-ovpn "ukr" {
|
||||||
|
endpoint = "vpn96.prd.kyiv.ovpn.com:9929";
|
||||||
|
publicKey = "CjZcXDxaaKpW8b5As1EcNbI6+42A6BjWahwXDCwfVFg=";
|
||||||
|
address = [
|
||||||
|
"172.18.180.159/32"
|
||||||
|
"fd00:0000:1337:cafe:1111:1111:ec5c:add3/128"
|
||||||
|
];
|
||||||
|
})
|
||||||
|
]
|
||||||
29
hosts/instantiate.nix
Normal file
29
hosts/instantiate.nix
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
# trampoline from flake.nix into the specific host definition, while doing a tiny bit of common setup
|
||||||
|
|
||||||
|
# args from flake-level `import`
|
||||||
|
{ hostName, localSystem }:
|
||||||
|
|
||||||
|
# module args
|
||||||
|
{ config, lib, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
./by-name/${hostName}
|
||||||
|
./common
|
||||||
|
./modules
|
||||||
|
];
|
||||||
|
|
||||||
|
networking.hostName = hostName;
|
||||||
|
nixpkgs.buildPlatform = lib.mkIf (localSystem != null) localSystem;
|
||||||
|
sane.cross.enablePatches = localSystem != null;
|
||||||
|
|
||||||
|
# nixpkgs.overlays = [
|
||||||
|
# (next: prev: {
|
||||||
|
# # for local != target we by default just emulate the target while building.
|
||||||
|
# # provide a `pkgs.cross.<pkg>` alias that consumers can use instead of `pkgs.<foo>`
|
||||||
|
# # to explicitly opt into non-emulated cross compilation for any specific package.
|
||||||
|
# # this is most beneficial for large packages with few pre-requisites -- like Linux.
|
||||||
|
# cross = prev.crossFrom."${localSystem}";
|
||||||
|
# })
|
||||||
|
# ];
|
||||||
|
}
|
||||||
16
hosts/modules/default.nix
Normal file
16
hosts/modules/default.nix
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
{ ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
./derived-secrets.nix
|
||||||
|
./gui
|
||||||
|
./hardware
|
||||||
|
./hostnames.nix
|
||||||
|
./hosts.nix
|
||||||
|
./nixcache.nix
|
||||||
|
./roles
|
||||||
|
./services
|
||||||
|
./wg-home.nix
|
||||||
|
./yggdrasil.nix
|
||||||
|
];
|
||||||
|
}
|
||||||
47
hosts/modules/derived-secrets.nix
Normal file
47
hosts/modules/derived-secrets.nix
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
{ config, lib, ... }:
|
||||||
|
|
||||||
|
let
|
||||||
|
inherit (builtins) toString;
|
||||||
|
inherit (lib) mapAttrs mkOption types;
|
||||||
|
cfg = config.sane.derived-secrets;
|
||||||
|
secret = types.submodule {
|
||||||
|
options = {
|
||||||
|
len = mkOption {
|
||||||
|
type = types.int;
|
||||||
|
};
|
||||||
|
encoding = mkOption {
|
||||||
|
type = types.enum [ "base64" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options = {
|
||||||
|
sane.derived-secrets = mkOption {
|
||||||
|
type = types.attrsOf secret;
|
||||||
|
default = {};
|
||||||
|
description = ''
|
||||||
|
fs path => secret options.
|
||||||
|
for each entry, we create an item at the given path whose value is deterministic,
|
||||||
|
but also pseudo-random and not predictable by anyone without root access to the machine.
|
||||||
|
as PRNG source we use the host ssh key, and derived secrets are salted based on the destination path.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = {
|
||||||
|
sane.fs = mapAttrs (path: c: {
|
||||||
|
generated.script.script = ''
|
||||||
|
echo "$1" | cat /dev/stdin /etc/ssh/host_keys/ssh_host_ed25519_key \
|
||||||
|
| sha512sum \
|
||||||
|
| cut -c 1-${toString (c.len * 2)} \
|
||||||
|
| tr a-z A-Z \
|
||||||
|
| basenc -d --base16 \
|
||||||
|
| basenc --${c.encoding} \
|
||||||
|
> "$1"
|
||||||
|
'';
|
||||||
|
generated.script.scriptArgs = [ path ];
|
||||||
|
generated.acl.mode = "0600";
|
||||||
|
}) cfg;
|
||||||
|
};
|
||||||
|
}
|
||||||
15
hosts/modules/gui/default.nix
Normal file
15
hosts/modules/gui/default.nix
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
{ lib, config, ... }:
|
||||||
|
|
||||||
|
let
|
||||||
|
inherit (lib) mkDefault mkIf mkOption types;
|
||||||
|
cfg = config.sane.gui;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
./gnome.nix
|
||||||
|
./phosh.nix
|
||||||
|
./plasma.nix
|
||||||
|
./plasma-mobile.nix
|
||||||
|
./sway.nix
|
||||||
|
];
|
||||||
|
}
|
||||||
@@ -2,18 +2,19 @@
|
|||||||
|
|
||||||
with lib;
|
with lib;
|
||||||
let
|
let
|
||||||
cfg = config.colinsane.gui.gnome;
|
cfg = config.sane.gui.gnome;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
options = {
|
options = {
|
||||||
colinsane.gui.gnome.enable = mkOption {
|
sane.gui.gnome.enable = mkOption {
|
||||||
default = false;
|
default = false;
|
||||||
type = types.bool;
|
type = types.bool;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config = mkIf cfg.enable {
|
config = mkIf cfg.enable {
|
||||||
colinsane.gui.enable = true;
|
sane.programs.guiApps.enableFor.user.colin = true;
|
||||||
|
|
||||||
# start gnome/gdm on boot
|
# start gnome/gdm on boot
|
||||||
services.xserver.enable = true;
|
services.xserver.enable = true;
|
||||||
services.xserver.desktopManager.gnome.enable = true;
|
services.xserver.desktopManager.gnome.enable = true;
|
||||||
@@ -24,7 +25,7 @@ in
|
|||||||
networking.networkmanager.enable = true;
|
networking.networkmanager.enable = true;
|
||||||
networking.wireless.enable = lib.mkForce false;
|
networking.wireless.enable = lib.mkForce false;
|
||||||
};
|
};
|
||||||
# home-mananger.users.colin extras
|
# user extras:
|
||||||
# obtain these by running `dconf dump /` after manually customizing gnome
|
# obtain these by running `dconf dump /` after manually customizing gnome
|
||||||
# TODO: fix "is not of type `GVariant value'"
|
# TODO: fix "is not of type `GVariant value'"
|
||||||
# dconf.settings = lib.mkIf (gui == "gnome") {
|
# dconf.settings = lib.mkIf (gui == "gnome") {
|
||||||
163
hosts/modules/gui/phosh.nix
Normal file
163
hosts/modules/gui/phosh.nix
Normal file
@@ -0,0 +1,163 @@
|
|||||||
|
{ lib, config, pkgs, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
let
|
||||||
|
cfg = config.sane.gui.phosh;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options = {
|
||||||
|
sane.gui.phosh.enable = mkOption {
|
||||||
|
default = false;
|
||||||
|
type = types.bool;
|
||||||
|
};
|
||||||
|
sane.gui.phosh.useGreeter = mkOption {
|
||||||
|
description = ''
|
||||||
|
launch phosh via a greeter (like lightdm-mobile-greeter).
|
||||||
|
phosh is usable without a greeter, but skipping the greeter means no PAM session.
|
||||||
|
'';
|
||||||
|
default = true;
|
||||||
|
type = types.bool;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkMerge [
|
||||||
|
{
|
||||||
|
sane.programs.phoshApps = {
|
||||||
|
package = null;
|
||||||
|
suggestedPrograms = [
|
||||||
|
"guiApps"
|
||||||
|
# TODO: see about removing gnome-bluetooth if the in-built gnome-settings bluetooth manager can work
|
||||||
|
"gnome.gnome-bluetooth"
|
||||||
|
"gnome.gnome-terminal"
|
||||||
|
"phosh-mobile-settings"
|
||||||
|
# "plasma5Packages.konsole" # more reliable terminal
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
{
|
||||||
|
sane.programs = {
|
||||||
|
inherit (pkgs // {
|
||||||
|
"gnome.gnome-bluetooth" = pkgs.gnome.gnome-bluetooth;
|
||||||
|
"gnome.gnome-terminal" = pkgs.gnome.gnome-terminal;
|
||||||
|
"plasma5Packages.konsole" = pkgs.plasma5Packages.konsole;
|
||||||
|
})
|
||||||
|
phosh-mobile-settings
|
||||||
|
"plasma5Packages.konsole"
|
||||||
|
# "gnome.gnome-bluetooth"
|
||||||
|
"gnome.gnome-terminal"
|
||||||
|
;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
(mkIf cfg.enable {
|
||||||
|
sane.programs.phoshApps.enableFor.user.colin = true;
|
||||||
|
|
||||||
|
# TODO(2023/02/28): remove this qt.style = "gtk2" override.
|
||||||
|
# gnome by default tells qt to stylize its apps similar to gnome.
|
||||||
|
# but the package needed for that doesn't cross-compile, hence i disable that here.
|
||||||
|
# qt.platformTheme = "gtk2";
|
||||||
|
# qt.style = "gtk2";
|
||||||
|
|
||||||
|
# docs: https://github.com/NixOS/nixpkgs/blob/nixos-22.05/nixos/modules/services/x11/desktop-managers/phosh.nix
|
||||||
|
services.xserver.desktopManager.phosh = {
|
||||||
|
enable = true;
|
||||||
|
user = "colin";
|
||||||
|
group = "users";
|
||||||
|
phocConfig = {
|
||||||
|
# xwayland = "true";
|
||||||
|
# find default outputs by catting /etc/phosh/phoc.ini
|
||||||
|
outputs.DSI-1 = {
|
||||||
|
scale = 1.5;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# phosh enables `services.gnome.{core-os-services, core-shell}`
|
||||||
|
# and this in turn enables some default apps we don't really care about.
|
||||||
|
# see <nixos/modules/services/x11/desktop-managers/gnome.nix>
|
||||||
|
environment.gnome.excludePackages = with pkgs; [
|
||||||
|
# gnome.gnome-menus # unused outside gnome classic, but probably harmless
|
||||||
|
gnome-tour
|
||||||
|
];
|
||||||
|
services.dleyna-renderer.enable = false;
|
||||||
|
services.dleyna-server.enable = false;
|
||||||
|
services.gnome.gnome-browser-connector.enable = false;
|
||||||
|
services.gnome.gnome-initial-setup.enable = false;
|
||||||
|
services.gnome.gnome-online-accounts.enable = false;
|
||||||
|
services.gnome.gnome-remote-desktop.enable = false;
|
||||||
|
services.gnome.gnome-user-share.enable = false;
|
||||||
|
services.gnome.rygel.enable = false;
|
||||||
|
|
||||||
|
# gnome doesn't use mkDefault for these -- unclear why not
|
||||||
|
services.gnome.evolution-data-server.enable = mkForce false;
|
||||||
|
services.gnome.gnome-online-miners.enable = mkForce false;
|
||||||
|
|
||||||
|
# XXX: phosh enables networkmanager by default; can probably disable these lines
|
||||||
|
networking.useDHCP = false;
|
||||||
|
networking.networkmanager.enable = true;
|
||||||
|
networking.wireless.enable = lib.mkForce false;
|
||||||
|
|
||||||
|
# XXX: not clear if these are actually needed?
|
||||||
|
hardware.bluetooth.enable = true;
|
||||||
|
services.blueman.enable = true;
|
||||||
|
|
||||||
|
hardware.opengl.enable = true;
|
||||||
|
hardware.opengl.driSupport = true;
|
||||||
|
|
||||||
|
environment.variables = {
|
||||||
|
# Qt apps won't always start unless this env var is set
|
||||||
|
QT_QPA_PLATFORM = "wayland";
|
||||||
|
# electron apps (e.g. Element) should use the wayland backend
|
||||||
|
# toggle this to have electron apps (e.g. Element) use the wayland backend.
|
||||||
|
# phocConfig.xwayland should be disabled if you do this
|
||||||
|
NIXOS_OZONE_WL = "1";
|
||||||
|
};
|
||||||
|
|
||||||
|
programs.dconf.packages = [
|
||||||
|
# org.kde.konsole.desktop
|
||||||
|
(pkgs.writeTextFile {
|
||||||
|
name = "dconf-phosh-settings";
|
||||||
|
destination = "/etc/dconf/db/site.d/00_phosh_settings";
|
||||||
|
text = ''
|
||||||
|
[org/gnome/desktop/interface]
|
||||||
|
show-battery-percentage=true
|
||||||
|
|
||||||
|
[org/gnome/settings-daemon/plugins/power]
|
||||||
|
sleep-inactive-ac-timeout=5400
|
||||||
|
sleep-inactive-battery-timeout=5400
|
||||||
|
|
||||||
|
[sm/puri/phosh]
|
||||||
|
favorites=['gpodder.desktop', 'nheko.desktop', 'sublime-music.desktop', 'firefox.desktop', 'org.gnome.Terminal.desktop']
|
||||||
|
'';
|
||||||
|
})
|
||||||
|
];
|
||||||
|
})
|
||||||
|
|
||||||
|
(mkIf (cfg.enable && cfg.useGreeter) {
|
||||||
|
services.xserver.enable = true;
|
||||||
|
# NB: setting defaultSession has the critical side-effect that it lets org.freedesktop.AccountsService
|
||||||
|
# know that our user exists. this ensures lightdm succeeds when calling /org/freedesktop/AccountsServices ListCachedUsers
|
||||||
|
# lightdm greeters get the login users from lightdm which gets it from org.freedesktop.Accounts.ListCachedUsers.
|
||||||
|
# this requires the user we want to login as to be cached.
|
||||||
|
services.xserver.displayManager.job.preStart = ''
|
||||||
|
${pkgs.systemd}/bin/busctl call org.freedesktop.Accounts /org/freedesktop/Accounts org.freedesktop.Accounts CacheUser s colin
|
||||||
|
'';
|
||||||
|
# services.xserver.displayManager.defaultSession = "sm.puri.Phosh"; # XXX: not sure why this doesn't propagate correctly.
|
||||||
|
services.xserver.displayManager.lightdm.extraSeatDefaults = ''
|
||||||
|
user-session = phosh
|
||||||
|
'';
|
||||||
|
# services.xserver.displayManager.lightdm.greeters.gtk.enable = false; # gtk greeter overrides our own?
|
||||||
|
# services.xserver.displayManager.lightdm.greeter = {
|
||||||
|
# enable = true;
|
||||||
|
# package = pkgs.lightdm-mobile-greeter.xgreeters;
|
||||||
|
# name = "lightdm-mobile-greeter";
|
||||||
|
# };
|
||||||
|
# # services.xserver.displayManager.lightdm.enable = true;
|
||||||
|
|
||||||
|
services.xserver.displayManager.lightdm.enable = true;
|
||||||
|
services.xserver.displayManager.lightdm.greeters.mobile.enable = true;
|
||||||
|
|
||||||
|
systemd.services.phosh.wantedBy = lib.mkForce []; # disable auto-start
|
||||||
|
})
|
||||||
|
];
|
||||||
|
}
|
||||||
@@ -2,18 +2,19 @@
|
|||||||
|
|
||||||
with lib;
|
with lib;
|
||||||
let
|
let
|
||||||
cfg = config.colinsane.gui.plasma-mobile;
|
cfg = config.sane.gui.plasma-mobile;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
options = {
|
options = {
|
||||||
colinsane.gui.plasma-mobile.enable = mkOption {
|
sane.gui.plasma-mobile.enable = mkOption {
|
||||||
default = false;
|
default = false;
|
||||||
type = types.bool;
|
type = types.bool;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config = mkIf cfg.enable {
|
config = mkIf cfg.enable {
|
||||||
colinsane.gui.enable = true;
|
sane.programs.guiApps.enableFor.user.colin = true;
|
||||||
|
|
||||||
# start plasma-mobile on boot
|
# start plasma-mobile on boot
|
||||||
services.xserver.enable = true;
|
services.xserver.enable = true;
|
||||||
services.xserver.desktopManager.plasma5.mobile.enable = true;
|
services.xserver.desktopManager.plasma5.mobile.enable = true;
|
||||||
28
hosts/modules/gui/plasma.nix
Normal file
28
hosts/modules/gui/plasma.nix
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
{ lib, config, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
let
|
||||||
|
cfg = config.sane.gui.plasma;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options = {
|
||||||
|
sane.gui.plasma.enable = mkOption {
|
||||||
|
default = false;
|
||||||
|
type = types.bool;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkIf cfg.enable {
|
||||||
|
sane.programs.guiApps.enableFor.user.colin = true;
|
||||||
|
|
||||||
|
# start plasma on boot
|
||||||
|
services.xserver.enable = true;
|
||||||
|
services.xserver.desktopManager.plasma5.enable = true;
|
||||||
|
services.xserver.displayManager.sddm.enable = true;
|
||||||
|
|
||||||
|
# gnome does networking stuff with networkmanager
|
||||||
|
networking.useDHCP = false;
|
||||||
|
networking.networkmanager.enable = true;
|
||||||
|
networking.wireless.enable = lib.mkForce false;
|
||||||
|
};
|
||||||
|
}
|
||||||
13
hosts/modules/gui/snippets.txt
Normal file
13
hosts/modules/gui/snippets.txt
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
https://search.nixos.org/options?channel=unstable&query=
|
||||||
|
https://search.nixos.org/packages?channel=unstable&query=
|
||||||
|
https://nixos.wiki/index.php?go=Go&search=
|
||||||
|
https://nixos.org/manual/nix/stable/language/builtins.html
|
||||||
|
https://github.com/nixos/nixpkgs/pulls?q=
|
||||||
|
https://nur.nix-community.org/
|
||||||
|
https://nix-community.github.io/home-manager/options.html
|
||||||
|
https://w.uninsane.org/viewer#search?books.name=wikipedia_en_all_maxi_2022-05&pattern=
|
||||||
|
https://jackett.uninsane.org/UI/Dashboard#search=
|
||||||
|
https://fed.uninsane.org
|
||||||
|
https://bt.uninsane.org
|
||||||
|
https://sci-hub.se
|
||||||
|
https://news.ycombinator.com
|
||||||
665
hosts/modules/gui/sway.nix
Normal file
665
hosts/modules/gui/sway.nix
Normal file
@@ -0,0 +1,665 @@
|
|||||||
|
{ config, lib, pkgs, sane-lib, ... }:
|
||||||
|
|
||||||
|
# docs: https://nixos.wiki/wiki/Sway
|
||||||
|
with lib;
|
||||||
|
let
|
||||||
|
cfg = config.sane.gui.sway;
|
||||||
|
# docs: https://github.com/Alexays/Waybar/wiki/Configuration
|
||||||
|
# format specifiers: https://fmt.dev/latest/syntax.html#syntax
|
||||||
|
waybar-config = [
|
||||||
|
{ # TOP BAR
|
||||||
|
layer = "top";
|
||||||
|
height = 40;
|
||||||
|
modules-left = ["sway/workspaces" "sway/mode"];
|
||||||
|
modules-center = ["sway/window"];
|
||||||
|
modules-right = ["custom/mediaplayer" "clock" "battery" "cpu" "network"];
|
||||||
|
"sway/window" = {
|
||||||
|
max-length = 50;
|
||||||
|
};
|
||||||
|
# include song artist/title. source: https://www.reddit.com/r/swaywm/comments/ni0vso/waybar_spotify_tracktitle/
|
||||||
|
"custom/mediaplayer" = {
|
||||||
|
exec = pkgs.writeShellScript "waybar-mediaplayer" ''
|
||||||
|
player_status=$(${pkgs.playerctl}/bin/playerctl status 2> /dev/null)
|
||||||
|
if [ "$player_status" = "Playing" ]; then
|
||||||
|
echo "$(${pkgs.playerctl}/bin/playerctl metadata artist) - $(${pkgs.playerctl}/bin/playerctl metadata title)"
|
||||||
|
elif [ "$player_status" = "Paused" ]; then
|
||||||
|
echo " $(${pkgs.playerctl}/bin/playerctl metadata artist) - $(${pkgs.playerctl}/bin/playerctl metadata title)"
|
||||||
|
fi
|
||||||
|
'';
|
||||||
|
interval = 2;
|
||||||
|
format = "{} ";
|
||||||
|
# return-type = "json";
|
||||||
|
on-click = "${pkgs.playerctl}/bin/playerctl play-pause";
|
||||||
|
on-scroll-up = "${pkgs.playerctl}/bin/playerctl next";
|
||||||
|
on-scroll-down = "${pkgs.playerctl}/bin/playerctl previous";
|
||||||
|
};
|
||||||
|
network = {
|
||||||
|
# docs: https://github.com/Alexays/Waybar/blob/master/man/waybar-network.5.scd
|
||||||
|
interval = 2;
|
||||||
|
max-length = 40;
|
||||||
|
# custom :> format specifier explained here: https://github.com/Alexays/Waybar/pull/472
|
||||||
|
format-ethernet = " {bandwidthUpBits:>}▲ {bandwidthDownBits:>}▼";
|
||||||
|
tooltip-format-ethernet = "{ifname} {bandwidthUpBits:>}▲ {bandwidthDownBits:>}▼";
|
||||||
|
|
||||||
|
format-wifi = "{ifname} ({signalStrength}%) {bandwidthUpBits:>}▲ {bandwidthDownBits:>}▼";
|
||||||
|
tooltip-format-wifi = "{essid} ({signalStrength}%) {bandwidthUpBits:>}▲ {bandwidthDownBits:>}▼";
|
||||||
|
|
||||||
|
format-disconnected = "";
|
||||||
|
};
|
||||||
|
cpu = {
|
||||||
|
format = " {usage:2}%";
|
||||||
|
tooltip = false;
|
||||||
|
};
|
||||||
|
battery = {
|
||||||
|
states = {
|
||||||
|
good = 95;
|
||||||
|
warning = 30;
|
||||||
|
critical = 10;
|
||||||
|
};
|
||||||
|
format = "{icon} {capacity}%";
|
||||||
|
format-icons = [
|
||||||
|
""
|
||||||
|
""
|
||||||
|
""
|
||||||
|
""
|
||||||
|
""
|
||||||
|
];
|
||||||
|
};
|
||||||
|
clock = {
|
||||||
|
format-alt = "{:%a, %d. %b %H:%M}";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
];
|
||||||
|
# waybar-config-text = lib.generators.toJSON {} waybar-config;
|
||||||
|
waybar-config-text = (pkgs.formats.json {}).generate "waybar-config.json" waybar-config;
|
||||||
|
|
||||||
|
# bare sway launcher
|
||||||
|
sway-launcher = pkgs.writeShellScriptBin "sway-launcher" ''
|
||||||
|
${pkgs.sway}/bin/sway --debug > /tmp/sway.log 2>&1
|
||||||
|
'';
|
||||||
|
# start sway and have it construct the gtkgreeter
|
||||||
|
sway-as-greeter = pkgs.writeShellScriptBin "sway-as-greeter" ''
|
||||||
|
${pkgs.sway}/bin/sway --debug --config ${sway-config-into-gtkgreet} > /tmp/sway-as-greeter.log 2>&1
|
||||||
|
'';
|
||||||
|
# (config file for the above)
|
||||||
|
sway-config-into-gtkgreet = pkgs.writeText "greetd-sway-config" ''
|
||||||
|
exec "${gtkgreet-launcher}"
|
||||||
|
'';
|
||||||
|
# gtkgreet which launches a layered sway instance
|
||||||
|
gtkgreet-launcher = pkgs.writeShellScript "gtkgreet-launcher" ''
|
||||||
|
# NB: the "command" field here is run in the user's shell.
|
||||||
|
# so that command must exist on the specific user's path who is logging in. it doesn't need to exist system-wide.
|
||||||
|
${pkgs.greetd.gtkgreet}/bin/gtkgreet --layer-shell --command sway-launcher
|
||||||
|
'';
|
||||||
|
greeter-session = {
|
||||||
|
# greeter session config
|
||||||
|
command = "${sway-as-greeter}/bin/sway-as-greeter";
|
||||||
|
# alternatives:
|
||||||
|
# - TTY: `command = "${pkgs.greetd.greetd}/bin/agreety --cmd ${pkgs.sway}/bin/sway";`
|
||||||
|
# - autologin: `command = "${pkgs.sway}/bin/sway"; user = "colin";`
|
||||||
|
# - Dumb Login (doesn't work)": `command = "${pkgs.greetd.dlm}/bin/dlm";`
|
||||||
|
};
|
||||||
|
greeterless-session = {
|
||||||
|
# no greeter
|
||||||
|
command = "${sway-launcher}/bin/sway-launcher";
|
||||||
|
user = "colin";
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options = {
|
||||||
|
sane.gui.sway.enable = mkOption {
|
||||||
|
default = false;
|
||||||
|
type = types.bool;
|
||||||
|
};
|
||||||
|
sane.gui.sway.useGreeter = mkOption {
|
||||||
|
description = ''
|
||||||
|
launch sway via a greeter (like greetd's gtkgreet).
|
||||||
|
sway is usable without a greeter, but skipping the greeter means no PAM session.
|
||||||
|
'';
|
||||||
|
default = true;
|
||||||
|
type = types.bool;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
config = mkMerge [
|
||||||
|
{
|
||||||
|
sane.programs.swayApps = {
|
||||||
|
package = null;
|
||||||
|
suggestedPrograms = [
|
||||||
|
"guiApps"
|
||||||
|
"swaylock"
|
||||||
|
"swayidle"
|
||||||
|
"wl-clipboard"
|
||||||
|
"mako" # notification daemon
|
||||||
|
# # "pavucontrol"
|
||||||
|
"gnome.gnome-bluetooth"
|
||||||
|
"gnome.gnome-control-center"
|
||||||
|
"sway-contrib.grimshot"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
{
|
||||||
|
sane.programs = {
|
||||||
|
inherit (pkgs // {
|
||||||
|
"gnome.gnome-bluetooth" = pkgs.gnome.gnome-bluetooth;
|
||||||
|
"gnome.gnome-control-center" = pkgs.gnome.gnome-control-center;
|
||||||
|
"sway-contrib.grimshot" = pkgs.sway-contrib.grimshot;
|
||||||
|
})
|
||||||
|
swaylock
|
||||||
|
swayidle
|
||||||
|
wl-clipboard
|
||||||
|
mako
|
||||||
|
"gnome.gnome-bluetooth"
|
||||||
|
"gnome.gnome-control-center"
|
||||||
|
"sway-contrib.grimshot"
|
||||||
|
;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
(mkIf cfg.enable {
|
||||||
|
sane.programs.swayApps.enableFor.user.colin = true;
|
||||||
|
|
||||||
|
# swap in these lines to use SDDM instead of `services.greetd`.
|
||||||
|
# services.xserver.displayManager.sddm.enable = true;
|
||||||
|
# services.xserver.enable = true;
|
||||||
|
services.greetd = {
|
||||||
|
# greetd source/docs:
|
||||||
|
# - <https://git.sr.ht/~kennylevinsen/greetd>
|
||||||
|
enable = true;
|
||||||
|
settings = {
|
||||||
|
default_session = if cfg.useGreeter then greeter-session else greeterless-session;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
# we need the greeter's command to be on our PATH
|
||||||
|
users.users.colin.packages = [ sway-launcher ];
|
||||||
|
|
||||||
|
# some programs (e.g. fractal) **require** a "Secret Service Provider"
|
||||||
|
services.gnome.gnome-keyring.enable = true;
|
||||||
|
|
||||||
|
# unlike other DEs, sway configures no audio stack
|
||||||
|
# administer with pw-cli, pw-mon, pw-top commands
|
||||||
|
services.pipewire = {
|
||||||
|
enable = true;
|
||||||
|
alsa.enable = true;
|
||||||
|
alsa.support32Bit = true; # ??
|
||||||
|
pulse.enable = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
networking.useDHCP = false;
|
||||||
|
networking.networkmanager.enable = true;
|
||||||
|
networking.wireless.enable = lib.mkForce false;
|
||||||
|
|
||||||
|
hardware.bluetooth.enable = true;
|
||||||
|
services.blueman.enable = true;
|
||||||
|
# gsd provides Rfkill, which is required for the bluetooth pane in gnome-control-center to work
|
||||||
|
services.gnome.gnome-settings-daemon.enable = true;
|
||||||
|
# start the components of gsd we need at login
|
||||||
|
systemd.user.targets."org.gnome.SettingsDaemon.Rfkill".wantedBy = [ "graphical-session.target" ];
|
||||||
|
# go ahead and `systemctl --user cat gnome-session-initialized.target`. i dare you.
|
||||||
|
# the only way i can figure out how to get Rfkill to actually load is to just disable all the shit it depends on.
|
||||||
|
# it doesn't actually seem to need ANY of them in the first place T_T
|
||||||
|
systemd.user.targets."gnome-session-initialized".enable = false;
|
||||||
|
# bluez can't connect to audio devices unless pipewire is running.
|
||||||
|
# a system service can't depend on a user service, so just launch it at graphical-session
|
||||||
|
systemd.user.services."pipewire".wantedBy = [ "graphical-session.target" ];
|
||||||
|
|
||||||
|
programs.sway = {
|
||||||
|
enable = true;
|
||||||
|
wrapperFeatures.gtk = true;
|
||||||
|
};
|
||||||
|
sane.user.fs.".config/sway/config" =
|
||||||
|
let
|
||||||
|
fuzzel = "${pkgs.fuzzel}/bin/fuzzel";
|
||||||
|
sed = "${pkgs.gnused}/bin/sed";
|
||||||
|
wtype = "${pkgs.wtype}/bin/wtype";
|
||||||
|
kitty = "${pkgs.kitty}/bin/kitty";
|
||||||
|
launcher-cmd = fuzzel;
|
||||||
|
terminal-cmd = kitty;
|
||||||
|
lock-cmd = "${pkgs.swaylock}/bin/swaylock --indicator-idle-visible --indicator-radius 100 --indicator-thickness 30";
|
||||||
|
vol-up-cmd = "${pkgs.pulsemixer}/bin/pulsemixer --change-volume +5";
|
||||||
|
vol-down-cmd = "${pkgs.pulsemixer}/bin/pulsemixer --change-volume -5";
|
||||||
|
mute-cmd = "${pkgs.pulsemixer}/bin/pulsemixer --toggle-mute";
|
||||||
|
brightness-up-cmd = "${pkgs.brightnessctl}/bin/brightnessctl set +2%";
|
||||||
|
brightness-down-cmd = "${pkgs.brightnessctl}/bin/brightnessctl set 2%-";
|
||||||
|
screenshot-cmd = "${pkgs.sway-contrib.grimshot}/bin/grimshot copy area";
|
||||||
|
# "bookmarking"/snippets inspired by Luke Smith:
|
||||||
|
# - <https://www.youtube.com/watch?v=d_11QaTlf1I>
|
||||||
|
snip-file = ./snippets.txt;
|
||||||
|
# TODO: querying sops here breaks encapsulation
|
||||||
|
list-snips = "cat ${snip-file} ${config.sops.secrets.snippets.path}";
|
||||||
|
strip-comments = "${sed} 's/ #.*$//'";
|
||||||
|
snip-cmd = "${wtype} $(${list-snips} | ${fuzzel} -d -i -w 60 | ${strip-comments})";
|
||||||
|
# TODO: next splatmoji release should allow `-s none` to disable skin tones
|
||||||
|
emoji-cmd = "${pkgs.splatmoji}/bin/splatmoji -s medium-light type";
|
||||||
|
in sane-lib.fs.wantedText ''
|
||||||
|
### default font
|
||||||
|
font pango:monospace 8
|
||||||
|
|
||||||
|
### pixel boundary between windows
|
||||||
|
default_border pixel 3
|
||||||
|
default_floating_border pixel 2
|
||||||
|
hide_edge_borders smart
|
||||||
|
|
||||||
|
### defaults
|
||||||
|
focus_wrapping no
|
||||||
|
focus_follows_mouse yes
|
||||||
|
focus_on_window_activation smart
|
||||||
|
mouse_warping output
|
||||||
|
workspace_layout default
|
||||||
|
workspace_auto_back_and_forth no
|
||||||
|
|
||||||
|
### default colors (#border #background #text #indicator #childBorder)
|
||||||
|
client.focused #4c7899 #285577 #ffffff #2e9ef4 #285577
|
||||||
|
client.focused_inactive #333333 #5f676a #ffffff #484e50 #5f676a
|
||||||
|
client.unfocused #333333 #222222 #888888 #292d2e #222222
|
||||||
|
client.urgent #2f343a #900000 #ffffff #900000 #900000
|
||||||
|
client.placeholder #000000 #0c0c0c #ffffff #000000 #0c0c0c
|
||||||
|
client.background #ffffff
|
||||||
|
|
||||||
|
### key bindings
|
||||||
|
floating_modifier Mod1
|
||||||
|
## media keys
|
||||||
|
bindsym XF86AudioRaiseVolume exec ${vol-up-cmd}
|
||||||
|
bindsym XF86AudioLowerVolume exec ${vol-down-cmd}
|
||||||
|
bindsym Mod1+Page_Up exec ${vol-up-cmd}
|
||||||
|
bindsym Mod1+Page_Down exec ${vol-down-cmd}
|
||||||
|
bindsym XF86AudioMute exec ${mute-cmd}
|
||||||
|
bindsym XF86MonBrightnessUp exec ${brightness-up-cmd}
|
||||||
|
bindsym XF86MonBrightnessDown exec ${brightness-down-cmd}
|
||||||
|
## special functions
|
||||||
|
bindsym Mod1+Print exec ${screenshot-cmd}
|
||||||
|
bindsym Mod1+l exec ${lock-cmd}
|
||||||
|
bindsym Mod1+s exec ${snip-cmd}
|
||||||
|
bindsym Mod1+slash exec ${emoji-cmd}
|
||||||
|
bindsym Mod1+d exec ${launcher-cmd}
|
||||||
|
bindsym Mod1+Return exec ${terminal-cmd}
|
||||||
|
bindsym Mod1+Shift+q kill
|
||||||
|
bindsym Mod1+Shift+e exec swaynag -t warning -m 'You pressed the exit shortcut. Do you really want to exit sway? This will end your Wayland session.' -b 'Yes, exit sway' 'swaymsg exit'
|
||||||
|
bindsym Mod1+Shift+c reload
|
||||||
|
## layout
|
||||||
|
bindsym Mod1+b splith
|
||||||
|
bindsym Mod1+v splitv
|
||||||
|
bindsym Mod1+f fullscreen toggle
|
||||||
|
bindsym Mod1+a focus parent
|
||||||
|
bindsym Mod1+w layout tabbed
|
||||||
|
bindsym Mod1+e layout toggle split
|
||||||
|
bindsym Mod1+Shift+space floating toggle
|
||||||
|
bindsym Mod1+space focus mode_toggle
|
||||||
|
bindsym Mod1+r mode resize
|
||||||
|
## movement
|
||||||
|
bindsym Mod1+Up focus up
|
||||||
|
bindsym Mod1+Down focus down
|
||||||
|
bindsym Mod1+Left focus left
|
||||||
|
bindsym Mod1+Right focus right
|
||||||
|
bindsym Mod1+Shift+Up move up
|
||||||
|
bindsym Mod1+Shift+Down move down
|
||||||
|
bindsym Mod1+Shift+Left move left
|
||||||
|
bindsym Mod1+Shift+Right move right
|
||||||
|
## workspaces
|
||||||
|
bindsym Mod1+1 workspace number 1
|
||||||
|
bindsym Mod1+2 workspace number 2
|
||||||
|
bindsym Mod1+3 workspace number 3
|
||||||
|
bindsym Mod1+4 workspace number 4
|
||||||
|
bindsym Mod1+5 workspace number 5
|
||||||
|
bindsym Mod1+6 workspace number 6
|
||||||
|
bindsym Mod1+7 workspace number 7
|
||||||
|
bindsym Mod1+8 workspace number 8
|
||||||
|
bindsym Mod1+9 workspace number 9
|
||||||
|
bindsym Mod1+Shift+1 move container to workspace number 1
|
||||||
|
bindsym Mod1+Shift+2 move container to workspace number 2
|
||||||
|
bindsym Mod1+Shift+3 move container to workspace number 3
|
||||||
|
bindsym Mod1+Shift+4 move container to workspace number 4
|
||||||
|
bindsym Mod1+Shift+5 move container to workspace number 5
|
||||||
|
bindsym Mod1+Shift+6 move container to workspace number 6
|
||||||
|
bindsym Mod1+Shift+7 move container to workspace number 7
|
||||||
|
bindsym Mod1+Shift+8 move container to workspace number 8
|
||||||
|
bindsym Mod1+Shift+9 move container to workspace number 9
|
||||||
|
## "scratchpad" = ??
|
||||||
|
bindsym Mod1+Shift+minus move scratchpad
|
||||||
|
bindsym Mod1+minus scratchpad show
|
||||||
|
|
||||||
|
### defaults
|
||||||
|
mode "resize" {
|
||||||
|
bindsym Down resize grow height 10 px
|
||||||
|
bindsym Escape mode default
|
||||||
|
bindsym Left resize shrink width 10 px
|
||||||
|
bindsym Return mode default
|
||||||
|
bindsym Right resize grow width 10 px
|
||||||
|
bindsym Up resize shrink height 10 px
|
||||||
|
bindsym h resize shrink width 10 px
|
||||||
|
bindsym j resize grow height 10 px
|
||||||
|
bindsym k resize shrink height 10 px
|
||||||
|
bindsym l resize grow width 10 px
|
||||||
|
}
|
||||||
|
|
||||||
|
### lightly modified bars
|
||||||
|
bar {
|
||||||
|
# TODO: fonts was:
|
||||||
|
# config.fonts.fontconfig.defaultFonts; (monospace ++ emoji)
|
||||||
|
font pango:Hack, Font Awesome 6 Free, Twitter Color Emoji 24.000000
|
||||||
|
mode dock
|
||||||
|
hidden_state hide
|
||||||
|
position top
|
||||||
|
status_command ${pkgs.i3status}/bin/i3status
|
||||||
|
swaybar_command ${pkgs.waybar}/bin/waybar
|
||||||
|
workspace_buttons yes
|
||||||
|
strip_workspace_numbers no
|
||||||
|
tray_output primary
|
||||||
|
colors {
|
||||||
|
background #000000
|
||||||
|
statusline #ffffff
|
||||||
|
separator #666666
|
||||||
|
# #border #background #text
|
||||||
|
focused_workspace #4c7899 #285577 #ffffff
|
||||||
|
active_workspace #333333 #5f676a #ffffff
|
||||||
|
inactive_workspace #333333 #222222 #888888
|
||||||
|
urgent_workspace #2f343a #900000 #ffffff
|
||||||
|
binding_mode #2f343a #900000 #ffffff
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
### displays
|
||||||
|
## DESKTOP
|
||||||
|
output "Samsung Electric Company S22C300 0x00007F35" {
|
||||||
|
pos 0,0
|
||||||
|
res 1920x1080
|
||||||
|
}
|
||||||
|
output "Goldstar Company Ltd LG ULTRAWIDE 0x00004E94" {
|
||||||
|
pos 1920,0
|
||||||
|
res 3440x1440
|
||||||
|
}
|
||||||
|
|
||||||
|
## LAPTOP
|
||||||
|
# sh/en TV
|
||||||
|
output "Pioneer Electronic Corporation VSX-524 0x00000101" {
|
||||||
|
pos 0,0
|
||||||
|
res 1920x1080
|
||||||
|
}
|
||||||
|
# internal display
|
||||||
|
output "Unknown 0x0637 0x00000000" {
|
||||||
|
pos 1920,0
|
||||||
|
res 1920x1080
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
|
||||||
|
sane.user.fs.".config/waybar/config" = sane-lib.fs.wantedSymlinkTo waybar-config-text;
|
||||||
|
|
||||||
|
# style docs: https://github.com/Alexays/Waybar/wiki/Styling
|
||||||
|
sane.user.fs.".config/waybar/style.css" = sane-lib.fs.wantedText ''
|
||||||
|
* {
|
||||||
|
font-family: monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* defaults below: https://github.com/Alexays/Waybar/blob/master/resources/style.css */
|
||||||
|
window#waybar {
|
||||||
|
background-color: rgba(43, 48, 59, 0.5);
|
||||||
|
border-bottom: 3px solid rgba(100, 114, 125, 0.5);
|
||||||
|
color: #ffffff;
|
||||||
|
transition-property: background-color;
|
||||||
|
transition-duration: .5s;
|
||||||
|
}
|
||||||
|
|
||||||
|
window#waybar.hidden {
|
||||||
|
opacity: 0.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
window#waybar.empty {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
window#waybar.solo {
|
||||||
|
background-color: #FFFFFF;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
window#waybar.termite {
|
||||||
|
background-color: #3F3F3F;
|
||||||
|
}
|
||||||
|
|
||||||
|
window#waybar.chromium {
|
||||||
|
background-color: #000000;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#workspaces button {
|
||||||
|
padding: 0 5px;
|
||||||
|
background-color: transparent;
|
||||||
|
color: #ffffff;
|
||||||
|
/* Use box-shadow instead of border so the text isn't offset */
|
||||||
|
box-shadow: inset 0 -3px transparent;
|
||||||
|
/* Avoid rounded borders under each workspace name */
|
||||||
|
border: none;
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* https://github.com/Alexays/Waybar/wiki/FAQ#the-workspace-buttons-have-a-strange-hover-effect */
|
||||||
|
#workspaces button:hover {
|
||||||
|
background: rgba(0, 0, 0, 0.2);
|
||||||
|
box-shadow: inset 0 -3px #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
#workspaces button.focused {
|
||||||
|
background-color: #64727D;
|
||||||
|
box-shadow: inset 0 -3px #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
#workspaces button.urgent {
|
||||||
|
background-color: #eb4d4b;
|
||||||
|
}
|
||||||
|
|
||||||
|
#mode {
|
||||||
|
background-color: #64727D;
|
||||||
|
border-bottom: 3px solid #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
#clock,
|
||||||
|
#battery,
|
||||||
|
#cpu,
|
||||||
|
#memory,
|
||||||
|
#disk,
|
||||||
|
#temperature,
|
||||||
|
#backlight,
|
||||||
|
#network,
|
||||||
|
#pulseaudio,
|
||||||
|
#custom-media,
|
||||||
|
#tray,
|
||||||
|
#mode,
|
||||||
|
#idle_inhibitor,
|
||||||
|
#mpd {
|
||||||
|
padding: 0 10px;
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
#window,
|
||||||
|
#workspaces {
|
||||||
|
margin: 0 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If workspaces is the leftmost module, omit left margin */
|
||||||
|
.modules-left > widget:first-child > #workspaces {
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If workspaces is the rightmost module, omit right margin */
|
||||||
|
.modules-right > widget:last-child > #workspaces {
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#clock {
|
||||||
|
background-color: #64727D;
|
||||||
|
}
|
||||||
|
|
||||||
|
#battery {
|
||||||
|
background-color: #ffffff;
|
||||||
|
color: #000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
#battery.charging, #battery.plugged {
|
||||||
|
color: #ffffff;
|
||||||
|
background-color: #26A65B;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes blink {
|
||||||
|
to {
|
||||||
|
background-color: #ffffff;
|
||||||
|
color: #000000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#battery.critical:not(.charging) {
|
||||||
|
background-color: #f53c3c;
|
||||||
|
color: #ffffff;
|
||||||
|
animation-name: blink;
|
||||||
|
animation-duration: 0.5s;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
animation-direction: alternate;
|
||||||
|
}
|
||||||
|
|
||||||
|
label:focus {
|
||||||
|
background-color: #000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
#cpu {
|
||||||
|
background-color: #2ecc71;
|
||||||
|
color: #000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
#memory {
|
||||||
|
background-color: #9b59b6;
|
||||||
|
}
|
||||||
|
|
||||||
|
#disk {
|
||||||
|
background-color: #964B00;
|
||||||
|
}
|
||||||
|
|
||||||
|
#backlight {
|
||||||
|
background-color: #90b1b1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#network {
|
||||||
|
background-color: #2980b9;
|
||||||
|
}
|
||||||
|
|
||||||
|
#network.disconnected {
|
||||||
|
background-color: #f53c3c;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pulseaudio {
|
||||||
|
background-color: #f1c40f;
|
||||||
|
color: #000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pulseaudio.muted {
|
||||||
|
background-color: #90b1b1;
|
||||||
|
color: #2a5c45;
|
||||||
|
}
|
||||||
|
|
||||||
|
#custom-media {
|
||||||
|
background-color: #66cc99;
|
||||||
|
color: #2a5c45;
|
||||||
|
min-width: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#custom-media.custom-spotify {
|
||||||
|
background-color: #66cc99;
|
||||||
|
}
|
||||||
|
|
||||||
|
#custom-media.custom-vlc {
|
||||||
|
background-color: #ffa000;
|
||||||
|
}
|
||||||
|
|
||||||
|
#temperature {
|
||||||
|
background-color: #f0932b;
|
||||||
|
}
|
||||||
|
|
||||||
|
#temperature.critical {
|
||||||
|
background-color: #eb4d4b;
|
||||||
|
}
|
||||||
|
|
||||||
|
#tray {
|
||||||
|
background-color: #2980b9;
|
||||||
|
}
|
||||||
|
|
||||||
|
#tray > .passive {
|
||||||
|
-gtk-icon-effect: dim;
|
||||||
|
}
|
||||||
|
|
||||||
|
#tray > .needs-attention {
|
||||||
|
-gtk-icon-effect: highlight;
|
||||||
|
background-color: #eb4d4b;
|
||||||
|
}
|
||||||
|
|
||||||
|
#idle_inhibitor {
|
||||||
|
background-color: #2d3436;
|
||||||
|
}
|
||||||
|
|
||||||
|
#idle_inhibitor.activated {
|
||||||
|
background-color: #ecf0f1;
|
||||||
|
color: #2d3436;
|
||||||
|
}
|
||||||
|
|
||||||
|
#mpd {
|
||||||
|
background-color: #66cc99;
|
||||||
|
color: #2a5c45;
|
||||||
|
}
|
||||||
|
|
||||||
|
#mpd.disconnected {
|
||||||
|
background-color: #f53c3c;
|
||||||
|
}
|
||||||
|
|
||||||
|
#mpd.stopped {
|
||||||
|
background-color: #90b1b1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#mpd.paused {
|
||||||
|
background-color: #51a37a;
|
||||||
|
}
|
||||||
|
|
||||||
|
#language {
|
||||||
|
background: #00b093;
|
||||||
|
color: #740864;
|
||||||
|
padding: 0 5px;
|
||||||
|
margin: 0 5px;
|
||||||
|
min-width: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#keyboard-state {
|
||||||
|
background: #97e1ad;
|
||||||
|
color: #000000;
|
||||||
|
padding: 0 0px;
|
||||||
|
margin: 0 5px;
|
||||||
|
min-width: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#keyboard-state > label {
|
||||||
|
padding: 0 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#keyboard-state > label.locked {
|
||||||
|
background: rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
# style = ''
|
||||||
|
# * {
|
||||||
|
# border: none;
|
||||||
|
# border-radius: 0;
|
||||||
|
# font-family: Source Code Pro;
|
||||||
|
# }
|
||||||
|
# window#waybar {
|
||||||
|
# background: #16191C;
|
||||||
|
# color: #AAB2BF;
|
||||||
|
# }
|
||||||
|
# #workspaces button {
|
||||||
|
# padding: 0 5px;
|
||||||
|
# }
|
||||||
|
# .custom-spotify {
|
||||||
|
# padding: 0 10px;
|
||||||
|
# margin: 0 4px;
|
||||||
|
# background-color: #1DB954;
|
||||||
|
# color: black;
|
||||||
|
# }
|
||||||
|
# '';
|
||||||
|
})
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
20
hosts/modules/hardware/x86_64.nix
Normal file
20
hosts/modules/hardware/x86_64.nix
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
{ lib, pkgs, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
config = lib.mkIf (pkgs.system == "x86_64-linux") {
|
||||||
|
boot.initrd.availableKernelModules = [
|
||||||
|
"xhci_pci" "ahci" "sd_mod" "sdhci_pci" # nixos-generate-config defaults
|
||||||
|
"usb_storage" # rpi needed this to boot from usb storage, i think.
|
||||||
|
"nvme" # to boot from nvme devices
|
||||||
|
# efi_pstore evivars
|
||||||
|
];
|
||||||
|
|
||||||
|
powerManagement.cpuFreqGovernor = "powersave";
|
||||||
|
hardware.cpu.amd.updateMicrocode = true; # desktop
|
||||||
|
hardware.cpu.intel.updateMicrocode = true; # laptop
|
||||||
|
|
||||||
|
hardware.opengl.driSupport = true;
|
||||||
|
# For 32 bit applications
|
||||||
|
hardware.opengl.driSupport32Bit = true;
|
||||||
|
};
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user