30 Commits

Author SHA1 Message Date
javalsai 833a21b1c1 draft: partially getting authentik to work
Check / Nix flake (push) Failing after 8s
Lint / Nix expressions (push) Failing after 9s
needs manual systemctl start once booted for now

its started at auth.tuxcord.test
2026-05-05 00:02:48 +02:00
javalsai 82c76dc390 nixos/users: port tuxcord.net motd
Check / Nix flake (push) Failing after 8s
Lint / Nix expressions (push) Failing after 11s
2026-05-04 20:50:25 +02:00
javalsai edf7aab2f0 nixos/services: serve a strict robots.txt everywhere
Check / Nix flake (push) Failing after 8s
Lint / Nix expressions (push) Failing after 9s
2026-05-04 12:36:34 -04:00
ErrorNoInternet 760c5c8284 nixos/hardware: add kvm-amd module
Check / Nix flake (push) Failing after 10s
Lint / Nix expressions (push) Failing after 10s
From running the virtual machine on an AMD system.
2026-05-04 01:36:59 -04:00
ErrorNoInternet 3a5d5d27f4 nixos/networking: fix extraHosts generation 2026-05-04 01:31:27 -04:00
ErrorNoInternet 015bbc3d66 npins: update website 2026-05-04 01:31:27 -04:00
ErrorNoInternet dc374e8c04 nixos/hosts: declare fileSystems for testing hosts 2026-05-04 01:31:27 -04:00
ErrorNoInternet a708c04a9a nixos/services/openssh: enable X11 forwarding 2026-05-04 01:31:27 -04:00
javalsai a2534a3dab nixos/hosts: enable autologin for testing hosts 2026-05-04 01:31:15 -04:00
javalsai b78c41a5f7 nixos/services: add default website on nginx 2026-05-04 01:27:11 -04:00
javalsai e1f2dc3161 nixos/services: disable nginx proxy buffering 2026-05-04 01:27:11 -04:00
ErrorNoInternet f1c5f038ec nixos/impermanence: remove ssh host key persistence
The SSH host key files are already defined in the OpenSSH module, so
there is no need to persist them with impermanence.nix.
2026-05-04 01:27:10 -04:00
ErrorNoInternet ae0d4f5958 shells: remove neovim
Some users may be using self-contained Neovim executables.
2026-05-04 01:27:10 -04:00
ErrorNoInternet ded0374c57 agenix: import initial user dns keys 2026-05-04 01:27:10 -04:00
ErrorNoInternet ab0f9a2ff2 treewide: create global user list 2026-05-04 01:27:10 -04:00
javalsai fb9526fec2 docs: add sections and fix typos/errors 2026-05-04 00:45:22 -04:00
ErrorNoInternet 0692e680b8 treewide: initialize npins 2026-05-04 00:45:22 -04:00
ErrorNoInternet 3a940586d5 treewide: refactor code 2026-05-04 00:45:21 -04:00
javalsai 7e7097f457 nixos/security: add acme through dns challenge
few side refactors of this:
- no more `dns.domain`, it all must rely on `fqdn`, prevents
  inconsistencies.
- also added an specific host `tuxcord-acmetest` that uses the key zone
  for `nix.tuxcord.net` to test certificate pulling.
2026-05-04 00:45:21 -04:00
javalsai 22b3a95bf8 docs: document installation, secrets, and setup steps 2026-05-04 00:45:21 -04:00
javalsai de4b8833bd nixos/services: make dns configuration easier 2026-05-04 00:45:21 -04:00
javalsai ac9b80573f nixos/service: add dns (bind named server) 2026-05-04 00:45:21 -04:00
javalsai 66a15a5d19 nixos/programs: add bind utils 2026-05-04 00:45:21 -04:00
javalsai 7e331f5e1a nixos/services: add gitea server 2026-05-04 00:45:21 -04:00
javalsai a8374e231f nixos/services: add nginx base configuration 2026-05-04 00:45:21 -04:00
javalsai 27b861d5a5 nixos/networking: add own fqdn to extraHosts 2026-05-04 00:45:21 -04:00
javalsai 6a29ac005c nixos/hosts: add tuxcord-vm host configuration 2026-05-04 00:45:21 -04:00
ErrorNoInternet 0b9f76dcb4 nixos: separate openssh firewall port 2026-05-04 00:45:21 -04:00
javalsai cc52b0e6cb lib/ssh: add more ssh keys 2026-05-04 00:41:23 -04:00
javalsai d4d560c30f nixos/vm: enable qemu network bridge 2026-05-04 01:55:29 +02:00
40 changed files with 933 additions and 206 deletions
+20
View File
@@ -0,0 +1,20 @@
age-encryption.org/v1
-> ssh-ed25519 Wl2fDA 7PqbYWjorqzuPIDZgOZGIMzZa/P89aGzvORfMAeePRU
J+gesdnj8VwqJSfD1ohDTSp7nBXdM4nEEB5/7aA1PMc
-> ssh-ed25519 zNC8SA z47u0fUlGVYiQr4/S0lLh6WEj7gyedjWsq4fUk5Z1CY
6qR4zdA1gQqpAcm5Q5AZJgn3ZnafXL4OeHfU4WJae40
-> ssh-ed25519 EiAAKw 8mPi6HaHW+oFZHZ0Y2fJ2XISgarW3i/yLKD2QJleFGs
Mch7D28T9eiJm8hmSuI7Wm/rjjT+EzzER9vQ7T6rA3k
-> ssh-rsa eFi+Zw
d3mwAM+p4yz/UK5g4+0WyeOPyEVHQEyzGSB+pPDf6IIXxGbh613h1WD5j3AQQXdH
178Es9PhkiZcy0Y0IsQt4dyqDzuqMMwzLLvLKgsfliFsPBcdo93V5r9rWtFi3+9S
jAfhsFzVUj3KhuBY+xsgBtHpLe5CVV52NnEzXkoJw1wbdunNi62QZvyyC+0NixFV
HW1lxan6g6XXPrXWWrLbZWvpuqvPV6DoLsofzkMm0nd1DhkeHRU1WU8ucnPaETrJ
E5G3YrlfhftwRzp/QzeoSFREmdAJca7ycIJaJuG8QIszTZLOOQBUAxg7sonATGUc
Zutg1lJEfaQSe8oG1iMrJlshGspuSmBc1Ki4iQJjhQnYzvkV+Th9trG3QGq5ur9O
RYCxqjMMzbp6kR2GdJorSM7P5fpzt0sSv2mxd+nQpMoyvOVfbBjmEbiuWrKSlIl0
tXYrI6723mRNsbtmodUdDttaDFnr2r0MWbpHPn/K6y422GEoAiKE96Z7Pcxo2+Ml
--- ILGiZiEBKY+7nych4vWMVWgiFNhF3eP7mtCvJ/JImxM
jFÍ%aë;¸õlËÔ éYÊ×ö…›´töÐ:Â÷ì ®û¦#í õÞ(¹ðÂV°;ê[Ç`üØë:tžS#ˆ
@²ãÒk7²àFž¿ÓEn®†!ÉlÈ¥ÛšŽÃ7°!•Òï‡êY3:+mzÕÒÈö
@@ -0,0 +1,19 @@
age-encryption.org/v1
-> ssh-ed25519 Wl2fDA sLlStq5Hzb2JNQubLtMk5/kyIp81aTyjUB/Ysv1gRR0
lTLWsvT5Oxk8ut/g+o9o0DMOIQVDmi9o4EO0fYeIToo
-> ssh-ed25519 zNC8SA G0XcS2gzF0RopI2DqkWaTYXwjUpkVtdrxSQ+p8bfE0w
pZVIg/1P8BbnpRfV5F0FG3xgLSiA8M+nosQ8iNeYmcU
-> ssh-ed25519 EiAAKw qWmO0IjKoUFVxbxFUx36JIhME2PU7lkD+3agKO7+6nA
yEIw8IzQmM8C9dZoPajtvdUOF5kJ/C+rtgLczcmP1bs
-> ssh-rsa eFi+Zw
O5XRvS+Y/1mm9nQ7IZmxEp7RmFjAH0OTKPkRTME7BybnePPZLL0l6wMP26hx88Nv
dOqdaS07Xb26EIgCS/4xCY4sPWZNEfAfnDVoF4/SNbmfbN0XpNpR981AWcxiTL35
Fngk0lPa1NtuUH4S4zTda21kXHE0zv2mYLNMuek8dTrUd2piC+Z0WJJdrG1LK0hN
dDuLzX/mNibNXDvYxyD6mtkO2S1wO9QL88ucNZptT29vcaD48EZM/SsAwgf3OoqH
kd7jSTTdZ/yk8ccTMiT5eskQ3ZZcqc7JaF+M2d88DP6LcSaJnNzyVSEMAHHfpoY1
/kHxZ88/ehwPDXrp0bL448jdPuWqPSerzCWyyZFbc8Jj6zRUtC5joL0Vq2Rqs+EH
rmKMfi1l2+utleGYfCyHI5/czsMhJ2jXLGPguWQQdixNtb/RWFw6DeRP9xdO9QJR
LkoAFgv0ykP+L+C6sA7bpJqIGNftl4x8OUQxrKtf3YQ8K2LhUZb23JPn4Ob/QXo/
--- W7eUDhB/RBUYV1gaM4ktPEOVU6l5IRgOoRDpKKpvAnM
O\òŒMúOýJä ÍÅ!ÒHûËÄpK¥Õ:gßÙ[6™M¡VÞÃbYæÌí;è€F'¡#ä7&Žs1„ 󨱉6º²5_nÂ’Ô.¼qñ'à˜ƒq®6Êf-ÖÄW™w›½ß#5³¯6ˆ¼ŸêªrÒð„Ð#œÅÄ€=4EÎËlžÕÿ[
Binary file not shown.
@@ -0,0 +1,7 @@
age-encryption.org/v1
-> ssh-ed25519 Wl2fDA 3CWPYLgoTMGb9gBbDzZIQxYJ9Gfm49g6lqQyqlegUDQ
ryhsPP5+Byus2e5GSXDJlKYX1o3HfQ87CLRv2htU4n4
-> ssh-ed25519 EiAAKw B2uGdkeC3OZISN2iH2DR1J7L3/mbuFvebzqaTdAURCw
ze0X/MmHP78rRqAn0O3VBtnMJsiOXPk8RIe82tdQMeg
--- kLBxPuJdbPmJ1Lz3iBu8EPItdZtpNHIyV6pz1QzhcUY
ä3ÛÿÉèŸP>gòh@­ö•AZ’üz-í6R€¸zèÚ¢[ÇÝÍòã¿y?•ÉŽUSNÝ©&ú#}ÝR+o?.B¶&´5]ÇW€OΉPuh‹½ŽÞ=t¶5|¿×“s×€ú&!­‰Î-æTÝSÆfÕ™-j"#žwzºš›ãjö¯“HŒí
Binary file not shown.
Binary file not shown.
Binary file not shown.
+17 -31
View File
@@ -1,34 +1,20 @@
age-encryption.org/v1
-> ssh-ed25519 Wl2fDA dM0TgKtswZcbEV9tGGY26YCksV2xadHWXv7D/KksAWk
1vCcuHmVP2xiHd/7hh0z2Hiq/EeA8uvdsRtQReC5hNY
-> ssh-ed25519 zNC8SA uTO/3ePjgiKqk3jeRGZX5D3LjzhSBlp2rD2ZakKmfX0
tVkEEcP/KfD9x52l7iz5F3hKK0LSckjXWK5YP2aeBt4
-> ssh-ed25519 EiAAKw Etu0I4IzJ3BB2SzCeiexx+dhcLUO5d2Ws+WiJyLk/Sw
9GBcZPsIXO3mXbri3lFYjtBBu0wFYul6hKsCvBKVLFs
-> ssh-ed25519 Wl2fDA 8rfiRx7+Gr9BtiSXsVEs2W+pXoms6ynODC1TL90+Wi4
/uMnYMJovbaPjwX1qCAtIokov40RYIAm2Mup5XKBJvw
-> ssh-ed25519 zNC8SA FlxMK7kMYnKHY9MBJ+HYDI4GNS0nSgZxVuRe4yTWBgg
HPOV31k8Ueb1W5usG7iLXDQxyAlISrgHThddHpGY2+s
-> ssh-ed25519 EiAAKw Bu7+NJXivoRA07glNWUlBGu03J0ueth7XDU7SWQYT30
r/DBmf4TRDJBgFF0KdeHuKL5hLdU1z6HtfAAVbc6Y0I
-> ssh-rsa eFi+Zw
uOZsBC+IMHdX2h9Jq/CF/L3BsxDW+dULk04JQbDeM85Mrxxdrv2X3w7AW8YU2KS+
Xg8LnzH01z4Nfs89uysM/lsWptc9qMeaK9o0oHC+tSJH4Ch43MejbmFYjFibHaCm
krQM7dAGIJwc/o0+ykaCrbXSvXAyfd6Nw1izou2ZcDRI7mTipOZO8F949SIk//Rc
UJgPLqpGwScEfrHf4f6tySC4LmD0bPIV1xDpmmXcS7c83E9+iVOtb5Y1In6CQrF1
XZQCb9MkPySbuicwR022CySb+lc7Ru44RdqBgV1e+wphyZCoqCk09i18egV3hNs6
iEul3M8dqV27yRKrWIUD5jT2tUszTNJfreiuZl9eDmLkcVWExkWzqWPUFJ48hQiZ
89Z4Evn04vZGoeL67K5q93lSRHz109zT/KIJSQMZpbaecGAoiZDM8Mdq3KzawGSG
ENQazx6lnGoMccvxFhjrVqfYj3U4S/pnCow5fatvkBQSyysL63UxE5ivcFUHHppB
Nu4gAM/vbh0kpEUIaT4P6iTe9qFFM/9IVxiiKPYHdPnCmPJHrug1afLLFrrrpqkd
o1NrfYIM9gW6jl5QMCcP5DpzMTppokX0P1Tz1ZeOEtZUVtGeZ7Q2wmL4zftwmG9J
qoDjsCd0z6MPDUdU46qc7kjQBhOwGLfHXTfGLXGNZxqj0oLvEoEKpdvFNBvMSyxK
oGZRwGsHQcUXKhCPtf6PVtSkHMABzpUAhgS8oqjp4RVurD0lcrPgsx8pSRRarfyE
ll1QbFCjftuJfeIEshgRkaLGjIQpZDFA3w2XMqDddFz5H/9Ak+F8/rkNnUrN2x4M
amca8s4Sbls6RjyysarIytilCtpaKEI2sgkD2fERao6ayTSnWF45qqh635OLaP5A
b7qcru9gO0C3Ik+UuiZMgovxo/+yBYe3+8x8q/uKR4apPAkt/2q28Uilw1WboIEB
rIjBr0BN1JeHvkiyljJGcvGf5jHdmOrpQu/L1xuSDjsTnh+U6BshQC8bbkJNsVoL
-> ssh-ed25519 QovoLQ wgg0cFlYEVafE3rXK4GrID3RTatZdKPYzsjT18WskFM
bgv+7an3xgdqf6WaiB1FFkXObcykUnvH6lJmX5gFJkQ
-> ssh-rsa OFkEIg
IIQbFB6VUwbB+ZtKR7Ayg9Im6vMU1AzqHT8CBagA5fwJ7Vp1GuX1X9SxL9hMPkd3
4osEbSu3JJDMwfC6AfFtcEjmxjmRYyiYlzmIjhVEsaTlwyeucAPd+fdj+TPjHidZ
dffizNEOiENY49jlmWTjMqYKnBsSP9GfH4ZsKpCaWMm2h9p687weuXFfbYfjYMII
a3C4iG8m+mZ4crYTKZu6WPbnHn9g0pMxZBs4v6MnBHk6eEJ0uiJvrzYApoFE5om7
9AknL27ra/+A1UQl+1kzLT+IivJa8FCfZ+zF1RYLRvSATlIzCqCiBiayAsVtQg5O
girBRnlAJTPisszyoAhsqbECvD6bJfwlTW0STg/M1u3ZPMTGL4V0gJgynANmjb7Y
TXd11zuhjRYgOBAj09trQFTmmwIgPvvu8+VXNDNPAp02ffBT8kMUvSEik98/35x1
Dwvm38t05O6nqyHUF957CRVTzPQPAnb5Cd+Rw/joID2YPyFN9IZwE4mi2Bf3zdZo
roxtqCupmWkpxMNN7GZJrmCE/Lh6YV4DgUd6VNQc7QlGsq5K4XRT7aa+s+17cC8e
HCxQfGM8sMe9T6IK+K4p6qTqluyI/X0r95kGfzhNmgzufc44i6X497i3fDSVoLpx
Uo7Ao3QRNPyaUXcqTTIg8Kx9YiLQC3tDblVJjIZU89o
--- Vb9o/bhuN6XXjfK04haEEUXnuIA02j4GH9PmAh0ayN8
óE¬dGs;’ްÀ± ü
ñ,OHˆÿœˆ{²¶>ú*wAÃLÌÄ\©0SQöÖ*{6fô‰+Xš¨.
--- GCTLfa/BICL9AWTaqGC13M101Z8sqSqPP4ysJVv5zvg
]
ý­¢Ôÿi¹‡7c·f`b@%X”¿J )û[<+;x-ÇKmTõ@ãÌ„ýŸK]7sc*ë­Ÿ‡¼2Ý®5
+18 -7
View File
@@ -1,15 +1,26 @@
let
users = import ../lib/ssh/keys.nix;
inherit (import ../lib)
users
adminSSHKeys
attrsToList
getSSHKeys
;
tuxcord-ca = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPxiko5Csyq9UODglYzLBvRfxkhQu9GXP7SH2BpC8G/7";
in
{
"ntfy.age".publicKeys = [ tuxcord-ca ] ++ builtins.attrValues users;
"ntfy.age".publicKeys = [ tuxcord-ca ] ++ adminSSHKeys;
"authentik.age".publicKeys = [ tuxcord-ca ] ++ adminSSHKeys;
# tsig-keygen etc.sub.domain.tld.
"dns/tuxcord.net/tuxcord.net.key.age".publicKeys = [ tuxcord-ca ] ++ [ users.error users.javalsai ];
# "dns/tuxcord.net/XXX.tuxcord.net.key.age".publicKeys = [ tuxcord-ca ] ++ [ users.XXX ];
"dns/tuxcord.test/tuxcord.test.key.age".publicKeys = [ tuxcord-ca ] ++ builtins.attrValues users;
"dns/tuxcord.test/sub.tuxcord.test.key.age".publicKeys = [ tuxcord-ca ] ++ builtins.attrValues users;
"dns/tuxcord.net/tuxcord.net.key.age".publicKeys = [ tuxcord-ca ] ++ adminSSHKeys;
"dns/nix.tuxcord.net/nix.tuxcord.net.key.age".publicKeys = [ tuxcord-ca ] ++ adminSSHKeys;
"dns/tuxcord.test/tuxcord.test.key.age".publicKeys = [ tuxcord-ca ] ++ adminSSHKeys;
"dns/tuxcord.test/sub.tuxcord.test.key.age".publicKeys = [ tuxcord-ca ] ++ adminSSHKeys;
}
// builtins.listToAttrs (
map (user: {
name = "dns/tuxcord.net/${user.name}.tuxcord.net.key.age";
value.publicKeys = [ tuxcord-ca ] ++ getSSHKeys user.name;
}) (builtins.filter (user: user.value.ddns or false) (attrsToList users))
)
+7 -1
View File
@@ -16,13 +16,19 @@ To test the environment, you can launch a virtualized NixOS system derived from
nix run '.#nixosConfigurations.<system>.config.system.build.vm'
```
Here, `<system>` refers to the hostname of the system you want to test (e.g., tuxcord-ca).
Here, `<system>` refers to the hostname of the system you want to test (e.g., tuxcord-test).
Note that this will create a `qcow2` image file in the current directory. Nix will automatically manage changes to the configuration and update the image file accordingly while keeping part of its mutable state (e.g., root bash history).
> [!WARNING]
> Not all changes are applied automatically. Updates such as user passwords changes or modifications to the filesystem layout will require deleting the image file so that Nix can re-create it from scratch.
# Access
The initial password for the `root` account is `tuxcord`.
SSH login is enabled for the configured user keys, if using the VM test configuration, yo will have to use the bridged IP.
# Tooling
Tooling used to aid in development.
+1 -1
View File
@@ -42,7 +42,7 @@ Host specific configuration can be found at `nixos/hosts/tuxcord-XX`. This is us
To learn how to get started, refer to the [Getting Started guide](./GETTING_STARTED.md).
The guide contains basic instructions as to how to use Nix for this repository, as well as tools to help in certain tasks, some of this tools might be assumed accross document resources.
The guide contains basic instructions as to how to use Nix for this repository, as well as tools to help in certain tasks, some of this tools might be assumed across document resources.
It might also be useful to read the [installation section](#installation) to learn how to configure your testing environment.
+9 -3
View File
@@ -6,14 +6,20 @@ Secrets are managed with `agenix` in the `agenix/` directory. This allows to dec
The `agenix` help menu is already very helpful, but here you have a survival guide:
- `agenix` commands should run relative to the `agenix/` direcotry.
- `agenix` commands should run relative to the `agenix/` directory.
- `agenix -d` allows you to descrypt such file if you possess any of the decryption keys.
- `agenix -e` decrypts (if present) and opens the file in your editor to re-encrypt when exited.
- `agenix -r` re-encypts `*.age` files in the case you ever change its decryption keys.
# Secrets
<!-- TODO: missing ntfy.sh secret docs -->
There is a `ntfy.age` secret file which contents look like:
```sh
NTFY_TOPIC=readable-name_XXXXXXXXXX
```
This secret file is meant to be sources by shells before using [ntfy.sh](<https://ntfy.sh/>) to push important notifications. This topic could contain sensitive information and must be kept secret amongst administrators.
## DNS TSIG Keys
@@ -24,5 +30,5 @@ These keys can be generated using `tsig-keygen <key-name>` (historically they we
When DNS is enabled for a host, it will look for `dns/${fqdn}/${zone}.key` secrets.
- The key whose zone matches the `${fqdn}` will be allowed to tramit updates for all the domain.
- Keys restrained to a specific `${subdomain}` will only be allowed to edit records of such subdomain.
- Keys restrained to a specific `${zone}` will only be allowed to edit records of such zone.
- All keys must be named with the zone they affect, final dot included, so that (e.g. `tuxcord.net/javalsai.tuxcord.net.key` must be generated by `tsig-keygen javalsai.tuxcord.net.`).
+7 -1
View File
@@ -2,7 +2,13 @@
The first configuration of the server needs some configuration of its mutable state:
Setup also heavily relies on the secrets configured, make sure you [undestand agenix](./SECRETS.md) good enough.
Setup also heavily relies on the secrets configured, make sure you [understand agenix](./SECRETS.md) good enough.
# Root Password
The `root` password is `tuxcord` by default on all system configurations. For security, it's important to remember to change it as soon as an installation is done.
The root account is intended to be kept active in case there ever is the need to perform a TTY login. But this will be rare so do keep a security complex password saved somewhere and don't share it beyond the necessary amount.
# SSH Keys
Generated
+276 -12
View File
@@ -23,6 +23,67 @@
"type": "github"
}
},
"authentik-go": {
"flake": false,
"locked": {
"lastModified": 1771856219,
"narHash": "sha256-zTEmvxe+BpfWYvAl675PnhXCH4jV4GUTFb1MrQ1Eyno=",
"owner": "goauthentik",
"repo": "client-go",
"rev": "4c1444ee54d945fbcc5ae107b4f191ca0352023d",
"type": "github"
},
"original": {
"owner": "goauthentik",
"repo": "client-go",
"type": "github"
}
},
"authentik-nix": {
"inputs": {
"authentik-go": "authentik-go",
"authentik-src": "authentik-src",
"flake-compat": "flake-compat",
"flake-parts": "flake-parts",
"flake-utils": "flake-utils",
"napalm": "napalm",
"nixpkgs": "nixpkgs",
"pyproject-build-systems": "pyproject-build-systems",
"pyproject-nix": "pyproject-nix",
"systems": "systems_2",
"uv2nix": "uv2nix"
},
"locked": {
"lastModified": 1776085803,
"narHash": "sha256-JvvWVbXJYSY8qOReMbAOD4lxcN2cjKV6lg/jLz8CEuY=",
"owner": "nix-community",
"repo": "authentik-nix",
"rev": "4370b561c8bafb59773ce3a518506bcf1161dbdb",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "authentik-nix",
"type": "github"
}
},
"authentik-src": {
"flake": false,
"locked": {
"lastModified": 1775573258,
"narHash": "sha256-Xq7JGI/8ppIydIuWd9KRJKUrh7UpeniwvZ4NAtXbYJ4=",
"owner": "goauthentik",
"repo": "authentik",
"rev": "5249546862986202b901c2afd860992ec48c6ef6",
"type": "github"
},
"original": {
"owner": "goauthentik",
"ref": "version/2026.2.2",
"repo": "authentik",
"type": "github"
}
},
"darwin": {
"inputs": {
"nixpkgs": [
@@ -46,6 +107,7 @@
}
},
"flake-compat": {
"flake": false,
"locked": {
"lastModified": 1767039857,
"narHash": "sha256-vNpUSpF5Nuw8xvDLj2KCwwksIbjua2LZCqhV1LNRDns=",
@@ -61,6 +123,21 @@
}
},
"flake-compat_2": {
"locked": {
"lastModified": 1767039857,
"narHash": "sha256-vNpUSpF5Nuw8xvDLj2KCwwksIbjua2LZCqhV1LNRDns=",
"owner": "edolstra",
"repo": "flake-compat",
"rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab",
"type": "github"
},
"original": {
"owner": "edolstra",
"repo": "flake-compat",
"type": "github"
}
},
"flake-compat_3": {
"flake": false,
"locked": {
"lastModified": 1767039857,
@@ -80,6 +157,24 @@
"inputs": {
"nixpkgs-lib": "nixpkgs-lib"
},
"locked": {
"lastModified": 1769996383,
"narHash": "sha256-AnYjnFWgS49RlqX7LrC4uA+sCCDBj0Ry/WOJ5XWAsa0=",
"owner": "hercules-ci",
"repo": "flake-parts",
"rev": "57928607ea566b5db3ad13af0e57e921e6b12381",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "flake-parts",
"type": "github"
}
},
"flake-parts_2": {
"inputs": {
"nixpkgs-lib": "nixpkgs-lib_2"
},
"locked": {
"lastModified": 1777678872,
"narHash": "sha256-EPIFsulyon7Z1vLQq5Fk64GR8L7cQsT+IPhcsukVbgk=",
@@ -94,6 +189,27 @@
"type": "github"
}
},
"flake-utils": {
"inputs": {
"systems": [
"authentik-nix",
"systems"
]
},
"locked": {
"lastModified": 1731533236,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"git-hooks-nix": {
"inputs": {
"flake-compat": [
@@ -188,9 +304,35 @@
"type": "github"
}
},
"napalm": {
"inputs": {
"flake-utils": [
"authentik-nix",
"flake-utils"
],
"nixpkgs": [
"authentik-nix",
"nixpkgs"
]
},
"locked": {
"lastModified": 1725806412,
"narHash": "sha256-lGZjkjds0p924QEhm/r0BhAxbHBJE1xMOldB/HmQH04=",
"owner": "willibutz",
"repo": "napalm",
"rev": "b492440d9e64ae20736d3bec5c7715ffcbde83f5",
"type": "github"
},
"original": {
"owner": "willibutz",
"ref": "avoid-foldl-stack-overflow",
"repo": "napalm",
"type": "github"
}
},
"nix-alien": {
"inputs": {
"flake-compat": "flake-compat",
"flake-compat": "flake-compat_2",
"nix-index-database": [
"nix-index-database"
],
@@ -234,12 +376,12 @@
},
"nix-super": {
"inputs": {
"flake-compat": "flake-compat_2",
"flake-compat": "flake-compat_3",
"flake-parts": [
"flake-parts"
],
"git-hooks-nix": "git-hooks-nix",
"nixpkgs": "nixpkgs",
"nixpkgs": "nixpkgs_2",
"nixpkgs-23-11": "nixpkgs-23-11",
"nixpkgs-regression": "nixpkgs-regression"
},
@@ -259,15 +401,18 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1771903837,
"narHash": "sha256-jEA8WggGKtMFeNeCKq3NK8cLEjJmG6/RLUElYYbBZ0E=",
"rev": "e764fc9a405871f1f6ca3d1394fb422e0a0c3951",
"type": "tarball",
"url": "https://releases.nixos.org/nixos/25.11/nixos-25.11.6495.e764fc9a4058/nixexprs.tar.xz"
"lastModified": 1771848320,
"narHash": "sha256-0MAd+0mun3K/Ns8JATeHT1sX28faLII5hVLq0L3BdZU=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "2fc6539b481e1d2569f25f8799236694180c0993",
"type": "github"
},
"original": {
"type": "tarball",
"url": "https://channels.nixos.org/nixos-25.11/nixexprs.tar.xz"
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs-23-11": {
@@ -287,6 +432,21 @@
}
},
"nixpkgs-lib": {
"locked": {
"lastModified": 1769909678,
"narHash": "sha256-cBEymOf4/o3FD5AZnzC3J9hLbiZ+QDT/KDuyHXVJOpM=",
"owner": "nix-community",
"repo": "nixpkgs.lib",
"rev": "72716169fe93074c333e8d0173151350670b824c",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "nixpkgs.lib",
"type": "github"
}
},
"nixpkgs-lib_2": {
"locked": {
"lastModified": 1777168982,
"narHash": "sha256-GOkGPcboWE9BmGCRMLX3worL4EMnsnG8MyKmXNeYuhQ=",
@@ -318,6 +478,19 @@
}
},
"nixpkgs_2": {
"locked": {
"lastModified": 1771903837,
"narHash": "sha256-jEA8WggGKtMFeNeCKq3NK8cLEjJmG6/RLUElYYbBZ0E=",
"rev": "e764fc9a405871f1f6ca3d1394fb422e0a0c3951",
"type": "tarball",
"url": "https://releases.nixos.org/nixos/25.11/nixos-25.11.6495.e764fc9a4058/nixexprs.tar.xz"
},
"original": {
"type": "tarball",
"url": "https://channels.nixos.org/nixos-25.11/nixexprs.tar.xz"
}
},
"nixpkgs_3": {
"locked": {
"lastModified": 1777428379,
"narHash": "sha256-ypxFOeDz+CqADEQNL72haqGjvZQdBR5Vc7pyx2JDttI=",
@@ -333,15 +506,66 @@
"type": "github"
}
},
"pyproject-build-systems": {
"inputs": {
"nixpkgs": [
"authentik-nix",
"nixpkgs"
],
"pyproject-nix": [
"authentik-nix",
"pyproject-nix"
],
"uv2nix": [
"authentik-nix",
"uv2nix"
]
},
"locked": {
"lastModified": 1771423342,
"narHash": "sha256-7uXPiWB0YQ4HNaAqRvVndYL34FEp1ZTwVQHgZmyMtC8=",
"owner": "pyproject-nix",
"repo": "build-system-pkgs",
"rev": "04e9c186e01f0830dad3739088070e4c551191a4",
"type": "github"
},
"original": {
"owner": "pyproject-nix",
"repo": "build-system-pkgs",
"type": "github"
}
},
"pyproject-nix": {
"inputs": {
"nixpkgs": [
"authentik-nix",
"nixpkgs"
]
},
"locked": {
"lastModified": 1771518446,
"narHash": "sha256-nFJSfD89vWTu92KyuJWDoTQJuoDuddkJV3TlOl1cOic=",
"owner": "pyproject-nix",
"repo": "pyproject.nix",
"rev": "eb204c6b3335698dec6c7fc1da0ebc3c6df05937",
"type": "github"
},
"original": {
"owner": "pyproject-nix",
"repo": "pyproject.nix",
"type": "github"
}
},
"root": {
"inputs": {
"agenix": "agenix",
"flake-parts": "flake-parts",
"authentik-nix": "authentik-nix",
"flake-parts": "flake-parts_2",
"impermanence": "impermanence",
"nix-alien": "nix-alien",
"nix-index-database": "nix-index-database",
"nix-super": "nix-super",
"nixpkgs": "nixpkgs_2"
"nixpkgs": "nixpkgs_3"
}
},
"systems": {
@@ -358,6 +582,46 @@
"repo": "default",
"type": "github"
}
},
"systems_2": {
"locked": {
"lastModified": 1689347949,
"narHash": "sha256-12tWmuL2zgBgZkdoB6qXZsgJEH9LR3oUgpaQq2RbI80=",
"owner": "nix-systems",
"repo": "default-linux",
"rev": "31732fcf5e8fea42e59c2488ad31a0e651500f68",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default-linux",
"type": "github"
}
},
"uv2nix": {
"inputs": {
"nixpkgs": [
"authentik-nix",
"nixpkgs"
],
"pyproject-nix": [
"authentik-nix",
"pyproject-nix"
]
},
"locked": {
"lastModified": 1772187362,
"narHash": "sha256-gCojeIlQ/rfWMe3adif3akyHsT95wiMkLURpxTeqmPc=",
"owner": "pyproject-nix",
"repo": "uv2nix",
"rev": "abe65de114300de41614002fe9dce2152ac2ac23",
"type": "github"
},
"original": {
"owner": "pyproject-nix",
"repo": "uv2nix",
"type": "github"
}
}
},
"root": "root",
+12
View File
@@ -31,6 +31,13 @@
url = "github:privatevoid-net/nix-super";
inputs.flake-parts.follows = "flake-parts";
};
authentik-nix = {
url = "github:nix-community/authentik-nix";
# inputs.nixpkgs.follows = "nixpkgs"
# inputs.flake-parts.follows = "flake-parts"
};
};
outputs =
@@ -52,6 +59,11 @@
formatter = pkgs.nixfmt;
};
flake = {
lib = import ./lib;
pins = import ./npins;
};
systems = [
"x86_64-linux"
"aarch64-linux"
+24
View File
@@ -0,0 +1,24 @@
rec {
toList = x: if builtins.isList x then x else [ x ];
nameValuePair = name: value: { inherit name value; };
mapAttrsToList = f: attrs: builtins.attrValues (builtins.mapAttrs f attrs);
attrsToList = mapAttrsToList nameValuePair;
getSSHKeys =
username:
if (builtins.hasAttr "ssh" users.${username}) then
toList users.${username}.ssh
else
builtins.warn "user ${username} declared without ssh keys" [ ];
users = import ./users.nix;
adminSSHKeys = builtins.concatLists (
map (user: getSSHKeys user.name) (
builtins.filter (user: user.value.admin or false) (attrsToList users)
)
);
}
-8
View File
@@ -1,8 +0,0 @@
{
error = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDzdpxex2GlFVf5G2qsh3Ixa/XCMjnbq4JSTmAev7WYJ error.nointernet@gmail.com";
javalsai = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDFjavnLqxIzFLIUpUWDOwhlYeoII4Qk1/9e0yWWxD/P";
max = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDxVfJhzPDZ108UjB3Vj/akzlzYn27kyAw29AuYAr7gvG5vrqhLUYYmK8t+ZVWVpc1g6cK7OF1oUn2E5Qfmy6wqyZQXftAZ4OcRS0MB71W1bAcRq3rGe6KQDm8RSEeygX+zO+2Z6zQmVWgPr/I+JFQZ8wiWdP8X8djqTRdhqUD+SR3ZgTcnY3aLmeB/I56rcZQ3lKIeg/pEsyQ8weptlV0rTWamna6Z7Nw48VwWNSI+6EqfW2/4/edm0Ue8jMNqNZ0yx+kHJbudPgZgSR1SiR2rqlEEUaiQJQQV3VdY4DhGm7143ZSKUxyKlfTuQ7qR1zSIg6f5V71A37ik9YiSbBlOZO86swR4qHESoMNf608IuqRt2NdALHwozFPUCu16qnhu5JTk8twSAzrAhOk5zWQj1LYMoQEBhcFSmwir/1gE71NSjYtqXGVAdfkVmZ4uqG5+a1D7H3VXWOqu/j839M045O1ZBY6X3lKDsEJ1Z1+LCl/NojWnvPtJUHYI6+SdQ6k=";
vectorum = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCwfPaylCSN7ZqB6Trz8CmQlyzf0NUIy06uschdIOkdzjUNe/dPGbyEFZy/4SDBhg585x8hwfhfYjLGrneYq+O42DBDTDKxduWnIdl5zgPRqt7jB59jkukf9WUdpUdZsKCM5K97HCnizNEKGRnYllVPVQSapPhOm5dZlUD9YVv1UqbDuxtWOLvArkL52e9T+yL6FagRg6NPqA70MXPMk+S2H7lotFVxP2Eg//BCaQ0/H1vhNy6P4N6LLq3sVK1DSJyd2v8zHkdb2Zo0/Ygukol10KizSsEcihm8+bXp699uSgWIsaIQgDZlE1yx2iabmzQST1kL9+USnZZBZ+KxwtLCCI8mpCv6sxlhq2Zzim5HvsyMYM+zdHWIn1s2c6mEl4ntBAB4s5wAggS5Gjh/BfJLSvGsTFMC/XYX4gWFXynY5NlcopeENL2Afg4gbQvKkxYkWB/TMZWuqj5c5kCy+7F0881DpYxapq6kQ6IE4gkGiEQdhVFGWEFoV/k9iHrl6aanqvFtvuBHHgkXAGPpHAZDVZdp9lU0tqNQIM/eGINq4Or6wd9XDYyj5ezDEBxx1pPgweUDZrNe9+vKR+3AwbzB/XQPxTCcjd4d7Yx58jPLflFP1dDYT+3bvp+vA7UpHcJnISbVNu0SiSaIqLYhwDj1od5l6JDfRCqnMF1T59nRCQ==";
pickzelle = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPUYQUWoL8iGc+PSrRrHyNwcOcmgGwPvJAM9HRJkPqcW pixel@DOOM-Machine";
}
+26
View File
@@ -0,0 +1,26 @@
{
error = {
ssh = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDzdpxex2GlFVf5G2qsh3Ixa/XCMjnbq4JSTmAev7WYJ error.nointernet@gmail.com";
admin = true;
ddns = true;
};
javalsai = {
ssh = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDFjavnLqxIzFLIUpUWDOwhlYeoII4Qk1/9e0yWWxD/P";
admin = true;
ddns = true;
};
max = {
ssh = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDxVfJhzPDZ108UjB3Vj/akzlzYn27kyAw29AuYAr7gvG5vrqhLUYYmK8t+ZVWVpc1g6cK7OF1oUn2E5Qfmy6wqyZQXftAZ4OcRS0MB71W1bAcRq3rGe6KQDm8RSEeygX+zO+2Z6zQmVWgPr/I+JFQZ8wiWdP8X8djqTRdhqUD+SR3ZgTcnY3aLmeB/I56rcZQ3lKIeg/pEsyQ8weptlV0rTWamna6Z7Nw48VwWNSI+6EqfW2/4/edm0Ue8jMNqNZ0yx+kHJbudPgZgSR1SiR2rqlEEUaiQJQQV3VdY4DhGm7143ZSKUxyKlfTuQ7qR1zSIg6f5V71A37ik9YiSbBlOZO86swR4qHESoMNf608IuqRt2NdALHwozFPUCu16qnhu5JTk8twSAzrAhOk5zWQj1LYMoQEBhcFSmwir/1gE71NSjYtqXGVAdfkVmZ4uqG5+a1D7H3VXWOqu/j839M045O1ZBY6X3lKDsEJ1Z1+LCl/NojWnvPtJUHYI6+SdQ6k=";
admin = true;
};
vectorum = {
ssh = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCwfPaylCSN7ZqB6Trz8CmQlyzf0NUIy06uschdIOkdzjUNe/dPGbyEFZy/4SDBhg585x8hwfhfYjLGrneYq+O42DBDTDKxduWnIdl5zgPRqt7jB59jkukf9WUdpUdZsKCM5K97HCnizNEKGRnYllVPVQSapPhOm5dZlUD9YVv1UqbDuxtWOLvArkL52e9T+yL6FagRg6NPqA70MXPMk+S2H7lotFVxP2Eg//BCaQ0/H1vhNy6P4N6LLq3sVK1DSJyd2v8zHkdb2Zo0/Ygukol10KizSsEcihm8+bXp699uSgWIsaIQgDZlE1yx2iabmzQST1kL9+USnZZBZ+KxwtLCCI8mpCv6sxlhq2Zzim5HvsyMYM+zdHWIn1s2c6mEl4ntBAB4s5wAggS5Gjh/BfJLSvGsTFMC/XYX4gWFXynY5NlcopeENL2Afg4gbQvKkxYkWB/TMZWuqj5c5kCy+7F0881DpYxapq6kQ6IE4gkGiEQdhVFGWEFoV/k9iHrl6aanqvFtvuBHHgkXAGPpHAZDVZdp9lU0tqNQIM/eGINq4Or6wd9XDYyj5ezDEBxx1pPgweUDZrNe9+vKR+3AwbzB/XQPxTCcjd4d7Yx58jPLflFP1dDYT+3bvp+vA7UpHcJnISbVNu0SiSaIqLYhwDj1od5l6JDfRCqnMF1T59nRCQ==";
};
pickzelle = {
ssh = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPUYQUWoL8iGc+PSrRrHyNwcOcmgGwPvJAM9HRJkPqcW pixel@DOOM-Machine";
};
}
+11 -15
View File
@@ -18,6 +18,7 @@ in
agenix.nixosModules.default
impermanence.nixosModules.default
nix-index-database.nixosModules.nix-index
authentik-nix.nixosModules.default
./hardware.nix
./impermanence.nix
@@ -28,6 +29,8 @@ in
./vm.nix
];
age.secrets.ntfy.file = "${self}/agenix/ntfy.age";
nix = {
package = inputs'.nix-super.packages.default;
@@ -97,22 +100,15 @@ in
extraHosts =
let
subdomains = [
""
".git"
];
subdomains = [ "git" "auth" ];
inherit (config.networking) fqdn;
hosts = [ fqdn ] ++ map (sub: "${sub}.${fqdn}") subdomains;
in
builtins.foldl' (
hosts-acc: domain-prefix:
let
host = "${domain-prefix}${config.networking.fqdn}";
in
hosts-acc
+ ''
127.0.0.1 ${host}
::1 ${host}
''
) "" subdomains;
lib.concatMapStrings (host: ''
127.0.0.1 ${host}
::1 ${host}
'') hosts;
};
virtualisation.podman.enable = true;
+1
View File
@@ -33,5 +33,6 @@ in
tuxcord-ca = mkSystem "tuxcord-ca" "x86_64-linux";
tuxcord-test = mkSystem "tuxcord-test" "x86_64-linux";
tuxcord-acmetest = mkSystem "tuxcord-acmetest" "x86_64-linux";
};
}
+4 -1
View File
@@ -15,7 +15,10 @@
"xhci_pci"
];
kernelModules = [ "kvm-intel" ];
kernelModules = [
"kvm-amd"
"kvm-intel"
];
};
hardware = {
+14
View File
@@ -0,0 +1,14 @@
{
imports = [
./storage.nix
];
networking.fqdn = "nix.tuxcord.net";
acme.rfc2136.nameserver = "tuxcord.net";
dns.enable = true;
services.getty.autologinUser = "root";
time.timeZone = "Europe/Madrid";
}
+6
View File
@@ -0,0 +1,6 @@
{
fileSystems."/" = {
device = "/dev/vda";
fsType = "ext4";
};
}
+6
View File
@@ -4,7 +4,13 @@
./storage.nix
];
acme = {
enable = true;
useSelfDns = true;
};
dns.enable = true;
networking.fqdn = "tuxcord.net";
time.timeZone = "Canada/Eastern";
}
+1
View File
@@ -32,6 +32,7 @@
device = "/dev/xvda2";
fsType = "btrfs";
options = [ "subvol=@persist" ] ++ defaultOptions;
neededForBoot = true;
};
};
}
+9 -1
View File
@@ -1,4 +1,12 @@
{
dns.enable = true;
imports = [
./storage.nix
];
networking.fqdn = "tuxcord.test";
acme.enable = false;
dns.enable = true;
services.getty.autologinUser = "root";
}
+6
View File
@@ -0,0 +1,6 @@
{
fileSystems."/" = {
device = "/dev/vda";
fsType = "ext4";
};
}
-6
View File
@@ -55,8 +55,6 @@
};
};
fileSystems."/persist".neededForBoot = true;
environment.persistence."/persist" = {
enable = true;
hideMounts = true;
@@ -72,10 +70,6 @@
];
files = [
"/etc/machine-id"
"/etc/ssh/ssh_host_ed25519_key"
"/etc/ssh/ssh_host_ed25519_key.pub"
"/etc/ssh/ssh_host_rsa_key"
"/etc/ssh/ssh_host_rsa_key.pub"
];
};
+89
View File
@@ -0,0 +1,89 @@
{
config,
pkgs,
lib,
...
}:
let
cfg = config.acme;
inherit (lib)
mkIf
mkEnableOption
mkOption
types
;
inherit (config.networking) fqdn;
in
{
# we'll only support rfc2136 based challenges
options.acme = {
enable = mkEnableOption "" // {
default = true;
};
useSelfDns = mkOption {
default = false;
description = "Sets values of the self DNS if enabled, otherwise requires manual `rfc2136` nameserver and key values.";
};
rfc2136 = {
key = mkOption {
type = types.path;
default = config.age.secrets."dns/${fqdn}.key.age".path;
};
nameserver = mkOption {
type = types.str;
default = if cfg.useSelfDns then fqdn else null;
};
};
};
config = mkIf cfg.enable {
assertions = [
{
assertion = with cfg.rfc2136; nameserver != null && key != null;
message = "ACME needs rfc2136 parameters to work, consider using `useSelfDns` option.";
}
];
environment.persistence."/persist".directories = [
{
directory = "/var/lib/acme";
group = "acme";
user = "acme";
}
];
security.acme = {
acceptTerms = true;
defaults = {
email = "error@tuxcord.net";
reloadServices = [ "nginx" ];
postRun = ''
source ${config.age.secrets.ntfy.path}
${pkgs.ntfy-sh}/bin/ntfy publish -T recycle -t "${config.host.name}" "HTTPS certificate has been renewed"
'';
};
certs."${fqdn}" = {
dnsProvider = "rfc2136";
environmentFile =
with cfg.rfc2136;
builtins.toFile "dns-01-challenge.cfg" ''
RFC2136_NAMESERVER=${nameserver}
RFC2136_TSIG_FILE="${key}"
'';
extraDomainNames = [
"*.${fqdn}"
"${fqdn}"
];
inherit (config.services.nginx) group;
};
};
};
}
+17
View File
@@ -0,0 +1,17 @@
{ config, self, ... }:
let
inherit (config.networking) fqdn;
in
{
age.secrets.authentik.file = "${self}/agenix/authentik.age";
services.authentik = {
enable = true;
environmentFile = config.age.secrets.authentik.path; # just trust, this specifies port 3001
# nginx = {
# enable = true;
# enableACME = true;
# host = "auth.${fqdn}";
# };
};
}
+2
View File
@@ -1,5 +1,7 @@
{
imports = [
./acme.nix
./authentik.nix
./dns.nix
./fail2ban.nix
./gitea.nix
+34 -32
View File
@@ -1,6 +1,21 @@
{ config, lib, ... }:
{
config,
lib,
self,
...
}:
let
agenixDnsDir = ../../agenix/dns + "/${config.dns.domain}";
cfg = config.dns;
inherit (lib)
mkEnableOption
mkIf
strings
;
inherit (config.networking) fqdn;
agenixDnsDir = "${self}/agenix/dns/${fqdn}";
agenixKeys = builtins.attrNames (builtins.readDir agenixDnsDir);
keys = map (
@@ -10,35 +25,23 @@ let
subdomain = name: "subdomain ${name}";
zoneDomain =
if lib.strings.hasSuffix ".key.age" filename then
lib.strings.removeSuffix ".key.age" filename
if strings.hasSuffix ".key.age" filename then
strings.removeSuffix ".key.age" filename
else
throw "${filename} is not a `.key.age` file";
in
{
inherit (config.age.secrets."dns/${filename}") path;
name = zoneDomain;
path = config.age.secrets."dns/${filename}".path;
type = if zoneDomain == config.dns.domain then zonesub else subdomain;
type = if zoneDomain == fqdn then zonesub else subdomain;
}
) agenixKeys;
cfg = config.dns;
inherit (lib)
mkEnableOption
mkOption
mkIf
;
in
{
options.dns = {
enable = mkEnableOption "" // {
default = true;
};
domain = mkOption {
type = with lib.types; str;
default = config.networking.fqdn;
};
};
config = mkIf cfg.enable {
@@ -53,7 +56,8 @@ in
value = {
file = path;
group = "named";
owner = "named";
owner = if config.acme.enable then "acme" else "named";
mode = "440";
};
}
) agenixKeys
@@ -64,19 +68,17 @@ in
extraConfig = builtins.concatStringsSep "\n" (map (key: "include \"${key.path}\";") keys);
zones = {
"${config.dns.domain}" = {
# grant "tuxcord.net" zonesub ANY;
extraConfig = ''
update-policy {
${builtins.concatStringsSep "\n" (
map (key: "grant \"${key.name}\" ${key.type key.name} ANY;") keys
)}
};
'';
file = "/var/dns/${config.dns.domain}.zone"; # need to put default stuff
master = true;
};
zones."${fqdn}" = {
# grant "tuxcord.net" zonesub ANY;
extraConfig = ''
update-policy {
${builtins.concatStringsSep "\n" (
map (key: "grant \"${key.name}\" ${key.type key.name} ANY;") keys
)}
};
'';
file = "/var/dns/${fqdn}.zone"; # need to put default stuff
master = true;
};
};
+26 -13
View File
@@ -1,27 +1,40 @@
{ config, lib, ... }:
{ config, ... }:
let
inherit (config.networking) fqdn;
acmeEnabled = config.acme.enable;
in
{
services.gitea = {
enable = true;
appName = "Tuxcord's Gitea";
appName = "TuxCord Gitea";
database.type = "mysql";
lfs.enable = true;
settings.server.DOMAIN = config.networking.fqdn;
# settings.server.ROOT_URL = "https://git.tuxcord.net/"; ? would also depend on ssl status
settings.server.HTTP_PORT = 3000;
settings = {
server = {
DOMAIN = fqdn;
ROOT_URL = "${if acmeEnabled then "https" else "http"}://${fqdn}/";
HTTP_PORT = 3000;
};
settings.service.DISABLE_REGISTRATION = true;
settings.service.REQUIRE_SIGNIN_VIEW = false;
service = {
DISABLE_REGISTRATION = true;
REQUIRE_SIGNIN_VIEW = false;
};
settings.repository.ENABLE_PUSH_CREATE_USER = true;
settings.repository.ENABLE_PUSH_CREATE_ORG = true;
settings.repository.DEFAULT_BRANCH = "main";
repository = {
ENABLE_PUSH_CREATE_USER = true;
ENABLE_PUSH_CREATE_ORG = true;
DEFAULT_BRANCH = "main";
};
# settings.ui.DEFAULT_THEME = "...";
# ui.DEFAULT_THEME = "...";
# TODO: once we have email setup this would be nice
settings.mailer.ENABLED = true;
# TODO: once we have email setup this would be nice
mailer.ENABLED = true;
};
};
}
+43 -10
View File
@@ -1,17 +1,46 @@
{ config, ... }:
{ config, self, ... }:
let
inherit (config.networking) fqdn;
mkVhost =
attrs:
attrs: locations:
let
acmeEnabled = config.acme.enable;
in
{
forceSSL = false; # TODO: tweak per host
forceSSL = acmeEnabled;
useACMEHost = if acmeEnabled then fqdn else null;
locations = {
"= /robots.txt" = {
alias = disallowedRobotsTxt;
};
}
// locations;
}
// attrs;
mkProxy = port: {
proxyPass = "http://127.0.0.1:${toString port}/";
extraConfig = ''
proxy_buffering off;
proxy_request_buffering off;
'';
};
mkSsi = webRoot: {
root = webRoot;
extraConfig = ''
ssi on;
'';
};
disallowedRobotsTxt = builtins.toFile "robots.txt" ''
User-agent: *
Disallow: /
'';
in
{
services.nginx = {
@@ -23,14 +52,18 @@ in
recommendedGzipSettings = true;
recommendedOptimisation = true;
# services.nginx.virtualHosts."${fqdn}" = {
# addSSL = true;
# root = "/var/www/myhost.org";
# default = true;
# };
virtualHosts = {
"${fqdn}" = mkVhost { default = true; } {
"/" = mkSsi "${self.pins.website}/web-root";
};
virtualHosts."git.${fqdn}" = mkVhost {
locations."/" = mkProxy config.services.gitea.settings.server.HTTP_PORT;
"git.${fqdn}" = mkVhost { } {
"/" = mkProxy config.services.gitea.settings.server.HTTP_PORT;
};
"auth.${fqdn}" = mkVhost { } {
"/" = mkProxy 3001;
};
};
};
+1
View File
@@ -4,6 +4,7 @@
settings = {
ClientAliveInterval = 300;
X11Forwarding = true;
KbdInteractiveAuthentication = false;
PasswordAuthentication = false;
+37 -61
View File
@@ -1,25 +1,6 @@
{ lib, self, ... }:
let
users = [
{
name = "error";
options.admin = true;
}
{
name = "javalsai";
options.admin = true;
}
{
name = "max";
options.admin = true;
}
{
name = "vectorum";
}
{
name = "pickzelle";
}
];
inherit (self.lib) users;
adminGroups = [
"adm"
@@ -30,60 +11,55 @@ let
"wheel"
];
getSSHKeys =
username:
let
sshKeys = import "${self}/lib/ssh/keys.nix";
in
if (builtins.hasAttr username sshKeys) then
lib.lists.toList sshKeys.${username}
else
lib.warn "user ${username} declared without ssh key" [ ];
mkUser =
name: uid: options:
let
admin = options.admin or false;
in
{
users.users.${name} = {
isNormalUser = true;
extraGroups = lib.optionals admin adminGroups;
inherit uid;
openssh.authorizedKeys.keys = getSSHKeys name;
};
systemd.slices."user-${builtins.toString uid}".sliceConfig = {
CPUQuota = "50%";
CPUWeight = "10";
IOAccounting = true;
IOWeight = "10";
MemoryMax = "2G";
MemorySwapMax = "1G";
TasksMax = "100";
};
mkUser = name: uid: admin: {
users.users.${name} = {
inherit uid;
isNormalUser = true;
extraGroups = lib.optionals admin adminGroups;
openssh.authorizedKeys.keys = self.lib.getSSHKeys name;
};
systemd.slices."user-${builtins.toString uid}".sliceConfig = {
CPUQuota = "50%";
CPUWeight = "10";
IOAccounting = true;
IOWeight = "10";
MemoryMax = "2G";
MemorySwapMax = "1G";
TasksMax = "100";
};
};
in
lib.recursiveUpdate
(builtins.foldl'
(attrs: user: {
options = lib.recursiveUpdate attrs.options (mkUser user.name attrs.uid (user.options or { }));
options = lib.recursiveUpdate attrs.options (
mkUser user.name attrs.uid (user.value.admin or false)
);
uid = attrs.uid + 1;
})
{
options = { };
uid = 1000;
}
users
(lib.attrsToList users)
).options
{
users.users.root = {
initialPassword = "tuxcord";
users = {
motd = ''
__ __ __
---------/\ \__ /\ \ /\ \__
---------\ \ ,_\ __ __ __ _ ___ ___ _ __ \_\ \ ___ __\ \ ,_\
----------\ \ \/ /\ \/\ \/\ \/'\ /'___\ / __`\/\`'__\/'_` \ /'_ `\ /'__`\ \ \/
-----------\ \ \_\ \ \_\ \/> <//\ \__//\ \L\ \ \ \//\ \L\ \ __/\ \/\ \/\ __/\ \ \_
------------\ \__\\ \____//\_/\_\ \____\ \____/\ \_\\ \___,_\/\_\ \_\ \_\ \____\\ \__\
-------------\/__/ \/___/ \//\/_/\/____/\/___/ \/_/ \/__,_ /\/_/\/_/\/_/\/____/ \/__/
A friendly Linux community - est. July 2023
'';
openssh.authorizedKeys.keys = lib.lists.concatLists (
map (user: getSSHKeys user.name) (builtins.filter (user: user.options.admin or false) users)
);
users.root = {
initialPassword = "tuxcord";
openssh.authorizedKeys.keys = self.lib.adminSSHKeys;
};
};
}
+2 -2
View File
@@ -7,8 +7,8 @@
memorySize = 4096;
qemu.networkingOptions = lib.mkForce [
"-net nic,netdev=user.0,model=virtio"
"-netdev user,id=user.0,\${QEMU_NET_OPTS:+,$QEMU_NET_OPTS}"
"-nic bridge,br=virbr0,id=hn0,model=virt-net-pci,helper=\${QEMU_BRIDGE_HELPER_PATH}"
"-device virtio-net-pci,netdev=hn0,id=nic1,\${QEMU_NET_OPTS:+,$QEMU_NET_OPTS}"
];
};
}
+146
View File
@@ -0,0 +1,146 @@
/*
This file is provided under the MIT licence:
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the Software), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
# Generated by npins. Do not modify; will be overwritten regularly
let
data = builtins.fromJSON (builtins.readFile ./sources.json);
version = data.version;
# https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/lists.nix#L295
range =
first: last: if first > last then [ ] else builtins.genList (n: first + n) (last - first + 1);
# https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L257
stringToCharacters = s: map (p: builtins.substring p 1 s) (range 0 (builtins.stringLength s - 1));
# https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L269
stringAsChars = f: s: concatStrings (map f (stringToCharacters s));
concatMapStrings = f: list: concatStrings (map f list);
concatStrings = builtins.concatStringsSep "";
# If the environment variable NPINS_OVERRIDE_${name} is set, then use
# the path directly as opposed to the fetched source.
# (Taken from Niv for compatibility)
mayOverride =
name: path:
let
envVarName = "NPINS_OVERRIDE_${saneName}";
saneName = stringAsChars (c: if (builtins.match "[a-zA-Z0-9]" c) == null then "_" else c) name;
ersatz = builtins.getEnv envVarName;
in
if ersatz == "" then
path
else
# this turns the string into an actual Nix path (for both absolute and
# relative paths)
builtins.trace "Overriding path of \"${name}\" with \"${ersatz}\" due to set \"${envVarName}\"" (
if builtins.substring 0 1 ersatz == "/" then
/. + ersatz
else
/. + builtins.getEnv "PWD" + "/${ersatz}"
);
mkSource =
name: spec:
assert spec ? type;
let
path =
if spec.type == "Git" then
mkGitSource spec
else if spec.type == "GitRelease" then
mkGitSource spec
else if spec.type == "PyPi" then
mkPyPiSource spec
else if spec.type == "Channel" then
mkChannelSource spec
else if spec.type == "Tarball" then
mkTarballSource spec
else
builtins.throw "Unknown source type ${spec.type}";
in
spec // { outPath = mayOverride name path; };
mkGitSource =
{
repository,
revision,
url ? null,
submodules,
hash,
branch ? null,
...
}:
assert repository ? type;
# At the moment, either it is a plain git repository (which has an url), or it is a GitHub/GitLab repository
# In the latter case, there we will always be an url to the tarball
if url != null && !submodules then
builtins.fetchTarball {
inherit url;
sha256 = hash; # FIXME: check nix version & use SRI hashes
}
else
let
url =
if repository.type == "Git" then
repository.url
else if repository.type == "GitHub" then
"https://github.com/${repository.owner}/${repository.repo}.git"
else if repository.type == "GitLab" then
"${repository.server}/${repository.repo_path}.git"
else
throw "Unrecognized repository type ${repository.type}";
urlToName =
url: rev:
let
matched = builtins.match "^.*/([^/]*)(\\.git)?$" url;
short = builtins.substring 0 7 rev;
appendShort = if (builtins.match "[a-f0-9]*" rev) != null then "-${short}" else "";
in
"${if matched == null then "source" else builtins.head matched}${appendShort}";
name = urlToName url revision;
in
builtins.fetchGit {
rev = revision;
inherit name;
# hash = hash;
inherit url submodules;
};
mkPyPiSource =
{ url, hash, ... }:
builtins.fetchurl {
inherit url;
sha256 = hash;
};
mkChannelSource =
{ url, hash, ... }:
builtins.fetchTarball {
inherit url;
sha256 = hash;
};
mkTarballSource =
{
url,
locked_url ? url,
hash,
...
}:
builtins.fetchTarball {
url = locked_url;
sha256 = hash;
};
in
if version == 5 then
builtins.mapAttrs mkSource data.pins
else
throw "Unsupported format version ${toString version} in sources.json. Try running `npins upgrade`"
+17
View File
@@ -0,0 +1,17 @@
{
"pins": {
"website": {
"type": "Git",
"repository": {
"type": "Git",
"url": "https://git.javalsai.tuxcord.net/tuxcord/website.git"
},
"branch": "main",
"submodules": false,
"revision": "b18dd7b863644debb0a843a5b21bb490bfe7d048",
"url": null,
"hash": "18czfxaldy0zhjprdsqzxnzj3p9qlc4canwigr13iw2wisi4ww5y"
}
},
"version": 5
}
+18 -1
View File
@@ -5,6 +5,24 @@
{
devShells.default = pkgs.mkShell {
name = "configuration.nix";
shellHook = ''
for path in \
/usr/lib/qemu/qemu-bridge-helper \
/run/wrappers/bin/qemu-bridge-helper
do
if [ -x "$path" ]; then
export QEMU_BRIDGE_HELPER_PATH="$path"
break
fi
done
if [ -z "$QEMU_BRIDGE_HELPER_PATH" ]; then
printf "\033[1;33m%s\033[0m\n" \
"WARN: 'qemu-bridge-helper' not found, make sure it is installed and the nix shell hook is looking for it" >&2
fi
'';
packages = with pkgs; [
bat
cachix
@@ -13,7 +31,6 @@
git
inputs.agenix.packages.${stdenv.hostPlatform.system}.default
jujutsu
neovim
nix-output-monitor
nixfmt
npins