From fa6f062830b4bc3cedb9694c1dbf01d5fdf775ac Mon Sep 17 00:00:00 2001 From: Jonas Heinrich Date: Fri, 29 Mar 2024 19:03:04 +0100 Subject: [PATCH] caddy support for nextcloud --- nextcloud-extras.nix | 172 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 172 insertions(+) create mode 100644 nextcloud-extras.nix diff --git a/nextcloud-extras.nix b/nextcloud-extras.nix new file mode 100644 index 0000000..e55ff59 --- /dev/null +++ b/nextcloud-extras.nix @@ -0,0 +1,172 @@ +{ config +, lib +, options +, ... +}: let + + inherit + (lib) + optionalString + escapeShellArg + types + concatStringsSep + mapAttrsToList + mkIf + mkOption + mkDefault + mkForce + ; + + cfg = config.services.nextcloud; + fpm = config.services.phpfpm.pools.nextcloud; + webserver = config.services.${cfg.webserver}; + +in { + + options = { + services.nextcloud = { + + ensureUsers = mkOption { + default = {}; + description = lib.mdDoc '' + List of user accounts which get automatically created if they don't + exist yet. This option does not delete accounts which are not listed + anymore. + ''; + example = { + user1 = { + passwordFile = /secrets/user1-localhost; + email = "user1@localhost"; + }; + user2 = { + passwordFile = /secrets/user2-localhost; + email = "user2@localhost"; + }; + }; + type = types.attrsOf (types.submodule { + options = { + passwordFile = mkOption { + type = types.path; + example = "/path/to/file"; + default = null; + description = lib.mdDoc '' + Specifies the path to a file containing the + clear text password for the user. + ''; + }; + email = mkOption { + type = types.str; + example = "user1@localhost"; + default = null; + }; + }; + }); + }; + + webserver = mkOption { + type = types.enum [ "nginx" "caddy" ]; + default = "nginx"; + description = '' + Whether to use nginx or caddy for virtual host management. + Further nginx configuration can be done by adapting services.nginx.virtualHosts.<name>. + See for further information. + ''; + }; + + }; + }; + + config = mkIf cfg.enable { + + systemd.services.nextcloud-ensure-users = { + enable = true; + script = '' + ${optionalString (cfg.ensureUsers != {}) '' + ${concatStringsSep "\n" (mapAttrsToList (name: cfg: '' + if ${config.services.nextcloud.occ}/bin/nextcloud-occ user:info "${name}" | grep "user not found"; then + export OC_PASS="$(cat ${escapeShellArg cfg.passwordFile})" + ${config.services.nextcloud.occ}/bin/nextcloud-occ user:add --password-from-env "${name}" + fi + if ! ${config.services.nextcloud.occ}/bin/nextcloud-occ user:info "${name}" | grep "user not found"; then + ${optionalString (cfg.email != null) '' + ${config.services.nextcloud.occ}/bin/nextcloud-occ user:setting "${name}" settings email "${cfg.email}" + ''} + fi + '') cfg.ensureUsers)} + ''} + ''; + wantedBy = [ "multi-user.target" ]; + after = ["nextcloud-setup.service"]; + }; + + services.phpfpm.pools.nextcloud.settings = { + "listen.owner" = webserver.user; + "listen.group" = webserver.group; + }; + + users.groups.nextcloud.members = [ "nextcloud" webserver.user ]; + + services.nginx = lib.mkIf (cfg.webserver == "caddy") { + enable = mkForce false; + }; + + services.caddy = lib.mkIf (cfg.webserver == "caddy") { + enable = mkDefault true; + virtualHosts."${if cfg.https then "https" else "http"}://${cfg.hostName}" = { + extraConfig = '' + encode zstd gzip + + root * ${config.services.nginx.virtualHosts.${cfg.hostName}.root} + + redir /.well-known/carddav /remote.php/dav 301 + redir /.well-known/caldav /remote.php/dav 301 + redir /.well-known/* /index.php{uri} 301 + redir /remote/* /remote.php{uri} 301 + + header { + Strict-Transport-Security max-age=31536000 + Permissions-Policy interest-cohort=() + X-Content-Type-Options nosniff + X-Frame-Options SAMEORIGIN + Referrer-Policy no-referrer + X-XSS-Protection "1; mode=block" + X-Permitted-Cross-Domain-Policies none + X-Robots-Tag "noindex, nofollow" + -X-Powered-By + } + + php_fastcgi unix/${fpm.socket} { + root ${config.services.nginx.virtualHosts.${cfg.hostName}.root} + env front_controller_active true + env modHeadersAvailable true + } + + @forbidden { + path /build/* /tests/* /config/* /lib/* /3rdparty/* /templates/* /data/* + path /.* /autotest* /occ* /issue* /indie* /db_* /console* + not path /.well-known/* + } + error @forbidden 404 + + @immutable { + path *.css *.js *.mjs *.svg *.gif *.png *.jpg *.ico *.wasm *.tflite + query v=* + } + header @immutable Cache-Control "max-age=15778463, immutable" + + @static { + path *.css *.js *.mjs *.svg *.gif *.png *.jpg *.ico *.wasm *.tflite + not query v=* + } + header @static Cache-Control "max-age=15778463" + + @woff2 path *.woff2 + header @woff2 Cache-Control "max-age=604800" + + file_server + ''; + }; + }; + + }; +}