diff --git a/flake.nix b/flake.nix index 3510761..910b131 100644 --- a/flake.nix +++ b/flake.nix @@ -44,6 +44,7 @@ inputs.home-manager.flakeModules.home-manager ./hosts/comfy-station ./hosts/monolith + ./hosts/harbor (./home + "/jonas@comfy-station") (./home + "/jonas@monolith") (import-tree ./modules) diff --git a/hosts/harbor/configuration.nix b/hosts/harbor/configuration.nix new file mode 100644 index 0000000..a79bd2c --- /dev/null +++ b/hosts/harbor/configuration.nix @@ -0,0 +1,150 @@ +{ + config, + pkgs, + ... +}: { + imports = [ + ./hardware-configuration.nix + ./disko.nix + ]; + + # Secret management + sops.age.keyFile = "/var/lib/sops-nix/key.txt"; + sops.secrets."nextcloud-admin-pass" = { + sopsFile = ../../secrets/harbor/nextcloud.yaml; + owner = "nextcloud"; + key = "admin-pass"; + }; + sops.secrets."wg-priv" = { + sopsFile = ../../secrets/harbor/wg.yaml; + key = "privateKey"; + }; + sops.secrets."gitea-db-pass" = { + sopsFile = ../../secrets/harbor/gitea.yaml; + owner = config.services.gitea.user; + key = "databasePassword"; + }; + sops.secrets."gotify-admin-pass" = { + sopsFile = ../../secrets/harbor/gotify.yaml; + owner = config.hive.gotify-instance.user; + key = "adminPassword"; + }; + + # gc settings and binary caches + nix = { + settings = { + substituters = [ + "https://aseipp-nix-cache.freetls.fastly.net" + "https://nix-community.cachix.org" + "https://cache.nixos.org/" + ]; + experimental-features = ["nix-command" "flakes"]; + auto-optimise-store = true; + }; + gc = { + automatic = true; + dates = "weekly"; + options = "--delete-older-than 30d"; + }; + }; + + # user with ssh access + users.users.jonas = { + isNormalUser = true; + description = "Jonas"; + extraGroups = ["wheel"]; + openssh.authorizedKeys.keys = [ + "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCyCyYsMSiy7shcehlzJEbCyRiHk+cicFB35Bc2uc4PjjkCjswLh01fRAV2QcplrNkH/5F4GBTbOoZHHc7/AVLyUxgwDC9ffD2i7fevuGpfBFy9D30uz6jDekxXkmRmIlidXLdG1Fh4zwVejGlwdhUu/Zb7PonO/dktx3EFdf1SpnW+y75anN85zoGsld7KQk42wEd0zXtCgx4CKI6Vvt6heWCEiJ9wyw1sLpTJr4H8In236CUj1/r1qY9Gfa8n9NA0J9XCpcwSCEWGRKQNicoQIpnp5txrgzaUq4r6qBKHmImYXmSTVnDZ9dJLRYNu2lDvBtTXP4ztlR6Lpxs873fPg51qgaX9rRVMMo/gGjq8fOFWsDVaJZab9VY3hZYNCKIbWFqo4GKyCQs9Xfzr2AUACm09HWiYMTefwEypOzvUb4z+LF2B/0c5XmghLF/TOzLVgDXzAgWMH4mCnPh9EDLHTtoJaGNURler9VRV8yQyLH6oK9UpHZovCFs7HpFN+WPv2QVFfkK8aHg7tnklFsT78z154bjuspiEI/fFGmTxoQUGufmHlRy/9GQDusgNfe24ZEB2hHBVjKv29XdIfvFAhoPVpA6+O/N3feSlmVISaU+8QraVQEf/TuQjopDUWpJTmqSxKvQSTPwcyWDy6NtcJ85bGAu6jSUGC3ouH4Rb2Q== cardno:000609618602" + ]; + }; + users.defaultUserShell = pkgs.zsh; + programs.zsh.enable = true; + services.openssh = { + enable = true; + settings.PasswordAuthentication = false; + settings.KbdInteractiveAuthentication = false; + }; + + # hive modules + hive.gitea-instance.enable = true; + hive.gitea-instance.nativeRunner = true; + hive.gitea-instance.instanceFQDN = "git.jroeger.de"; + hive.gitea-instance.databasePasswordFile = config.sops.secrets.gitea-db-pass.path; + hive.gotify-instance.enable = true; + hive.gotify-instance.instanceFQDN = "gotify.jroeger.de"; + hive.gotify-instance.adminPasswordSopsKey = config.sops.secrets.gotify-admin-pass.name; + hive.nextcloud-instance.enable = true; + hive.nextcloud-instance.ssl = true; + hive.nextcloud-instance.adminPasswordFile = config.sops.secrets.nextcloud-admin-pass.path; + hive.nextcloud-instance.instanceFQDN = "nextcloud.jroeger.de"; + hive.minecraft-server.enable = true; + hive.borg-server.enable = true; + hive.borg-server.repositories.comfy-station.ssh_public_key = builtins.readFile (../../static/keys + "/borg-jonas@comfy-station.pub"); + hive.wg.server.enable = true; + hive.wg.server.privateKeyFile = config.sops.secrets.wg-priv.path; + + # 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 = "25.11"; # Did you read the comment? + + # VPS compat + boot.loader.grub.enable = true; + boot.loader.grub.device = "/dev/sda"; + boot.loader.grub.version = 2; + boot.kernelParams = [ + "net.ifnames=0" # ensure iface is called eth0 + "ip=173.249.42.252::173.249.42.1:255.255.255.0:harbor:eth0:none:8.8.8.8" + ]; + networking.networkmanager.enable = true; + networking = { + # Static network configuration + hostName = "harbor"; + domain = "jroeger.de"; + defaultGateway = "173.249.42.1"; + nameservers = ["8.8.8.8"]; + interfaces.eth0.ipv4.addresses = [ + { + address = "173.249.42.252"; + prefixLength = 24; + } + ]; + }; + # Temporary ssh server for disk unlock + boot.initrd = { + availableKernelModules = ["virtio_pci"]; + network = { + enable = true; + ssh = { + enable = true; + port = 2222; + authorizedKeys = [ + "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCyCyYsMSiy7shcehlzJEbCyRiHk+cicFB35Bc2uc4PjjkCjswLh01fRAV2QcplrNkH/5F4GBTbOoZHHc7/AVLyUxgwDC9ffD2i7fevuGpfBFy9D30uz6jDekxXkmRmIlidXLdG1Fh4zwVejGlwdhUu/Zb7PonO/dktx3EFdf1SpnW+y75anN85zoGsld7KQk42wEd0zXtCgx4CKI6Vvt6heWCEiJ9wyw1sLpTJr4H8In236CUj1/r1qY9Gfa8n9NA0J9XCpcwSCEWGRKQNicoQIpnp5txrgzaUq4r6qBKHmImYXmSTVnDZ9dJLRYNu2lDvBtTXP4ztlR6Lpxs873fPg51qgaX9rRVMMo/gGjq8fOFWsDVaJZab9VY3hZYNCKIbWFqo4GKyCQs9Xfzr2AUACm09HWiYMTefwEypOzvUb4z+LF2B/0c5XmghLF/TOzLVgDXzAgWMH4mCnPh9EDLHTtoJaGNURler9VRV8yQyLH6oK9UpHZovCFs7HpFN+WPv2QVFfkK8aHg7tnklFsT78z154bjuspiEI/fFGmTxoQUGufmHlRy/9GQDusgNfe24ZEB2hHBVjKv29XdIfvFAhoPVpA6+O/N3feSlmVISaU+8QraVQEf/TuQjopDUWpJTmqSxKvQSTPwcyWDy6NtcJ85bGAu6jSUGC3ouH4Rb2Q== cardno:000609618602" + ]; + hostKeys = ["/etc/secrets/initrd/ssh_host_rsa_key"]; + shell = "/bin/cryptsetup-askpass"; + }; + }; + }; + + # Set your time zone. + time.timeZone = "Europe/Berlin"; + + # Select internationalisation properties. + i18n.defaultLocale = "en_US.UTF-8"; + i18n.extraLocaleSettings = { + LC_ADDRESS = "de_DE.UTF-8"; + LC_IDENTIFICATION = "de_DE.UTF-8"; + LC_MEASUREMENT = "de_DE.UTF-8"; + LC_MONETARY = "de_DE.UTF-8"; + LC_NAME = "de_DE.UTF-8"; + LC_NUMERIC = "de_DE.UTF-8"; + LC_PAPER = "de_DE.UTF-8"; + LC_TELEPHONE = "de_DE.UTF-8"; + LC_TIME = "de_DE.UTF-8"; + }; + console.keyMap = "de"; +} diff --git a/hosts/harbor/default.nix b/hosts/harbor/default.nix new file mode 100644 index 0000000..4d02ca7 --- /dev/null +++ b/hosts/harbor/default.nix @@ -0,0 +1,25 @@ +{ + inputs, + self, + ... +}: { + flake.nixosConfigurations.harbor = inputs.nixpkgs.lib.nixosSystem { + modules = [ + ({...}: { + nixpkgs.config.allowUnfree = true; + }) + + ./configuration.nix + + inputs.sops-nix.nixosModules.sops + inputs.disko.nixosModules.disko + self.nixosModules.nix-scripts + self.nixosModules.gitea-instance + self.nixosModules.gotify-instance + self.nixosModules.nextcloud-instance + self.nixosModules.minecraft-server + self.nixosModules.borg-server + self.nixosModules.wireguard-server + ]; + }; +} diff --git a/hosts/harbor/disko.nix b/hosts/harbor/disko.nix new file mode 100644 index 0000000..9a3b8a8 --- /dev/null +++ b/hosts/harbor/disko.nix @@ -0,0 +1,71 @@ +let + btrfsopt = [ + "compress=zstd" + "noatime" + "ssd" + "space_cache=v2" + "user_subvol_rm_allowed" + ]; +in { + disko.devices = { + disk = { + main = { + type = "disk"; + device = "/dev/sda"; + content = { + type = "gpt"; + partitions = { + boot = { + name = "boot"; + size = "1M"; + type = "ef02"; + }; + esp = { + name = "esp"; + size = "500M"; + type = "ef00"; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot"; + }; + }; + luks = { + size = "100%"; + content = { + type = "luks"; + name = "nixos"; + passwordFile = "/tmp/pass"; + additionalKeyFiles = ["/nixos-enc.key"]; + extraFormatArgs = [ + "--type luks1" + "--iter-time 3000" + ]; + settings = { + allowDiscards = true; + }; + content = { + type = "btrfs"; + subvolumes = { + "@root" = { + mountpoint = "/"; + mountOptions = btrfsopt; + }; + "@home" = { + mountpoint = "/home"; + mountOptions = btrfsopt; + }; + "@nix" = { + mountpoint = "/nix"; + mountOptions = btrfsopt; + }; + }; + }; + }; + }; + }; + }; + }; + }; + }; +} diff --git a/hosts/harbor/hardware-configuration.nix b/hosts/harbor/hardware-configuration.nix new file mode 100644 index 0000000..4ed0dd5 --- /dev/null +++ b/hosts/harbor/hardware-configuration.nix @@ -0,0 +1,21 @@ +# Do not modify this file! It was generated by ‘nixos-generate-config’ +# and may be overwritten by future invocations. Please make changes +# to /etc/nixos/configuration.nix instead. +{ + config, + lib, + pkgs, + modulesPath, + ... +}: { + imports = [ + (modulesPath + "/profiles/qemu-guest.nix") + ]; + + boot.initrd.availableKernelModules = ["ata_piix" "uhci_hcd" "virtio_pci" "virtio_scsi" "sd_mod" "sr_mod"]; + boot.initrd.kernelModules = []; + boot.kernelModules = []; + boot.extraModulePackages = []; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; +} diff --git a/modules/networking/wireguard/server.nix b/modules/networking/wireguard/server.nix index 10b2a88..e34d67a 100644 --- a/modules/networking/wireguard/server.nix +++ b/modules/networking/wireguard/server.nix @@ -9,6 +9,7 @@ peers = import ./peers.nix {inherit lib;}; in { options.hive.wg.server = { + enable = lib.mkEnableOption "Enable WireGuard server"; port = lib.mkOption { type = lib.types.port; default = 51820; @@ -20,7 +21,7 @@ }; }; - config = { + config = lib.mkIf cfg.enable { # Firewall rule networking.firewall.allowedUDPPorts = [cfg.port]; diff --git a/modules/services/borg-server.nix b/modules/services/borg-server.nix new file mode 100644 index 0000000..93ce12c --- /dev/null +++ b/modules/services/borg-server.nix @@ -0,0 +1,63 @@ +{ + flake.nixosModules.borg-server = { + lib, + config, + pkgs, + ... + }: let + cfg = config.hive.borg-server; + in { + options.hive.borg-server = { + enable = lib.mkEnableOption "Enable the borg server"; + package = lib.mkOption { + type = lib.types.package; + default = pkgs.borgbackup; + example = "pkgs.borgbackup"; + description = "The borg package to use"; + }; + borg_user = lib.mkOption { + type = lib.types.str; + example = "borg"; + default = "borg"; + description = "The user for the borg repository home."; + }; + repositories_path = lib.mkOption { + type = lib.types.path; + example = "/var/lib/borg-repositories"; + default = "/var/lib/borg-repositories"; + description = "The user for the borg repository home."; + }; + repositories = lib.mkOption { + type = lib.types.attrsOf (lib.types.submodule { + options = { + name = lib.mkOption { + type = lib.types.nullOr (lib.types.strMatching "^[a-zA-Z0-9._-]+$"); + default = null; + example = "borg-repo"; + description = "The name of the borg repository. If null, use key of attrset"; + }; + ssh_public_key = lib.mkOption { + type = lib.types.singleLineStr; + example = "ssh-rsa AAAA..."; + description = "The path to the public key for the borg repository."; + }; + }; + }); + }; + }; + + config = lib.mkIf cfg.enable { + users.users.${cfg.borg_user} = { + isNormalUser = true; + description = "Borg user"; + home = cfg.repositories_path; + createHome = true; + extraGroups = ["borg"]; + openssh.authorizedKeys.keys = + lib.attrsets.mapAttrsToList + (key: repo: "command=\"${cfg.package}/bin/borg serve --restrict-to-path=${cfg.repositories_path}/${lib.defaultTo key repo.name}\",restrict ${repo.ssh_public_key}") + cfg.repositories; + }; + }; + }; +} diff --git a/modules/services/gitea-instance.nix b/modules/services/gitea-instance.nix new file mode 100644 index 0000000..dde7503 --- /dev/null +++ b/modules/services/gitea-instance.nix @@ -0,0 +1,125 @@ +{ + flake.nixosModules.gitea-instance = { + config, + lib, + ... + }: let + cfg = config.hive.gitea-instance; + in { + options.hive.gitea-instance = { + enable = lib.mkEnableOption "Enable the Gitea instance"; + + instanceFQDN = lib.mkOption { + type = lib.types.singleLineStr; + example = "git.example.com"; + description = "Fully qualified domain name of the Gitea instance"; + }; + + databasePasswordFile = lib.mkOption { + type = lib.types.path; + example = "/etc/gitea-db-pass.txt"; + description = "Path to the file containing the Gitea database password"; + }; + nativeRunner = lib.mkOption { + type = lib.types.bool; + description = "Install a gitea act_runner using the native nix store"; + default = false; + }; + }; + + config = lib.mkIf cfg.enable { + # Gitea instance + services.gitea = { + enable = true; + lfs.enable = true; + appName = "Git yourself some Tea!"; + database = { + name = "gitea"; + type = "postgres"; + passwordFile = cfg.databasePasswordFile; + }; + settings = { + server.PROTOCOL = "http+unix"; + server.ROOT_URL = "https://${cfg.instanceFQDN}/"; + server.DOMAIN = cfg.instanceFQDN; + service.DISABLE_REGISTRATION = true; + }; + }; + + # Fallback server with only 403 + services.nginx.virtualHosts.${config.networking.domain} = lib.mkDefault { + default = true; + locations."/".return = 403; + forceSSL = true; + enableACME = true; + }; + + # Virtual host for gitea + services.nginx.virtualHosts."${cfg.instanceFQDN}" = { + forceSSL = true; + enableACME = true; + locations."/" = { + proxyPass = "http://unix:/run/gitea/gitea.sock"; + }; + }; + + # Database setup + services.postgresql = { + enable = true; + ensureDatabases = [config.services.gitea.user]; + ensureUsers = [ + { + name = config.services.gitea.database.user; + ensureDBOwnership = true; + } + ]; + }; + + # act_runner + services.gitea-actions-runner = lib.mkIf cfg.nativeRunner { + instances.nixos-host = { + enable = true; + name = "nixos-host-runner"; + url = "https://${cfg.instanceFQDN}"; + tokenFile = "/var/lib/gitea-registration/nixos-host"; + + labels = ["nixos:host"]; + + settings = { + runner = { + capacity = 1; + }; + }; + }; + }; + systemd.services.gitea-runner-nixos-host = lib.mkIf cfg.nativeRunner { + after = ["gitea-runner-gen-token.service"]; + requires = ["gitea-runner-gen-token.service"]; + serviceConfig.Environment = '' + PATH=/run/current-system/sw/bin:/usr/bin:/bin + ''; + }; + systemd.services.gitea-runner-gen-token = lib.mkIf cfg.nativeRunner { + wantedBy = ["multi-user.target"]; + after = ["gitea.service"]; + environment = { + GITEA_CUSTOM = "/var/lib/gitea/custom"; + GITEA_WORK_DIR = "/var/lib/gitea"; + }; + script = '' + set -euo pipefail + token=$(${config.services.gitea.package}/bin/gitea actions generate-runner-token) + echo "TOKEN=$token" > /var/lib/gitea-registration/nixos-host + ''; + unitConfig.ConditionPathExists = ["!/var/lib/gitea-registration/nixos-host"]; + serviceConfig = { + User = "gitea"; + Group = "gitea"; + StateDirectory = "gitea-registration"; + Type = "oneshot"; + RemainAfterExit = true; + }; + }; + }; + }; +} diff --git a/modules/services/gotify-instance.nix b/modules/services/gotify-instance.nix new file mode 100644 index 0000000..fddeddd --- /dev/null +++ b/modules/services/gotify-instance.nix @@ -0,0 +1,133 @@ +{ + flake.nixosModules.gotify-instance = { + config, + lib, + ... + }: let + cfg = config.hive.gotify-instance; + server-config = { + server = { + listenaddr = "localhost"; + port = 54545; + ssl.enabled = false; + ssl.redirecttohttps = false; + cors.alloworigins = ["${cfg.instanceFQDN}"]; + stream.allowedorigins = ["${cfg.instanceFQDN}"]; + }; + database = { + dialect = "postgres"; + connection = "host=/run/postgresql dbname=${cfg.user} user=${cfg.user}"; + }; + defaultuser = { + name = "admin"; + pass = config.sops.placeholder.${cfg.adminPasswordSopsKey}; + }; + registration = false; + }; + server-config-yaml = lib.generators.toYAML {} server-config; + in { + options.hive.gotify-instance = { + enable = lib.mkEnableOption "Enable the Gotify instance"; + instanceFQDN = lib.mkOption { + type = lib.types.singleLineStr; + example = "gotify.example.com"; + description = "Fully qualified domain name of the Gotify instance"; + }; + user = lib.mkOption { + type = lib.types.singleLineStr; + default = "gotify"; + description = "The user to run the service as"; + }; + group = lib.mkOption { + type = lib.types.singleLineStr; + default = "gotify"; + description = "The group to run the service as"; + }; + adminPasswordSopsKey = lib.mkOption { + type = lib.types.singleLineStr; + description = "The SOPS key for the default admin user"; + }; + }; + + config = lib.mkIf cfg.enable { + services.gotify.enable = true; + + # Config setup + sops.templates."gotify-server-config.yml" = { + owner = cfg.user; + content = server-config-yaml; + }; + environment.etc."gotify/config.yml".source = config.sops.templates."gotify-server-config.yml".path; + + # User setup + users.users = lib.mkIf (cfg.user == "gotify") { + gotify = { + description = "Gotify service"; + useDefaultShell = true; + group = cfg.group; + isSystemUser = true; + }; + }; + + users.groups = lib.mkIf (cfg.group == "gotify") { + gotify = {}; + }; + + # Configure gotify to run as the specified user (for postgres authentication) + systemd.services.gotify-server = { + serviceConfig = { + DynamicUser = lib.mkForce false; + User = cfg.user; + RuntimeDirectory = "gotify"; + }; + }; + + # Fallback server with only 403 + services.nginx.virtualHosts.${config.networking.domain} = lib.mkDefault { + default = true; + locations."/".return = 403; + forceSSL = true; + enableACME = true; + }; + + # Virtual host for gotify + services.nginx.virtualHosts."${cfg.instanceFQDN}" = { + forceSSL = true; + enableACME = true; + locations."/" = { + proxyPass = "http://${server-config.server.listenaddr}:${toString server-config.server.port}"; + extraConfig = '' + # Ensuring it can use websockets + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto http; + proxy_redirect http:// $scheme://; + + # The proxy must preserve the host because gotify verifies the host with the origin + # for WebSocket connections + proxy_set_header Host $host; + + # These sets the timeout so that the websocket can stay alive + proxy_connect_timeout 1m; + proxy_send_timeout 1m; + proxy_read_timeout 1m; + ''; + }; + }; + + # Database setup + services.postgresql = { + enable = true; + ensureDatabases = [cfg.user]; + ensureUsers = [ + { + name = cfg.user; + ensureDBOwnership = true; + } + ]; + }; + }; + }; +} diff --git a/modules/services/minecraft-server/_loadCurseForge.nix b/modules/services/minecraft-server/_loadCurseForge.nix new file mode 100644 index 0000000..32ba046 --- /dev/null +++ b/modules/services/minecraft-server/_loadCurseForge.nix @@ -0,0 +1,36 @@ +{ + url ? null, + hash ? null, + pkgs, + lib, + ... +}: let + modpack = pkgs.fetchzip { + inherit url hash; + stripRoot = false; + }; + + variablesStr = builtins.readFile "${modpack}/variables.txt"; + variableLines = + builtins.filter (l: l != "" && (lib.strings.elemAt (lib.stringToCharacters l) 0) != "#") + (lib.strings.splitString "\n" variablesStr); + + stripQuotes = s: + if builtins.match "^\".*\"$" s != null + then builtins.substring 1 (builtins.stringLength s - 2) s + else s; + + parseLine = line: let + parts = lib.strings.splitString "=" line; + in { + name = builtins.elemAt parts 0; + value = stripQuotes (builtins.concatStringsSep "=" (builtins.tail parts)); + }; + + variables = builtins.listToAttrs (map parseLine variableLines); +in { + inherit variables; + root = modpack; + mods = "${modpack}/mods"; + config = "${modpack}/config"; +} diff --git a/modules/services/minecraft-server/minecraft-server.nix b/modules/services/minecraft-server/minecraft-server.nix new file mode 100644 index 0000000..7b28a29 --- /dev/null +++ b/modules/services/minecraft-server/minecraft-server.nix @@ -0,0 +1,46 @@ +{ + flake.nixosModules.minecraft-server = { + config, + pkgs, + lib, + ... + }: let + cfg = config.hive.minecraft-server; + + modpack = pkgs.callPackage ./_loadCurseForge.nix { + url = "https://mediafilez.forgecdn.net/files/7765/203/BMC3_Server_Pack_v44.zip"; + hash = "sha256-doqPzo9fhYM9ng/3RO6OPqhKA2ibfoaKx3Es7M0lpuU="; + }; + + mcVersion = modpack.variables.MINECRAFT_VERSION; + loader = lib.toLower modpack.variables.MODLOADER; + loaderVersion = modpack.variables.MODLOADER_VERSION; + serverVersion = lib.replaceStrings ["."] ["_"] "${loader}-${mcVersion}"; + in { + options.hive.minecraft-server = { + enable = lib.mkEnableOption "Enable BMC3 server"; + }; + + config = lib.mkIf cfg.enable { + services.minecraft-servers = { + enable = true; + eula = true; + openFirewall = true; + + servers.bmc3 = lib.optionalAttrs cfg.enable { + enable = true; + autoStart = false; + package = pkgs."${loader}Servers".${serverVersion}.override {inherit loaderVersion;}; + jvmOpts = modpack.variables.JAVA_ARGS; + symlinks = { + "mods" = "${modpack.root}/mods"; + }; + serverProperties = { + motd = "Woher kommt der Stein?"; + white-list = true; + }; + }; + }; + }; + }; +} diff --git a/modules/services/nextcloud-instance.nix b/modules/services/nextcloud-instance.nix new file mode 100644 index 0000000..8f31474 --- /dev/null +++ b/modules/services/nextcloud-instance.nix @@ -0,0 +1,136 @@ +{ + flake.nixosModules.nextcloud-instance = { + config, + lib, + pkgs, + ... + }: let + cfg = config.hive.nextcloud-instance; + in { + options.hive.nextcloud-instance = { + enable = lib.mkEnableOption "Enable the Nextcloud instance"; + + instanceFQDN = lib.mkOption { + type = lib.types.str; + example = "nextcloud.example.com"; + description = "Fully qualified domain name of the Nextcloud instance"; + }; + + ssl = lib.mkOption { + type = lib.types.bool; + default = true; + description = "Use SSL and auto-update certificates"; + }; + + adminPasswordFile = lib.mkOption { + type = lib.types.path; + example = "/etc/nc-admin-pass.txt"; + description = "Path to the file containing the Nextcloud admin password"; + }; + }; + + config = lib.mkIf cfg.enable { + services.nextcloud = { + # Instance + enable = true; + package = pkgs.nextcloud33; + hostName = cfg.instanceFQDN; + https = cfg.ssl; + configureRedis = true; + + # DB + config.dbtype = "pgsql"; + config.dbhost = "/run/postgresql"; + config.adminpassFile = cfg.adminPasswordFile; + + #Mail + settings = { + mail_smtpmode = "sendmail"; + mail_sendmailmode = "pipe"; + }; + + # Apps + extraAppsEnable = true; + extraApps = { + inherit + (config.services.nextcloud.package.packages.apps) + calendar + contacts + tasks + ; + drop_account = pkgs.fetchNextcloudApp { + sha256 = "sha256-J+bZVNIb/MokuTYQu8RBKdnZFakh180pa1pW5KHlC80="; + url = "https://packages.framasoft.org/projects/nextcloud-apps/drop-account/drop_account-3.0.0.tar.gz"; + license = "agpl3Only"; + }; + }; + + # Raise Upload limit + maxUploadSize = "20G"; + + # Preview settings (video may be a security risk) + settings = { + enable_previews = true; + enabledPreviewProviders = [ + "OC\\Preview\\BMP" + "OC\\Preview\\GIF" + "OC\\Preview\\JPEG" + "OC\\Preview\\Krita" + "OC\\Preview\\MarkDown" + "OC\\Preview\\MP3" + "OC\\Preview\\OpenDocument" + "OC\\Preview\\PNG" + "OC\\Preview\\TXT" + "OC\\Preview\\XBitmap" + "OC\\Preview\\Movie" + "OC\\Preview\\MP4" + "OC\\Preview\\AVI" + "OC\\Preview\\MKV" + ]; + preview_ffmpeg_path = "${pkgs.ffmpeg}/bin/ffmpeg"; + }; + }; + + # Fallback server with only 403 + services.nginx.virtualHosts.${config.networking.domain} = lib.mkDefault { + default = true; + locations."/".return = 403; + forceSSL = cfg.ssl; + enableACME = cfg.ssl; + }; + + # Webserver setup with optional SSL + services.nginx.virtualHosts.${cfg.instanceFQDN} = + if cfg.ssl + then { + forceSSL = true; + enableACME = true; + } + else { + listen = [ + { + addr = "0.0.0.0"; + port = 80; + } + ]; + }; + security.acme = lib.mkIf cfg.ssl { + acceptTerms = true; + defaults.email = "jonas.roeger+acme@gmail.com"; + }; + networking.firewall.allowedTCPPorts = [80] ++ lib.optional cfg.ssl 443; + + # DB setup + services.postgresql = { + enable = true; + ensureDatabases = ["nextcloud"]; + ensureUsers = [ + { + name = "nextcloud"; + ensureDBOwnership = true; + } + ]; + }; + }; + }; +}