{ config, lib, pkgs, ... }: { imports = [ ./hardware.nix ./variables.nix ./packages.nix ./jobs.nix ./matrix.nix ./magnetico.nix ./nameserver.nix ./custom ./secrets ]; ### State # Stateful things to do before updating: # 1. Postgres migration # 2. Matrix Synapse migration system.stateVersion = "20.03"; boot.kernelPackages = pkgs.linuxPackages_latest; boot.tmpOnTmpfs = true; boot.kernel.sysctl = { # avoid OOM hangs "vm.admin_reserve_kbytes" = 262144; }; time.timeZone = "Europe/Rome"; i18n.defaultLocale = "en_US.UTF-8"; systemd.enableEmergencyMode = false; networking = { hostName = "maxwell"; firewall.allowedTCPPorts = [ 443 80 # reverse proxy 8080 # hubot 5349 # turn server 5350 # turn server 3551 # apcups 5001 # iperf server 18080 # monero p2p 20000 # syncthing transfert 64738 # mumble server ]; firewall.allowedUDPPorts = [ 53 # powerdns 1194 # dnscrypt 21027 # syncthing discovery 64738 # mumble server ]; firewall.allowedUDPPortRanges = [ { from=49152; to=49999; } # turn relay ]; usePredictableInterfaceNames = false; nameservers = [ "127.0.0.1" ]; hosts."127.0.0.1" = [ config.var.hostname ]; }; # Only declarative users and no password logins users.mutableUsers = false; users.users ={ # Only needed for local (read emergency) shell access root.passwordFile = config.secrets.passwords.root; # Admin rnhmjoj = { uid = 1000; extraGroups = [ "wheel" ]; isNormalUser = true; shell = pkgs.fish; openssh.authorizedKeys.keyFiles = [ config.secrets.publicKeys.rnhmjoj ]; }; # Admin fazo = { extraGroups = [ "wheel" ]; isNormalUser = true; openssh.authorizedKeys.keyFiles = [ config.secrets.publicKeys.fazo]; }; # Runs two chatbots meme = { extraGroups = [ "ubino" "miguelbridge" ]; isNormalUser = true; shell = pkgs.fish; openssh.authorizedKeys.keyFiles = [ config.secrets.publicKeys.meme ]; }; # Hosts the cactalogo giu = { isNormalUser = true; shell = pkgs.fish; openssh.authorizedKeys.keyFiles = with config.secrets.publicKeys; [ rnhmjoj giu ]; }; # Needed to perform remote builds on Maxwell builder = { description = "Remote Nix builds user"; isNormalUser = true; openssh.authorizedKeys.keyFiles = [ config.secrets.publicKeys.rnhmjoj-builder ]; }; # Use "git" instead of the default name to make # SSH operation handier, example: # git clone git@maxwell:user/repo git = { description = "Git server user"; home = "/var/lib/gitea"; useDefaultShell = true; }; }; # Generate Diffie-Hellman parameters # for TLS applications, like nginx. security.dhparams = { enable = true; params.nginx = 2048; # prime modulus bits }; security.sudo = { enable = true; # Users don't have a password wheelNeedsPassword = false; extraConfig = let path = "/run/current-system/sw/bin"; journal = name: "${path}/journalctl -* ${name}"; services = lib.concatMapStringsSep "," (name: "${journal name}"); in '' # Allow meme to see his logs. Cmnd_Alias MEME_UNITS = ${services ["ubino" "miguelbridge"]} meme ALL=(root) NOPASSWD: MEME_UNITS ''; }; security.polkit.extraConfig = '' // Allow meme to manage his services. polkit.addRule(function(action, subject) { if (action.id == "org.freedesktop.systemd1.manage-units" && subject.user == "meme" && (action.lookup("unit") == "ubino.service" || action.lookup("unit") == "miguelbridge.service")) { return polkit.Result.YES; } }); ''; # Limit user process to stop fork bombs security.pam.loginLimits = [ { domain = "@users"; type = "hard"; item = "nproc"; value = "400"; } ]; ### ACME certificates security.acme = with config.var; { email = "rnhmjoj@inventati.org"; acceptTerms = true; certs."${hostname}" = { group = "maxwell-ydns-eu"; }; certs."riot.${hostname}" = { group = "riot-maxwell-ydns-eu"; }; }; # Allow read access to ACME certificate # to specific (service) users. users.groups."maxwell-ydns-eu".members = [ "murmur" "turnserver" "nginx" ]; users.groups."riot-maxwell-ydns-eu".members = [ "nginx" ]; services.openssh = { enable = true; permitRootLogin = "no"; passwordAuthentication = false; challengeResponseAuthentication = false; }; # Traceroute easter egg services.fakeroute = { enable = true; route = [ "89.111.117.32" "99.97.110.110" "111.116.32.104" "105.100.101.46" "32.73.32.115" "101.101.32.121" "111.117.46.32" "84.104.101.114" "101.32.105.115" "32.110.111.32" "108.105.102.101" "32.105.110.32" "116.104.101.32" "118.111.105.100" "46.32.79.110" "108.121.32.100" "101.97.116.104" ]; }; ### Mumble server services.murmur = { enable = true; password = "allwellthatmaxwell"; registerHostname = config.var.hostname; registerName = "Maxwell Mumble"; registerPassword = config.secrets.murmur.password; users = 10; extraConfig = with config.var; '' sslCert=/var/lib/acme/${hostname}/fullchain.pem sslKey=/var/lib/acme/${hostname}/key.pem ''; }; ### Syncthing node services.syncthing = { enable = true; openDefaultPorts = true; }; ### Monero node with local RPC services.monero = { enable = true; mining = { enable = false; threads = 4; address = config.secrets.monero.address; }; limits = { upload = 250; download = 625; threads = 4; }; rpc.user = config.secrets.monero.user; rpc.password = config.secrets.monero.password; }; ### URL shortner services.breve = with config.secrets; { enable = true; hostname = "localhost"; baseUrl = "https://brve.bit/"; port = 2000; certificate = certs.breve.crt; key = certs.breve.key; }; ### Git server services.gitea = with config.var; { enable = true; domain = hostname; appName = "Maxwell git server"; rootUrl = "https://${hostname}/git/"; user = "git"; database.user = "git"; log.level = "Error"; cookieSecure = true; disableRegistration = false; settings = { security.LOGIN_REMEMBER_DAYS = 365; attachment.MAX_SIZE = 10; }; }; ### Searx instance services.searx = { enable = true; environmentFile = config.secrets.searx.environment; settings = { general.instance_name = "searxwell"; server.port = 8083; server.base_url = "https://${config.var.hostname}/srx/"; # Replace DOI links with Sci-Hub doi_resolvers."sci-hub.se" = "https://sci-hub.se/"; default_doi_resolver = "sci-hub.se"; # Use authenticated APIs for some services engines = [ { name = "wolframalpha"; api_key = "@WOLFRAM_API_KEY@"; engine = "wolframalpha_api"; } { name = "youtube"; api_key = "@YOUTUBE_API_KEY@"; engine = "youtube_api"; } ]; }; }; ### Reverse Proxy services.nginx = with config.var; let disableLog = '' error_log syslog:server=unix:/dev/log crit; access_log off; ''; enableSTS = '' add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; ''; in { enable = true; enableReload = true; commonHttpConfig = '' # recommendedTlsSettings = true; # android doesn't like this one: # ssl_ecdh_curve secp384r1; ssl_session_cache shared:SSL:42m; ssl_session_timeout 23m; ssl_prefer_server_ciphers on; ssl_stapling on; ssl_stapling_verify on; ''; recommendedGzipSettings = true; recommendedProxySettings = true; # Large enough to allow file uploads. clientMaxBodySize = "1000M"; sslDhparam = "${config.security.dhparams.path}/nginx.pem"; # Maxwell virtualHosts."${hostname}" = { enableACME = true; forceSSL = true; default = true; extraConfig = disableLog + enableSTS; # Returns IP address locations."/ip".extraConfig = "return 200 $remote_addr;"; # Asjon code coverage reports locations."/asjon/report/" = { index = "index.html"; alias = "/var/lib/asjon/tree/report/"; }; # Searx instance locations."/srx/" = { proxyPass = "http://localhost:8083/"; extraConfig = '' proxy_set_header X-Scheme $scheme; proxy_set_header X-Script-Name /srx/; proxy_buffering off; ''; }; # Git server locations."/git/" .proxyPass = "http://localhost:3000/"; # Syncthing locations."/sync/".proxyPass = "http://localhost:8384/"; }; # Breve URL shortner virtualHosts."brve.bit" = with config.secrets; { forceSSL = true; sslCertificate = certs.breve.crt; sslCertificateKey = certs.breve.key; locations."/" = { proxyPass = "https://localhost:2000"; extraConfig = "proxy_ssl_verify off;"; }; extraConfig = disableLog; }; # The Cactalogue virtualHosts."cacta.bit" = { locations."/".alias = "/home/giu/cactalogue/"; extraConfig = disableLog; }; }; ### Misc. services services.ubino.enable = true; services.miguelbridge.enable = true; services.asjon.enable = true; # Needed for the Asjon memory module services.redis.enable = true; ### Program configuration programs = { fish.enable = true; mosh.enable = true; tmux = { enable = true; newSession = true; baseIndex = 1; escapeTime = 0; historyLimit = 4096; keyMode = "vi"; terminal = "screen-256color"; customPaneNavigationAndResize = true; extraConfig = '' set -g mouse on # bindings bind | split-window -h bind - split-window -v bind : command-prompt bind -n C-k clear-history # colors set -g pane-border-style fg=brightblack set -g pane-active-border fg=green set -g message-style fg=white,bg=black set -g status-style fg=brightblue,bg=black setw -g mode-style fg=black,bg=cyan # status line set -g status on set -g status-justify left set -g status-left "" set -g status-right-length 60 set -g status-right '#[fg=yellow]#(cut -d\ -f 1-3 /proc/loadavg) | #[fg=brightgreen]%a %H:%M' setw -g window-status-format "#[fg=black#,bg=brightblack] #I #[fg=blue#,bg=black] #W " setw -g window-status-current-format "#[fg=white#,bg=cyan] #I #[fg=black#,bg=brightblack] #W " ''; }; }; nix = { useSandbox = true; # Can connect to the Nix daemon # and upload/run code as root! trustedUsers = [ "builder" "rnhmjoj" ]; # Use at most half the cores buildCores = 8; extraOptions = '' # Always keep at least 256MiB free min-free = 268435456 ''; }; environment.variables = { PATH = "$HOME/.local/bin/:$PATH"; XDG_CONFIG_HOME = "$HOME/.config"; XDG_DATA_HOME = "$HOME/.local/share"; XDG_CACHE_HOME = "$HOME/.cache"; NIX_PROFILE = "$XDG_CONFIG_HOME/nix/profile"; }; # Needed to make the mosh server survive a # user logout: systemd kills everything by default environment.shellAliases = { mosh-server = "systemd-run --user --scope mosh-server"; }; }