Skip to content

Webserver offload

ernolf edited this page Oct 8, 2026 · 2 revisions

📤 Webserver offload

Tip

TL;DR Apache or nginx send the file body instead of PHP. Off by default. With nginx set a size threshold: offloaded nginx responses carry no CSP.

⚙️ Settings

Key Type Default Effect
raw_sendfile_backend off, apache, nginx off which mechanism to use
raw_sendfile_allow_private bool false also offload private URLs (/raw/u/...)
raw_sendfile_min_size_mb int 0 offload only files of at least this size, 0 = no threshold
raw_sendfile_nginx_prefix string /_raw_sendfile internal nginx location

A file is offloaded only when all of these hold:

  • it lies on local storage inside Nextcloud's datadirectory;
  • the request is public, or raw_sendfile_allow_private is true;
  • with a threshold set, its size is known and reaches the threshold.

Otherwise PHP streams the file as usual.

Warning

The app restricts offload to the data directory. The webserver side is the administrator's responsibility.

  • nginx: internal; is mandatory. Without it the offload location can be requested directly from the internet, and every file in the data directory is reachable without authentication.
  • Apache: set XSendFilePath. The app only sends paths inside the data directory, so this is defense in depth.

🪶 Apache

Needs mod_xsendfile or an equivalent X-Sendfile implementation, enabled for the Nextcloud vhost:

XSendFile On
XSendFilePath /path/to/nextcloud/data
'raw_sendfile_backend' => 'apache',

🟩 nginx

Uses X-Accel-Redirect, no extra module. The location must match raw_sendfile_nginx_prefix:

location /_raw_sendfile/ {
    internal;
    alias /path/to/nextcloud/data/;
}
'raw_sendfile_backend' => 'nginx',
'raw_sendfile_nginx_prefix' => '/_raw_sendfile',
'raw_sendfile_min_size_mb' => 10,

Tip

The redirect target is the file path with the realpath of datadirectory stripped. The alias must use that same resolved path with a trailing /. If datadirectory is a symlink and nginx points elsewhere, the paths do not match.

Warning

nginx offload drops the Content-Security-Policy header. With X-Accel-Redirect nginx sends the body itself and does not pass on the CSP set by PHP. Set raw_sendfile_min_size_mb (for example 10) so HTML, text, feeds and images stay with PHP and keep their CSP, and only large binaries are offloaded. If every response needs a CSP, do not use the nginx backend.

🐞 Debugging

Send X-Raw-Offload-Debug: 1 to get the reason in the response:

curl -sI -H 'X-Raw-Offload-Debug: 1' 'https://cloud.example.com/raw/<token>/video.mp4' | grep -i '^x-raw-offload'
X-Raw-Offload Meaning
apache-xsendfile; reason=offloaded sent by Apache
nginx-x-accel; reason=offloaded sent by nginx
none; reason=backend_off raw_sendfile_backend is off
none; reason=private_disallowed private URL, raw_sendfile_allow_private is false
none; reason=too_small below raw_sendfile_min_size_mb
none; reason=size_unknown threshold set, size not reported by the storage
none; reason=not_in_datadir file outside datadirectory
none; reason=no_local_path storage has no local file, for example external or object storage
none; reason=nginx_map_fail datadirectory could not be resolved
none; reason=no_fast_etag storage reports no mtime or size, PHP sends the body
none; reason=head_request HEAD, no body to send
none; reason=not_modified 304, no body to send

Without the debug header an offloaded response still carries X-Raw-Offload: apache-xsendfile or nginx-x-accel.

➡️ Next

Configuration reference

Clone this wiki locally