396 lines
11 KiB
Nix
396 lines
11 KiB
Nix
{ config, hostRegistry, lib, libC, nixos, pkgs, 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!";
|
|
}
|
|
{
|
|
assertion = config.networking.nftables.enable || config.networking.firewall.extraInputRules == "";
|
|
message = "\"config.networking.firewall.extraInputRules\" is defined but nftables is not activated";
|
|
}
|
|
];
|
|
|
|
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;
|
|
};
|
|
|
|
c3d2 = {
|
|
# NOTE: this must be off, otherwise our nix binary cache creates a loop with itself
|
|
addBinaryCache = lib.mkForce false;
|
|
addKnownHosts = true;
|
|
sshKeys = libC.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 towards failed services
|
|
systemctl --no-pager --failed || true
|
|
'';
|
|
|
|
# headless systems have no input devices like touchpads
|
|
noXlibs = lib.mkDefault (!config.services.libinput.enable);
|
|
|
|
systemPackages = with pkgs; [
|
|
bmon
|
|
curl
|
|
dig
|
|
ethtool
|
|
fd
|
|
git
|
|
htop
|
|
iotop
|
|
iproute2
|
|
jq
|
|
lsof # to find lingering nix processes locking files in nix store
|
|
mtr
|
|
pv
|
|
ripgrep
|
|
rsync
|
|
screen
|
|
strace
|
|
tcpdump
|
|
traceroute
|
|
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
|
|
];
|
|
logRefusedConnections = false; # prevent log spam
|
|
};
|
|
nameservers = with hostRegistry.dnscache; [
|
|
ip6
|
|
ip4
|
|
] ++ (if config.services.resolved.enable then [
|
|
"9.9.9.9#dns.quad9.net"
|
|
"1.1.1.1#cloudflare-dns.com"
|
|
] else [
|
|
"9.9.9.9"
|
|
"1.1.1.1"
|
|
]);
|
|
useHostResolvConf = lib.mkIf (!config.services.resolved.enable) true;
|
|
};
|
|
|
|
# TODO: drop when https://github.com/Mic92/sops-nix/pull/555 is merged
|
|
sops.environment.SOPS_GPG_EXEC = lib.getExe (pkgs.gnupg.override { enableMinimal = 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 = [
|
|
"hydra.hq.c3d2.de:KZRGGnwOYzys6pxgM8jlur36RmkJQ/y8y62e52fj1ps="
|
|
];
|
|
stalled-download-timeout = 30; # in case hydra is not reachable fail faster
|
|
# don't self feed hydra
|
|
substituters = lib.mkIf (config.networking.hostName != "hydra") (
|
|
lib.mkBefore [ "https://hydra.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";
|
|
};
|
|
|
|
htop = {
|
|
enable = true;
|
|
settings = {
|
|
cpu_count_from_one = true;
|
|
hide_kernel_threads = true;
|
|
hide_userland_threads = true;
|
|
highlight_base_name = true;
|
|
};
|
|
};
|
|
|
|
tmux = {
|
|
enable = true;
|
|
historyLimit = 50000;
|
|
extraConfig = /* tmux */ ''
|
|
# 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 access it like nixos-modules grafana
|
|
# keep in sync with nixos/modules/services/misc/portunus.nix
|
|
dex.settings.issuer = "https://${config.services.portunus.domain}/dex";
|
|
|
|
fail2ban = {
|
|
enable = lib.mkIf config.services.openssh.enable true;
|
|
bantime-increment = {
|
|
enable = true;
|
|
multipliers = "1 2 4 8 16 64 256 1024 4096";
|
|
overalljails = true;
|
|
rndtime = "8m";
|
|
};
|
|
daemonSettings.DEFAULT = {
|
|
allowipv6 = "auto";
|
|
loglevel = "NOTICE";
|
|
};
|
|
ignoreIP = libC.subnets.v4 ++ libC.subnets.v6 ++ [
|
|
"127.0.0.0/8"
|
|
"fe80::/64"
|
|
"::1/128"
|
|
];
|
|
jails.DEFAULT.settings.findtime = 86400; # 24h
|
|
};
|
|
|
|
gitea = {
|
|
ldap = {
|
|
adminGroup = "gitea-admins";
|
|
userGroup = "gitea-users";
|
|
};
|
|
oidc = {
|
|
enable = true;
|
|
# used as an unique identifier
|
|
options.name = lib.mkForce "auth.c3d2.de";
|
|
};
|
|
settings.server.DOMAIN = "gitea.c3d2.de";
|
|
};
|
|
|
|
gnome = {
|
|
# less webkitgtk's
|
|
evolution-data-server.enable = lib.mkForce false;
|
|
gnome-initial-setup.enable = false;
|
|
};
|
|
|
|
grafana = {
|
|
oauth = {
|
|
enable = true;
|
|
adminGroup = "grafana-admins";
|
|
userGroup = "grafana-users";
|
|
};
|
|
settings.server.domain = "grafana.hq.c3d2.de";
|
|
};
|
|
|
|
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";
|
|
};
|
|
|
|
mailman = {
|
|
webHosts = [ "lists.c3d2.de" ];
|
|
openidConnect.enable = true;
|
|
};
|
|
|
|
mastodon.ldap.userGroup = "mastodon-users";
|
|
|
|
matrix-synapse.ldap.userGroup = "matrix-users";
|
|
|
|
nginx = {
|
|
appendHttpConfig = /* nginx */ ''
|
|
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; /* nginx */ ''
|
|
# 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;
|
|
|
|
# undistinguable from a cordinadted DOS attack
|
|
if ($http_user_agent = "Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; ClaudeBot/1.0; +claudebot@anthropic.com)"){
|
|
return 403;
|
|
}
|
|
'';
|
|
};
|
|
|
|
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 = {
|
|
domain = "auth.serv.zentralwerk.org";
|
|
webDomain = "auth.c3d2.de";
|
|
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 Admins"
|
|
"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.statistics.enable "collectd";
|
|
};
|
|
|
|
redis.package = pkgs.valkey;
|
|
};
|
|
|
|
security.acme = {
|
|
acceptTerms = true;
|
|
defaults = {
|
|
email = "mail@c3d2.de"; # TODO: change but it would request new certs
|
|
# letsencrypt staging server with way higher rate limits
|
|
# server = "https://acme-staging-v02.api.letsencrypt.org/directory";
|
|
reloadServices = lib.optional config.services.nginx.enable "nginx";
|
|
};
|
|
};
|
|
|
|
# does not succeed 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;
|
|
}
|