diff options
author | tdback <tyler@tdback.net> | 2024-12-21 15:32:13 -0500 |
---|---|---|
committer | tdback <tyler@tdback.net> | 2024-12-21 15:32:13 -0500 |
commit | 0a5754541bb01e96021ca7ee74f1256a8ee68bc4 (patch) | |
tree | 2d0b8089e98239963a1e240cff676b1515fc8431 /modules |
initial commit to self-hosted git
Diffstat (limited to 'modules')
43 files changed, 1310 insertions, 0 deletions
diff --git a/modules/containers/freshrss/default.nix b/modules/containers/freshrss/default.nix new file mode 100644 index 0000000..3854a8e --- /dev/null +++ b/modules/containers/freshrss/default.nix @@ -0,0 +1,30 @@ +{ lib, ... }: +let + directory = "/opt/freshrss"; + port = "8888"; +in +{ + systemd.tmpfiles.rules = + map (x: "d ${x} 0755 share share - -") (lib.lists.singleton directory); + + virtualisation.oci-containers.containers.freshrss = { + image = "freshrss/freshrss:latest"; + autoStart = true; + ports = [ + "${port}:80" + ]; + volumes = [ + "${directory}/data:/var/www/FreshRSS/data" + "${directory}/extensions:/var/www/FreshRSS/extensions" + ]; + environment = { + TZ = "America/Detroit"; + CRON_MIN = "*/20"; + }; + }; + + services.caddy.virtualHosts."fresh.brownbread.net".extraConfig = '' + encode zstd gzip + reverse_proxy http://localhost:${port} + ''; +} diff --git a/modules/containers/jellyfin/default.nix b/modules/containers/jellyfin/default.nix new file mode 100644 index 0000000..96b6deb --- /dev/null +++ b/modules/containers/jellyfin/default.nix @@ -0,0 +1,27 @@ +{ lib, ... }: +let + directory = "/opt/jellyfin"; +in +{ + systemd.tmpfiles.rules = + map (x: "d ${x} 0755 share share - -") (lib.lists.singleton directory); + + virtualisation.oci-containers.containers.jellyfin = { + image = "jellyfin/jellyfin:latest"; + autoStart = true; + user = "994:994"; + ports = [ + "8096:8096/tcp" + ]; + volumes = [ + "${directory}/config:/config" + "${directory}/cache:/cache" + "/lagoon/media:/media" + ]; + }; + + services.caddy.virtualHosts."buttered.brownbread.net".extraConfig = '' + encode zstd gzip + reverse_proxy http://localhost:8096 + ''; +} diff --git a/modules/containers/pinchflat/default.nix b/modules/containers/pinchflat/default.nix new file mode 100644 index 0000000..9428c32 --- /dev/null +++ b/modules/containers/pinchflat/default.nix @@ -0,0 +1,23 @@ +{ ... }: +let + directories = [ + "/opt/pinchflat" + ]; +in +{ + systemd.tmpfiles.rules = map (x: "d ${x} 0755 share share - -") directories; + virtualisation.oci-containers.containers.pinchflat = { + image = "keglin/pinchflat:latest"; + autoStart = true; + ports = [ + "8945:8945" + ]; + volumes = [ + "/opt/pinchflat:/config" + "/lagoon/media/yt:/downloads" + ]; + environment = { + TZ = "America/Detroit"; + }; + }; +} diff --git a/modules/containers/vaultwarden/default.nix b/modules/containers/vaultwarden/default.nix new file mode 100644 index 0000000..cc6b86f --- /dev/null +++ b/modules/containers/vaultwarden/default.nix @@ -0,0 +1,34 @@ +{ lib, ... }: +let + directory = "/opt/vaultwarden"; + domain = "steel-mountain.brownbread.net"; + port = "11001"; +in +{ + systemd.tmpfiles.rules = + map (x: "d ${x} 0755 share share - -") (lib.lists.singleton directory); + + virtualisation.oci-containers.containers.vaultwarden = { + image = "vaultwarden/server:latest"; + autoStart = true; + ports = [ + "${port}:80" + ]; + volumes = [ + "${directory}/data:/data" + ]; + environment = { + DOMAIN = domain; + WEBSOCKET_ENABLED = "true"; + SIGNUPS_ALLOWED = "false"; + SHOW_PASSWORD_HINT = "false"; + }; + }; + + services.caddy.virtualHosts.${domain}.extraConfig = '' + encode zstd gzip + reverse_proxy http://localhost:${port} { + header_up X-Real-IP {remote_host} + } + ''; +} diff --git a/modules/containers/watchtower/default.nix b/modules/containers/watchtower/default.nix new file mode 100644 index 0000000..bc819cd --- /dev/null +++ b/modules/containers/watchtower/default.nix @@ -0,0 +1,15 @@ +{ ... }: +{ + virtualisation.oci-containers.containers.watchtower = { + image = "containrrr/watchtower:latest"; + autoStart = true; + volumes = [ + "/var/run/podman/podman.sock:/var/run/docker.sock:ro" + "/etc/localtime:/etc/localtime:ro" + ]; + environment = { + WATCHTOWER_CLEANUP = "true"; + WATCHTOWER_SCHEDULE = "0 0 5 * * *"; + }; + }; +} diff --git a/modules/customs/cgit/default.nix b/modules/customs/cgit/default.nix new file mode 100644 index 0000000..19eac01 --- /dev/null +++ b/modules/customs/cgit/default.nix @@ -0,0 +1,134 @@ +{ config, lib, pkgs, ... }: +with lib; +let + cfg = config.services.cgit; + + mkCgitrc = cfg: + pkgs.writeText "cgitrc" (let + cgitConfig = { + css = "/cgit.css"; + logo = "/cgit.png"; + favicon = "/favicon.ico"; + about-filter = "${cfg.package}/lib/cgit/filters/about-formatting.sh"; + source-filter = "${cfg.package}/lib/cgit/filters/syntax-highlighting.py"; + enable-git-config = 1; + # Disable cgit's HTTP "dumb" protocol and use git itself to provide the + # HTTP "smart" protocol instead. + enable-http-clone = 0; + remove-suffix = 1; + clone-url = "https://${cfg.virtualHost}/$CGIT_REPO_URL.git"; + scan-path = cfg.scanPath; + }; + in + generators.toKeyValue { } (cfg.settings // cgitConfig) + ); + + mkCgitAssets = pkg: files: + builtins.map (f: '' + handle_path /${f} { + root * ${pkg}/cgit/${f} + file_server + } + '') files |> strings.concatStringsSep "\n"; +in +{ + disabledModules = [ "services/networking/cgit.nix" ]; + + options = { + services.cgit = { + enable = mkEnableOption "cgit"; + package = mkPackageOption pkgs "cgit" { }; + user = mkOption { + description = "User to run cgit service as"; + type = types.str; + default = "git"; + }; + group = mkOption { + description = "Group to run cgit service as"; + type = types.str; + default = "git"; + }; + scanPath = mkOption { + description = "A path which will be scanned for repositories"; + type = types.path; + default = "/var/lib/cgit"; + }; + virtualHost = mkOption { + description = "Virtual host to serve cgit on"; + type = types.str; + default = null; + }; + authorizedKeys = mkOption { + description = "SSH keys for authorized git users"; + type = types.listOf types.str; + default = [ ]; + }; + settings = mkOption { + description = "Additional cgit configuration. see cgitrc(5)"; + type = with types; let settingType = oneOf [ bool int str ]; in + attrsOf (oneOf [ + settingType + (listOf settingType) + ]); + default = { }; + }; + }; + }; + + config = mkIf cfg.enable { + programs.git = { + enable = true; + config.init.defaultBranch = "main"; + }; + + # Setup git user with git-shell for authenticated pushes. + users.users.${cfg.user} = { + isSystemUser = true; + home = cfg.scanPath; + group = cfg.group; + shell = "${pkgs.git}/bin/git-shell"; + openssh.authorizedKeys.keys = cfg.authorizedKeys; + }; + + users.groups.${cfg.group} = {}; + + # Harden git user to prevent SSH port forwarding to other servers. + services.openssh = { + enable = true; + settings.AllowUsers = [ cfg.user ]; + extraConfig = '' + Match user ${cfg.user} + AllowTCPForwarding no + AllowAgentForwarding no + PasswordAuthentication no + PermitTTY no + X11Forwarding no + ''; + }; + + # Configure fcgiwrap instance for caddy to properly serve cgi scripts. + # Reference: https://github.com/NixOS/nixpkgs/blob/nixos-24.11/nixos/modules/services/networking/cgit.nix + services.fcgiwrap.instances.cgit = { + process = { inherit (cfg) user group; }; + socket = { inherit (config.services.caddy) user group; }; + }; + + services.caddy.virtualHosts.${cfg.virtualHost}.extraConfig = + let + socket = config.services.fcgiwrap.instances.cgit.socket.address; + in '' + encode zstd gzip + + reverse_proxy unix/${socket} { + transport fastcgi { + env SCRIPT_FILENAME ${cfg.package}/cgit/cgit.cgi + env CGIT_CONFIG ${mkCgitrc cfg} + } + } + + ${mkCgitAssets cfg.package [ + "cgit.css" "cgit.png" "favicon.ico" "robots.txt" + ]} + ''; + }; +} diff --git a/modules/customs/soft-serve/default.nix b/modules/customs/soft-serve/default.nix new file mode 100644 index 0000000..05156fd --- /dev/null +++ b/modules/customs/soft-serve/default.nix @@ -0,0 +1,60 @@ +{ config, lib, pkgs, ... }: +with lib; +let + cfg = config.services.soft-serve; + cfgFile = format.generate "config.yaml" cfg.settings; + format = pkgs.formats.yaml { }; + dataDir = cfg.dataDir; + docUrl = "https://github.com/charmbracelet/soft-serve"; +in +{ + disabledModules = [ "services/misc/soft-serve.nix" ]; + + options = { + services.soft-serve = { + enable = mkEnableOption "soft-serve"; + package = mkPackageOption pkgs "soft-serve" { }; + dataDir = mkOption { + type = types.str; + default = "/var/lib/soft-serve"; + description = '' + The directory where soft-serve stores its data files. + ''; + }; + settings = mkOption { + type = format.type; + default = { }; + description = '' + soft-serve server configurations stored under your data directory. + See <${docUrl}>. + ''; + }; + }; + }; + + config = mkIf cfg.enable { + systemd.tmpfiles.rules = [ + "L+ ${dataDir}/config.yaml - - - - ${cfgFile}" + ]; + + systemd.services.soft-serve = { + description = "Soft Serve git server"; + documentation = lists.singleton docUrl; + requires = lists.singleton "network-online.target"; + after = lists.singleton "network-online.target"; + wantedBy = lists.singleton "multi-user.target"; + environment.SOFT_SERVE_DATA_PATH = dataDir; + serviceConfig = { + Type = "simple"; + Restart = "always"; + RestartSec = 1; + ExecStart = "${getExe cfg.package} serve"; + WorkingDirectory = dataDir; + }; + }; + + environment.systemPackages = with pkgs; [ + git + ]; + }; +} diff --git a/modules/default.nix b/modules/default.nix new file mode 100644 index 0000000..4930139 --- /dev/null +++ b/modules/default.nix @@ -0,0 +1,26 @@ +{ inputs }: +let + genModules = { type, modules }: + builtins.map (module: "${inputs.self}/modules/${type}/${module}") modules; + + makeModules = moduleAttrList: + builtins.concatMap (moduleAttr: genModules moduleAttr) moduleAttrList; +in +{ + makeSystem = hostname: nixpkgsVersion: modules: { + ${hostname} = nixpkgsVersion.lib.nixosSystem { + system = "x86_64-linux"; + modules = (makeModules modules) ++ [ + "${inputs.self}/hosts/${hostname}" + "${inputs.self}/modules/users" + inputs.home-manager.nixosModules.home-manager + inputs.agenix.nixosModules.default + ]; + specialArgs = { inherit inputs; }; + }; + }; + + mergeSets = inputs.nixpkgs.lib.lists.foldl' ( + x: y: inputs.nixpkgs.lib.attrsets.recursiveUpdate x y + ) { }; +} diff --git a/modules/profiles/common/default.nix b/modules/profiles/common/default.nix new file mode 100644 index 0000000..c25fece --- /dev/null +++ b/modules/profiles/common/default.nix @@ -0,0 +1,46 @@ +{ inputs, lib, pkgs, ... }: +{ + nix = { + settings = { + trusted-users = [ "@wheel" "root" ]; + experimental-features = lib.mkDefault [ + "nix-command" + "flakes" + "pipe-operators" + ]; + auto-optimise-store = true; + }; + gc = { + automatic = true; + dates = "weekly"; + options = "--delete-older-than 14d"; + }; + }; + + nixpkgs = { + config = { + allowUnfree = true; + allowUnfreePredicate = (_: true); + }; + overlays = [ + (final: prev: { + unstable = import inputs.nixpkgs-unstable { + system = final.system; + config.allowUnfree = true; + }; + }) + ]; + }; + + programs = { + git.enable = true; + htop.enable = true; + neovim = { + enable = true; + package = pkgs.unstable.neovim-unwrapped; + viAlias = true; + vimAlias = true; + defaultEditor = true; + }; + }; +} diff --git a/modules/profiles/fstrim/default.nix b/modules/profiles/fstrim/default.nix new file mode 100644 index 0000000..03da691 --- /dev/null +++ b/modules/profiles/fstrim/default.nix @@ -0,0 +1,7 @@ +{ ... }: +{ + services.fstrim = { + enable = true; + interval = "weekly"; + }; +} diff --git a/modules/profiles/libvirtd/default.nix b/modules/profiles/libvirtd/default.nix new file mode 100644 index 0000000..fa617d1 --- /dev/null +++ b/modules/profiles/libvirtd/default.nix @@ -0,0 +1,21 @@ +{ config, ... }: +{ + virtualisation.libvirtd = { + enable = true; + qemu = { + ovmf.enable = true; + runAsRoot = false; + }; + onBoot = "ignore"; + onShutdown = "shutdown"; + }; + + programs.virt-manager.enable = true; + + # Add any users in the 'wheel' group to the 'libvirtd' group. + users.groups.libvirtd.members = let users = config.users.users; in + builtins.attrNames users + |> builtins.filter ( + x: builtins.elem "wheel" users.${x}.extraGroups + ); +} diff --git a/modules/profiles/nvidia/default.nix b/modules/profiles/nvidia/default.nix new file mode 100644 index 0000000..50e0f6f --- /dev/null +++ b/modules/profiles/nvidia/default.nix @@ -0,0 +1,16 @@ +{ config, ... }: +{ + hardware.nvidia = { + package = config.boot.kernelPackages.nvidiaPackages.stable; + open = false; + nvidiaSettings = true; + forceFullCompositionPipeline = true; + modesetting.enable = true; + powerManagement = { + enable = false; + finegrained = false; + }; + }; + + services.xserver.videoDrivers = [ "nvidia" ]; +} diff --git a/modules/profiles/pipewire/default.nix b/modules/profiles/pipewire/default.nix new file mode 100644 index 0000000..ac70f08 --- /dev/null +++ b/modules/profiles/pipewire/default.nix @@ -0,0 +1,13 @@ +{ ... }: +{ + services.pipewire = { + enable = true; + alsa = { + enable = true; + support32Bit = true; + }; + pulse.enable = true; + }; + + security.rtkit.enable = true; +} diff --git a/modules/profiles/podman/default.nix b/modules/profiles/podman/default.nix new file mode 100644 index 0000000..1ec3406 --- /dev/null +++ b/modules/profiles/podman/default.nix @@ -0,0 +1,12 @@ +{ ... }: +{ + virtualisation = { + containers.enable = true; + oci-containers.backend = "podman"; + podman = { + enable = true; + dockerCompat = true; + defaultNetwork.settings.dns_enabled = true; + }; + }; +} diff --git a/modules/profiles/security/default.nix b/modules/profiles/security/default.nix new file mode 100644 index 0000000..47fe1a3 --- /dev/null +++ b/modules/profiles/security/default.nix @@ -0,0 +1,16 @@ +{ lib, ... }: +{ + security = { + polkit.enable = true; + + sudo.enable = lib.mkDefault false; + doas = { + enable = lib.mkDefault true; + extraRules = [{ + groups = [ "wheel" ]; + keepEnv = true; + persist = true; + }]; + }; + }; +} diff --git a/modules/profiles/share/default.nix b/modules/profiles/share/default.nix new file mode 100644 index 0000000..c4ee4ff --- /dev/null +++ b/modules/profiles/share/default.nix @@ -0,0 +1,11 @@ +{ ... }: +{ + users = { + users.share = { + uid = 994; + isSystemUser = true; + group = "share"; + }; + groups.share.gid = 994; + }; +} diff --git a/modules/profiles/steam/default.nix b/modules/profiles/steam/default.nix new file mode 100644 index 0000000..c8008f9 --- /dev/null +++ b/modules/profiles/steam/default.nix @@ -0,0 +1,8 @@ +{ ... }: +{ + programs.steam = { + enable = true; + remotePlay.openFirewall = true; + dedicatedServer.openFirewall = true; + }; +} diff --git a/modules/profiles/upgrade/default.nix b/modules/profiles/upgrade/default.nix new file mode 100644 index 0000000..32c49a8 --- /dev/null +++ b/modules/profiles/upgrade/default.nix @@ -0,0 +1,30 @@ +{ inputs, config, ... }: +{ + system.autoUpgrade = { + enable = true; + flake = inputs.self.outPath; + flags = [ + "--update-input" + "nixpkgs" + "-L" + ]; + dates = "Sat *-*-* 06:00:00"; + randomizedDelaySec = "45min"; + allowReboot = true; + }; + + systemd.services."reboot-alert" = + let + hostname = config.networking.hostName; + dependencies = [ "network-online.target" ]; + in { + wantedBy = [ "multi-user.target" ]; + wants = dependencies; + after = dependencies; + serviceConfig.Type = "oneshot"; + script = '' + /run/current-system/sw/bin/pushover -t "${hostname} restarted" \ + "${hostname} has restarted on $(date '+%a, %b %d at %T %p %Z')." + ''; + }; +} diff --git a/modules/profiles/vpn/default.nix b/modules/profiles/vpn/default.nix new file mode 100644 index 0000000..0482c31 --- /dev/null +++ b/modules/profiles/vpn/default.nix @@ -0,0 +1,18 @@ +{ pkgs, ... }: +{ + networking.nameservers = [ "9.9.9.9" ]; + + services = { + mullvad-vpn = { + enable = true; + package = pkgs.mullvad-vpn; + }; + + resolved = { + enable = true; + dnssec = "true"; + domains = [ "~." ]; + dnsovertls = "true"; + }; + }; +} diff --git a/modules/profiles/wireguard/default.nix b/modules/profiles/wireguard/default.nix new file mode 100644 index 0000000..8c25d7a --- /dev/null +++ b/modules/profiles/wireguard/default.nix @@ -0,0 +1,15 @@ +{ ... }: +let + port = 51820; +in +{ + networking = { + firewall.allowedUDPPorts = [ port ]; + + wg-quick.interfaces.wg0 = { + autostart = true; + listenPort = port; + configFile = "/etc/wireguard/wg0.conf"; + }; + }; +} diff --git a/modules/profiles/wireshark/default.nix b/modules/profiles/wireshark/default.nix new file mode 100644 index 0000000..d4d0627 --- /dev/null +++ b/modules/profiles/wireshark/default.nix @@ -0,0 +1,14 @@ +{ config, pkgs, ... }: +{ + programs.wireshark = { + enable = true; + package = pkgs.wireshark; + }; + + # Add any users in the 'wheel' group to the 'wireshark' group. + users.groups.wireshark.members = let users = config.users.users; in + builtins.attrNames users + |> builtins.filter ( + x: builtins.elem "wheel" users.${x}.extraGroups + ); +} diff --git a/modules/profiles/x11/default.nix b/modules/profiles/x11/default.nix new file mode 100644 index 0000000..52e7975 --- /dev/null +++ b/modules/profiles/x11/default.nix @@ -0,0 +1,33 @@ +{ pkgs, ... }: +{ + services = { + xserver = { + enable = true; + xkb.layout = "us"; + displayManager.lightdm.enable = true; + windowManager.bspwm.enable = true; + }; + + displayManager.autoLogin = { + enable = true; + user = "tdback"; + }; + }; + + hardware.graphics.enable32Bit = true; + + environment.systemPackages = with pkgs.xorg; [ + libX11 + xset + ]; + + fonts.packages = with pkgs; [ + dejavu_fonts + dina-font + iosevka-comfy.comfy-motion-fixed + liberation_ttf + noto-fonts + noto-fonts-emoji + ubuntu_font_family + ]; +} diff --git a/modules/profiles/zfs/default.nix b/modules/profiles/zfs/default.nix new file mode 100644 index 0000000..8344450 --- /dev/null +++ b/modules/profiles/zfs/default.nix @@ -0,0 +1,28 @@ +{ lib, pkgs, ... }: +{ + boot = { + zfs.forceImportRoot = false; + supportedFilesystems.zfs = lib.mkForce true; + }; + + services.zfs = { + autoScrub.enable = true; + zed = { + enableMail = false; + settings = { + ZED_DEBUG_LOG = "/tmp/zed.debug.log"; + ZED_EMAIL_ADDR = [ "root" ]; + ZED_EMAIL_PROG = "/run/current-system/sw/bin/pushover"; + ZED_EMAIL_OPTS = "-t '@SUBJECT@'"; + ZED_NOTIFY_INTERVAL_SECS = 3600; + ZED_NOTIFY_VERBOSE = true; + ZED_USE_ENCLOSURE_LEDS = true; + ZED_SCRUB_AFTER_RESILVER = true; + }; + }; + }; + + environment.systemPackages = with pkgs; [ + zfs + ]; +} diff --git a/modules/retired/forgejo/default.nix b/modules/retired/forgejo/default.nix new file mode 100644 index 0000000..9db55b2 --- /dev/null +++ b/modules/retired/forgejo/default.nix @@ -0,0 +1,65 @@ +{ inputs, config, lib, pkgs, ... }: +let + domain = "git.tdback.net"; + port = 3000; +in +{ + services.forgejo = { + enable = true; + package = pkgs.unstable.forgejo; + stateDir = "/tank/forgejo"; + database.type = "postgres"; + lfs.enable = true; + settings = { + server = { + DOMAIN = domain; + ROOT_URL = "https://${domain}/"; + HTTP_PORT = port; + }; + service.DISABLE_REGISTRATION = true; + actions = { + ENABLED = true; + DEFAULT_ACTIONS_URL = "https://${domain}"; + }; + }; + }; + + age.secrets.forgejoAdminPass = { + file = "${inputs.self}/secrets/forgejoAdminPass.age"; + mode = "770"; + owner = "forgejo"; + group = "forgejo"; + }; + + systemd.services.forgejo.preStart = + let + adminCmd = "${lib.getExe config.services.forgejo.package} admin user"; + password = config.age.secrets.forgejoAdminPass.path; + user = "tdback"; + email = "tyler@tdback.net"; + in '' + ${adminCmd} create --admin --email ${email} --username ${user} --password "$(tr -d '\n' < ${password})" || true + ''; + + services.openssh.settings.AllowUsers = [ "forgejo" ]; + + services.caddy.virtualHosts.${domain}.extraConfig = '' + encode zstd gzip + reverse_proxy http://localhost:${builtins.toString port} + ''; + + age.secrets.forgejoRunnerToken.file = "${inputs.self}/secrets/forgejoRunnerToken.age"; + services.gitea-actions-runner = { + package = pkgs.unstable.forgejo-runner; + instances.default = { + enable = true; + name = "monolith"; + url = "https://${domain}"; + tokenFile = config.age.secrets.forgejoRunnerToken.path; + labels = [ + "ubuntu-latest:docker://node:20-bookworm" + "ubuntu-22.04:docker://node:20-bookworm" + ]; + }; + }; +} diff --git a/modules/retired/kavita/default.nix b/modules/retired/kavita/default.nix new file mode 100644 index 0000000..c72aca6 --- /dev/null +++ b/modules/retired/kavita/default.nix @@ -0,0 +1,28 @@ +{ ... }: +let + directories = [ + "/opt/kavita" + ]; +in +{ + systemd.tmpfiles.rules = map (x: "d ${x} 0755 share share - -") directories; + virtualisation.oci-containers.containers.kavita = { + image = "jvmilazz0/kavita:latest"; + autoStart = true; + ports = [ + "5000:5000" + ]; + volumes = [ + "/opt/kavita/config:/kavita/config" + "/lagoon/media/library/Books:/books" + ]; + environment = { + TZ = "America/Detroit"; + }; + }; + + services.caddy.virtualHosts."library.tdback.net".extraConfig = '' + encode zstd gzip + reverse_proxy http://localhost:5000 + ''; +} diff --git a/modules/retired/mealie/default.nix b/modules/retired/mealie/default.nix new file mode 100644 index 0000000..2d869ce --- /dev/null +++ b/modules/retired/mealie/default.nix @@ -0,0 +1,22 @@ +{ config, pkgs, ... }: +let + domain = "toasted.brownbread.net"; +in +{ + services.mealie = { + enable = true; + package = pkgs.unstable.mealie; + settings = { + BASE_URL = domain; + DB_ENGINE = "sqlite"; + ALLOW_SIGNUP = "false"; + SECURITY_MAX_LOGIN_ATTEMPTS = 3; + TZ = "America/Detroit"; + }; + }; + + services.caddy.virtualHosts.${domain}.extraConfig = '' + encode zstd gzip + reverse_proxy http://localhost:${builtins.toString config.services.mealie.port} + ''; +} diff --git a/modules/retired/mumble/default.nix b/modules/retired/mumble/default.nix new file mode 100644 index 0000000..29e3339 --- /dev/null +++ b/modules/retired/mumble/default.nix @@ -0,0 +1,11 @@ +{ pkgs, ... }: +{ + services.murmur = { + enable = true; + package = pkgs.murmur; + port = 64738; + openFirewall = true; + environmentFile = "/var/lib/murmur/murmurd.env"; + password = "$MURMURD_PASSWORD"; + }; +} diff --git a/modules/retired/navidrome/default.nix b/modules/retired/navidrome/default.nix new file mode 100644 index 0000000..d98117b --- /dev/null +++ b/modules/retired/navidrome/default.nix @@ -0,0 +1,31 @@ +{ lib, ... }: +let + directory = "/opt/navidrome"; +in +{ + systemd.tmpfiles.rules = + map (x: "d ${x} 0755 share share - -") (lib.lists.singleton directory); + + virtualisation.oci-containers.containers.navidrome = { + image = "deluan/navidrome:latest"; + autoStart = true; + ports = [ + "4533:4533" + ]; + volumes = [ + "${directory}/data:/data" + "/lagoon/media/music:/music:ro" + ]; + environment = { + ND_SCANSCHEDULE = "1h"; + ND_LOGLEVEL = "info"; + ND_SESSIONTIMEOUT = "24h"; + ND_ENABLEUSEREDITING = "false"; + }; + }; + + services.caddy.virtualHosts."radioactive.brownbread.net".extraConfig = '' + encode zstd gzip + reverse_proxy http://localhost:4533 + ''; +} diff --git a/modules/retired/pihole/default.nix b/modules/retired/pihole/default.nix new file mode 100644 index 0000000..034c91b --- /dev/null +++ b/modules/retired/pihole/default.nix @@ -0,0 +1,52 @@ +{ inputs, config, lib, ... }: +let + # TODO: Think about changing this to config.networking.interface... + # Will have to pull the first value in the list, which might be messy but it + # will definitely make it more producible across machines. + ip = "10.0.0.203"; + interface = "eno1"; + directory = "/opt/pihole"; +in +{ + systemd.tmpfiles.rules = + map (x: "d ${x} 0755 share share - -") (lib.lists.singleton directory); + + virtualisation.oci-containers.containers.pihole = { + image = "pihole/pihole:latest"; + autoStart = true; + ports = [ + "53:53/udp" + "53:53/tcp" + "80:80/tcp" + ]; + volumes = [ + "${directory}/etc:/etc/pihole" + "${directory}/etc-dnsmasq.d:/etc/dnsmasq.d" + ]; + environment = { + TZ = "America/Detroit"; + FTLCONF_LOCAL_IPV4 = ip; + INTERFACE = interface; + }; + extraOptions = [ "--network=host" ]; + }; + + age.secrets.piholeAdminPass = { + file = "${inputs.self}/secrets/piholeAdminPass.age"; + mode = "770"; + owner = "share"; + group = "share"; + }; + + systemd.services.podman-pihole.postStart = + let + password = config.age.secrets.piholeAdminPass.path; + in '' + podman exec -it pihole pihole -a -p "$(tr -d '\n' < ${password})" + ''; + + networking.firewall = { + allowedTCPPorts = [ 53 80 ]; + allowedUDPPorts = [ 53 ]; + }; +} diff --git a/modules/retired/stirling-pdf/default.nix b/modules/retired/stirling-pdf/default.nix new file mode 100644 index 0000000..904fd6d --- /dev/null +++ b/modules/retired/stirling-pdf/default.nix @@ -0,0 +1,23 @@ +{ ... }: +let + directories = [ + "/opt/stirling" + ]; +in +{ + systemd.tmpfiles.rules = map (x: "d ${x} 0755 share share - -") directories; + virtualisation.oci-containers.containers.pdf-tools = { + image = "frooodle/s-pdf:latest"; + autoStart = true; + ports = [ + "8060:8080" + ]; + volumes = [ + "/opt/stirling/training-data:/usr/share/tesseract-ocr/4.00/tessdata" + "/opt/stirling/configs:/configs" + ]; + environment = { + DOCKER_ENABLE_SECURITY = "false"; + }; + }; +} diff --git a/modules/retired/xonotic/default.nix b/modules/retired/xonotic/default.nix new file mode 100644 index 0000000..7ae5442 --- /dev/null +++ b/modules/retired/xonotic/default.nix @@ -0,0 +1,25 @@ +{ pkgs, ... }: +{ + services.xonotic = { + enable = true; + package = pkgs.xonotic-dedicated; + openFirewall = true; + settings = { + hostname = "tdback's Xonotic Server"; + net_address = "0.0.0.0"; + port = 26000; + sv_motd = "GLHF! Please report any issues to @tdback on irc.libera.chat"; + + # Specify bots and player count. + maxplayers = 8; + minplayers = 4; + minplayers_per_team = 2; + + # Configure mutators. + g_instagib = 0; + g_grappling_hook = 1; + g_jetpack = 0; + g_vampire = 0; + }; + }; +} diff --git a/modules/scripts/motd/default.nix b/modules/scripts/motd/default.nix new file mode 100644 index 0000000..d59f787 --- /dev/null +++ b/modules/scripts/motd/default.nix @@ -0,0 +1,99 @@ +{ config, lib, pkgs, ... }: +let + motd = + pkgs.writeShellScriptBin "motd" '' + #!/usr/bin/env bash + RED="\e[31m" + GREEN="\e[32m" + YELLOW="\e[33m" + BOLD="\e[1m" + ENDCOLOR="\e[0m" + + case "$(date +'%H')" in + [0-9]|1[0-1]) + TIME="morning" + ;; + 1[2-7]) + TIME="afternoon" + ;; + *) + TIME="evening" + ;; + esac + + UPTIME=$(cat /proc/uptime | cut -f1 -d.) + UPDAYS=$((UPTIME/60/60/24)) + UPHOURS=$((UPTIME/60/60%24)) + UPMINS=$((UPTIME/60%60)) + UPSECS=$((UPTIME%60)) + + MEMORY=$(free -m | awk 'NR == 2 { printf "%s/%sMB (%.2f%%)\n", $3, $2, ($3 * 100) / $2 }') + + SERVICES=$(systemctl list-units | grep -P 'podman-|${lib.strings.concatStringsSep "|" config.motd.servicesToCheck}') + + printf "\n" + printf "''${BOLD}Good $TIME $(whoami), welcome to $(hostname)!$ENDCOLOR\n" + printf "\n" + ${lib.strings.concatStrings (lib.lists.forEach config.motd.networkInterfaces (x: + "printf \"$BOLD * %-20s$ENDCOLOR %s\\n\" \"IPv4 ${x}\" \"$(ip -4 addr show ${x} | grep -oP '(?<=inet\\s)\\d+(\\.\\d+){3}')\"\n" + ))} + printf "$BOLD * %-20s$ENDCOLOR %s\n" "Release" "$(awk -F= '/PRETTY_NAME/ { print $2 }' /etc/os-release | tr -d '"')" + printf "$BOLD * %-20s$ENDCOLOR %s\n" "Kernel" "$(uname -rs)" + printf "\n" + printf "$BOLD * %-20s$ENDCOLOR %s\n" "CPU Usage" "$(awk '{ print $1 ", " $2 ", " $3 }' /proc/loadavg) (1, 5, 15 min)" + printf "$BOLD * %-20s$ENDCOLOR %s\n" "Memory" "$MEMORY" + printf "$BOLD * %-20s$ENDCOLOR %s\n" "System Uptime" "$UPDAYS days $UPHOURS hours $UPMINS minutes $UPSECS seconds" + printf "\n" + + [ -z "$SERVICES" ] && exit + + printf "''${BOLD}Service status:$ENDCOLOR\n" + while IFS= read -r line; do + if [[ ! $line =~ ".service" ]] || [[ $line =~ ".mount" ]]; then + continue + fi + if echo "$line" | grep -q 'failed'; then + name=$(echo "$line" | awk '{ print $1 }' | sed 's/podman-//g') + printf "$RED• $ENDCOLOR%-50s $RED[failed]$ENDCOLOR\n" "$name" + elif echo "$line" | grep -q 'running'; then + name=$(echo "$line" | awk '{ print $1 }' | sed 's/podman-//g') + printf "$GREEN• $ENDCOLOR%-50s $GREEN[active]$ENDCOLOR\n" "$name" + elif echo "$line" | grep -q 'exited'; then + name=$(echo "$line" | awk '{ print $1 }' | sed 's/podman-//g') + printf "$YELLOW• $ENDCOLOR%-50s $YELLOW[exited]$ENDCOLOR\n" "$name" + else + echo "service status unknown" + fi + done <<< "$SERVICES" + printf "\n" + ''; +in +{ + options.motd = { + networkInterfaces = lib.mkOption { + description = "Network interfaces to monitor."; + type = lib.types.listOf lib.types.str; + default = [ ]; + }; + + servicesToCheck = lib.mkOption { + description = "Services to validate alongside podman containers."; + type = lib.types.listOf lib.types.str; + default = [ ]; + }; + }; + + config = { + environment.systemPackages = [ + motd + ]; + + programs.bash.loginShellInit = '' + [ -z "$PS1" ] && return + + if command -v motd &> /dev/null; then + motd + fi + ''; + }; +} diff --git a/modules/scripts/pushover/default.nix b/modules/scripts/pushover/default.nix new file mode 100644 index 0000000..f20a5be --- /dev/null +++ b/modules/scripts/pushover/default.nix @@ -0,0 +1,47 @@ +{ inputs, config, pkgs, ... }: +let + pushover = + pkgs.writeShellScriptBin "pushover" '' + #!/bin/sh + + die() { echo "$0: $*" >&2; exit 111; } + + APP=$(cat ${config.age.secrets.pushoverAppToken.path}) + USER=$(cat ${config.age.secrets.pushoverUserToken.path}) + + while getopts ":t:" args; do + case "$args" in + t) + TITLE="$OPTARG" + ;; + :) + die "missing option argument for -$OPTARG" + ;; + *) + die "invalid option -$OPTARG" + ;; + esac + done + shift $((OPTIND - 1)) + + MESSAGE="$*" + if [ -z "$MESSAGE" ] || [ "$MESSAGE" = " " ]; then + MESSAGE="No errors to report." + fi + + /run/current-system/sw/bin/curl -s \ + --form-string "token=$APP" \ + --form-string "user=$USER" \ + --form-string "title=$TITLE" \ + --form-string "message=$MESSAGE" \ + https://api.pushover.net/1/messages.json + ''; +in +{ + age.secrets = { + pushoverAppToken.file = "${inputs.self}/secrets/pushoverAppToken.age"; + pushoverUserToken.file = "${inputs.self}/secrets/pushoverUserToken.age"; + }; + + environment.systemPackages = [ pushover ]; +} diff --git a/modules/services/blocky/default.nix b/modules/services/blocky/default.nix new file mode 100644 index 0000000..ca58f4f --- /dev/null +++ b/modules/services/blocky/default.nix @@ -0,0 +1,93 @@ +{ pkgs, ... }: +{ + services.blocky = { + enable = true; + package = pkgs.blocky; + settings = { + upstreams = { + init.strategy = "fast"; + groups.default = [ + "9.9.9.9" + "149.112.112.112" + ]; + }; + bootstrapDns = [{ + upstream = "https://dns.quad9.net/dns-query"; + ips = [ "9.9.9.9" ]; + }]; + ports = { + dns = 53; + tls = 853; + https = 443; + }; + blocking = { + denylists = { + ads = [ + "https://adaway.org/hosts.txt" + "https://v.firebog.net/hosts/AdguardDNS.txt" + "https://v.firebog.net/hosts/Admiral.txt" + "https://raw.githubusercontent.com/anudeepND/blacklist/master/adservers.txt" + "https://v.firebog.net/hosts/Easylist.txt" + "https://pgl.yoyo.org/adservers/serverlist.php?hostformat=hosts&showintro=0&mimetype=plaintext" + "https://raw.githubusercontent.com/FadeMind/hosts.extras/master/UncheckyAds/hosts" + "https://raw.githubusercontent.com/bigdargon/hostsVN/master/hosts" + ]; + malicious = [ + "https://osint.digitalside.it/Threat-Intel/lists/latestdomains.txt" + "https://v.firebog.net/hosts/Prigent-Crypto.txt" + "https://raw.githubusercontent.com/FadeMind/hosts.extras/master/add.Risk/hosts" + "https://phishing.army/download/phishing_army_blocklist_extended.txt" + "https://gitlab.com/quidsup/notrack-blocklists/raw/master/notrack-malware.txt" + "https://raw.githubusercontent.com/Spam404/lists/master/main-blacklist.txt" + "https://raw.githubusercontent.com/AssoEchap/stalkerware-indicators/master/generated/hosts" + "https://urlhaus.abuse.ch/downloads/hostfile/" + "https://v.firebog.net/hosts/Prigent-Malware.txt" + ]; + other = [ + "https://zerodot1.gitlab.io/CoinBlockerLists/hosts_browser" + ]; + suspicious = [ + "https://raw.githubusercontent.com/PolishFiltersTeam/KADhosts/master/KADhosts.txt" + "https://raw.githubusercontent.com/FadeMind/hosts.extras/master/add.Spam/hosts" + "https://v.firebog.net/hosts/static/w3kbl.txt" + "https://raw.githubusercontent.com/matomo-org/referrer-spam-blacklist/master/spammers.txt" + "https://someonewhocares.org/hosts/zero/hosts" + "https://raw.githubusercontent.com/VeleSila/yhosts/master/hosts" + "https://winhelp2002.mvps.org/hosts.txt" + "https://v.firebog.net/hosts/neohostsbasic.txt" + "https://raw.githubusercontent.com/RooneyMcNibNug/pihole-stuff/master/SNAFU.txt" + "https://paulgb.github.io/BarbBlock/blacklists/hosts-file.txt" + ]; + tracking-telemetry = [ + "https://v.firebog.net/hosts/Easyprivacy.txt" + "https://v.firebog.net/hosts/Prigent-Ads.txt" + "https://raw.githubusercontent.com/FadeMind/hosts.extras/master/add.2o7Net/hosts" + "https://raw.githubusercontent.com/crazy-max/WindowsSpyBlocker/master/data/hosts/spy.txt" + "https://hostfiles.frogeye.fr/firstparty-trackers-hosts.txt" + "https://www.github.developerdan.com/hosts/lists/ads-and-tracking-extended.txt" + "https://raw.githubusercontent.com/Perflyst/PiHoleBlocklist/master/android-tracking.txt" + "https://raw.githubusercontent.com/Perflyst/PiHoleBlocklist/master/SmartTV.txt" + "https://raw.githubusercontent.com/Perflyst/PiHoleBlocklist/master/AmazonFireTV.txt" + "https://gitlab.com/quidsup/notrack-blocklists/raw/master/notrack-blocklist.txt" + ]; + }; + clientGroupsBlock.default = [ + "ads" + "malicious" + "other" + "suspicious" + "tracking-telemetry" + ]; + loading = { + concurrency = 16; + strategy = "failOnError"; + }; + }; + }; + }; + + networking.firewall = { + allowedTCPPorts = [ 53 443 853 ]; + allowedUDPPorts = [ 53 ]; + }; +} diff --git a/modules/services/cgit/default.nix b/modules/services/cgit/default.nix new file mode 100644 index 0000000..5309e6f --- /dev/null +++ b/modules/services/cgit/default.nix @@ -0,0 +1,28 @@ +{ inputs, lib, pkgs, ... }: +let + scanPath = "/tank/git"; + domain = "git.tdback.net"; +in +{ + imports = lib.lists.singleton "${inputs.self}/modules/customs/cgit"; + + services.cgit = { + enable = true; + package = pkgs.cgit; + scanPath = scanPath; + virtualHost = domain; + authorizedKeys = [ + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEzLpTEoej7P04KoNzokQ9IOnNZiKyi2+YQ8yU5WSKCb" + ]; + settings = { + root-title = domain; + root-desc = "tdback's git repositories"; + enable-index-links = 1; + enable-index-owner = 0; + enable-commit-graph = 1; + enable-log-filecount = 1; + enable-log-linecount = 1; + readme = ":README.md"; + }; + }; +} diff --git a/modules/services/fediverse/default.nix b/modules/services/fediverse/default.nix new file mode 100644 index 0000000..0c3c696 --- /dev/null +++ b/modules/services/fediverse/default.nix @@ -0,0 +1,26 @@ +{ pkgs, ... }: +let + domain = "social.tdback.net"; + port = 8080; +in +{ + services.gotosocial = { + enable = true; + package = pkgs.unstable.gotosocial; + settings = { + application-name = "gotosocial"; + host = "${domain}"; + protocol = "https"; + bind-address = "localhost"; + port = port; + db-type = "sqlite"; + db-address = "/var/lib/gotosocial/database.sqlite"; + storage-local-base-path = "/var/lib/gotosocial/storage"; + }; + }; + + services.caddy.virtualHosts.${domain}.extraConfig = '' + encode zstd gzip + reverse_proxy http://localhost:${builtins.toString port} + ''; +} diff --git a/modules/services/immich/default.nix b/modules/services/immich/default.nix new file mode 100644 index 0000000..e33dd97 --- /dev/null +++ b/modules/services/immich/default.nix @@ -0,0 +1,18 @@ +{ pkgs, ... }: +{ + services.immich = { + enable = true; + package = pkgs.immich; + host = "localhost"; + port = 2283; + mediaLocation = "/lagoon/media/immich"; + environment = { + IMMICH_LOG_LEVEL = "log"; + }; + }; + + services.caddy.virtualHosts."photographs.brownbread.net".extraConfig = '' + encode zstd gzip + reverse_proxy http://localhost:2283 + ''; +} diff --git a/modules/services/proxy/default.nix b/modules/services/proxy/default.nix new file mode 100644 index 0000000..e11beab --- /dev/null +++ b/modules/services/proxy/default.nix @@ -0,0 +1,9 @@ +{ pkgs, ... }: +{ + services.caddy = { + enable = true; + package = pkgs.caddy; + }; + + networking.firewall.allowedTCPPorts = [ 80 443 ]; +} diff --git a/modules/services/searx/default.nix b/modules/services/searx/default.nix new file mode 100644 index 0000000..2b4a9d8 --- /dev/null +++ b/modules/services/searx/default.nix @@ -0,0 +1,33 @@ +{ pkgs, ... }: +let + port = 8888; +in +{ + services.searx = { + enable = true; + package = pkgs.searxng; + environmentFile = "/var/lib/searx/env"; + settings = { + general = { + debug = false; + instance_name = "searx"; + }; + search = { + safe_search = 1; + autocomplete = "duckduckgo"; + autocomplete_min = 4; + default_lang = "en-US"; + }; + server = { + port = port; + bind_address = "0.0.0.0"; + secret_key = "@SEARX_SECRET_KEY@"; + public_instance = false; + image_proxy = true; + }; + ui.static_use_hash = true; + }; + }; + + networking.firewall.allowedTCPPorts = [ port ]; +} diff --git a/modules/services/sftpgo/default.nix b/modules/services/sftpgo/default.nix new file mode 100644 index 0000000..27318b2 --- /dev/null +++ b/modules/services/sftpgo/default.nix @@ -0,0 +1,21 @@ +{ config, pkgs, ... }: +{ + services.sftpgo = { + enable = true; + package = pkgs.sftpgo; + settings = { + httpd.bindings = [{ + port = 8080; + address = "0.0.0.0"; + enable_web_client = true; + enable_web_admin = true; + }]; + }; + }; + + services.caddy.virtualHosts."${config.networking.hostName}.brownbread.net".extraConfig = '' + root * /web/client + encode zstd gzip + reverse_proxy http://localhost:8080 + ''; +} diff --git a/modules/services/ssh/default.nix b/modules/services/ssh/default.nix new file mode 100644 index 0000000..ec8f188 --- /dev/null +++ b/modules/services/ssh/default.nix @@ -0,0 +1,17 @@ +{ lib, ... }: +let + ports = lib.lists.singleton 2222; +in +{ + services.openssh = { + enable = lib.mkDefault true; + ports = ports; + openFirewall = true; + startWhenNeeded = true; + settings = { + AllowUsers = [ "tdback" ]; + PermitRootLogin = "no"; + PasswordAuthentication = lib.mkDefault false; + }; + }; +} diff --git a/modules/services/web/default.nix b/modules/services/web/default.nix new file mode 100644 index 0000000..b6a45af --- /dev/null +++ b/modules/services/web/default.nix @@ -0,0 +1,10 @@ +{ ... }: +{ + services.caddy.virtualHosts = { + "tdback.net".extraConfig = '' + root * /var/www/tdback.net/ + encode zstd gzip + file_server + ''; + }; +} diff --git a/modules/users/default.nix b/modules/users/default.nix new file mode 100644 index 0000000..027ca0f --- /dev/null +++ b/modules/users/default.nix @@ -0,0 +1,15 @@ +{ pkgs, ... }: +{ + users = { + users.tdback = { + isNormalUser = true; + uid = 1000; + home = "/home/tdback"; + group = "tdback"; + extraGroups = [ "wheel" "users" "networkmanager" "video" "audio" ]; + shell = pkgs.bash; + ignoreShellProgramCheck = true; + }; + groups.tdback.gid = 1000; + }; +} |