about summary refs log tree commit diff
path: root/users/tazjin/nixos/koptevo/default.nix
# NUC in my closet.
_: # ignore readTree options

{ config, depot, lib, pkgs, ... }:

let
  mod = name: depot.path.origSrc + ("/ops/modules/" + name);
  usermod = name: depot.path.origSrc + ("/users/tazjin/nixos/modules/" + name);
in
{
  imports = [
    (mod "quassel.nix")
    (mod "www/base.nix")
    (usermod "airsonic.nix")
    (usermod "geesefs.nix")
    (usermod "homepage.nix")
    (usermod "miniflux.nix")
    (usermod "predlozhnik.nix")
    (usermod "tgsa.nix")
    (depot.third_party.agenix.src + "/modules/age.nix")
  ];

  boot = {
    loader.systemd-boot.enable = true;
    loader.efi.canTouchEfiVariables = true;
    initrd.availableKernelModules = [ "ahci" "xhci_pci" "usb_storage" "sd_mod" "sdhci_pci" ];
    kernelModules = [ "kvm-intel" ];
    kernelParams = [ "nomodeset" ];
  };

  nix.settings.trusted-users = [ "tazjin" ];

  fileSystems = {
    "/" = {
      device = "rpool/root";
      fsType = "zfs";
    };

    "/boot" = {
      device = "/dev/disk/by-uuid/E214-E6B3";
      fsType = "vfat";
    };

    "/var" = {
      device = "rpool/var";
      fsType = "zfs";
    };

    "/home" = {
      device = "rpool/home";
      fsType = "zfs";
    };
  };

  hardware.cpu.intel.updateMicrocode = true;
  hardware.enableRedistributableFirmware = true;
  services.fwupd.enable = true;

  networking = {
    hostName = "koptevo";
    hostId = "07bbbf4f";
    domain = "tazj.in";
    useDHCP = true;
    firewall.enable = true;
    firewall.allowedTCPPorts = [ 22 80 443 8776 9443 ];

    wireless.enable = true;
    wireless.networks."How do I computer fast?" = {
      psk = "washyourface";
    };
  };

  time.timeZone = "UTC";

  security.acme = {
    acceptTerms = true;
    defaults.email = lib.mkForce "acme@tazj.in";

    # wildcard cert for usage with Yggdrasil services
    certs."y.tazj.in" = {
      dnsProvider = "yandexcloud";
      credentialFiles.YANDEX_CLOUD_IAM_TOKEN_FILE = "/run/agenix/lego-yandex";
      extraDomainNames = [ "*.y.tazj.in" ];

      # folder tvl/tazjin-private/default
      environmentFile = builtins.toFile "lego-yandex-env" ''
        YANDEX_CLOUD_FOLDER_ID=b1gq41rsbggeum4qafnh
      '';
    };
  };

  programs.fish.enable = true;

  users.users.tazjin = {
    isNormalUser = true;
    extraGroups = [ "wheel" "docker" "systemd-journal" ];
    shell = pkgs.fish;
    openssh.authorizedKeys.keys = depot.users.tazjin.keys.all;
  };

  users.users.nginx.extraGroups = [ "acme" ];

  age.secrets =
    let
      secretFile = name: depot.users.tazjin.secrets."${name}.age";
    in
    {
      lego-yandex.file = secretFile "lego-yandex";
      tgsa-yandex.file = secretFile "tgsa-yandex";
    };

  security.sudo.wheelNeedsPassword = false;

  services.openssh.enable = true;

  services.depot.quassel = {
    enable = true;
    acmeHost = "koptevo.tazj.in";
    bindAddresses = [
      "0.0.0.0"
      "::"
    ];
  };

  services.tailscale = {
    enable = true;
    useRoutingFeatures = "server"; # for exit-node usage
  };

  # Automatically collect garbage from the Nix store.
  services.depot.automatic-gc = {
    enable = true;
    interval = "daily";
    diskThreshold = 15; # GiB
    maxFreed = 10; # GiB
    preserveGenerations = "14d";
  };

  services.nginx.virtualHosts."koptevo.tazj.in" = {
    addSSL = true;
    enableACME = true;

    extraConfig = ''
      location = / {
        return 302 https://at.tvl.fyi/?q=%2F%2Fusers%2Ftazjin%2Fnixos%2Fkoptevo%2Fdefault.nix;
      }
    '';
  };

  # I don't use the podcast nor playlist feature,
  # but I *have to* supply podcasts to gonic ...
  systemd.tmpfiles.rules = [
    "d /tmp/fake-podcasts 0555 nobody nobody -"
    "d /tmp/fake-playlists 0555 nobody nobody -"
  ];

  services.gonic = {
    enable = true;
    settings = {
      listen-addr = "0.0.0.0:4747";
      scan-interval = 5;
      scan-at-start-enabled = true;
      podcast-path = [ "/tmp/fake-podcasts" ];
      playlists-path = [ "/tmp/fake-playlists" ];
      music-path = [ "/var/lib/geesefs/tazjins-files/music" ];
    };
  };

  # hack to work around the strict sandboxing of the gonic module
  # breaking DNS resolution
  systemd.services.gonic.serviceConfig.BindReadOnlyPaths = [
    "-/etc/resolv.conf"
  ];

  # add a hard dependency on the FUSE mount
  systemd.services.gonic.requires = [ "geesefs.service" ];

  services.nginx.virtualHosts."music.tazj.in" = {
    addSSL = true;
    enableACME = true;

    locations."/" = {
      proxyPass = "http://127.0.0.1:4747";
    };
  };

  # List packages installed in system profile. To search, run:
  # $ nix search wget
  environment.systemPackages = with pkgs; [
    bat
    curl
    emacs-nox
    htop
    jq
    nano
    nmap
    radicle-node
    wget
  ];

  # configure Yggdrasil network
  services.yggdrasil = {
    enable = true;
    persistentKeys = true;
    openMulticastPort = true;

    settings = {
      Listen = [ "tls://[::]:9443" ]; # yggd
      IfName = "ygg0";
      Peers = [
        "quic://ygg-msk-1.averyan.ru:8364"
        "tls://ekb.itrus.su:7992"
        "tls://s-mow-1.sergeysedoy97.ru:65534"
      ];

      MulticastInterfaces = [{
        Regex = "enp.*";
        Beacon = true;
        Listen = true;
        Port = 0;
      }];

      AllowedPublicKeys = [
        "573fd89392e2741ead4edd85034c91c88f1e560d991bbdbf1fccb6233db4d325" # khamovnik
        "a56300c3af1ad54840f4b38b9438e3c108a0aa0fd72793dc7d6bd57325c6d691" # zamalek
        "152b658f8a3e0cd6d1486c3cb984795ec7c9a02274c9f096bd2045cabf8bfa92" # A9
        "550f4920592d2831d013fd1c83ba9ad174ec352273260fd5d7c2627dbe60d097" # matepad
      ];
    };
  };

  # TODO(tazjin): move this to a module for radicle stuff
  services.radicle = {
    enable = true;
    publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILHs6jSvMdtu9oJCt48etEs8ExjfGY5PmWQsRzFleogS";
    privateKeyFile = "/etc/secrets/radicle"; # TODO: to manage, or not to manage ...

    settings = {
      web.pinned.repositories = [
        "rad:z3r5zMi9U3az3i4cPKxMcA3K7xx9L" # depot
        "rad:z2mdnBK1tX6pibdBfRct3ThCgheHu" # tvix-go
      ];

      node = {
        alias = "rad.tazj.in";
        seedingPolicy.default = "block";
      };
    };

    node = {
      openFirewall = true;
      listenAddress = "[::]";
    };

    httpd = {
      enable = true;
      listenAddress = "127.0.0.1";
      listenPort = 7235; # radl
    };
  };

  services.nginx.virtualHosts."rad.tazj.in" = {
    enableACME = true;
    forceSSL = true;
    locations."/".proxyPass = "http://127.0.0.1:7235";
  };

  services.nginx.virtualHosts."rad.y.tazj.in" = {
    enableSSL = true;
    useACMEHost = "y.tazj.in";
    locations = config.services.nginx.virtualHosts."rad.tazj.in".locations;
  };

  services.nginx.virtualHosts."src.tazj.in" = {
    enableACME = true;
    forceSSL = true;
    root = depot.third_party.radicle-explorer.withPreferredSeeds [{
      hostname = "rad.tazj.in";
      port = 443;
      scheme = "https";
    }];

    locations."/" = {
      index = "index.html";
      extraConfig = ''
        try_files $uri $uri/ /index.html;
      '';
    };
  };

  services.nginx.virtualHosts."src.y.tazj.in" = {
    enableSSL = true;
    useACMEHost = "y.tazj.in";
    root = depot.third_party.radicle-explorer.withPreferredSeeds [{
      hostname = "rad.y.tazj.in";
      port = 443;
      scheme = "https";
    }];

    locations = config.services.nginx.virtualHosts."src.tazj.in".locations;
  };

  programs.mtr.enable = true;
  programs.mosh.enable = true;
  zramSwap.enable = true;

  system.stateVersion = "23.05";
}