yep, more dotfiles
1{ self
2, config
3, pkgs
4, ...
5}:
6
7let
8 inherit (self.inputs) srvos hypixel-bank-tracker tangled;
9
10 json-format = pkgs.formats.json { };
11
12 ext-if = "eth0";
13 external-ip = "91.99.55.74";
14 external-netmask = 27;
15 external-gw = "144.x.x.255";
16 external-ip6 = "2a01:4f8:c2c:76d2::1";
17 external-netmask6 = 64;
18 external-gw6 = "fe80::1";
19
20 well-known-discord-dir = pkgs.writeTextDir ".well-known/discord" ''
21 dh=919234284ceb2aba439d15b9136073eb2308989b
22 '';
23 webfinger-dir = pkgs.writeTextDir ".well-known/webfinger" ''
24 {
25 "subject": "acct:milo@wiro.world",
26 "aliases": [
27 "mailto:milo@wiro.world",
28 "https://wiro.world/"
29 ],
30 "links": [
31 {
32 "rel": "http://wiro.world/rel/avatar",
33 "href": "https://wiro.world/logo.jpg",
34 "type": "image/jpeg"
35 },
36 {
37 "rel": "http://webfinger.net/rel/profile-page",
38 "href": "https://wiro.world/",
39 "type": "text/html"
40 },
41 {
42 "rel": "http://openid.net/specs/connect/1.0/issuer",
43 "href": "https://auth.wiro.world"
44 }
45 ]
46 }
47 '';
48
49 website-hostname = "wiro.world";
50
51 pds-port = 3001;
52 pds-hostname = "pds.wiro.world";
53
54 grafana-port = 3002;
55 grafana-hostname = "console.wiro.world";
56
57 tangled-owner = "did:plc:xhgrjm4mcx3p5h3y6eino6ti";
58 tangled-knot-port = 3003;
59 tangled-knot-hostname = "knot.wiro.world";
60 tangled-spindle-port = 3004;
61 tangled-spindle-hostname = "spindle.wiro.world";
62
63 thelounge-port = 3005;
64 thelounge-hostname = "lounge.wiro.world";
65
66 headscale-port = 3006;
67 headscale-derp-port = 3478;
68 headscale-hostname = "headscale.wiro.world";
69
70 lldap-port = 3007;
71 lldap-hostname = "ldap.wiro.world";
72
73 authelia-port = 3008;
74 authelia-hostname = "auth.wiro.world";
75
76 matrix-port = 3009;
77 matrix-hostname = "matrix.wiro.world";
78
79 goatcounter-port = 3010;
80 goatcounter-hostname = "stats.wiro.world";
81
82 vaultwarden-port = 3011;
83 vaultwarden-hostname = "vault.wiro.world";
84
85 miniflux-port = 3012;
86 miniflux-hostname = "news.wiro.world";
87
88 static-hostname = "static.wiro.world";
89
90 hbt-main-port = 3013;
91 hbt-banana-port = 3014;
92
93 warrior-port = 3015;
94 warrior-hostname = "warrior.wiro.world";
95
96 prometheus-port = 9001;
97 prometheus-node-exporter-port = 9002;
98 headscale-metrics-port = 9003;
99 authelia-metrics-port = 9004;
100in
101{
102 imports = [
103 srvos.nixosModules.server
104 srvos.nixosModules.hardware-hetzner-cloud
105 srvos.nixosModules.mixins-terminfo
106
107 hypixel-bank-tracker.nixosModules.default
108
109 tangled.nixosModules.knot
110 tangled.nixosModules.spindle
111 ];
112
113 config = {
114 boot.loader.grub.enable = true;
115 boot.initrd.availableKernelModules = [ "ahci" "xhci_pci" "virtio_pci" "virtio_scsi" "sd_mod" "sr_mod" "ext4" ];
116
117 # Single network card is `eth0`
118 networking.usePredictableInterfaceNames = false;
119
120 networking.nameservers = [ "2001:4860:4860::8888" "2001:4860:4860::8844" ];
121
122 networking = {
123 interfaces.${ext-if} = {
124 ipv4.addresses = [{ address = external-ip; prefixLength = external-netmask; }];
125 ipv6.addresses = [{ address = external-ip6; prefixLength = external-netmask6; }];
126 };
127 defaultGateway = { interface = ext-if; address = external-gw; };
128 defaultGateway6 = { interface = ext-if; address = external-gw6; };
129
130 # Reflect firewall configuration on Hetzner
131 firewall.allowedTCPPorts = [ 22 80 443 ];
132 firewall.allowedUDPPorts = [ headscale-derp-port ];
133 };
134
135 services.qemuGuest.enable = true;
136
137 services.openssh.enable = true;
138
139 services.tailscale.enable = true;
140
141 security.sudo.wheelNeedsPassword = false;
142
143 local.fragment.nix.enable = true;
144
145 programs.fish.enable = true;
146
147 services.fail2ban = {
148 enable = true;
149
150 maxretry = 5;
151 ignoreIP = [ ];
152
153 bantime = "24h";
154 bantime-increment = {
155 enable = true;
156 multipliers = "1 2 4 8 16 32 64";
157 maxtime = "168h";
158 overalljails = true;
159 };
160
161 jails = { };
162 };
163
164 services.caddy = {
165 enable = true;
166
167 globalConfig = ''
168 metrics { per_host }
169
170 on_demand_tls {
171 ask http://localhost:${toString pds-port}/tls-check
172 }
173 '';
174
175 virtualHosts.${website-hostname}.extraConfig =
176 ''
177 @discord {
178 path /.well-known/discord
179 method GET HEAD
180 }
181 route @discord {
182 header {
183 Access-Control-Allow-Origin "*"
184 X-Robots-Tag "noindex"
185 }
186 root ${well-known-discord-dir}
187 file_server
188 }
189 '' +
190 ''
191 @webfinger {
192 path /.well-known/webfinger
193 method GET HEAD
194 query resource=acct:milo@wiro.world
195 query resource=mailto:milo@wiro.world
196 query resource=https://wiro.world
197 query resource=https://wiro.world/
198 }
199 route @webfinger {
200 header {
201 Content-Type "application/jrd+json"
202 Access-Control-Allow-Origin "*"
203 X-Robots-Tag "noindex"
204 }
205 root ${webfinger-dir}
206 file_server
207 }
208 '' +
209 ''
210 reverse_proxy /.well-known/matrix/* http://localhost:${toString matrix-port}
211 '' +
212 # TODO: host website on server with automatic deployment
213 ''
214 reverse_proxy https://mrnossiom.github.io {
215 header_up Host {http.request.host}
216 }
217 '';
218
219 virtualHosts.${grafana-hostname}.extraConfig = ''
220 reverse_proxy http://localhost:${toString grafana-port}
221 '';
222
223 virtualHosts.${pds-hostname} = {
224 serverAliases = [ "*.${pds-hostname}" ];
225 extraConfig = ''
226 tls { on_demand }
227 reverse_proxy http://localhost:${toString pds-port}
228 '';
229 };
230
231 virtualHosts.${tangled-knot-hostname}.extraConfig = ''
232 reverse_proxy http://localhost:${toString tangled-knot-port}
233 '';
234
235 virtualHosts.${tangled-spindle-hostname}.extraConfig = ''
236 reverse_proxy http://localhost:${toString tangled-spindle-port}
237 '';
238
239 virtualHosts.${thelounge-hostname}.extraConfig = ''
240 reverse_proxy http://localhost:${toString thelounge-port}
241 '';
242
243 virtualHosts.${headscale-hostname}.extraConfig = ''
244 reverse_proxy http://localhost:${toString headscale-port}
245 '';
246
247 virtualHosts.${lldap-hostname}.extraConfig = ''
248 reverse_proxy http://localhost:${toString lldap-port}
249 '';
250
251 virtualHosts.${authelia-hostname}.extraConfig = ''
252 reverse_proxy http://localhost:${toString authelia-port}
253 '';
254
255 virtualHosts.${matrix-hostname}.extraConfig = ''
256 reverse_proxy /_matrix/* http://localhost:${toString matrix-port}
257 '';
258
259 virtualHosts.${goatcounter-hostname}.extraConfig = ''
260 reverse_proxy http://localhost:${toString goatcounter-port}
261 '';
262
263 virtualHosts.${vaultwarden-hostname}.extraConfig = ''
264 reverse_proxy http://localhost:${toString vaultwarden-port}
265 '';
266
267 virtualHosts.${miniflux-hostname}.extraConfig = ''
268 reverse_proxy http://localhost:${toString miniflux-port}
269 '';
270
271 virtualHosts.${static-hostname}.extraConfig = ''
272 root /var/www/static
273 file_server browse
274 '';
275
276 virtualHosts."hypixel-bank-tracker.xyz".extraConfig = ''
277 reverse_proxy http://localhost:${toString hbt-main-port}
278 '';
279 virtualHosts."banana.hypixel-bank-tracker.xyz".extraConfig = ''
280 reverse_proxy http://localhost:${toString hbt-banana-port}
281 '';
282
283 virtualHosts.${warrior-hostname}.extraConfig = ''
284 forward_auth localhost:${toString authelia-port} {
285 uri /api/authz/forward-auth
286 }
287 reverse_proxy http://localhost:${toString warrior-port}
288 '';
289 };
290
291 age.secrets.pds-env.file = ../../secrets/pds-env.age;
292 services.bluesky-pds = {
293 enable = true;
294
295 settings = {
296 PDS_HOSTNAME = "pds.wiro.world";
297 PDS_PORT = pds-port;
298 # is in systemd /tmp subfolder
299 LOG_DESTINATION = "/tmp/pds.log";
300 };
301
302 environmentFiles = [
303 config.age.secrets.pds-env.path
304 ];
305 };
306
307 services.tangled.knot = {
308 enable = true;
309 openFirewall = true;
310
311 motd = "Welcome to @wiro.world's knot!\n";
312 server = {
313 listenAddr = "localhost:${toString tangled-knot-port}";
314 hostname = tangled-knot-hostname;
315 owner = tangled-owner;
316 };
317 };
318
319 services.tangled.spindle = {
320 enable = true;
321
322 server = {
323 listenAddr = "localhost:${toString tangled-spindle-port}";
324 hostname = tangled-spindle-hostname;
325 owner = tangled-owner;
326 };
327 };
328
329 age.secrets.grafana-oidc-secret = { file = ../../secrets/grafana-oidc-secret.age; owner = "grafana"; };
330 services.grafana = {
331 enable = true;
332
333 settings = {
334 server = {
335 http_port = grafana-port;
336 domain = grafana-hostname;
337 root_url = "https://${grafana-hostname}";
338 };
339
340 "auth.generic_oauth" = {
341 enable = true;
342 name = "Authelia";
343 icon = "signin";
344
345 client_id = "grafana";
346 client_secret_path = config.age.secrets.grafana-oidc-secret.path;
347 auto_login = true;
348
349 scopes = [ "openid" "profile" "email" "groups" ];
350 auth_url = "https://auth.wiro.world/api/oidc/authorization";
351 token_url = "https://auth.wiro.world/api/oidc/token";
352 api_url = "https://auth.wiro.world/api/oidc/userinfo";
353 use_pkce = true;
354 };
355 };
356 };
357
358 services.prometheus = {
359 enable = true;
360 port = prometheus-port;
361
362 scrapeConfigs = [
363 {
364 job_name = "caddy";
365 static_configs = [{ targets = [ "localhost:${toString 2019}" ]; }];
366 }
367 {
368 job_name = "node-exporter";
369 static_configs = [{ targets = [ "localhost:${toString config.services.prometheus.exporters.node.port}" ]; }];
370 }
371 {
372 job_name = "headscale";
373 static_configs = [{ targets = [ "localhost:${toString headscale-metrics-port}" ]; }];
374 }
375 {
376 job_name = "authelia";
377 static_configs = [{ targets = [ "localhost:${toString authelia-metrics-port}" ]; }];
378 }
379 {
380 job_name = "miniflux";
381 static_configs = [{ targets = [ "localhost:${toString miniflux-port}" ]; }];
382 }
383 ];
384
385 exporters.node = {
386 enable = true;
387 port = prometheus-node-exporter-port;
388 };
389 };
390
391 services.thelounge = {
392 enable = true;
393 port = thelounge-port;
394 public = false;
395
396 extraConfig = {
397 host = "127.0.0.1";
398 reverseProxy = true;
399
400 # TODO: use ldap, find a way to hide password
401 };
402 };
403
404 age.secrets.headscale-oidc-secret = { file = ../../secrets/headscale-oidc-secret.age; owner = config.services.headscale.user; };
405 # TODO: add dependency on authelia
406 services.headscale = {
407 enable = true;
408
409 port = headscale-port;
410 settings = {
411 server_url = "https://${headscale-hostname}";
412 metrics_listen_addr = "127.0.0.1:${toString headscale-metrics-port}";
413
414 policy.path = json-format.generate "policy.json" {
415 acls = [
416 {
417 action = "accept";
418 src = [ "autogroup:member" ];
419 dst = [ "autogroup:self:*" ];
420 }
421 ];
422 ssh = [
423 {
424 action = "accept";
425 src = [ "autogroup:member" ];
426 dst = [ "autogroup:self" ];
427 # Adding root here is privilege escalation as a feature :)
428 users = [ "autogroup:nonroot" ];
429 }
430 ];
431 };
432
433 # disable TLS
434 tls_cert_path = null;
435 tls_key_path = null;
436
437 dns = {
438 magic_dns = true;
439 base_domain = "net.wiro.world";
440
441 override_local_dns = true;
442 # Quad9 nameservers
443 nameservers.global = [ "9.9.9.9" "149.112.112.112" "2620:fe::fe" "2620:fe::9" ];
444 };
445
446 oidc = {
447 only_start_if_oidc_is_available = true;
448 issuer = "https://auth.wiro.world";
449 client_id = "headscale";
450 client_secret_path = config.age.secrets.headscale-oidc-secret.path;
451 scope = [ "openid" "profile" "email" "groups" ];
452 pkce.enabled = true;
453 };
454
455 derp.server = {
456 enable = true;
457 stun_listen_addr = "0.0.0.0:${toString headscale-derp-port}";
458 };
459 };
460 };
461
462 age.secrets.lldap-env.file = ../../secrets/lldap-env.age;
463 users.users.lldap = { isSystemUser = true; group = "lldap"; };
464 users.groups.lldap = { };
465 age.secrets.lldap-user-pass = { file = ../../secrets/lldap-user-pass.age; owner = "lldap"; };
466 services.lldap = {
467 enable = true;
468 settings = {
469 http_url = "https://${lldap-hostname}";
470 http_port = lldap-port;
471
472 ldap_user_pass_file = config.age.secrets.lldap-user-pass.path;
473 force_ldap_user_pass_reset = false;
474
475 ldap_base_dn = "dc=wiro,dc=world";
476 };
477 environmentFile = config.age.secrets.lldap-env.path;
478 };
479
480 age.secrets.authelia-jwt-secret = { file = ../../secrets/authelia-jwt-secret.age; owner = config.services.authelia.instances.main.user; };
481 age.secrets.authelia-issuer-private-key = { file = ../../secrets/authelia-issuer-private-key.age; owner = config.services.authelia.instances.main.user; };
482 age.secrets.authelia-storage-key = { file = ../../secrets/authelia-storage-key.age; owner = config.services.authelia.instances.main.user; };
483 age.secrets.authelia-ldap-password = { file = ../../secrets/authelia-ldap-password.age; owner = config.services.authelia.instances.main.user; };
484 age.secrets.authelia-smtp-password = { file = ../../secrets/authelia-smtp-password.age; owner = config.services.authelia.instances.main.user; };
485 services.authelia.instances.main = {
486 enable = true;
487
488 secrets = {
489 jwtSecretFile = config.age.secrets.authelia-jwt-secret.path;
490 oidcIssuerPrivateKeyFile = config.age.secrets.authelia-issuer-private-key.path;
491 storageEncryptionKeyFile = config.age.secrets.authelia-storage-key.path;
492 };
493 environmentVariables = {
494 AUTHELIA_AUTHENTICATION_BACKEND_LDAP_PASSWORD_FILE = config.age.secrets.authelia-ldap-password.path;
495 AUTHELIA_NOTIFIER_SMTP_PASSWORD_FILE = config.age.secrets.authelia-smtp-password.path;
496 };
497 settings = {
498 server.address = "localhost:${toString authelia-port}";
499 storage.local.path = "/var/lib/authelia-main/db.sqlite3";
500 telemetry.metrics = {
501 enabled = true;
502 address = "tcp://:${toString authelia-metrics-port}/metrics";
503 };
504
505 session = {
506 cookies = [{
507 domain = "wiro.world";
508 authelia_url = "https://${authelia-hostname}";
509 default_redirection_url = "https://wiro.world";
510 }];
511 };
512
513 authentication_backend.ldap = {
514 address = "ldap://localhost:3890";
515 timeout = "5m"; # replace with systemd dependency
516
517 user = "uid=authelia,ou=people,dc=wiro,dc=world";
518 # Set in `AUTHELIA_AUTHENTICATION_BACKEND_LDAP_PASSWORD_FILE`.
519 # password = "";
520
521 base_dn = "dc=wiro,dc=world";
522 users_filter = "(&(|({username_attribute}={input})({mail_attribute}={input}))(objectClass=person))";
523 additional_users_dn = "ou=people";
524 groups_filter = "(&(member={dn})(objectClass=groupOfNames))";
525 additional_groups_dn = "ou=groups";
526
527 attributes = {
528 username = "uid";
529 display_name = "cn";
530 given_name = "givenname";
531 family_name = "last_name";
532 mail = "mail";
533 picture = "avatar";
534
535 group_name = "cn";
536 };
537 };
538
539 access_control = {
540 default_policy = "deny";
541 # Rules are sequential and do not apply to OIDC
542 rules = [
543 {
544 domain = "headscale.wiro.world";
545 policy = "two_factor";
546
547 }
548 {
549 domain = "news.wiro.world";
550 policy = "one_factor";
551
552 subject = [ [ "group:miniflux" "oauth2:client:miniflux" ] ];
553 }
554 {
555 domain = "*.wiro.world";
556 policy = "two_factor";
557 }
558 ];
559 };
560
561 identity_providers.oidc = {
562 enforce_pkce = "always";
563
564 authorization_policies =
565 let
566 mkStrictPolicy = policy: subject:
567 { default_policy = "deny"; rules = [{ inherit policy subject; }]; };
568 in
569 {
570 headscale = mkStrictPolicy "two_factor" [ "group:headscale" ];
571 tailscale = mkStrictPolicy "two_factor" [ "group:headscale" ];
572 grafana = mkStrictPolicy "one_factor" [ "group:grafana" ];
573 miniflux = mkStrictPolicy "one_factor" [ "group:miniflux" ];
574 };
575
576 claims_policies.headscale = { id_token = [ "email" "name" "preferred_username" "picture" "groups" ]; };
577
578 clients = [
579 {
580 client_name = "Headscale";
581 client_id = "headscale";
582 client_secret = "$pbkdf2-sha256$310000$XY680D9gkSoWhD0UtYHNFg$ptWB3exOYCga6uq1N.oimuV3ILjK3F8lBWBpsBpibos";
583 redirect_uris = [ "https://${headscale-hostname}/oidc/callback" ];
584 authorization_policy = "headscale";
585 claims_policy = "headscale";
586 }
587 {
588 client_name = "Tailscale";
589 client_id = "tailscale";
590 client_secret = "$pbkdf2-sha256$310000$PcUaup9aWKI9ZLeCF6.avw$FpsTxkDaxcoQlBi8aIacegXpjEDiCI6nXcaHyZ2Sxyc";
591 redirect_uris = [ "https://login.tailscale.com/a/oauth_response" ];
592 authorization_policy = "tailscale";
593 }
594 {
595 client_name = "Grafana Console";
596 client_id = "grafana";
597 client_secret = "$pbkdf2-sha256$310000$UkwrqxTZodGMs9.Ca2cXAA$HCWFgQbFHGXZpuz.I3HHdkTZLUevRVGlhKEFaOlPmKs";
598 redirect_uris = [ "https://${grafana-hostname}/login/generic_oauth" ];
599 authorization_policy = "grafana";
600 }
601 {
602 client_name = "Miniflux";
603 client_id = "miniflux";
604 client_secret = "$pbkdf2-sha256$310000$uPqbWfCOBXDY6nV1vsx3uA$HOWG2hL.c/bs9Dwaee3b9DxjH7KFO.SaZMbasXV9Vdw";
605 redirect_uris = [ "https://${miniflux-hostname}/oauth2/oidc/callback" ];
606 authorization_policy = "miniflux";
607 }
608 ];
609 };
610
611 notifier.smtp = {
612 address = "smtp://smtp.resend.com:2587";
613 username = "resend";
614 # Set in `AUTHELIA_NOTIFIER_SMTP_PASSWORD_FILE`.
615 # password = "";
616 sender = "authelia@wiro.world";
617 };
618 };
619 };
620
621 age.secrets.tuwunel-registration-tokens = { file = ../../secrets/tuwunel-registration-tokens.age; owner = config.services.matrix-tuwunel.user; };
622 services.matrix-tuwunel = {
623 enable = true;
624
625 settings.global = {
626 address = [ "127.0.0.1" ];
627 port = [ matrix-port ];
628
629 server_name = "wiro.world";
630 well_known = {
631 client = "https://matrix.wiro.world";
632 server = "matrix.wiro.world:443";
633 };
634
635 grant_admin_to_first_user = true;
636 new_user_displayname_suffix = "";
637
638 allow_registration = true;
639 registration_token_file = config.age.secrets.tuwunel-registration-tokens.path;
640 };
641 };
642
643 services.goatcounter = {
644 enable = true;
645
646 port = goatcounter-port;
647 proxy = true;
648 extraArgs = [ "-automigrate" ];
649 };
650
651 age.secrets.vaultwarden-env.file = ../../secrets/vaultwarden-env.age;
652 services.vaultwarden = {
653 enable = true;
654
655 environmentFile = config.age.secrets.vaultwarden-env.path;
656 config = {
657 ROCKET_PORT = vaultwarden-port;
658 DOMAIN = "https://${vaultwarden-hostname}";
659 SIGNUPS_ALLOWED = false;
660 ADMIN_TOKEN = "$argon2id$v=19$m=65540,t=3,p=4$YIe9wmrTsmjgZNPxe8m34O/d3XW3Fl/uZPPLQs79dAc$mjDVQSdBJqz2uBJuxtAvCIoHPzOnTDhNPuhER3dhHrY";
661
662 SMTP_HOST = "smtp.resend.com";
663 SMTP_PORT = 2465;
664 SMTP_SECURITY = "force_tls";
665 SMTP_USERNAME = "resend";
666 # SMTP_PASSWORD = ...; # Via secret env
667 SMTP_FROM = "bitwarden@wiro.world";
668 SMTP_FROM_NAME = "Bitwarden wiro.world";
669 };
670 };
671
672 users.users.miniflux = { isSystemUser = true; group = "miniflux"; };
673 users.groups.miniflux = { };
674 age.secrets.miniflux-oidc-secret = { file = ../../secrets/miniflux-oidc-secret.age; owner = "miniflux"; };
675 services.miniflux = {
676 enable = true;
677
678 createDatabaseLocally = true;
679 config = {
680 BASE_URL = "https://${miniflux-hostname}/";
681 LISTEN_ADDR = "127.0.0.1:${toString miniflux-port}";
682 CREATE_ADMIN = 0;
683
684 METRICS_COLLECTOR = 1;
685
686 OAUTH2_PROVIDER = "oidc";
687 OAUTH2_OIDC_PROVIDER_NAME = "wiro.world SSO";
688 OAUTH2_CLIENT_ID = "miniflux";
689 OAUTH2_CLIENT_SECRET_FILE = config.age.secrets.miniflux-oidc-secret.path;
690 OAUTH2_REDIRECT_URL = "https://${miniflux-hostname}/oauth2/oidc/callback";
691 OAUTH2_OIDC_DISCOVERY_ENDPOINT = "https://auth.wiro.world";
692 OAUTH2_USER_CREATION = 1;
693 DISABLE_LOCAL_AUTH = 1;
694
695 RUN_MIGRATIONS = 1;
696
697 # NetNewsWire is a very good iOS oss client that integrates well
698 # https://b.j4.lc/2025/05/05/setting-up-netnewswire-with-miniflux/
699 };
700 };
701
702 age.secrets.hypixel-bank-tracker-main.file = ../../secrets/hypixel-bank-tracker-main.age;
703 services.hypixel-bank-tracker.instances.main = {
704 enable = true;
705
706 port = hbt-main-port;
707 environmentFile = config.age.secrets.hypixel-bank-tracker-main.path;
708 };
709
710 age.secrets.hypixel-bank-tracker-banana.file = ../../secrets/hypixel-bank-tracker-banana.age;
711 services.hypixel-bank-tracker.instances.banana = {
712 enable = true;
713
714 port = hbt-banana-port;
715 environmentFile = config.age.secrets.hypixel-bank-tracker-banana.path;
716 };
717
718 virtualisation.oci-containers.containers.archive-warrior = {
719 image = "atdr.meo.ws/archiveteam/warrior-dockerfile";
720 ports = [ "127.0.0.1:${toString warrior-port}:8001" ];
721 pull = "newer";
722 };
723 };
724}