{ flake, config, pkgs, ... }: let inherit (flake.config.people) user0; inherit (flake.config.people.users.${user0}) name; inherit (flake.config.services.instances) nextcloud nginx caddy smtp web ; service = nextcloud; localhost = web.localhost.address0; host = service.domains.url0; in { services = { nextcloud = { appstoreEnable = true; autoUpdateApps.enable = true; configureRedis = true; enable = true; hostName = host; https = true; package = pkgs.nextcloud31; phpOptions."opcache.interned_strings_buffer" = "24"; extraAppsEnable = true; extraApps = { inherit (pkgs.nextcloud31Packages.apps) contacts calendar deck ; }; config = { adminpassFile = config.sops.secrets."${service.name}-pass".path; adminuser = name; dbtype = "pgsql"; }; database = { createLocally = true; }; settings = { default_phone_region = "CA"; log_type = "file"; mail_domain = host; mail_from_address = "noreply"; mail_sendmailmode = smtp.name; mail_smtpmode = smtp.name; mail_smtphost = smtp.hostname; mail_smtpport = smtp.ports.port1; mail_smtpsecure = ""; mail_smtptimeout = 30; mail_smtpauth = 1; mail_smtpname = smtp.email.address0; mail_smtppassword = config.sops.secrets."${service.name}-smtp".path; maintenance_window_start = 4; overwriteprotocol = "https"; trusted_proxies = [ localhost web.localhost.address1 ]; security.headers = { Strict-Transport-Security = "max-age=15552000; includeSubDomains"; X-XSS-Protection = "1; mode=block"; X-Content-Type-Options = "nosniff"; X-Frame-Options = "SAMEORIGIN"; Referrer-Policy = "strict-origin-when-cross-origin"; }; }; }; nginx = { enable = true; virtualHosts.${host} = { listen = [ { addr = localhost; port = nginx.ports.port0; } ]; forceSSL = false; onlySSL = false; addSSL = false; }; }; caddy = { virtualHosts = { ":${toString caddy.ports.port3}" = { extraConfig = '' header { # Enable XSS protection and block instead of sanitizing X-XSS-Protection "1; mode=block" # Enable HSTS with 6 month duration Strict-Transport-Security "max-age=15552000; includeSubDomains" # Additional security headers X-Content-Type-Options "nosniff" X-Frame-Options "SAMEORIGIN" Referrer-Policy "strict-origin-when-cross-origin" # Remove server identification -Server } reverse_proxy http://${localhost}:${toString nginx.ports.port0} ''; }; }; }; }; sops = let sopsPath = secret: { path = "${service.sops.path0}/${service.name}-${secret}"; owner = service.name; mode = "600"; }; in { secrets = builtins.listToAttrs ( map (secret: { name = "${service.name}-${secret}"; value = sopsPath secret; }) [ "pass" "smtp" ] ); }; systemd = { tmpfiles.rules = [ "Z ${service.sops.path0} 755 ${service.name} ${service.name} -" ]; }; users.users.${service.name} = { packages = with pkgs; [ php ]; extraGroups = [ "caddy" "nginx" "postgres" ]; }; networking = { firewall = { allowedTCPPorts = [ nginx.ports.port0 service.ports.port0 caddy.ports.port3 ]; }; }; }