diff --git a/os/linux/nix/flake.nix b/os/linux/nix/flake.nix new file mode 100644 index 0000000..86547af --- /dev/null +++ b/os/linux/nix/flake.nix @@ -0,0 +1,36 @@ +# Welcome to my nix config! I'm just getting started with flakes, so please +# forgive the mess. + +# TODO: would be nice to get hardware congigs in here as well + +# TODO: declarative disks with https://github.com/nix-community/disko +# TODO: home-manager? + + +{ + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-23.05"; + + home-manager = { + url = "github:nix-community/home-manager/release-23.05"; + + # use the version of nixpkgs we specified above rather than the one HM would ordinarily use + inputs.nixpkgs.follows = "nixpkgs"; + }; + }; + + outputs = inputs: { + nixosConfigurations = { + beefcake = inputs.nixpkgs.lib.nixosSystem { + system = "x86_64-linux"; + modules = [ + ./machines/beefcake.nix + inputs.home-manager.nixosModules.home-manager + { + home-manager.useGlobalPkgs = true; + } + ]; + }; + }; + }; +} diff --git a/os/linux/nix/init.d.fish b/os/linux/nix/init.d.fish deleted file mode 100644 index 4ea06d3..0000000 --- a/os/linux/nix/init.d.fish +++ /dev/null @@ -1,5 +0,0 @@ -symlink_nixos_config() { - rm --force "/etc/nixos/lytedev" - ln --symbolic "$1" "/etc/nixos/lytedev" -} - diff --git a/os/linux/nix/lyte-nixos-cleanup b/os/linux/nix/lyte-nixos-cleanup deleted file mode 100755 index 91a4f8c..0000000 --- a/os/linux/nix/lyte-nixos-cleanup +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/env bash - -sudo nix-collect-garbage -d -sudo nixos-rebuild switch diff --git a/os/linux/nix/machines/beefcake.nix b/os/linux/nix/machines/beefcake.nix new file mode 100644 index 0000000..ebc18ba --- /dev/null +++ b/os/linux/nix/machines/beefcake.nix @@ -0,0 +1,512 @@ +# Edit this configuration file to define what should be installed on +# your system. Help is available in the configuration.nix(5) man page +# and in the NixOS manual (accessible by running 'nixos-help'). + +{ pkgs, ... }: +let + unstable = import { config = { allowUnfree = true; }; }; +in +{ + nix.settings.experimental-features = [ "nix-command" "flakes" ]; + imports = + [ + ./hardware-configuration.nix + ]; + + # TODO: directory attributes for /storage subdirectories? + # example: user daniel should be able to write to /storage/files.lyte.dev and + # caddy should be able to serve it + + # TODO: declarative directory quotas? for storage/$USER and /home/$USER + + # TODO: would be nice to get ALL the storage stuff declared in here + # should I be using btrfs subvolumes? can I capture file ownership, perimssions, and ACLs? + + boot.loader.systemd-boot.enable = true; + boot.loader.efi.canTouchEfiVariables = true; + + systemd.tmpfiles.rules = [ + "d /var/spool/samba 1777 root root -" + ]; + + networking.hostName = "beefcake"; + + time.timeZone = "America/Chicago"; + + i18n.defaultLocale = "en_US.UTF-8"; + console = { + font = "Lat2-Terminus16"; + keyMap = "us"; + }; + + users.groups.daniel.members = [ "daniel" ]; + users.groups.nixadmin.members = [ "daniel" ]; + + users.users.daniel = { + isNormalUser = true; + openssh.authorizedKeys.keys = [ + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAPLXOjupz3ScYjgrF+ehrbp9OvGAWQLI6fplX6w9Ijb daniel@lyte.dev" + ]; + group = "daniel"; + extraGroups = [ + "nixadmin" # write access to /etc/nixos/ files + "wheel" # sudo access + "caddy" # write access to /storage/files.lyte.dev + "users" # general users group + "jellyfin" # write access to /storage/jellyfin + ]; + # packages = with pkgs; []; + }; + + users.users.lytedev = { + # for running my services and applications and stuff + isNormalUser = true; + openssh.authorizedKeys.keys = [ + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAPLXOjupz3ScYjgrF+ehrbp9OvGAWQLI6fplX6w9Ijb daniel@lyte.dev" + ]; + group = "lytedev"; + extraGroups = [ + ]; + }; + + users.users.restic = { + # used for other machines to backup to + isNormalUser = true; + openssh.authorizedKeys.keys = [ + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJbPqzKB09U+i4Kqu136yOjflLZ/J7pYsNulTAd4x903 root@chromebox.h.lyte.dev" + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAPLXOjupz3ScYjgrF+ehrbp9OvGAWQLI6fplX6w9Ijb daniel@lyte.dev" + ]; + }; + + users.users.guest = { + isSystemUser = true; + group = "user"; + createHome = true; + }; + + programs.fish.enable = true; + users.defaultUserShell = pkgs.fish; + + environment.variables = { + EDITOR = "hx"; + }; + + # TODO: right now, I use a flake for helix that gets the latest since my config uses newer features + # would be nice to get that declared here + + # search for packages: `nix search $PACKAGE_NAME` + environment.systemPackages = with pkgs; [ + unstable.helix + unstable.zellij + mosh + btrfs-progs + iperf3 + pv + linuxquota + traceroute + hexyl + restic + speedtest-cli + fish + restic + nil + nixpkgs-fmt + fd + ripgrep + exa + skim + git + wget + tmux + sqlite + ]; + + services.xserver.layout = "us"; + + # TODO: make the client declarative? right now I think it's manually git + # clone'd to /root + systemd.services.deno-netlify-ddns-client = { + serviceConfig.Type = "oneshot"; + path = with pkgs; [ curl bash ]; + environment = { + NETLIFY_DDNS_RC_FILE = "/root/deno-netlify-ddns-client/.env"; + }; + script = '' + bash /root/deno-netlify-ddns-client/netlify-ddns-client.sh + ''; + }; + systemd.timers.deno-netlify-ddns-client = { + wantedBy = [ "timers.target" ]; + partOf = [ "deno-netlify-ddns-client.service" ]; + timerConfig = { + OnBootSec = "10sec"; + OnUnitActiveSec = "5min"; + Unit = "deno-netlify-ddns-client.service"; + }; + }; + + services.smartd.enable = true; + services.caddy = { + enable = true; + adapter = "caddyfile"; + # acmeCA = "https://acme-staging-v02.api.letsencrypt.org/directory"; + configFile = pkgs.writeText "Caddyfile" '' + video.lyte.dev { + reverse_proxy :8096 + } + + bw.lyte.dev { + reverse_proxy :8222 + } + + a.lyte.dev { + reverse_proxy :8899 + } + + git.lyte.dev { + reverse_proxy :3088 + } + + files.lyte.dev { + file_server browse { + root /storage/files.lyte.dev + } + } + + # proxy everything else to chromebox + :80 { + reverse_proxy 10.0.0.5:80 + } + + :443 { + reverse_proxy 10.0.0.5:443 + } + ''; + }; + + services.vaultwarden = { + enable = true; + config = { + DOMAIN = "https://bw.lyte.dev"; + SIGNUPS_ALLOWED = "false"; + ROCKET_ADDRESS = "127.0.0.1"; + ROCKET_PORT = 8222; + }; + }; + + services.gitea = { + enable = true; + appName = "git.lyte.dev"; + stateDir = "/storage/gitea"; + settings = { + server = { + ROOT_URL = "https://git.lyte.dev"; + HTTP_ADDR = "127.0.0.1"; + HTTP_PORT = 3088; + DOMAIN = "git.lyte.dev"; + }; + service = { + DISABLE_REGISTRATION = true; + }; + session = { + COOKIE_SECURE = true; + }; + log = { + # TODO: raise the log level + LEVEL = "Debug"; + }; + }; + lfs = { + enable = true; + }; + dump = { + enable = true; + }; + database = { + # TODO: move to postgres? + type = "sqlite3"; + }; + }; + + # TODO: ensure we're not doing the same dumb thing we were doing on the old host and eating storage + services.clickhouse.enable = true; + + services.plausible = { + enable = false; # TODO: enable this and fix access? probably need a proper secrets management system that integrates with nix (sops-nix?) + # otherwise we can probably chown these files to a group that plausible has access to for reading + releaseCookiePath = "/root/plausible-erlang-cookie"; + database = { + clickhouse.setup = true; + postgres.setup = true; + }; + server = { + baseUrl = "http://beefcake.hare-cod.ts.net:8899"; + disableRegistration = true; + port = 8899; + secretKeybaseFile = "/root/plusible-secret-key-base"; + }; + adminUser = { + activate = true; + email = "daniel@lyte.dev"; + passwordFile = "/root/plausible-admin-password"; + }; + }; + + services.postgresql = { + enable = true; + ensureDatabases = [ "daniel" "plausible" ]; + ensureUsers = [ + { + name = "daniel"; + ensurePermissions = { + "DATABASE daniel" = "ALL PRIVILEGES"; + }; + } + { + name = "plausible"; + ensurePermissions = { + "DATABASE plausible" = "ALL PRIVILEGES"; + }; + } + ]; + dataDir = "/storage/postgres"; + enableTCPIP = true; + + package = unstable.postgresql_15; + + authentication = pkgs.lib.mkOverride 10 '' + #type database DBuser auth-method + local all postgres peer map=superuser_map + local sameuser all peer map=superuser_map + local plausible plausible peer map=superuser_map + + # lan ipv4 + host all all 10.0.0.0/24 trust + + # tailnet ipv4 + host all all 100.64.0.0/10 trust + ''; + + identMap = '' + # ArbitraryMapName systemUser DBUser + superuser_map root postgres + superuser_map postgres postgres + superuser_map daniel postgres + # Let other names login as themselves + superuser_map /^(.*)$ \1 + ''; + }; + + services.postgresqlBackup = { + enable = true; + backupAll = true; + compression = "none"; # hoping for deduplication here? + location = "/storage/postgres-backups"; + startAt = "*-*-* 03:00:00"; + }; + + services.tailscale = { + enable = true; + package = unstable.tailscale; + }; + + services.jellyfin = { + enable = true; + openFirewall = true; + # uses port 8096 by default, configurable from admin UI + }; + + # NOTE: this server's xeon chips DO NOT seem to support quicksync or graphics in general + # but I can probably throw in a crappy GPU (or a big, cheap ebay GPU for ML + # stuff, too?) and get good transcoding performance + + # jellyfin hardware encoding + # hardware.opengl = { + # enable = true; + # extraPackages = with pkgs; [ + # intel-media-driver + # vaapiIntel + # vaapiVdpau + # libvdpau-va-gl + # intel-compute-runtime + # ]; + # }; + # nixpkgs.config.packageOverrides = pkgs: { + # vaapiIntel = pkgs.vaapiIntel.override { enableHybridCodec = true; }; + # }; + + services.openssh = { + enable = true; + settings = { + PasswordAuthentication = false; + }; + listenAddresses = [ + { addr = "0.0.0.0"; port = 64022; } + { addr = "0.0.0.0"; port = 22; } + ]; + }; + + services.samba-wsdd.enable = true; + + services.samba = { + enable = true; + openFirewall = true; + securityType = "user"; + package = pkgs.sambaFull; + + extraConfig = '' + workgroup = WORKGROUP + server string = beefcake + netbios name = beefcake + security = user + #use sendfile = yes + #max protocol = smb2 + # note: localhost is the ipv6 localhost ::1 + hosts allow = 10. 192.168.0. 127.0.0.1 localhost + hosts deny = 0.0.0.0/0 + guest account = nobody + map to guest = bad user + load printers = yes + printing = cups + printcap name = cups + ''; + shares = { + libre = { + path = "/storage/libre"; + browseable = "yes"; + "read only" = "no"; + "guest ok" = "yes"; + "create mask" = "0666"; + "directory mask" = "0777"; + "force user" = "nobody"; + "force group" = "users"; + }; + public = { + path = "/storage/public"; + browseable = "yes"; + "read only" = "no"; + "guest ok" = "yes"; + "create mask" = "0664"; + "directory mask" = "0775"; + "force user" = "nobody"; + "force group" = "users"; + }; + family = { + path = "/storage/family"; + browseable = "yes"; + "read only" = "no"; + "guest ok" = "no"; + "create mask" = "0664"; + "directory mask" = "0775"; + "force user" = "nobody"; + "force group" = "family"; + }; + daniel = { + path = "/storage/daniel"; + browseable = "yes"; + "read only" = "no"; + "guest ok" = "no"; + "create mask" = "0640"; + "directory mask" = "0750"; + "force user" = "daniel"; + "force group" = "users"; + }; + printers = { + comment = "All Printers"; + path = "/var/spool/samba"; + public = "yes"; + browseable = "yes"; + # to allow user 'guest account' to print. + "guest ok" = "yes"; + writable = "no"; + printable = "yes"; + "create mode" = 0700; + }; + }; + }; + + # paths: + # TODO: move previous backups over and put here + # clickhouse and plausible analytics once they're up and running? + + services.restic.backups = rec { + local = { + initialize = true; + passwordFile = "/root/restic-localbackup-password"; + paths = [ + "/storage/files.lyte.dev" + "/storage/daniel" + "/storage/gitea" # TODO: should maybe use configuration.nix's services.gitea.dump ? + "/var/lib/bitwarden_rs" # does this need any sqlite preprocessing? + # https://github.com/dani-garcia/vaultwarden/wiki/Backing-up-your-vault + # specifically, https://github.com/dani-garcia/vaultwarden/wiki/Backing-up-your-vault#sqlite-database-files + + "/storage/postgres-backups" + ]; + exclude = [ ]; + repository = "/storage/backups/local"; + }; + rascal = { + initialize = true; + extraOptions = [ + "sftp.command='ssh beefcake@rascal -i /root/.ssh/id_ed25519 -s sftp'" + ]; + passwordFile = local.passwordFile; + paths = local.paths; + repository = "sftp://beefcake@rascal://storage/backups/beefcake"; + timerConfig = { + OnCalendar = "04:45"; + }; + }; + # TODO: add ruby? + benland = { + initialize = true; + extraOptions = [ + "sftp.command='ssh daniel@n.benhaney.com -p 10022 -i /root/.ssh/id_ed25519 -s sftp'" + ]; + passwordFile = local.passwordFile; + paths = local.paths; + repository = "sftp://daniel@n.benhaney.com://storage/backups/beefcake"; + timerConfig = { + OnCalendar = "04:45"; + }; + }; + }; + + networking.firewall.allowedTCPPorts = [ + 80 # http (caddy) + 443 # https (caddy) + # 5357 # ??? + 22 # ssh + 64022 # ssh (for ben?) + ]; + networking.firewall.allowedUDPPorts = [ + # 53 # DNS + # 3702 # ??? + 64020 # mosh (for ben?) + ]; + networking.firewall.allowedUDPPortRanges = [ + { + # mosh + from = 60000; + to = 60010; + } + ]; + + networking.firewall = { + enable = true; + allowPing = true; + checkReversePath = "loose"; # needed for tailscale? + }; + + # TODO: should I upgrade this? + + # This value determines the NixOS release from which the default + # settings for stateful data, like file locations and database versions + # on your system were taken. It's perfectly fine and recommended to leave + # this value at the release version of the first install of this system. + # Before changing this value read the documentation for this option + # (e.g. man configuration.nix or on https://nixos.org/nixos/options.html). + system.stateVersion = "22.05"; # Did you read the comment? +} +