Kieran's opinionated (and probably slightly dumb) nix config
1{
2 inputs,
3 lib,
4 config,
5 pkgs,
6 ...
7}:
8{
9 imports = [
10 ./disk-config.nix
11 ./home-manager.nix
12
13 (inputs.import-tree ../../modules/nixos)
14 inputs.tangled.nixosModules.knot
15 inputs.tangled.nixosModules.spindle
16 ];
17
18 nixpkgs = {
19 hostPlatform = "aarch64-linux";
20 config = {
21 allowUnfree = true;
22 };
23 };
24
25 nix =
26 let
27 flakeInputs = lib.filterAttrs (_: lib.isType "flake") inputs;
28 in
29 {
30 settings = {
31 experimental-features = "nix-command flakes";
32 flake-registry = "";
33 nix-path = config.nix.nixPath;
34 trusted-users = [
35 "kierank"
36 ];
37 };
38 channel.enable = false;
39 optimise.automatic = true;
40 registry = lib.mapAttrs (_: flake: { inherit flake; }) flakeInputs;
41 nixPath = lib.mapAttrsToList (n: _: "${n}=flake:${n}") flakeInputs;
42 };
43
44 time.timeZone = "America/New_York";
45
46 environment.systemPackages = with pkgs; [
47 # core
48 coreutils
49 screen
50 bc
51 jq
52 psmisc
53 # cli_utils
54 direnv
55 zsh
56 gum
57 vim
58 # networking
59 xh
60 curl
61 wget
62 dogdns
63 inetutils
64 mosh
65 # nix_tools
66 inputs.nixvim.packages.aarch64-linux.default
67 nixd
68 nil
69 nixfmt-rfc-style
70 inputs.agenix.packages.aarch64-linux.default
71 # security
72 openssl
73 gpgme
74 gnupg
75 # dev_langs
76 nodejs_22
77 unstable.bun
78 python3
79 go
80 gopls
81 gotools
82 go-tools
83 gcc
84 # misc
85 neofetch
86 git
87 ];
88
89 programs.nh = {
90 enable = true;
91 clean.enable = true;
92 clean.extraArgs = "--keep-since 4d --keep 3";
93 flake = "/home/kierank/dots";
94 };
95
96 age.identityPaths = [
97 "/home/kierank/.ssh/id_rsa"
98 "/etc/ssh/id_rsa"
99 ];
100 age.secrets = {
101 wakatime = {
102 file = ../../secrets/wakatime.age;
103 path = "/home/kierank/.wakatime.cfg";
104 owner = "kierank";
105 };
106 cachet = {
107 file = ../../secrets/cachet.age;
108 owner = "cachet";
109 };
110 hn-alerts = {
111 file = ../../secrets/hn-alerts.age;
112 owner = "hn-alerts";
113 };
114 emojibot = {
115 file = ../../secrets/emojibot.age;
116 owner = "emojibot";
117 };
118 cloudflare = {
119 file = ../../secrets/cloudflare.age;
120 owner = "caddy";
121 };
122 github-knot-sync = {
123 file = ../../secrets/github-knot-sync.age;
124 owner = "git";
125 };
126 };
127
128 environment.sessionVariables = {
129 XDG_CACHE_HOME = "$HOME/.cache";
130 XDG_CONFIG_HOME = "$HOME/.config";
131 XDG_DATA_HOME = "$HOME/.local/share";
132 XDG_STATE_HOME = "$HOME/.local/state";
133 EDITOR = "nvim";
134 SYSTEMD_EDITOR = "nvim";
135 VISUAL = "nvim";
136 };
137
138 atelier = {
139 authentication.enable = true;
140 };
141
142 networking = {
143 hostName = "terebithia";
144 networkmanager.enable = true;
145 };
146
147 programs.zsh.enable = true;
148 programs.direnv.enable = true;
149
150 users.users = {
151 kierank = {
152 initialPassword = "changeme";
153 isNormalUser = true;
154 shell = pkgs.zsh;
155 openssh.authorizedKeys.keys = [
156 "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCzEEjvbL/ttqmYoDjxYQmDIq36BabROJoXgQKeh9liBxApwp+2PmgxROzTg42UrRc9pyrkq5kVfxG5hvkqCinhL1fMiowCSEs2L2/Cwi40g5ZU+QwdcwI8a4969kkI46PyB19RHkxg54OUORiIiso/WHGmqQsP+5wbV0+4riSnxwn/JXN4pmnE//stnyAyoiEZkPvBtwJjKb3Ni9n3eNLNs6gnaXrCtaygEZdebikr9kS2g9mM696HvIFgM6cdR/wZ7DcLbG3IdTXuHN7PC3xxL+Y4ek5iMreQIPmuvs4qslbthPGYoYbYLUQiRa9XO5s/ksIj5Z14f7anHE6cuTQVpvNWdGDOigyIVS5qU+4ZF7j+rifzOXVL48gmcAvw/uV68m5Wl/p0qsC/d8vI3GYwEsWG/EzpAlc07l8BU2LxWgN+d7uwBFaJV9VtmUDs5dcslsh8IbzmtC9gq3OLGjklxTfIl6qPiL8U33oc/UwqzvZUrI2BlbagvIZYy6rP+q0= kierank@mockingjay"
157 ];
158 extraGroups = [
159 "wheel"
160 "networkmanager"
161 "services"
162 ];
163 };
164 root.openssh.authorizedKeys.keys = [
165 "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCzEEjvbL/ttqmYoDjxYQmDIq36BabROJoXgQKeh9liBxApwp+2PmgxROzTg42UrRc9pyrkq5kVfxG5hvkqCinhL1fMiowCSEs2L2/Cwi40g5ZU+QwdcwI8a4969kkI46PyB19RHkxg54OUORiIiso/WHGmqQsP+5wbV0+4riSnxwn/JXN4pmnE//stnyAyoiEZkPvBtwJjKb3Ni9n3eNLNs6gnaXrCtaygEZdebikr9kS2g9mM696HvIFgM6cdR/wZ7DcLbG3IdTXuHN7PC3xxL+Y4ek5iMreQIPmuvs4qslbthPGYoYbYLUQiRa9XO5s/ksIj5Z14f7anHE6cuTQVpvNWdGDOigyIVS5qU+4ZF7j+rifzOXVL48gmcAvw/uV68m5Wl/p0qsC/d8vI3GYwEsWG/EzpAlc07l8BU2LxWgN+d7uwBFaJV9VtmUDs5dcslsh8IbzmtC9gq3OLGjklxTfIl6qPiL8U33oc/UwqzvZUrI2BlbagvIZYy6rP+q0= kierank@mockingjay"
166 ];
167 };
168
169 # Allow passwordless sudo for wheel group (needed for deploy-rs)
170 security.sudo.wheelNeedsPassword = false;
171
172 services.openssh = {
173 enable = true;
174 openFirewall = true;
175 settings = {
176 PermitRootLogin = "no";
177 PasswordAuthentication = false;
178 };
179 };
180
181 networking.firewall = {
182 enable = true;
183 allowedTCPPorts = [
184 22
185 80
186 443
187 ];
188 logRefusedConnections = false;
189 rejectPackets = true;
190 };
191
192 services.tailscale = {
193 enable = true;
194 useRoutingFeatures = "client";
195 };
196
197 services.caddy = {
198 enable = true;
199 package = pkgs.caddy.withPlugins {
200 plugins = [ "github.com/caddy-dns/cloudflare@v0.2.2" ];
201 hash = "sha256-ea8PC/+SlPRdEVVF/I3c1CBprlVp1nrumKM5cMwJJ3U=";
202 };
203 email = "me@dunkirk.sh";
204 globalConfig = ''
205 acme_dns cloudflare {env.CLOUDFLARE_API_TOKEN}
206 '';
207 virtualHosts."knot.dunkirk.sh" = {
208 extraConfig = ''
209 tls {
210 dns cloudflare {env.CLOUDFLARE_API_TOKEN}
211 }
212 header {
213 Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
214 }
215 reverse_proxy localhost:5555 {
216 header_up X-Forwarded-Proto {scheme}
217 header_up X-Forwarded-For {remote}
218 }
219 '';
220 };
221 virtualHosts."spindle.dunkirk.sh" = {
222 extraConfig = ''
223 tls {
224 dns cloudflare {env.CLOUDFLARE_API_TOKEN}
225 }
226 header {
227 Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
228 }
229 reverse_proxy localhost:6555 {
230 header_up X-Forwarded-Proto {scheme}
231 header_up X-Forwarded-For {remote}
232 }
233 '';
234 };
235 virtualHosts."emojibot.dunkirk.sh" = {
236 extraConfig = ''
237 tls {
238 dns cloudflare {env.CLOUDFLARE_API_TOKEN}
239 }
240 header {
241 Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
242 }
243 reverse_proxy localhost:3002 {
244 header_up X-Forwarded-Proto {scheme}
245 header_up X-Forwarded-For {remote}
246 }
247 '';
248 };
249 extraConfig = ''
250 # Default response for unhandled domains
251 :80 {
252 respond "404 - Looks like this bridge doesn't have an end" 404
253 }
254 :443 {
255 respond "404 - Looks like this bridge doesn't have an end" 404
256 }
257 '';
258 };
259
260 systemd.services.caddy.serviceConfig = {
261 EnvironmentFile = config.age.secrets.cloudflare.path;
262 };
263
264 atelier.services.cachet = {
265 enable = true;
266 domain = "cachet.dunkirk.sh";
267 secretsFile = config.age.secrets.cachet.path;
268 };
269
270 atelier.services.hn-alerts = {
271 enable = true;
272 domain = "hn.dunkirk.sh";
273 secretsFile = config.age.secrets.hn-alerts.path;
274 };
275
276 atelier.services.emojibot = {
277 enable = true;
278 domain = "emojibot.dunkirk.sh";
279 secretsFile = config.age.secrets.emojibot.path;
280 };
281
282 services.tangled.knot = {
283 enable = true;
284 package = inputs.tangled.packages.aarch64-linux.knot;
285 appviewEndpoint = "https://tangled.org";
286 server = {
287 owner = "did:plc:krxbvxvis5skq7jj6eot23ul";
288 hostname = "knot.dunkirk.sh";
289 listenAddr = "127.0.0.1:5555";
290 };
291 };
292
293 services.tangled.spindle = {
294 enable = true;
295 package = inputs.tangled.packages.aarch64-linux.spindle;
296 server = {
297 owner = "did:plc:krxbvxvis5skq7jj6eot23ul";
298 hostname = "spindle.dunkirk.sh";
299 listenAddr = "127.0.0.1:6555";
300 };
301 };
302
303 atelier.services.knot-sync = {
304 enable = true;
305 secretsFile = config.age.secrets.github-knot-sync.path;
306 };
307
308 services.n8n = {
309 enable = true;
310 environment = {
311 N8N_HOST = "n8n.dunkirk.sh";
312 N8N_PROTOCOL = "https";
313 WEBHOOK_URL = "https://n8n.dunkirk.sh";
314 };
315 };
316
317 services.caddy.virtualHosts."n8n.dunkirk.sh" = {
318 extraConfig = ''
319 tls {
320 dns cloudflare {env.CLOUDFLARE_API_TOKEN}
321 }
322 header {
323 Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
324 }
325 reverse_proxy localhost:5678 {
326 header_up X-Forwarded-Proto {scheme}
327 header_up X-Forwarded-For {remote}
328 }
329 '';
330 };
331
332 boot.loader.systemd-boot.enable = true;
333 boot.loader.efi.canTouchEfiVariables = true;
334 boot.kernelParams = [ "console=ttyS0" ];
335
336 system.stateVersion = "23.05";
337}