# Edit this configuration file to define what should be installed on # your system. Help is available in the configuration.nix(5) man page, on # https://search.nixos.org/options and in the NixOS manual (`nixos-help`). { config, lib, pkgs, ... }: let baseDomain = "push-f.com"; acmeEmail = "martin@push-f.com"; backupHost = "u518695-sub1@u518695-sub1.your-storagebox.de"; ports = import ./ports.nix; sources = import ; helpers = import { inherit config lib pkgs; }; gitoliteDataDir = "/srv/gitolite"; reposDir = "${gitoliteDataDir}/repositories"; in { imports = [ ./hardware-configuration.nix ./web-personal.nix ./git-web.nix ./gitolite.nix ./headscale.nix ./exporters.nix ./grafana.nix "${sources.my-git-grep-exporter}/service.nix" "${sources.my-lex-surf}/service.nix" "${sources.my-osm-proposals}/service.nix" "${sources.my-geopos-link}/service.nix" "${sources.my-rust-features}/service.nix" "${sources.my-spec-pub}/service.nix" "${sources.my-web-feed-exporter}/service.nix" ]; # Use the GRUB 2 boot loader. boot.loader.grub.enable = true; # boot.loader.grub.efiSupport = true; # boot.loader.grub.efiInstallAsRemovable = true; # boot.loader.efi.efiSysMountPoint = "/boot/efi"; # Define on which hard drive you want to install Grub. boot.loader.grub.device = "/dev/sda"; # or "nodev" for efi only networking.hostName = "tente"; networking.networkmanager.enable = true; time.timeZone = "Europe/Vienna"; environment.systemPackages = with pkgs; [ # The essentials are installed via the imported profile. sqlite-interactive ]; users.groups = { www-generator = {}; www-personal = {}; }; systemd.tmpfiles.rules = [ "d /srv/www/${baseDomain} 2770 root www-personal -" ]; users.users = { martin = { isNormalUser = true; extraGroups = [ "wheel" # Enable ‘sudo’ for the user. "www-personal" ]; }; cgit = { isSystemUser = true; extraGroups = ["git"]; }; nginx = { isSystemUser = true; extraGroups = [ "www-personal" ]; }; www-generator = { isSystemUser = true; group = "www-generator"; }; }; # Services # comes with a pre-configured SSH jail services.fail2ban.enable = true; gitolite = { dataDir = gitoliteDataDir; user = "git"; group = "git"; }; grafana = { port = ports.grafana; }; headscale = { domain = "tailscale.${baseDomain}"; port = ports.headscale; }; # Websites services.nginx = { enable = true; virtualHosts."tente.tailnet" = helpers.serviceIndexHost "tente.tailnet" ports.webUis; appendHttpConfig = '' # Close the connection for unknown Host headers. # If we don't do this nginx serves some random virtualhost. server { listen 80 default_server; listen [::]:80 default_server; listen 443 ssl default_server; listen [::]:443 ssl default_server; ssl_reject_handshake on; return 444; } ''; commonHttpConfig = helpers.commonHttpConfig; }; security.acme = { acceptTerms = true; # https://letsencrypt.org/repository/ defaults.email = acmeEmail; }; services.logrotate.settings.nginx = { delaycompress = false; }; web-personal = { domain = baseDomain; dir = "/srv/www/${baseDomain}/current"; # not managed via Nix }; gitWeb = { domain = "git.${baseDomain}"; reposDir = reposDir; user = "cgit"; group = "cgit"; }; services.geopos-share = let domain = "geopos.link"; in { enable = true; virtualHost = domain; nginx = { enableACME = true; forceSSL = true; extraConfig = helpers.mkNginxConfig domain; }; }; services.lex-surf = let domain = "lex.surf"; in { enable = true; domain = domain; enableACME = true; fetchUser = "www-generator"; nginx = { forceSSL = true; extraConfig = helpers.mkNginxConfig domain; }; }; services.osm-proposals = let domain = "osm-proposals.${baseDomain}"; in { enable = true; user = "www-generator"; virtualHost = domain; nginx = { enableACME = true; forceSSL = true; extraConfig = helpers.mkNginxConfig domain; }; }; services.rust-features = let domain = "rust-features.${baseDomain}"; in { enable = true; user = "www-generator"; virtualHost = domain; nginx = { enableACME = true; forceSSL = true; extraConfig = helpers.mkNginxConfig domain; }; }; services.spec-pub = let domain = "spec.pub"; in { enable = true; virtualHost = domain; nginx = { enableACME = true; forceSSL = true; extraConfig = helpers.mkNginxConfig domain; }; }; # Monitoring exporters = { sqlExporterPort = ports.prometheusSqlExporter; storageboxExporterPort = ports.prometheusStorageboxExporter; }; services.gitGrepExporter = { enable = true; port = ports.prometheusGitGrepExporter; extraGroups = ["git"]; patterns = { todo = ''\bTO'' + ''DO\b''; fixme = ''\bFIX'' + ''ME\b''; }; reposDir = reposDir; onlyExported = true; }; services.webFeedExporter = { enable = true; port = ports.prometheusWebFeedExporter; feeds = { blog = "https://push-f.com/posts/index.xml"; bluesky = "https://bsky.app/profile/push-f.com/rss"; }; }; monitoring = { alloyUiPort = ports.grafanaAlloy; lokiPort = ports.grafanaLoki; lokiRetentionStream = [ # TODO: set same retention for nginx logs in loki and logrotate # (set up recording rule in Loki so we can still have some stats longer than that) { selector = ''{vhost="git.push-f.com"}''; period = "${toString (24*30)}h"; } ]; prometheusPort = ports.prometheus; prometheusNodeExporterPort = ports.prometheusNodeExporter; prometheusScrapeConfigs = [ { job_name = "sql"; static_configs = [{ targets = ["localhost:${toString ports.prometheusSqlExporter}"]; }]; } { job_name = "storagebox"; scrape_interval = "5m"; static_configs = [{ targets = ["localhost:${toString ports.prometheusStorageboxExporter}"]; }]; } { job_name = "git-grep"; scrape_interval = "10m"; static_configs = [{ targets = ["localhost:${toString ports.prometheusGitGrepExporter}"]; }]; } { job_name = "web-feed"; scrape_interval = "10m"; static_configs = [{ targets = ["localhost:${toString ports.prometheusWebFeedExporter}"]; }]; } ]; }; # Backups systemd.services.backup-repos = { serviceConfig = { Type = "oneshot"; ExecStart = "${pkgs.rsync}/bin/rsync -a --delete ${reposDir}/ ${backupHost}:repos -e '${pkgs.openssh}/bin/ssh -p23'"; }; startAt = "00:00"; }; age.secrets.restic-db.file = ./secrets/restic-db.age; restic-database-backups = { repository = "sftp://${backupHost}:23" + "/db"; passwordFile = config.age.secrets.restic-db.path; postgresDatabases = []; sqliteDatabases = { grafana = "/var/lib/grafana/data/grafana.db"; }; timerConfig = { OnCalendar = "00:10"; }; pruneOpts = ["--keep-daily 30" "--keep-weekly 8" "--keep-monthly 12"]; }; # Open ports in the firewall. networking.firewall.allowedTCPPorts = [ # Enabling openssh automatically opens its port in the firewall. # For all other services we need to manually list the ports here. 80 443 ]; networking.firewall.allowedUDPPorts = []; # This option defines the first version of NixOS you have installed on this particular machine, # and is used to maintain compatibility with application data (e.g. databases) created on older NixOS versions. # # Most users should NEVER change this value after the initial install, for any reason, # even if you've upgraded your system to a new NixOS release. # # This value does NOT affect the Nixpkgs version your packages and OS are pulled from, # so changing it will NOT upgrade your system - see https://nixos.org/manual/nixos/stable/#sec-upgrading for how # to actually do that. # # This value being lower than the current NixOS release does NOT mean your system is # out of date, out of support, or vulnerable. # # Do NOT change this value unless you have manually inspected all the changes it would make to your configuration, # and migrated your data accordingly. # # For more information, see `man configuration.nix` or https://nixos.org/manual/nixos/stable/options#opt-system.stateVersion . system.stateVersion = "24.11"; # Did you read the comment? }