nixos-config

NixOS configs for my systems
Log | Files | Refs

default.nix (9489B)


      1 {
      2   config,
      3   lib,
      4   pkgs,
      5   inputs,
      6   ...
      7 }:
      8 
      9 {
     10   imports = [
     11     ./hardware.nix
     12   ];
     13 
     14   # decrypt agenix secrets
     15   age.secrets = {
     16     email_vinbiz.file = ../../secrets/email_vinbiz.age;
     17     email_vineetk.file = ../../secrets/email_vineetk.age;
     18     email_13f0.file = ../../secrets/email_13f0.age;
     19 
     20     hetzner_dns = {
     21       file = ../../secrets/hetzner_dns.age;
     22       owner = "root";
     23       group = "root";
     24     };
     25 
     26     radicale_users = {
     27       file = ../../secrets/radicale_users.age;
     28       owner = "radicale";
     29     };
     30 
     31     tailscale_saklas = {
     32       file = ../../secrets/tailscale_saklas.age;
     33       owner = "root";
     34       group = "root";
     35     };
     36   };
     37 
     38   # disable wifi and open some ports
     39   networking = {
     40     hostName = "saklas";
     41     hostId = "b0bababe";
     42     useDHCP = false;
     43 
     44     wireless.enable = false;
     45 
     46     firewall = {
     47       allowedTCPPorts = [
     48         22
     49         80
     50         443
     51         5222
     52         5269
     53       ];
     54       allowedUDPPorts = [
     55         3478
     56         51820
     57       ];
     58     };
     59   };
     60 
     61   systemd.network = {
     62     enable = true;
     63     networks."10-wan" = {
     64       matchConfig.Name = "enp1s0";
     65       networkConfig.DHCP = "no";
     66       address = [
     67         "95.217.18.52/32"
     68         "2a01:4f9:c010:a653::1/64"
     69       ];
     70       dns = [
     71         "185.12.64.1"
     72         "185.12.64.2"
     73       ];
     74       routes = [
     75         { Destination = "172.31.1.1"; }
     76         {
     77           Gateway = "172.31.1.1";
     78           GatewayOnLink = true;
     79         }
     80       ];
     81     };
     82   };
     83 
     84   # Set your time zone.
     85   time.timeZone = "America/Toronto";
     86 
     87   # Select internationalisation properties.
     88   i18n.defaultLocale = "en_US.UTF-8";
     89   console = {
     90     font = "Lat2-Terminus16";
     91   };
     92 
     93   # enable flakes and nix cli
     94   nix.settings.experimental-features = [
     95     "nix-command"
     96     "flakes"
     97   ];
     98 
     99   # user accounts
    100   users.users.root.openssh.authorizedKeys.keys = [
    101     "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEvM0xCLziR+ZT/SYE1aZM6dklbw4fEC17TWqbADIZRH kou@demiurge"
    102   ];
    103 
    104   users.users.vin = {
    105     isNormalUser = true;
    106 
    107     extraGroups = [
    108       "nginx"
    109       "wheel"
    110     ];
    111 
    112     shell = pkgs.zsh;
    113 
    114     openssh.authorizedKeys.keys = [
    115       "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEvM0xCLziR+ZT/SYE1aZM6dklbw4fEC17TWqbADIZRH kou@demiurge"
    116     ];
    117   };
    118 
    119   # default packages for both me and root
    120   environment = {
    121     systemPackages = with pkgs; [
    122       doas-sudo-shim
    123       gitMinimal
    124       htop
    125       ncdu
    126       wget
    127     ];
    128 
    129     pathsToLink = [ "/share/zsh" ];
    130   };
    131 
    132   programs = {
    133     # disable nano. I don't like nano.
    134     nano.enable = false;
    135 
    136     # configuration in home-manager
    137     zsh.enable = true;
    138     zsh.promptInit = "PS1='$ '";
    139   };
    140 
    141   security = {
    142     # TLS
    143     acme = {
    144       acceptTerms = true;
    145 
    146       defaults = {
    147         credentialFiles."HETZNER_API_KEY_FILE" = config.age.secrets.hetzner_dns.path;
    148         dnsProvider = "hetzner";
    149         email = "acme@vineetk.net";
    150         server = "https://acme-v02.api.letsencrypt.org/directory";
    151       };
    152 
    153       certs = {
    154         "vinbiz.ca".extraDomainNames = [ "*.vinbiz.ca" ];
    155         "vineetk.net".extraDomainNames = [ "*.vineetk.net" ];
    156         "13f0.net".extraDomainNames = [ "*.13f0.net" ];
    157 
    158         "xmpp.vineetk.net" = {
    159           group = config.services.prosody.group;
    160           extraDomainNames = [
    161             "vineetk.net"
    162             "muc.vineetk.net"
    163             "u.vineetk.net"
    164           ];
    165           reloadServices = [ "prosody" ];
    166         };
    167       };
    168     };
    169 
    170     # I prefer doas over sudo for simplicity
    171     doas = {
    172       enable = true;
    173       extraRules = [
    174         {
    175           users = [ "vin" ];
    176           keepEnv = true;
    177           persist = true;
    178         }
    179       ];
    180     };
    181 
    182     sudo.enable = false;
    183   };
    184 
    185   services = {
    186     # git
    187     cgit."git.vineetk.net" = {
    188       enable = true;
    189       scanPath = "/var/lib/git";
    190     };
    191 
    192     # VPN
    193     headscale = {
    194       enable = true;
    195       address = "127.0.0.1";
    196       port = 8080;
    197       settings = {
    198         server_url = "https://headscale.13f0.net";
    199         dns = {
    200           base_domain = "epistemia";
    201           extra_records = [
    202             {
    203               name = "invidious.demiurge.epistemia";
    204               type = "A";
    205               value = "100.64.0.2";
    206             }
    207             {
    208               name = "llm.demiurge.epistemia";
    209               type = "A";
    210               value = "100.64.0.2";
    211             }
    212             {
    213               name = "navidrome.demiurge.epistemia";
    214               type = "A";
    215               value = "100.64.0.2";
    216             }
    217             {
    218               name = "redlib.demiurge.epistemia";
    219               type = "A";
    220               value = "100.64.0.2";
    221             }
    222             {
    223               name = "sdui.demiurge.epistemia";
    224               type = "A";
    225               value = "100.64.0.2";
    226             }
    227             {
    228               name = "searx.demiurge.epistemia";
    229               type = "A";
    230               value = "100.64.0.2";
    231             }
    232           ];
    233         };
    234         logtail.enabled = false;
    235       };
    236     };
    237 
    238     tailscale = {
    239       enable = true;
    240       authKeyFile = config.age.secrets.tailscale_saklas.path;
    241       extraDaemonFlags = [ "--no-logs-no-support" ];
    242       extraUpFlags = [ "--login-server=https://headscale.13f0.net" ];
    243       openFirewall = true;
    244     };
    245 
    246     # XMPP
    247     prosody = {
    248       enable = true;
    249 
    250       admins = [ "vin@vineetk.net" ];
    251       httpFileShare.domain = "u.vineetk.net";
    252 
    253       ssl.cert = config.security.acme.certs."xmpp.vineetk.net".directory + "/full.pem";
    254       ssl.key = config.security.acme.certs."xmpp.vineetk.net".directory + "/key.pem";
    255 
    256       muc = [ { domain = "muc.vineetk.net"; } ];
    257       virtualHosts.vineetk = {
    258         domain = "vineetk.net";
    259         enabled = true;
    260       };
    261     };
    262 
    263     # web server and reverse proxy
    264     nginx = {
    265       enable = true;
    266 
    267       recommendedGzipSettings = true;
    268       recommendedOptimisation = true;
    269       recommendedProxySettings = true;
    270       recommendedTlsSettings = true;
    271       recommendedZstdSettings = true;
    272 
    273       virtualHosts = {
    274         "vineetk.net" = {
    275           enableACME = true;
    276           forceSSL = true;
    277           default = true;
    278           locations."/" = {
    279             index = "index.html";
    280             root = "/var/www/vineetk_html";
    281           };
    282         };
    283 
    284         "radicale.vineetk.net" = {
    285           useACMEHost = "vineetk.net";
    286           forceSSL = true;
    287           locations."/" = {
    288             proxyPass = "http://127.0.0.1:5232/";
    289             extraConfig = ''
    290               proxy_pass_header Authorization;
    291             '';
    292           };
    293         };
    294 
    295         "git.vineetk.net" = {
    296           useACMEHost = "vineetk.net";
    297           forceSSL = true;
    298           locations."/".proxyPass = "http://127.0.0.1:3000/";
    299         };
    300 
    301         "13f0.net" = {
    302           enableACME = true;
    303           forceSSL = true;
    304           locations."/" = {
    305             index = "index.html";
    306             root = "/var/www/13f0_html";
    307           };
    308         };
    309 
    310         "headscale.13f0.net" = {
    311           useACMEHost = "13f0.net";
    312           forceSSL = true;
    313           locations."/" = {
    314             proxyPass = "http://127.0.0.1:8080";
    315             proxyWebsockets = true;
    316           };
    317         };
    318 
    319         "vinbiz.ca" = {
    320           enableACME = true;
    321           forceSSL = true;
    322           locations."/" = {
    323             index = "index.html";
    324             root = "/var/www/vinbiz_html";
    325           };
    326         };
    327       };
    328     };
    329 
    330     # CalDAV and CardDAV
    331     radicale = {
    332       enable = true;
    333       settings = {
    334         server.hosts = [ "127.0.0.1:5232" ];
    335         auth = {
    336           type = "htpasswd";
    337           htpasswd_filename = config.age.secrets.radicale_users.path;
    338           htpasswd_encryption = "bcrypt";
    339         };
    340       };
    341     };
    342 
    343     # SSH
    344     # first use tarpit
    345     endlessh = {
    346       enable = true;
    347       port = 22;
    348       openFirewall = true;
    349     };
    350 
    351     # fail2ban if skiddie uses different port
    352     fail2ban = {
    353       enable = true;
    354       ignoreIP = [
    355         "35.142.66.239/20"
    356         "45.134.142.0/24"
    357       ];
    358     };
    359 
    360     # normal openssh
    361     openssh = {
    362       enable = true;
    363       ports = [ 2222 ];
    364 
    365       settings = {
    366         KbdInteractiveAuthentication = false;
    367         PasswordAuthentication = false;
    368         PermitRootLogin = "prohibit-password";
    369         X11Forwarding = true;
    370       };
    371     };
    372   };
    373 
    374   # email via simple-nixos-mailserver
    375   mailserver = {
    376     enable = true;
    377     fqdn = "mail.vineetk.net";
    378     domains = [
    379       "vineetk.net"
    380       "vinbiz.ca"
    381       "13f0.net"
    382     ];
    383 
    384     # A list of all login accounts. To create the password hashes, use
    385     # nix-shell -p mkpasswd --run 'mkpasswd -sm bcrypt'
    386     loginAccounts = {
    387       "vineet@vineetk.net" = {
    388         hashedPasswordFile = config.age.secrets.email_vineetk.path;
    389         aliases = [ "@vineetk.net" ];
    390       };
    391 
    392       "kar@13f0.net" = {
    393         hashedPasswordFile = config.age.secrets.email_13f0.path;
    394         aliases = [ "@13f0.net" ];
    395       };
    396 
    397       "vineet@vinbiz.ca" = {
    398         hashedPasswordFile = config.age.secrets.email_vinbiz.path;
    399         aliases = [ "postmaster@vinbiz.ca" ];
    400       };
    401       "suresh@vinbiz.ca".hashedPasswordFile = config.age.secrets.email_vinbiz.path;
    402       "revathy@vinbiz.ca".hashedPasswordFile = config.age.secrets.email_vinbiz.path;
    403       "suren@vinbiz.ca".hashedPasswordFile = config.age.secrets.email_vinbiz.path;
    404     };
    405 
    406     acmeCertificateName = "vineetk.net";
    407     certificateScheme = "acme";
    408   };
    409 
    410   # create caches and use mandoc
    411   documentation.man = {
    412     enable = true;
    413     generateCaches = true;
    414     man-db.enable = false;
    415     mandoc.enable = true;
    416   };
    417 
    418   system.stateVersion = "24.11";
    419 }