aboutsummaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/containers/freshrss/default.nix30
-rw-r--r--modules/containers/jellyfin/default.nix27
-rw-r--r--modules/containers/pinchflat/default.nix23
-rw-r--r--modules/containers/vaultwarden/default.nix34
-rw-r--r--modules/containers/watchtower/default.nix15
-rw-r--r--modules/customs/cgit/default.nix134
-rw-r--r--modules/customs/soft-serve/default.nix60
-rw-r--r--modules/default.nix26
-rw-r--r--modules/profiles/common/default.nix46
-rw-r--r--modules/profiles/fstrim/default.nix7
-rw-r--r--modules/profiles/libvirtd/default.nix21
-rw-r--r--modules/profiles/nvidia/default.nix16
-rw-r--r--modules/profiles/pipewire/default.nix13
-rw-r--r--modules/profiles/podman/default.nix12
-rw-r--r--modules/profiles/security/default.nix16
-rw-r--r--modules/profiles/share/default.nix11
-rw-r--r--modules/profiles/steam/default.nix8
-rw-r--r--modules/profiles/upgrade/default.nix30
-rw-r--r--modules/profiles/vpn/default.nix18
-rw-r--r--modules/profiles/wireguard/default.nix15
-rw-r--r--modules/profiles/wireshark/default.nix14
-rw-r--r--modules/profiles/x11/default.nix33
-rw-r--r--modules/profiles/zfs/default.nix28
-rw-r--r--modules/retired/forgejo/default.nix65
-rw-r--r--modules/retired/kavita/default.nix28
-rw-r--r--modules/retired/mealie/default.nix22
-rw-r--r--modules/retired/mumble/default.nix11
-rw-r--r--modules/retired/navidrome/default.nix31
-rw-r--r--modules/retired/pihole/default.nix52
-rw-r--r--modules/retired/stirling-pdf/default.nix23
-rw-r--r--modules/retired/xonotic/default.nix25
-rw-r--r--modules/scripts/motd/default.nix99
-rw-r--r--modules/scripts/pushover/default.nix47
-rw-r--r--modules/services/blocky/default.nix93
-rw-r--r--modules/services/cgit/default.nix28
-rw-r--r--modules/services/fediverse/default.nix26
-rw-r--r--modules/services/immich/default.nix18
-rw-r--r--modules/services/proxy/default.nix9
-rw-r--r--modules/services/searx/default.nix33
-rw-r--r--modules/services/sftpgo/default.nix21
-rw-r--r--modules/services/ssh/default.nix17
-rw-r--r--modules/services/web/default.nix10
-rw-r--r--modules/users/default.nix15
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;
+ };
+}