{ config, hostRegistry, lib, nixos, pkgs, ssh-public-keys, zentralwerk, ... }: # this file contains default configuration that may be turned on depending on other config settings. # options should go to modules. { assertions = [ { assertion = config.system.replaceRuntimeDependencies == []; message = "system.replaceRuntimeDependencies causes hydra to build the system at evaluation time. It must be removed!"; } { assertion = lib.versions.major pkgs.ceph.version != 16; message = "Please pin ceph to major version 16!"; } ]; boot = { enableContainers = false; # should be enabled explicitly loader.systemd-boot = { configurationLimit = lib.mkDefault 10; editor = false; graceful = true; }; kernel.sysctl = { "kernel.panic" = 60; # reset 60 seconds after a kernel panic "net.ipv4.tcp_congestion_control" = "bbr"; }; tmp.cleanOnBoot = true; # recommend to turn off, only on by default for backwards compatibility zfs.forceImportRoot = false; }; c3d2 = { # NOTE: this must be off, otherwise our nix binary cache creates a loop with itself addBinaryCache = lib.mkForce false; addKnownHosts = true; sshKeys = ssh-public-keys; }; documentation.enable = false; environment = { etc."resolv.conf" = lib.mkIf (!config.services.resolved.enable) { text = lib.concatMapStrings (ns: '' nameserver ${ns} '') config.networking.nameservers; }; gnome.excludePackages = with pkgs; with gnome; [ baobab cheese epiphany # we are using firefox or chromium and requires second webkitgtk geary gnome-calendar gnome-contacts gnome-maps gnome-music gnome-photos gnome-weather orca simple-scan totem yelp # less webkitgtk's ]; interactiveShellInit = /* sh */ '' # raise some awareness torwards failed services systemctl --no-pager --failed || true ''; noXlibs = !config.services.xserver.enable; systemPackages = with pkgs; [ bmon curl dig ethtool fd git htop iotop (iproute2.overrideAttrs ({ configureFlags ? [], src, ... }: let version = "6.8.0"; in { inherit version; src = pkgs.fetchurl { url = "mirror://kernel/linux/utils/net/iproute2/iproute2-${version}.tar.xz"; hash = "sha256-A6bMo9cakI0fFfe0lb4rj+hR+UFFjcRmSQDX9F/PaM4="; }; configureFlags = configureFlags ++ [ "--color" "auto" ]; })) jq lsof # to find lingering nix processes locking files in nix store mtr pv ripgrep rsync screen strace tcpdump tree vim wget ]; }; hardware.enableRedistributableFirmware = lib.mkDefault true; i18n = { defaultLocale = "en_US.UTF-8"; supportedLocales = [ "en_US.UTF-8/UTF-8" "de_DE.UTF-8/UTF-8" ]; }; networking = { firewall.allowedTCPPorts = lib.mkIf config.services.nginx.enable [ # proxy protocol used by public-access-proxy 8080 8443 ]; nameservers = with hostRegistry.dnscache; [ ip4 ip6 "9.9.9.9" ]; useHostResolvConf = lib.mkIf (!config.services.resolved.enable) true; }; nix = { deleteChannels = true; deleteUserProfiles = true; gc = { automatic = lib.mkDefault true; dates = "06:00"; options = "--delete-older-than 21d"; randomizedDelaySec = "6h"; }; nixPath = [ "nixpkgs=${builtins.unsafeDiscardStringContext nixos}" "nixos=${builtins.unsafeDiscardStringContext nixos}" "nixos-config=/you/shall/deploy/from/the/flake" ]; registry.nixpkgs.flake = nixos; settings = { extra-experimental-features = "ca-derivations"; # if a download from hydra fails, we want to stop and retry it, instead of building it fallback = false; trusted-public-keys = [ "nix-cache.hq.c3d2.de:KZRGGnwOYzys6pxgM8jlur36RmkJQ/y8y62e52fj1ps=" ]; stalled-download-timeout = 60; # in case hydra is not reachable fail faster # don't self feed hydra substituters = lib.mkIf (config.networking.hostName != "hydra") ( lib.mkBefore [ "https://nix-cache.hq.c3d2.de" ] ); }; }; nixpkgs.config.allowUnfreePredicate = pkg: builtins.elem (pkgs.lib.getName pkg) [ "drone.io" "drone-runner-ssh" "elasticsearch" # mastodon ]; # trust sandro to set good defaults in nixos-modules opinionatedDefaults = true; programs = { fzf.keybindings = true; git = { enable = true; # silence hints in various programs like drone config.init.defaultBranch = "master"; }; tmux = { enable = true; historyLimit = 50000; extraConfig = '' # mouse control set -g mouse on # don't clear selection on copy bind-key -Tcopy-mode-vi MouseDragEnd1Pane send -X copy-selection-no-clear bind-key -Tcopy-mode-vi y send -X copy-selection-no-clear ''; }; vim.defaultEditor = true; }; security.ldap.domainComponent = [ "c3d2" "de" ]; services = { # set here explicitly, so that other modules can acces it like nixos-modules grafana # keep in sync with nixos/modules/services/misc/portunus.nix dex.settings.issuer = "https://${config.services.portunus.domain}/dex"; gitea.ldap = { adminGroup = "gitea-admins"; userGroup = "gitea-users"; }; gnome = { # less webkitgtk's evolution-data-server.enable = lib.mkForce false; gnome-initial-setup.enable = false; }; grafana.oauth = { adminGroup = "grafana-admins"; userGroup = "grafana-users"; }; hedgedoc.ldap.userGroup = "hedgedoc-users"; home-assistant.ldap = { adminGroup = "home-assistant-admins"; userGroup = "home-assistant-users"; }; hydra.ldap = { roleMappings = [ { hydra-admins = "admin"; } ]; userGroup = "hydra-users"; }; mastodon.ldap.userGroup = "mastodon-users"; matrix-synapse.ldap.userGroup = "matrix-users"; nginx = { appendHttpConfig = '' log_format proxyCombined '$proxy_protocol_addr - $remote_user [$time_local] ' '"$request" $status $body_bytes_sent ' '"$http_referer" "$http_user_agent"'; access_log /var/log/nginx/access.log proxyCombined; ''; commonServerConfig = with zentralwerk.lib.config.site.net.serv; '' # https://docs.nginx.com/nginx/admin-guide/load-balancer/using-proxy-protocol/ set_real_ip_from ${hosts4.public-access-proxy}; set_real_ip_from ${hosts6.up4.public-access-proxy}; real_ip_header proxy_protocol; proxy_set_header X-Real-IP $proxy_protocol_addr; proxy_set_header X-Forwarded-For $proxy_protocol_addr; ''; }; openssh = { # Required for deployment and sops enable = true; settings = { AcceptEnv = "SYSTEMD_PAGER"; LoginGraceTime = 30; # throw out unauthenticated connections earlier than the 120 default PasswordAuthentication = lib.mkIf (!config.c3d2.k-ot.enable) false; PermitRootLogin = lib.mkOverride 900 "prohibit-password"; }; }; portunus = with zentralwerk.lib.config.site.net.serv; { domain = "auth.c3d2.de"; internalIp4 = hosts4.auth; internalIp6 = hosts6.up4.auth; ldapPreset = true; # those can't be under hosts/*/default.nix because those are not imported for the auth microvm seedSettings.groups = map (n: { long_name = n; name = lib.toLower (lib.replaceStrings [" "] ["-"] n); permissions = { }; }) [ "Mail Users" "Mobilizon Users" "Vaultwarden Users" "Vaultwarden Social Media Accounts" ]; }; postgresql.upgrade = { extraArgs = [ "--link" ] ++ lib.optional (config ? microvm) "--jobs=${toString config.microvm.vcpu}"; newPackage = pkgs.postgresql_16; stopServices = lib.optional config.services.nginx.enable "nginx" ++ lib.optional config.c3d2.hq.statistics.enable "collectd"; }; redis.vmOverCommit = true; }; security.acme = { acceptTerms = true; defaults = { email = "mail@c3d2.de"; # letsencrypt staging server with way higher rate limits # server = "https://acme-staging-v02.api.letsencrypt.org/directory"; }; }; # does not suceed on installation which is okay system.activationScripts.deleteOldSystemProfiles = lib.mkIf config.nix.gc.automatic '' echo "Deleting old system profiles..." ${config.nix.package}/bin/nix-env --profile /nix/var/nix/profiles/system --delete-generations +10 || true ''; systemd = { # don't kick us out if one disk is missing enableEmergencyMode = false; # maybe set enable = false instead? network.wait-online.anyInterface = true; services.nix-daemon.serviceConfig = { # kill all worker thread when restarting KillMode = "control-group"; # restart if killed eg oom killed Restart = "on-failure"; }; # Reboot on hang watchdog = lib.mkIf (!config.boot.isContainer) { runtimeTime = "15s"; rebootTime = "15s"; }; }; time.timeZone = lib.mkDefault "Europe/Berlin"; users.motdFile = ./motd; }