Skip to main content
https://github.com/collective/collective.xsendfile/actions/workflows/tests.yml/badge.svg?branch=master

collective.xsendfile

Introduction

Offload ZODB blob downloads to the front-end web server using the X-Sendfile / X-Accel-Redirect headers.

X-Sendfile (Apache, Lighttpd) and X-Accel-Redirect (nginx) let a backend application tell the front-end web server to send a file from disk, instead of sending the file content itself.

collective.xsendfile adds this to Plone:

  • Plone still handles the request as normal: traversal, permission checks, response headers.

  • Instead of streaming the file content through the proxy connection, Plone sends a response with a header holding the blob’s file path. The front-end web server reads the file from disk and sends it to the user.

Requirements

  • The front-end web server must be able to read the ZODB blob files, so it needs access to the blob directory on the same filesystem (or a shared mount), with permissions that let its user read the files.

  • Blobs must be committed. An image scale generated on the fly for the current request is streamed by Plone as usual; later requests for it are offloaded.

Compatibility

Version 2.x supports Plone 6.0, 6.1 and 6.2 on Python 3.10 or later. For older Plone and Python versions, use version 1.4 (git tag 1.4) from GitHub.

Supported front-end web servers

  • Apache, with mod_xsendfile (X-Sendfile header)

  • nginx (X-Accel-Redirect header)

  • Lighttpd (X-Sendfile header)

Supported download urls

  • .../@@download/fieldname/filename

  • .../@@display-file/fieldname/filename

  • .../context/form/++widget++widgetname/@@download/filename

  • .../@@images/fieldname and image scales, e.g. .../@@images/image/preview

Other urls will use the normal Zope download mechanism.

Installation

Adding collective.xsendfile to your project

Install it with pip:

pip install collective.xsendfile

or, if you use buildout, include it in the buildout.cfg:

eggs =
     collective.xsendfile

Its ZCML is loaded automatically through plone.autoinclude.

Configuration

There are two ways to configure collective.xsendfile, either site by site, or globally per Zope instance.

Per site

  • Install the add-on in your site(s) through the Plone add-on control panel

  • Enable XSendFile on your front-end web server and virtual host configuration (see below)

  • In the XSendFile Plone control panel, set the HTTP response header for your server and, if needed, the path rewriting

Per Zope instance

collective.xsendfile can also be configured globally for all Plone sites in a Zope instance using environment variables. When XSENDFILE_RESPONSEHEADER is set, the per-site settings are ignored, and there is no need to install the add-on in your sites.

XSENDFILE_RESPONSEHEADER

Activates global configuration. Either X-Sendfile (Apache, Lighttpd) or X-Accel-Redirect (nginx).

XSENDFILE_ENABLE_FALLBACK

true (the default) or yes means the file is served by Zope as usual when the request has no X-Forwarded-For header, i.e. when it did not come through the front-end proxy. Any other value always uses the header.

XSENDFILE_PATHREGEX_SEARCH

Regular expression applied to the blob’s absolute file path. Defaults to (.*).

XSENDFILE_PATHREGEX_SUBSTITUTE

Replacement for the matched path (Python re.sub syntax). Defaults to \1. For nginx this has to produce a URL under an internal location, for example /xsendfile/\1.

The per-site control panel has the same four settings.

Disabling for a request

Code that needs Zope to serve a file itself can disable xsendfile for the current request:

from collective.xsendfile.utils import disable_xsendfile

disable_xsendfile(request)

XSendFile installation for Apache on Debian/Ubuntu

Install and enable the Apache module:

sudo apt-get install libapache2-mod-xsendfile
sudo a2enmod xsendfile
sudo systemctl reload apache2

Related virtual host configuration. Limit XSendFilePath to the blob directory, so the header cannot be used to send any other file:

<VirtualHost *:80>

    ServerName example.com

    XSendFile on
    XSendFilePath /path/to/var/blobstorage

    RewriteEngine On
    RewriteRule (.*) http://127.0.0.1:8080/VirtualHostBase/http/example.com:80/VirtualHostRoot/$1 [L,P]

</VirtualHost>

Use the X-Sendfile header and leave the path settings at their defaults.

XSendFile installation on nginx

nginx needs an internal location that maps a URL prefix to the blob directory. internal is essential: it stops browsers from requesting that location directly:

server {
    listen 80;
    server_name example.com;

    location / {
        proxy_pass http://127.0.0.1:8080/VirtualHostBase/http/$host:80/VirtualHostRoot/;
        proxy_set_header Host            $host;
        proxy_set_header X-Real-IP       $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }

    location /xsendfile/ {
        internal;
        alias /path/to/var/blobstorage/;
    }
}

Then use the X-Accel-Redirect header and rewrite the blob path into that location:

  • path regex search: ^/path/to/var/blobstorage/(.*)

  • path regex substitution: /xsendfile/\1

More info

Troubleshooting

If you get an HTTP response like:

OK

The requested URL /site-images/xxx/cairo.jpg was not found on this server.

it is probably a file permission issue: the web server user cannot read the blob file. Also check that the path in the response header, after rewriting, matches your web server configuration.

Authors

Special thanks to Kapil Thangavelu, we extensively borrowed from his code ;-)

License

GNU General Public License, version 2 or later (GPL-2.0-or-later). See LICENSE.

Changelog

2.0.0 (2026-10-07)

  • Breaking: require Python 3.10 or later. Drop support for Python 2, Plone 5 and below. [instification]

  • Licence changed to GPLv2 or later, was GPL [instification]

  • Switch to semantic versioning [instification]

  • Add support for Plone 6.2 [instification]

  • Don’t monkeypatch ZODB blobs on ZODB 5.2.2 or later [instification]

  • Support Python 3 & Plone >= 5.2 [frapell, instification]

1.4 (2022-06-13)

  • Log OSError on creating blob directory. [enfold]

1.3 (2021-08-11)

  • Do not use binary mode for reading/writing the .layout [frapell]

1.2 (2021-07-01)

  • Plone 5.2 / Python 3 [frapell]

  • Add suport for image scales [frapell]

1.1 (2021-06-24)

  • add function disable_xsendfile to disable x-sendfile via code [enfold]

  • rebuilt code so it works with namedfile as well as plone.app.blob [djay]

  • added tests [djay]

1.1b1 (no pypi release)

  • Can use environment variables to globally set xsendfile for all sites [djay]

1.0dev (no pypi release)

  • Initial release

Metadata

Release files for collective.xsendfile 2.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for collective.xsendfile 2.0.0
File Size Uploaded
collective_xsendfile-2.0.0.tar.gz 26.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for collective.xsendfile 2.0.0
File Interpreter ABI Platform
collective_xsendfile-2.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 50.9 kB

Release files / collective_xsendfile-2.0.0.tar.gz

Download URL collective_xsendfile-2.0.0.tar.gz
Size 26.6 kB
Tags Source
SHA-256 checksum
How to use checksums
4f0267b714cd67cf9934a32156b09d7c94af4f4d9506088158e96b5e4d8a9e3f
BLAKE2b-256 checksum
How to use checksums
62d330e5c88fd1a93f9e32089072d10daecd068e03fa56f010cbd743d469ff64
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.7

Release files / collective_xsendfile-2.0.0-py3-none-any.whl

Download URL collective_xsendfile-2.0.0-py3-none-any.whl
Size 24.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
529f6b375ce66a55890dcb28961a4091d3ed6329dbd9cc6cba1fd7e239d38e45
BLAKE2b-256 checksum
How to use checksums
32a1e5f8e27acff6725dfea0a1cffc6cf4a26047c6b7c744c306455d1e137a0f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.7

Release history Release notifications | RSS feed

This release

2.0.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page