1# Nextcloud {#module-services-nextcloud}
2
3[Nextcloud](https://nextcloud.com/) is an open-source,
4self-hostable cloud platform. The server setup can be automated using
5[services.nextcloud](#opt-services.nextcloud.enable). A
6desktop client is packaged at `pkgs.nextcloud-client`.
7
8The current default by NixOS is `nextcloud31` which is also the latest
9major version available.
10
11## Basic usage {#module-services-nextcloud-basic-usage}
12
13Nextcloud is a PHP-based application which requires an HTTP server
14([`services.nextcloud`](#opt-services.nextcloud.enable)
15and optionally supports
16[`services.nginx`](#opt-services.nginx.enable)).
17
18For the database, you can set
19[`services.nextcloud.config.dbtype`](#opt-services.nextcloud.config.dbtype) to
20either `sqlite` (the default), `mysql`, or `pgsql`. The simplest is `sqlite`,
21which will be automatically created and managed by the application. For the
22last two, you can easily create a local database by setting
23[`services.nextcloud.database.createLocally`](#opt-services.nextcloud.database.createLocally)
24to `true`, Nextcloud will automatically be configured to connect to it through
25socket.
26
27A very basic configuration may look like this:
28```nix
29{ pkgs, ... }:
30{
31 services.nextcloud = {
32 enable = true;
33 hostName = "nextcloud.tld";
34 database.createLocally = true;
35 config = {
36 dbtype = "pgsql";
37 adminpassFile = "/path/to/admin-pass-file";
38 };
39 };
40
41 networking.firewall.allowedTCPPorts = [
42 80
43 443
44 ];
45}
46```
47
48The `hostName` option is used internally to configure an HTTP
49server using [`PHP-FPM`](https://php-fpm.org/)
50and `nginx`. The `config` attribute set is
51used by the imperative installer and all values are written to an additional file
52to ensure that changes can be applied by changing the module's options.
53
54In case the application serves multiple domains (those are checked with
55[`$_SERVER['HTTP_HOST']`](https://www.php.net/manual/en/reserved.variables.server.php))
56it's needed to add them to
57[`services.nextcloud.settings.trusted_domains`](#opt-services.nextcloud.settings.trusted_domains).
58
59Auto updates for Nextcloud apps can be enabled using
60[`services.nextcloud.autoUpdateApps`](#opt-services.nextcloud.autoUpdateApps.enable).
61
62## `nextcloud-occ` {#module-services-nextcloud-occ}
63
64The management command [`occ`](https://docs.nextcloud.com/server/stable/admin_manual/occ_command.html) can be
65invoked by using the `nextcloud-occ` wrapper that's globally available on a system with Nextcloud enabled.
66
67It requires elevated permissions to become the `nextcloud` user. Given the way the privilege
68escalation is implemented, parameters passed via the environment to Nextcloud are
69currently ignored, except for `OC_PASS` and `NC_PASS`.
70
71Custom service units that need to run `nextcloud-occ` either need elevated privileges
72or the systemd configuration from `nextcloud-setup.service` (recommended):
73
74```nix
75{ config, ... }:
76{
77 systemd.services.my-custom-service = {
78 script = ''
79 nextcloud-occ …
80 '';
81 serviceConfig = {
82 inherit (config.systemd.services.nextcloud-cron.serviceConfig)
83 User
84 LoadCredential
85 KillMode
86 ;
87 };
88 };
89}
90```
91
92Please note that the options required are subject to change. Please make sure to read the
93release notes when upgrading.
94
95## Common problems {#module-services-nextcloud-pitfalls-during-upgrade}
96
97 - **General notes.**
98 Unfortunately Nextcloud appears to be very stateful when it comes to
99 managing its own configuration. The config file lives in the home directory
100 of the `nextcloud` user (by default
101 `/var/lib/nextcloud/config/config.php`) and is also used to
102 track several states of the application (e.g., whether installed or not).
103
104 All configuration parameters are also stored in
105 {file}`/var/lib/nextcloud/config/override.config.php` which is generated by
106 the module and linked from the store to ensure that all values from
107 {file}`config.php` can be modified by the module.
108 However {file}`config.php` manages the application's state and shouldn't be
109 touched manually because of that.
110
111 ::: {.warning}
112 Don't delete {file}`config.php`! This file
113 tracks the application's state and a deletion can cause unwanted
114 side-effects!
115 :::
116
117 ::: {.warning}
118 Don't rerun `nextcloud-occ maintenance:install`!
119 This command tries to install the application
120 and can cause unwanted side-effects!
121 :::
122 - **Multiple version upgrades.**
123 Nextcloud doesn't allow to move more than one major-version forward. E.g., if you're on
124 `v16`, you cannot upgrade to `v18`, you need to upgrade to
125 `v17` first. This is ensured automatically as long as the
126 [stateVersion](#opt-system.stateVersion) is declared properly. In that case
127 the oldest version available (one major behind the one from the previous NixOS
128 release) will be selected by default and the module will generate a warning that reminds
129 the user to upgrade to latest Nextcloud *after* that deploy.
130 - **`Error: Command "upgrade" is not defined.`**
131 This error usually occurs if the initial installation
132 ({command}`nextcloud-occ maintenance:install`) has failed. After that, the application
133 is not installed, but the upgrade is attempted to be executed. Further context can
134 be found in [NixOS/nixpkgs#111175](https://github.com/NixOS/nixpkgs/issues/111175).
135
136 First of all, it makes sense to find out what went wrong by looking at the logs
137 of the installation via {command}`journalctl -u nextcloud-setup` and try to fix
138 the underlying issue.
139
140 - If this occurs on an *existing* setup, this is most likely because
141 the maintenance mode is active. It can be deactivated by running
142 {command}`nextcloud-occ maintenance:mode --off`. It's advisable though to
143 check the logs first on why the maintenance mode was activated.
144 - ::: {.warning}
145 Only perform the following measures on
146 *freshly installed instances!*
147 :::
148
149 A re-run of the installer can be forced by *deleting*
150 {file}`/var/lib/nextcloud/config/config.php`. This is the only time
151 advisable because the fresh install doesn't have any state that can be lost.
152 In case that doesn't help, an entire re-creation can be forced via
153 {command}`rm -rf ~nextcloud/`.
154
155 - **Server-side encryption.**
156 Nextcloud supports [server-side encryption (SSE)](https://docs.nextcloud.com/server/latest/admin_manual/configuration_files/encryption_configuration.html).
157 This is not an end-to-end encryption, but can be used to encrypt files that will be persisted
158 to external storage such as S3.
159
160 - **Issues with file permissions / unsafe path transitions**
161
162 {manpage}`systemd-tmpfiles(8)` makes sure that the paths for
163
164 * configuration (including declarative config)
165 * data
166 * app store
167 * home directory itself (usually `/var/lib/nextcloud`)
168
169 are properly set up. However, `systemd-tmpfiles` will refuse to do so
170 if it detects an unsafe path transition, i.e. creating files/directories
171 within a directory that is neither owned by `root` nor by `nextcloud`, the
172 owning user of the files/directories to be created.
173
174 Symptoms of that include
175
176 * `config/override.config.php` not being updated (and the config file
177 eventually being garbage-collected).
178 * failure to read from application data.
179
180 To work around that, please make sure that all directories in question
181 are owned by `nextcloud:nextcloud`.
182
183 - **`Failed to open stream: No such file or directory` after deploys**
184
185 Symptoms are errors like this after a deployment that disappear after
186 a few minutes:
187
188 ```
189 Warning: file_get_contents(/run/secrets/nextcloud_db_password): Failed to open stream: No such file or directory in /nix/store/lqw657xbh6h67ccv9cgv104qhcs1i2vw-nextcloud-config.php on line 11
190
191 Warning: http_response_code(): Cannot set response code - headers already sent (output started at /nix/store/lqw657xbh6h67ccv9cgv104qhcs1i2vw-nextcloud-config.php:11) in /nix/store/ikxpaq7kjdhpr4w7cgl1n28kc2gvlhg6-nextcloud-29.0.7/lib/base.php on line 639
192 Cannot decode /run/secrets/nextcloud_secrets, because: Syntax error
193 ```
194
195 This can happen if [](#opt-services.nextcloud.secretFile) or
196 [](#opt-services.nextcloud.config.dbpassFile) are managed by
197 [sops-nix](https://github.com/Mic92/sops-nix/).
198
199 Here, `/run/secrets/nextcloud_secrets` is a symlink to
200 `/run/secrets.d/N/nextcloud_secrets`. The `N` will be incremented
201 when the sops-nix activation script runs, i.e.
202 `/run/secrets.d/N` doesn't exist anymore after a deploy,
203 only `/run/secrets.d/N+1`.
204
205 PHP maintains a [cache for `realpath`](https://www.php.net/manual/en/ini.core.php#ini.realpath-cache-size)
206 that still resolves to the old path which is causing
207 the `No such file or directory` error. Interestingly,
208 the cache isn't used for `file_exists` which is why this warning
209 comes instead of the error from `nix_read_secret` in
210 `override.config.php`.
211
212 One option to work around this is to turn off the cache by setting
213 the cache size to zero:
214
215 ```nix
216 { services.nextcloud.phpOptions."realpath_cache_size" = "0"; }
217 ```
218
219 - **Empty Files on chunked uploads**
220
221 Due to a limitation of PHP-FPM, Nextcloud is unable to handle chunked
222 uploads. See upstream issue
223 [nextcloud/server#7995](https://github.com/nextcloud/server/issues/7995)
224 for details.
225
226 A workaround is to disable chunked uploads with
227 {option}`nextcloud.nginx.enableFastcgiRequestBuffering`.
228
229## Using an alternative webserver as reverse-proxy (e.g. `httpd`) {#module-services-nextcloud-httpd}
230
231By default, `nginx` is used as reverse-proxy for `nextcloud`.
232However, it's possible to use e.g. `httpd` by explicitly disabling
233`nginx` using [](#opt-services.nginx.enable) and fixing the
234settings `listen.owner` & `listen.group` in the
235[corresponding `phpfpm` pool](#opt-services.phpfpm.pools).
236
237An exemplary configuration may look like this:
238```nix
239{
240 config,
241 lib,
242 pkgs,
243 ...
244}:
245{
246 services.nginx.enable = false;
247 services.nextcloud = {
248 enable = true;
249 hostName = "localhost";
250
251 # further, required options
252 };
253 services.phpfpm.pools.nextcloud.settings = {
254 "listen.owner" = config.services.httpd.user;
255 "listen.group" = config.services.httpd.group;
256 };
257 services.httpd = {
258 enable = true;
259 adminAddr = "webmaster@localhost";
260 extraModules = [ "proxy_fcgi" ];
261 virtualHosts."localhost" = {
262 documentRoot = config.services.nextcloud.package;
263 extraConfig = ''
264 <Directory "${config.services.nextcloud.package}">
265 <FilesMatch "\.php$">
266 <If "-f %{REQUEST_FILENAME}">
267 SetHandler "proxy:unix:${config.services.phpfpm.pools.nextcloud.socket}|fcgi://localhost/"
268 </If>
269 </FilesMatch>
270 <IfModule mod_rewrite.c>
271 RewriteEngine On
272 RewriteBase /
273 RewriteRule ^index\.php$ - [L]
274 RewriteCond %{REQUEST_FILENAME} !-f
275 RewriteCond %{REQUEST_FILENAME} !-d
276 RewriteRule . /index.php [L]
277 </IfModule>
278 DirectoryIndex index.php
279 Require all granted
280 Options +FollowSymLinks
281 </Directory>
282 '';
283 };
284 };
285}
286```
287
288## Installing Apps and PHP extensions {#installing-apps-php-extensions-nextcloud}
289
290Nextcloud apps are installed statefully through the web interface.
291Some apps may require extra PHP extensions to be installed.
292This can be configured with the [](#opt-services.nextcloud.phpExtraExtensions) setting.
293
294Alternatively, extra apps can also be declared with the [](#opt-services.nextcloud.extraApps) setting.
295When using this setting, apps can no longer be managed statefully because this can lead to Nextcloud updating apps
296that are managed by Nix:
297
298```nix
299{ config, pkgs, ... }:
300{
301 services.nextcloud.extraApps = with config.services.nextcloud.package.packages.apps; {
302 inherit user_oidc calendar contacts;
303 };
304}
305```
306
307Keep in mind that this is essentially a mirror of the apps from the appstore, but managed in
308nixpkgs. This is by no means a curated list of apps that receive special testing on each update.
309
310If you want automatic updates it is recommended that you use web interface to install apps.
311
312## Known warnings {#module-services-nextcloud-known-warnings}
313
314### Logreader application only supports "file" log_type {#module-services-nextcloud-warning-logreader}
315
316This is because
317
318* our module writes logs into the journal (`journalctl -t Nextcloud`)
319* the Logreader application that allows reading logs in the admin panel is enabled
320 by default and requires logs written to a file.
321
322If you want to view logs in the admin panel,
323set [](#opt-services.nextcloud.settings.log_type) to "file".
324
325If you prefer logs in the journal, disable the logreader application to shut up the
326"info". We can't really do that by default since whether apps are enabled/disabled
327is part of the application's state and tracked inside the database.
328
329## Maintainer information {#module-services-nextcloud-maintainer-info}
330
331As stated in the previous paragraph, we must provide a clean upgrade-path for Nextcloud
332since it cannot move more than one major version forward on a single upgrade. This chapter
333adds some notes how Nextcloud updates should be rolled out in the future.
334
335While minor and patch-level updates are no problem and can be done directly in the
336package-expression (and should be backported to supported stable branches after that),
337major-releases should be added in a new attribute (e.g. Nextcloud `v19.0.0`
338should be available in `nixpkgs` as `pkgs.nextcloud19`).
339To provide simple upgrade paths it's generally useful to backport those as well to stable
340branches. As long as the package-default isn't altered, this won't break existing setups.
341After that, the versioning-warning in the `nextcloud`-module should be
342updated to make sure that the
343[package](#opt-services.nextcloud.package)-option selects the latest version
344on fresh setups.
345
346If major-releases will be abandoned by upstream, we should check first if those are needed
347in NixOS for a safe upgrade-path before removing those. In that case we should keep those
348packages, but mark them as insecure in an expression like this (in
349`<nixpkgs/pkgs/servers/nextcloud/default.nix>`):
350```nix
351# ...
352{
353 nextcloud17 = generic {
354 version = "17.0.x";
355 sha256 = "0000000000000000000000000000000000000000000000000000";
356 eol = true;
357 };
358}
359```
360
361Ideally we should make sure that it's possible to jump two NixOS versions forward:
362i.e. the warnings and the logic in the module should guard a user to upgrade from a
363Nextcloud on e.g. 19.09 to a Nextcloud on 20.09.