Compare commits

...

5 commits

Author SHA1 Message Date
Jo
f5e5adb2fd Configure attic compression and garbage-collection
Some checks are pending
Nix: check for unused code / Run deadnix (push) Waiting to run
Nix: validate flake / Validate x86_64-linux (push) Waiting to run
2025-05-26 00:28:43 +02:00
Jo
229b768537 Add attic-client package and catppuccin cache substituter 2025-05-26 00:16:16 +02:00
Jo
79cb2e9354 🐛 Fix traefik config options for atticd 2025-05-25 22:13:17 +00:00
Jo
4cf6a65764 Add fail2ban to server archetype 2025-05-25 22:43:15 +02:00
Jo
cc5ba78ddb 🐛 Tons of type and bug fixes (thanks language server for not working) 2025-05-25 22:38:12 +02:00
14 changed files with 104 additions and 28 deletions

View file

@ -9,10 +9,12 @@
extra-substituters = [ extra-substituters = [
"https://cache.nixos.org" "https://cache.nixos.org"
"https://nix-community.cachix.org" "https://nix-community.cachix.org"
"https://catppuccin.cachix.org"
]; ];
extra-trusted-public-keys = [ extra-trusted-public-keys = [
"cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY=" "cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY="
"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=" "nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs="
"catppuccin.cachix.org-1:noG/4HkbhJb+lUAdKrph6LaozJvAeEEZj4N732IysmU="
]; ];
}; };
@ -44,17 +46,10 @@
url = "github:h-banii/youtube-music-nix"; url = "github:h-banii/youtube-music-nix";
inputs.nixpkgs.follows = "nixpkgs"; inputs.nixpkgs.follows = "nixpkgs";
}; };
attic = {
url = "github:zhaofengli/attic";
inputs.nixpkgs.follows = "nixpkgs";
};
}; };
outputs = {flake-parts, ...} @ inputs: outputs = {flake-parts, ...} @ inputs:
flake-parts.lib.mkFlake {inherit inputs;} { flake-parts.lib.mkFlake {inherit inputs;} {
debug = true;
imports = [ imports = [
./modules/flake ./modules/flake
]; ];

View file

@ -38,6 +38,7 @@
## RUNTIMES and CLIs for development ## RUNTIMES and CLIs for development
bun bun
git git
attic-client
]; ];
home.stateVersion = "25.05"; home.stateVersion = "25.05";

View file

@ -17,7 +17,6 @@
(lib.optionals (class == "nixos") [ (lib.optionals (class == "nixos") [
inputs.home-manager.nixosModules.default inputs.home-manager.nixosModules.default
inputs.sops-nix.nixosModules.sops inputs.sops-nix.nixosModules.sops
inputs.attic.nixosModules.atticd
]) ])
++ (self.lib.dirToModuleList ../${class}); # Import modules based on current classname. ++ (self.lib.dirToModuleList ../${class}); # Import modules based on current classname.
}; };

View file

@ -34,5 +34,8 @@ in {
# Enable SSH for remote login # Enable SSH for remote login
services.openssh.enable = true; services.openssh.enable = true;
# SSH rate-limiting and bans
services.fail2ban.enable = true;
}; };
} }

View file

@ -34,7 +34,7 @@ in {
nix = { nix = {
enable = true; enable = true;
use-lix = true; use-lix = true;
use-nixld = true; use-nixld = true;
}; };
}; };

View file

@ -4,7 +4,7 @@
config, config,
... ...
}: let }: let
inherit (lib) mkEnableOption mkIf; inherit (lib) mkEnableOption mkIf types;
inherit (self) namespace; inherit (self) namespace;
inherit (self.lib) mkOpt; inherit (self.lib) mkOpt;
@ -12,13 +12,13 @@
in { in {
options.${namespace}.services.atticd = { options.${namespace}.services.atticd = {
enable = mkEnableOption "the attic service, a multi-tenant nix binary cache."; enable = mkEnableOption "the attic service, a multi-tenant nix binary cache.";
sopsFile = mkOpt types.str null "The location of the sops secret file for the Atticd service."; sopsFile = mkOpt types.path null "The location of the sops secret file for the Atticd service.";
sopsFormat = mkOpt types.str null "The format of the sops secret file for the Atticd service."; sopsFormat = mkOpt types.str null "The format of the sops secret file for the Atticd service.";
subdomain = mkOpt types.str "cache" "The subdomain, of the system domain, the service should be exposed on."; subdomain = mkOpt types.str "cache" "The subdomain, of the system domain, the service should be exposed on.";
}; };
config = mkIf cfg.enable { config = mkIf cfg.enable {
config.sops.secrets."services/atticd" = { sops.secrets."services/atticd" = {
sopsFile = cfg.sopsFile; sopsFile = cfg.sopsFile;
format = cfg.sopsFormat; format = cfg.sopsFormat;
}; };
@ -38,15 +38,23 @@ in {
avg-size = 64 * 1024; # 64 KiB avg-size = 64 * 1024; # 64 KiB
max-size = 256 * 1024; # 256 KiB max-size = 256 * 1024; # 256 KiB
}; };
compression = {
type = "zstd";
level = 12;
};
garbage-collection.interval = "8 hours";
}; };
}; };
services.traefik.dynamicConfigOptions = { services.traefik.dynamicConfigOptions = {
http = { http = {
services.atticd.loadBalancer.server.url = "http://localhost:3900"; services.atticd.loadBalancer.servers = [{url = "http://localhost:3900";}];
routers.atticd = { routers.atticd = {
entrypoints = ["websecure"]; entryPoints = ["websecure"];
rule = "Host(`${cfg.subdomain}.${config.services.domain}`)"; service = "atticd";
rule = "Host(`${cfg.subdomain}.${config.${namespace}.services.domain}`)";
}; };
}; };
}; };

View file

@ -9,5 +9,6 @@
in { in {
options.${namespace}.services = { options.${namespace}.services = {
domain = mkOpt types.str "thevoid.cafe" "The main system domain, used for exposing services."; domain = mkOpt types.str "thevoid.cafe" "The main system domain, used for exposing services.";
mail = mkOpt types.str "system@thevoid.cafe" "The main system administration E-Mail, used for logs and services.";
}; };
} }

View file

@ -12,7 +12,7 @@
in { in {
options.${namespace}.services.duckdns = { options.${namespace}.services.duckdns = {
enable = mkEnableOption "DuckDNS, the dynamic dns service. Will periodically refresh your IP."; enable = mkEnableOption "DuckDNS, the dynamic dns service. Will periodically refresh your IP.";
sopsFile = mkOpt types.str null "The location of the sops secret file for the DuckDNS service."; sopsFile = mkOpt types.path null "The location of the sops secret file for the DuckDNS service.";
sopsFormat = mkOpt types.str null "The format of the sops secret file for the DuckDNS service."; sopsFormat = mkOpt types.str null "The format of the sops secret file for the DuckDNS service.";
}; };
@ -25,7 +25,7 @@ in {
virtualisation.oci-containers.containers.duckdns = { virtualisation.oci-containers.containers.duckdns = {
image = "lscr.io/linuxserver/duckdns:latest"; image = "lscr.io/linuxserver/duckdns:latest";
autoStart = true; autoStart = true;
hostname = config.networking.hostname; hostname = config.networking.hostName;
environmentFiles = [ environmentFiles = [
config.sops.secrets.duckdns.path config.sops.secrets.duckdns.path
]; ];

View file

@ -13,7 +13,7 @@ in {
options.${namespace}.services.homepage = { options.${namespace}.services.homepage = {
enable = mkEnableOption "Homepage, an intuitive dashboard for your services."; enable = mkEnableOption "Homepage, an intuitive dashboard for your services.";
subdomain = mkOpt types.str "home" "The subdomain, of the system domain, the service should be exposed on."; subdomain = mkOpt types.str "home" "The subdomain, of the system domain, the service should be exposed on.";
configDir = mkOpt types.str null "The config directory, which will be copied to the Homepage directory during compilation."; configDir = mkOpt types.path null "The config directory, which will be copied to the Homepage directory during compilation.";
}; };
config = mkIf cfg.enable { config = mkIf cfg.enable {
@ -31,11 +31,11 @@ in {
virtualisation.oci-containers.containers.homepage = { virtualisation.oci-containers.containers.homepage = {
image = "ghcr.io/gethomepage/homepage:latest"; image = "ghcr.io/gethomepage/homepage:latest";
autoStart = true; autoStart = true;
hostname = config.networking.hostname; hostname = config.networking.hostName;
labels = { labels = {
"traefik.enable" = "true"; "traefik.enable" = "true";
"traefik.http.routers.homepage.entrypoints" = "websecure"; "traefik.http.routers.homepage.entrypoints" = "websecure";
"traefik.http.routers.homepage.rule" = "Host(`${cfg.subdomain}.${config.services.domain}`)"; "traefik.http.routers.homepage.rule" = "Host(`${cfg.subdomain}.${config.${namespace}.services.domain}`)";
"traefik.http.services.homepage.loadbalancer.server.port" = "3000"; "traefik.http.services.homepage.loadbalancer.server.port" = "3000";
}; };
volumes = [ volumes = [
@ -46,7 +46,7 @@ in {
"/var/run/docker.sock:/var/run/docker.sock:ro" "/var/run/docker.sock:/var/run/docker.sock:ro"
]; ];
environment = { environment = {
"HOMEPAGE_ALLOWED_HOSTS" = "${cfg.subdomain}.${config.services.domain}"; "HOMEPAGE_ALLOWED_HOSTS" = "${cfg.subdomain}.${config.${namespace}.services.domain}";
}; };
extraOptions = ["--network=proxy"]; extraOptions = ["--network=proxy"];
}; };

View file

@ -4,14 +4,15 @@
config, config,
... ...
}: let }: let
inherit (lib) mkEnableOption mkIf; inherit (lib) mkEnableOption mkIf types;
inherit (self) namespace; inherit (self) namespace;
inherit (self.lib) mkOpt;
cfg = config.${namespace}.services.traefik; cfg = config.${namespace}.services.traefik;
in { in {
options.${namespace}.services.traefik = { options.${namespace}.services.traefik = {
enable = mkEnableOption "the Traefik service."; enable = mkEnableOption "the Traefik service.";
sopsFile = mkOpt types.str null "The location of the sops secret file for the Traefik service."; sopsFile = mkOpt types.path null "The location of the sops secret file for the Traefik service.";
sopsFormat = mkOpt types.str null "The format of the sops secret file for the Traefik service."; sopsFormat = mkOpt types.str null "The format of the sops secret file for the Traefik service.";
}; };
@ -57,7 +58,7 @@ in {
certificatesResolvers = { certificatesResolvers = {
letsencrypt = { letsencrypt = {
acme = { acme = {
email = cfg.cloudflareEmail; email = config.${namespace}.services.mail;
storage = "/var/lib/traefik/acme.json"; storage = "/var/lib/traefik/acme.json";
#caServer = "https://acme-staging-v02.api.letsencrypt.org/directory"; # Uncomment this when testing stuff! #caServer = "https://acme-staging-v02.api.letsencrypt.org/directory"; # Uncomment this when testing stuff!
dnsChallenge = { dnsChallenge = {

View file

@ -12,7 +12,7 @@
in { in {
options.${namespace}.services.vaultwarden = { options.${namespace}.services.vaultwarden = {
enable = mkEnableOption "Vaultwarden, a self-hostable password manager."; enable = mkEnableOption "Vaultwarden, a self-hostable password manager.";
sopsFile = mkOpt types.str null "The location of the sops secret file for the Vaultwarden service."; sopsFile = mkOpt types.path null "The location of the sops secret file for the Vaultwarden service.";
sopsFormat = mkOpt types.str null "The format of the sops secret file for the Vaultwarden service."; sopsFormat = mkOpt types.str null "The format of the sops secret file for the Vaultwarden service.";
subdomain = mkOpt types.str "vault" "The subdomain, of the system domain, the service should be exposed on."; subdomain = mkOpt types.str "vault" "The subdomain, of the system domain, the service should be exposed on.";
}; };
@ -31,11 +31,11 @@ in {
virtualisation.oci-containers.containers.vaultwarden = { virtualisation.oci-containers.containers.vaultwarden = {
image = "vaultwarden/server"; image = "vaultwarden/server";
autoStart = true; autoStart = true;
hostname = config.networking.hostname; hostname = config.networking.hostName;
labels = { labels = {
"traefik.enable" = "true"; "traefik.enable" = "true";
"traefik.http.routers.vaultwarden.entrypoints" = "websecure"; "traefik.http.routers.vaultwarden.entrypoints" = "websecure";
"traefik.http.routers.vaultwarden.rule" = "Host(`${cfg.subdomain}.${config.services.domain}`)"; "traefik.http.routers.vaultwarden.rule" = "Host(`${cfg.subdomain}.${config.${namespace}.services.domain}`)";
}; };
volumes = [ volumes = [
"/var/lib/containers/vaultwarden/data:/data:rw" "/var/lib/containers/vaultwarden/data:/data:rw"

View file

@ -5,8 +5,9 @@
config, config,
... ...
}: let }: let
inherit (lib) mkEnableOption mkIf; inherit (lib) mkEnableOption mkIf types;
inherit (self) namespace; inherit (self) namespace;
inherit (self.lib) mkOpt;
cfg = config.${namespace}.system.nix; cfg = config.${namespace}.system.nix;
in { in {
@ -14,6 +15,7 @@ in {
enable = mkEnableOption "Nix configuration overrides."; enable = mkEnableOption "Nix configuration overrides.";
use-lix = mkEnableOption "Lix as an alternative to CppNix."; use-lix = mkEnableOption "Lix as an alternative to CppNix.";
use-nixld = mkEnableOption "the use of dynamically linked executables on nix based systems."; use-nixld = mkEnableOption "the use of dynamically linked executables on nix based systems.";
trusted-users = mkOpt (types.listOf types.str) ["@wheel"] "List of trusted users for this NixOS system.";
}; };
config = mkIf cfg.enable { config = mkIf cfg.enable {
@ -26,6 +28,7 @@ in {
keep-outputs = true; keep-outputs = true;
max-jobs = "auto"; max-jobs = "auto";
warn-dirty = false; warn-dirty = false;
trusted-users = cfg.trusted-users;
}; };
# Garbage collection configuration. # Garbage collection configuration.

View file

@ -1,4 +1,8 @@
{pkgs, ...}: { {pkgs, ...}: {
imports = [
./hardware.nix
];
# Setup Sops # Setup Sops
sops.age.sshKeyPaths = ["/etc/ssh/ssh_host_ed25519_key"]; sops.age.sshKeyPaths = ["/etc/ssh/ssh_host_ed25519_key"];
sops.age.keyFile = "/var/lib/sops-nix/key.txt"; sops.age.keyFile = "/var/lib/sops-nix/key.txt";
@ -36,6 +40,12 @@
enable = true; enable = true;
configDir = ./resources/homepage-config; configDir = ./resources/homepage-config;
}; };
atticd = {
enable = true;
sopsFile = ./secrets/atticd.env;
sopsFormat = "dotenv";
};
}; };
}; };

View file

@ -0,0 +1,55 @@
# Do not modify this file! It was generated by nixos-generate-config
# and may be overwritten by future invocations. Please make changes
# to /etc/nixos/configuration.nix instead.
{
config,
lib,
modulesPath,
...
}: {
imports = [
(modulesPath + "/installer/scan/not-detected.nix")
];
boot.initrd.availableKernelModules = ["xhci_pci" "ahci" "usbhid" "uas" "sd_mod"];
boot.initrd.kernelModules = [];
boot.kernelModules = ["kvm-intel"];
boot.extraModulePackages = [];
fileSystems."/" = {
device = "/dev/disk/by-uuid/5d4f9f57-085f-44a0-b987-bad24ff58769";
fsType = "btrfs";
options = ["subvol=@"];
};
fileSystems."/boot" = {
device = "/dev/disk/by-uuid/8D0F-2821";
fsType = "vfat";
options = ["fmask=0077" "dmask=0077"];
};
fileSystems."/mnt/storage" = {
device = "/dev/disk/by-uuid/237eb43e-1e4e-4cb1-873e-6b07f1368f4f";
fsType = "ext4";
};
swapDevices = [
{device = "/dev/disk/by-uuid/42fc926f-f066-48e8-8c07-3627b2ba3cd4";}
];
# Enables DHCP on each ethernet and wireless interface. In case of scripted networking
# (the default) this is the recommended approach. When using systemd-networkd it's
# still possible to use this option, but it's recommended to use it in conjunction
# with explicit per-interface declarations with `networking.interfaces.<interface>.useDHCP`.
networking.useDHCP = lib.mkDefault true;
# networking.interfaces.br-32acd0b5b342.useDHCP = lib.mkDefault true;
# networking.interfaces.docker0.useDHCP = lib.mkDefault true;
# networking.interfaces.enp1s0.useDHCP = lib.mkDefault true;
# networking.interfaces.veth0b3552e.useDHCP = lib.mkDefault true;
# networking.interfaces.veth3873910.useDHCP = lib.mkDefault true;
# networking.interfaces.veth9323c9b.useDHCP = lib.mkDefault true;
# networking.interfaces.wlp2s0.useDHCP = lib.mkDefault true;
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
}