diff options
Diffstat (limited to 'nixos/modules/services/web-apps/nextcloud.nix')
-rw-r--r-- | nixos/modules/services/web-apps/nextcloud.nix | 277 |
1 files changed, 154 insertions, 123 deletions
diff --git a/nixos/modules/services/web-apps/nextcloud.nix b/nixos/modules/services/web-apps/nextcloud.nix index 5b9065dec3c55..7da119758fc91 100644 --- a/nixos/modules/services/web-apps/nextcloud.nix +++ b/nixos/modules/services/web-apps/nextcloud.nix @@ -45,6 +45,22 @@ let inherit (config.system) stateVersion; in { + + imports = [ + (mkRemovedOptionModule [ "services" "nextcloud" "nginx" "enable" ] '' + The nextcloud module supports `nginx` as reverse-proxy by default and doesn't + support other reverse-proxies officially. + + However it's possible to use an alternative reverse-proxy by + + * disabling nginx + * setting `listen.owner` & `listen.group` in the phpfpm-pool to a different value + + Further details about this can be found in the `Nextcloud`-section of the NixOS-manual + (which can be openend e.g. by running `nixos-help`). + '') + ]; + options.services.nextcloud = { enable = mkEnableOption "nextcloud"; hostName = mkOption { @@ -69,7 +85,7 @@ in { package = mkOption { type = types.package; description = "Which package to use for the Nextcloud instance."; - relatedPackages = [ "nextcloud17" "nextcloud18" ]; + relatedPackages = [ "nextcloud17" "nextcloud18" "nextcloud19" ]; }; maxUploadSize = mkOption { @@ -91,16 +107,6 @@ in { ''; }; - nginx.enable = mkOption { - type = types.bool; - default = false; - description = '' - Whether to enable nginx virtual host management. - Further nginx configuration can be done by adapting <literal>services.nginx.virtualHosts.<name></literal>. - See <xref linkend="opt-services.nginx.virtualHosts"/> for further information. - ''; - }; - webfinger = mkOption { type = types.bool; default = false; @@ -303,6 +309,14 @@ in { ''; }; }; + occ = mkOption { + type = types.package; + default = occ; + internal = true; + description = '' + The nextcloud-occ program preconfigured to target this Nextcloud instance. + ''; + }; }; config = mkIf cfg.enable (mkMerge [ @@ -336,7 +350,16 @@ in { server, and wait until the upgrade to 17 is finished. Then, set `services.nextcloud.package` to `pkgs.nextcloud18` to upgrade to - Nextcloud version 18. + Nextcloud version 18. Please note that Nextcloud 19 is already out and it's + recommended to upgrade to nextcloud19 after that. + '') + ++ (optional (versionOlder cfg.package.version "19") '' + A legacy Nextcloud install (from before NixOS 20.09/unstable) may be installed. + + If/After nextcloud18 is installed successfully, you can safely upgrade to + nextcloud19. If not, please upgrade to nextcloud18 first since Nextcloud doesn't + support upgrades that skip multiple versions (i.e. an upgrade from 17 to 19 isn't + possible, but an upgrade from 18 to 19). ''); services.nextcloud.package = with pkgs; @@ -348,7 +371,8 @@ in { `pkgs.nextcloud`. '' else if versionOlder stateVersion "20.03" then nextcloud17 - else nextcloud18 + else if versionOlder stateVersion "20.09" then nextcloud18 + else nextcloud19 ); } @@ -360,6 +384,11 @@ in { }; systemd.services = { + # When upgrading the Nextcloud package, Nextcloud can report errors such as + # "The files of the app [all apps in /var/lib/nextcloud/apps] were not replaced correctly" + # Restarting phpfpm on Nextcloud package update fixes these issues (but this is a workaround). + phpfpm-nextcloud.restartTriggers = [ cfg.package ]; + nextcloud-setup = let c = cfg.config; writePhpArrary = a: "[${concatMapStringsSep "," (val: ''"${toString val}"'') a}]"; @@ -445,10 +474,18 @@ in { script = '' chmod og+x ${cfg.home} ln -sf ${cfg.package}/apps ${cfg.home}/ - mkdir -p ${cfg.home}/config ${cfg.home}/data ${cfg.home}/store-apps - ln -sf ${overrideConfig} ${cfg.home}/config/override.config.php - chown -R nextcloud:nginx ${cfg.home}/config ${cfg.home}/data ${cfg.home}/store-apps + # create nextcloud directories. + # if the directories exist already with wrong permissions, we fix that + for dir in ${cfg.home}/config ${cfg.home}/data ${cfg.home}/store-apps; do + if [ ! -e $dir ]; then + install -o nextcloud -g nextcloud -d $dir + elif [ $(stat -c "%G" $dir) != "nextcloud" ]; then + chgrp -R nextcloud $dir + fi + done + + ln -sf ${overrideConfig} ${cfg.home}/config/override.config.php # Do not install if already installed if [[ ! -e ${cfg.home}/config/config.php ]]; then @@ -461,6 +498,7 @@ in { ${occSetTrustedDomainsCmd} ''; serviceConfig.Type = "oneshot"; + serviceConfig.User = "nextcloud"; }; nextcloud-cron = { environment.NEXTCLOUD_CONFIG_DIR = "${cfg.home}/config"; @@ -479,7 +517,7 @@ in { services.phpfpm = { pools.nextcloud = { user = "nextcloud"; - group = "nginx"; + group = "nextcloud"; phpOptions = phpOptionsStr; phpPackage = phpPackage; phpEnv = { @@ -487,128 +525,121 @@ in { PATH = "/run/wrappers/bin:/nix/var/nix/profiles/default/bin:/run/current-system/sw/bin:/usr/bin:/bin"; }; settings = mapAttrs (name: mkDefault) { - "listen.owner" = "nginx"; - "listen.group" = "nginx"; + "listen.owner" = config.services.nginx.user; + "listen.group" = config.services.nginx.group; } // cfg.poolSettings; extraConfig = cfg.poolConfig; }; }; - users.extraUsers.nextcloud = { + users.users.nextcloud = { home = "${cfg.home}"; - group = "nginx"; + group = "nextcloud"; createHome = true; }; + users.groups.nextcloud.members = [ "nextcloud" config.services.nginx.user ]; environment.systemPackages = [ occ ]; - } - (mkIf cfg.nginx.enable { - services.nginx = { - enable = true; - virtualHosts = { - ${cfg.hostName} = { - root = cfg.package; - locations = { - "= /robots.txt" = { - priority = 100; - extraConfig = '' - allow all; - log_not_found off; - access_log off; - ''; - }; - "/" = { - priority = 200; - extraConfig = "rewrite ^ /index.php;"; - }; - "~ ^/store-apps" = { - priority = 201; - extraConfig = "root ${cfg.home};"; - }; - "= /.well-known/carddav" = { - priority = 210; - extraConfig = "return 301 $scheme://$host/remote.php/dav;"; - }; - "= /.well-known/caldav" = { - priority = 210; - extraConfig = "return 301 $scheme://$host/remote.php/dav;"; - }; - "~ ^\\/(?:build|tests|config|lib|3rdparty|templates|data)\\/" = { - priority = 300; - extraConfig = "deny all;"; - }; - "~ ^\\/(?:\\.|autotest|occ|issue|indie|db_|console)" = { - priority = 300; - extraConfig = "deny all;"; - }; - "~ ^\\/(?:index|remote|public|cron|core/ajax\\/update|status|ocs\\/v[12]|updater\\/.+|ocs-provider\\/.+|ocm-provider\\/.+)\\.php(?:$|\\/)" = { - priority = 500; - extraConfig = '' - include ${config.services.nginx.package}/conf/fastcgi.conf; - fastcgi_split_path_info ^(.+\.php)(\\/.*)$; - try_files $fastcgi_script_name =404; - fastcgi_param PATH_INFO $fastcgi_path_info; - fastcgi_param HTTPS ${if cfg.https then "on" else "off"}; - fastcgi_param modHeadersAvailable true; - fastcgi_param front_controller_active true; - fastcgi_pass unix:${fpm.socket}; - fastcgi_intercept_errors on; - fastcgi_request_buffering off; - fastcgi_read_timeout 120s; - ''; - }; - "~ ^\\/(?:updater|ocs-provider|ocm-provider)(?:$|\\/)".extraConfig = '' - try_files $uri/ =404; - index index.php; - ''; - "~ \\.(?:css|js|woff2?|svg|gif)$".extraConfig = '' - try_files $uri /index.php$request_uri; - add_header Cache-Control "public, max-age=15778463"; - add_header X-Content-Type-Options nosniff; - add_header X-XSS-Protection "1; mode=block"; - add_header X-Robots-Tag none; - add_header X-Download-Options noopen; - add_header X-Permitted-Cross-Domain-Policies none; - add_header X-Frame-Options sameorigin; - add_header Referrer-Policy no-referrer; - access_log off; - ''; - "~ \\.(?:png|html|ttf|ico|jpg|jpeg|bcmap|mp4|webm)$".extraConfig = '' - try_files $uri /index.php$request_uri; - access_log off; - ''; - }; + services.nginx.enable = mkDefault true; + services.nginx.virtualHosts.${cfg.hostName} = { + root = cfg.package; + locations = { + "= /robots.txt" = { + priority = 100; + extraConfig = '' + allow all; + log_not_found off; + access_log off; + ''; + }; + "/" = { + priority = 900; + extraConfig = "try_files $uri $uri/ /index.php$request_uri;"; + }; + "~ ^/store-apps" = { + priority = 201; + extraConfig = "root ${cfg.home};"; + }; + "^~ /.well-known" = { + priority = 210; + extraConfig = '' + location = /.well-known/carddav { + return 301 $scheme://$host/remote.php/dav; + } + location = /.well-known/caldav { + return 301 $scheme://$host/remote.php/dav; + } + try_files $uri $uri/ =404; + ''; + }; + "~ ^/(?:build|tests|config|lib|3rdparty|templates|data)(?:$|/)".extraConfig = '' + return 404; + ''; + "~ ^/(?:\\.|autotest|occ|issue|indie|db_|console)".extraConfig = '' + return 404; + ''; + "~ \\.php(?:$|/)" = { + priority = 500; extraConfig = '' - add_header X-Content-Type-Options nosniff; - add_header X-XSS-Protection "1; mode=block"; - add_header X-Robots-Tag none; - add_header X-Download-Options noopen; - add_header X-Permitted-Cross-Domain-Policies none; - add_header X-Frame-Options sameorigin; - add_header Referrer-Policy no-referrer; - add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always; - error_page 403 /core/templates/403.php; - error_page 404 /core/templates/404.php; - client_max_body_size ${cfg.maxUploadSize}; - fastcgi_buffers 64 4K; - fastcgi_hide_header X-Powered-By; - gzip on; - gzip_vary on; - gzip_comp_level 4; - gzip_min_length 256; - gzip_proxied expired no-cache no-store private no_last_modified no_etag auth; - gzip_types application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy; - - ${optionalString cfg.webfinger '' - rewrite ^/.well-known/host-meta /public.php?service=host-meta last; - rewrite ^/.well-known/host-meta.json /public.php?service=host-meta-json last; - ''} + include ${config.services.nginx.package}/conf/fastcgi.conf; + fastcgi_split_path_info ^(.+?\.php)(\\/.*)$; + set $path_info $fastcgi_path_info; + try_files $fastcgi_script_name =404; + fastcgi_param PATH_INFO $path_info; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + fastcgi_param HTTPS ${if cfg.https then "on" else "off"}; + fastcgi_param modHeadersAvailable true; + fastcgi_param front_controller_active true; + fastcgi_pass unix:${fpm.socket}; + fastcgi_intercept_errors on; + fastcgi_request_buffering off; + fastcgi_read_timeout 120s; ''; }; + "~ \\.(?:css|js|svg|gif|map)$".extraConfig = '' + try_files $uri /index.php$request_uri; + expires 6M; + access_log off; + ''; + "~ \\.woff2?$".extraConfig = '' + try_files $uri /index.php$request_uri; + expires 7d; + access_log off; + ''; + "~ ^\\/(?:updater|ocs-provider|ocm-provider)(?:$|\\/)".extraConfig = '' + try_files $uri/ =404; + index index.php; + ''; }; + extraConfig = '' + index index.php index.html /index.php$request_uri; + expires 1m; + add_header X-Content-Type-Options nosniff; + add_header X-XSS-Protection "1; mode=block"; + add_header X-Robots-Tag none; + add_header X-Download-Options noopen; + add_header X-Permitted-Cross-Domain-Policies none; + add_header X-Frame-Options sameorigin; + add_header Referrer-Policy no-referrer; + add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always; + client_max_body_size ${cfg.maxUploadSize}; + fastcgi_buffers 64 4K; + fastcgi_hide_header X-Powered-By; + gzip on; + gzip_vary on; + gzip_comp_level 4; + gzip_min_length 256; + gzip_proxied expired no-cache no-store private no_last_modified no_etag auth; + gzip_types application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy; + + ${optionalString cfg.webfinger '' + rewrite ^/.well-known/host-meta /public.php?service=host-meta last; + rewrite ^/.well-known/host-meta.json /public.php?service=host-meta-json last; + ''} + ''; }; - }) + } ]); meta.doc = ./nextcloud.xml; |