Skip to content

Web Server ​

QUIQQER supports Apache, Nginx and FrankenPHP (based on Caddy). Choose your server below for routing configuration and optional media delivery.

Web serverPHP integration
Apachemod_php or PHP-FPM
NginxPHP-FPM
FrankenPHP / CaddyEmbedded PHP

The Caddy configuration generator targets FrankenPHP. For standalone Caddy with PHP-FPM, configure routing and PHP integration in your own Caddyfile.

Keep local changes in the custom files described for each server. Regenerate the generated routing files after changing the corresponding QUIQQER settings.

Apache ​

Routing ​

Generate the Apache .htaccess file from the installation root:

shell
./console htaccess

See Console for the general command calling pattern.

The generated file includes custom rules from:

text
etc/htaccess.custom.php

Put local Apache customizations into that custom file instead of editing the generated .htaccess directly. Regenerate .htaccess after changing the custom file.

See Configuration for the role of etc/ files.

The generator creates a backup of an existing .htaccess below var/backup/ before writing the new file. Keep custom rules in etc/htaccess.custom.php; the generated root .htaccess can be replaced during updates or regeneration.

PHP-FPM ​

QUIQQER's generated Apache rules route virtual URLs to index.php and map special paths such as /bin, /lib, and /admin to the Core package directories.

When Apache is used with PHP-FPM or another proxy/FastCGI setup, make sure:

  • rewrite rules are processed before the QUIQQER front controller receives the request
  • PHP receives the original request URI and query string
  • static package assets below /packages/, /bin/, and generated media paths stay readable
  • the web server user and PHP-FPM user can write runtime directories that need writes

If a static path is handled by QUIQQER instead of the web server, add an early exception in etc/htaccess.custom.php and regenerate .htaccess.

Static Directories ​

When a static directory should be served before QUIQQER handles the request, add the exception near the top of etc/htaccess.custom.php.

Example for a static documentation directory under /docs:

apache
<IfModule mod_rewrite.c>
    RewriteEngine On

    RewriteRule ^docs/?$ /docs/index.html [END]

    RewriteCond %{DOCUMENT_ROOT}/docs/$1 -f
    RewriteRule ^docs/(.*)$ - [END]

    RewriteCond %{DOCUMENT_ROOT}/docs/$1 -d
    RewriteRule ^docs/(.*)$ - [END]

    RewriteCond %{DOCUMENT_ROOT}/docs/$1/index.html -f
    RewriteRule ^docs/(.*)/?$ /docs/$1/index.html [END]

    RewriteCond %{DOCUMENT_ROOT}/docs/$1.html -f
    RewriteRule ^docs/(.*)$ /docs/$1.html [END]
</IfModule>

This lets Apache serve existing files, directories, directory index pages, and extensionless static HTML pages under /docs before the QUIQQER front controller handles the request.

Media Delivery ​

Optional, from QUIQQER 2.34. Read the shared media delivery requirements before configuring X-Sendfile.

Install and load mod_xsendfile, then add the following to the virtual host configuration. XSendFilePath belongs in the server/virtual host configuration, not in the generated .htaccess:

apache
XSendFile On
# For module builds supporting URL decoding, including Debian's 0.12+git build:
XSendFileUnescape Off
XSendFilePath /srv/quiqqer/media
XSendFilePath /srv/quiqqer/var/media

# Apache with mod_php:
SetEnv QUIQQER_SENDFILE_TYPE X-Sendfile

With PHP-FPM via mod_proxy_fcgi, replace the SetEnv line with:

apache
ProxyFCGISetEnvIf "true" QUIQQER_SENDFILE_TYPE "X-Sendfile"

Symfony passes the resolved filesystem path without URL encoding. Therefore, module builds with URL decoding enabled need XSendFileUnescape Off, including for filenames containing a literal percent sign. Omit that directive only for older module versions without URL decoding support, such as the original 0.12 release.

Keep existing rules denying direct access to protected originals. XSendFilePath permits delegated delivery; it does not block ordinary URL access. Run apachectl configtest before reloading Apache.

Nginx ​

Routing ​

QUIQQER also provides a console tool for NGINX configuration generation:

shell
./console quiqqer:nginx

Use the generated output as the basis for the web server configuration and keep local server-specific changes in the server configuration managed by operations.

The generator writes the main example configuration to:

text
etc/nginx/nginx.example.conf

It also creates include files below:

text
etc/nginx/conf.d/

Use these include files for local server-specific changes such as PHP-FPM, redirect, SSL, whitelist, and server configuration. Replace the generated example PHP-FPM socket path with the real PHP-FPM socket or upstream used by the server.

The generated NGINX routing uses virtual path checks. Missing real files are rewritten to QUIQQER's front controller, while known static paths and admin paths are handled separately.

Media Delivery ​

Optional, from QUIQQER 2.34. Read the shared media delivery requirements before configuring X-Accel-Redirect.

Add these parameters inside the existing FastCGI locations that serve image.php and the QUIQQER front controller, after their existing fastcgi_params or fastcgi.conf include:

nginx
fastcgi_param QUIQQER_SENDFILE_TYPE X-Accel-Redirect;
fastcgi_param QUIQQER_ACCEL_MAPPING "/srv/quiqqer/media/=/__quiqqer_media/,/srv/quiqqer/var/media/=/__quiqqer_var_media/";

Add the corresponding locations at server level:

nginx
location ^~ /__quiqqer_media/ {
    internal;
    alias /srv/quiqqer/media/;
}

location ^~ /__quiqqer_var_media/ {
    internal;
    alias /srv/quiqqer/var/media/;
}

internal prevents direct requests from bypassing the PHP access check. Keep the installation's existing protections for original media URLs as well. Do not disable X-Accel-Redirect processing with fastcgi_ignore_headers, or override private/no-store cache policies in these locations.

Keep these additions in the server configuration managed by operations, rather than editing generated example files. Run nginx -t before reloading NGINX.

FrankenPHP / Caddy ​

QUIQQER provides FrankenPHP configuration support from QUIQQER 2.23. Optional web server media delivery requires QUIQQER 2.34; see the media delivery setup for the required FrankenPHP and Caddy versions.

Routing ​

Generate the FrankenPHP routing configuration from the installation root:

shell
./console quiqqer:frankenphp

The generator writes:

text
etc/webserver/frankenphp/Caddyfile.include

Import this file inside your site's Caddyfile block. Replace the domain and installation path with your own values:

text
http://example.com, https://example.com {
    import /srv/quiqqer/etc/webserver/frankenphp/Caddyfile.include
}

Keep domain names, TLS, logging and server-wide settings in your own Caddyfile. The generated include supplies the installation's document root and routing for the frontend, administration interface and package assets.

Put local routing changes in etc/webserver/frankenphp/conf.d/. The generator creates pre.caddy, php.caddy, redirects.caddy, whitelist.caddy, optimizations.caddy and post.caddy if they do not exist, and preserves existing custom files. PHP handler options belong in php.caddy.

Do not edit Caddyfile.include directly. The generator backs up an existing file below var/backup/ before replacing it.

Media Delivery ​

This is optional. Read the shared media delivery requirements before configuring X-Accel-Redirect.

For this configuration, use FrankenPHP 1.4.0 or later with Caddy 2.9.1 or later. FrankenPHP 1.4.0 includes Caddy 2.9.1, which supports the response interception used here. These server requirements apply in addition to QUIQQER 2.34 or later.

See the FrankenPHP 1.4.0 release and its Caddy dependency.

Integrate the following fragment into the existing QUIQQER site's route, preserving its routing and private-file protections:

caddyfile
route {
    # Reject direct requests before PHP handles the request.
    respond /__quiqqer_media/* 404

    intercept {
        @media header X-Accel-Redirect *
        handle_response @media {
            root * /srv/quiqqer/media
            rewrite * {resp.header.X-Accel-Redirect}
            uri strip_prefix /__quiqqer_media
            header -X-Accel-Redirect
            file_server
        }
    }

    php_server {
        env QUIQQER_SENDFILE_TYPE X-Accel-Redirect
        env QUIQQER_ACCEL_MAPPING /srv/quiqqer/media/=/__quiqqer_media/
    }
}

The original GET/HEAD method is retained. Files outside this mapping, such as previews in a separate VAR_DIR, continue streaming through PHP. To delegate those as well, add matching internal routes and mappings with their respective filesystem roots and direct-access protection.

For standalone Caddy with PHP-FPM, use the same interception route and place the env parameters inside the existing php_fastcgi block instead of php_server. Validate the complete configuration with frankenphp validate --config /etc/frankenphp/Caddyfile or caddy validate before reloading.

Media Delivery ​

Available from QUIQQER 2.34.

QUIQQER can check access to a media file in PHP and delegate its delivery to the web server. This avoids passing the file content through PHP and is particularly useful for large files or many concurrent downloads.

No QUIQQER backend setting is required. Enable the feature through the web server configuration in the Apache, Nginx or FrankenPHP / Caddy section. Without that configuration, QUIQQER continues streaming files through PHP.

This applies to image.php and media delivery through QUI\Rewrite::sendFileWithRange(), including backend previews using that method. Other package download endpoints and downloads using QUI\Utils\System\File::downloadHeader() are not covered. SVG files continue through PHP so that their content is sanitized before delivery.

Server Parameters ​

The web server supplies these internal CGI/environment parameters to PHP:

ParameterValue
QUIQQER_SENDFILE_TYPEExactly X-Sendfile for Apache or X-Accel-Redirect for NGINX/Caddy.
QUIQQER_ACCEL_MAPPINGFor X-Accel-Redirect: comma-separated absolute-directory/=internal-uri/ pairs.

Both sides of each mapping must end with /. The filesystem prefix must match the resolved absolute path visible to PHP. The URI prefix must match the web server's internal file-serving route. The first valid matching pair is used. Do not use commas or equals signs inside mapping paths.

Adapt the examples to the actual media directories and VAR_DIR of the installation. Map only the media directories needed for delivery. The web server must be able to read those files; container deployments need corresponding shared mounts.

Set these parameters directly in the server configuration. Do not derive them from HTTP headers, query parameters or other client input. QUIQQER ignores client-supplied X-Sendfile-Type, X-Accel-Mapping and HTTP_QUIQQER_* values for this feature.

Verify Media Delivery ​

Test through the public web server using a non-SVG media URL handled by PHP:

  • An authorized GET returns the complete file and the expected content type, disposition and cache policy.
  • HEAD returns file metadata without a body.
  • A request with Range: bytes=0-9 returns status 206 and the first ten bytes.
  • Unauthorized requests and direct requests to internal media URIs cannot read protected files.
  • SVG responses still contain sanitized content.
  • Removing the internal server parameters restores PHP streaming, including range support.
  • Supplying fake Sendfile HTTP headers does not change the delivery behavior.

Missing or unknown server parameters, and invalid or unmatched acceleration mappings, retain PHP streaming. However, if a server advertises support but its file-serving configuration is broken, PHP cannot retry after handing over the response. Check the server error log, mappings and file permissions.

The server consumes the offload response header. Its absence in the browser alone does not prove delegation; use upstream response inspection or server diagnostics in a test environment when checking the handoff.

See also Symfony's file responses, NGINX internal locations, Apache mod_xsendfile and FrankenPHP file delivery.

Validation ​

After changing routing rules:

  • regenerate the generated server file when Apache .htaccess is used
  • reload the web server when the server configuration changed
  • test the public homepage
  • test the administration interface
  • test static directories and assets
  • check the web server error log

Troubleshooting ​

SymptomCheck
Static files return a QUIQQER pageAdd an early Apache/NGINX exception for the static path before the front-controller rewrite.
Extensionless static docs return 404Add a rewrite from the extensionless path to the generated .html file.
Admin or frontend returns 403 after web server changesCheck generated deny rules, custom rules, document root, and whether the request is rewritten to the expected target.
NGINX returns 502/504Check the PHP-FPM socket/upstream path in etc/nginx/conf.d/ and PHP-FPM availability.
CLI generation works but web requests failCompare CLI user, PHP-FPM user, file ownership, and web server include paths.

Released under GPL-3.0-or-later.