{ pkgs, state-version, inputs, ... }: let hostVolumeDir = "/var/lib/container-storage/"; hostBackupDir = "/mnt/backup"; lib = import ./lib.nix { inherit pkgs; } // inputs // { inherit hostVolumeDir hostBackupDir; }; services = with builtins; let services_no_ip = map (s: import (./services + "/${s}") { inherit pkgs lib; }) (filter (s: ! isNull (match ".*\.nix" s)) (attrNames (readDir ./services))); in genList (i: elemAt services_no_ip i // { ip = "10.10.0.${toString (i+2)}"; }) (length services_no_ip); secrets = import ./secrets/secrets.nix; hostIp = "10.10.0.1"; in { containers = lib.flatMap ({ name, config, ip, ports, volumes, ... }: { ${name} = { autoStart = true; ephemeral = true; privateNetwork = true; hostAddress = hostIp; localAddress = ip; bindMounts = lib.flatMap (volume@{ name, mountPoint, ... }: { "${name}" = { inherit mountPoint; isReadOnly = if volume ? readOnly then volume.readOnly else false; hostPath = hostVolumeDir + name; }; } ) volumes; forwardPorts = builtins.map ({ container, host, proto }: { containerPort = container; hostPort = host; protocol = proto; }) ports.forward; config = config // { boot.isContainer = true; networking = { hostName = "${name}"; hosts = lib.flatMap ({ name, ip, ...}: { "${ip}" = [ "${name}.containers" "${name}" ]; } ) services; firewall.enable = true; firewall.allowedTCPPorts = ports.tcp; firewall.allowedUDPPorts = ports.udp; }; system.stateVersion = state-version; }; }; } ) services; } // { imports = builtins.map (service: if service ? hostConfig then service.hostConfig else {}) services; system.activationScripts.makeBindMounts = with builtins; lib.flatMapS (name: '' mkdir -p ${hostVolumeDir + name} '') (concatMap (s: map (v: v.name) s.volumes) services); # [NGINX] services.nginx = { enable = true; recommendedProxySettings = true; recommendedOptimisation = true; virtualHosts = lib.flatMap ({ ports, hosts, ip, ... }: lib.flatMap (host: if (builtins.isNull ports.http) then {} else { "${host}" = { # enableACME = true; locations."/".proxyPass = "http://${ip}:${builtins.toString ports.http}"; }; } ) hosts ) services; }; # [SSHD] services.openssh = { enable = true; ports = [ 222 ]; settings = { PermitRootLogin = "no"; PasswordAuthentication = false; }; }; # [NETWORK] networking = { hostName = "cafe"; firewall.allowedTCPPorts = [ 22 222 80 443 ]; firewall.allowedUDPPorts = [ ]; nat = { enable = true; internalInterfaces = ["ve-+"]; externalInterface = "lo"; }; }; # [USER] users.users.admin = { isNormalUser = true; group = "admin"; extraGroups = [ "wheel" ]; hashedPassword = pkgs.lib.removeSuffix "\n" (builtins.readFile ./secrets/admin_password); openssh.authorizedKeys.keyFiles = [ ./secrets/id_ed25519.pub ]; }; users.groups.admin = {}; # [SOFTWARE] programs.bash.interactiveShellInit = '' set -o vi alias doas=sudo ''; # [NIX] nix = { settings = { experimental-features = [ "nix-command" "flakes" ]; auto-optimise-store = true; }; gc = { automatic = true; dates = "monthly"; options = "--delete-older-than 30d"; }; }; # [BACKUPS] systemd = { timers.backup-container-storage = { enable = true; description = "Backup container volumes"; wantedBy = ["multi-user.target"]; timerConfig = { OnCalendar = "*-*-* 02:00:00"; Unit = "backup-container-storage.service"; }; }; services.backup-container-storage = { description = "Backup container volumes"; startLimitBurst = 1; startLimitIntervalSec = 1800; script = with builtins; let volumes = concatMap (s: s.volumes) services; backupVolumes = filter (v: if v ? backup then v.backup else true) volumes; backupMountpoints = map (v: hostVolumeDir + v.name) backupVolumes; in '' PATH="$PATH:${pkgs.lib.makeBinPath [ pkgs.gnutar pkgs.gzip ]}" mountpoint ${hostBackupDir} || { echo "${hostBackupDir} is not a mountpoint!" exit 7 } echo "Starting Backup" # 7 days of backups rm -rf ${hostBackupDir}/backup.7.tgz for x in $(seq 6); do mv "${hostBackupDir}/backup.$x.tgz" "${hostBackupDir}/backup.$((x+1)).tgz" done tar -zcvpf ${hostBackupDir}/backup.1.tgz ${toString backupMountpoints} ''; }; }; # [SECURITY] security.sudo.execWheelOnly = true; system.stateVersion = state-version; }