Skip to the content
Documentation
Help Start
Reading in:
  • German: 9,059 of 9,059 pages
About the help in other languages
All help pages

Web server examples

Complete, checked configurations for serving Exponential 6 with Velocity, Apache, nginx, Caddy, FrankenPHP, LiteSpeed, IIS and PHP-FPM, each with the same routing rules as the shipped .htaccess_root.

Download as PDF

Address: https://doc.exponential.earth/exphelp/viewer/examples/web-servers/README.md

On this page

Web server examples

Exponential is a directory of PHP files. Whatever serves it, the document root is the installation root (the directory with index.php) and the same routing applies: a short list of asset paths is sent as files, three front controllers run, and every other request is answered by index.php, which never hands out a file. That is what keeps settings/, var/, vendor/, kernel/, composer.json and the SQLite database safe although they lie inside the document root. The list is written down once, in .htaccess_root, and Velocity implements it rule for rule (expVelocity::STATIC_PATHS, FRONT_CONTROLLERS and ENTRY_SCRIPTS in kernel/classes/expvelocity.php).

Warning

.htaccess slows down every request. When .htaccess files are enabled (AllowOverride anything but None), let alone used, Apache looks for them and reads and evaluates them on every request, in every directory of the path, and page loading times go up drastically (measured). The only real fix is to switch the feature off for the virtual host: AllowOverride None in the HTTPS virtual host, and the rules in the virtual host's own configuration as mod_rewrite rules. That is far faster in production speed tests and well worth the time it takes to optimize a production configuration. Switch over right away: copy the rules of the example HTTPS virtual host into your virtual host (with the static cache, also staticcache_offload.conf), set AllowOverride None, run apachectl configtest, reload Apache and test the site. The same rules for other servers: nginx, LiteSpeed, Caddy, IIS, Velocity (built in); where virtual host rules go in a control panel: Plesk, cPanel, DirectAdmin, ISPConfig. On LiteSpeed or OpenLiteSpeed, the server's own page cache can also answer anonymous visitors and crawlers without PHP: Page caching with LiteSpeed and OpenLiteSpeed.

Every example on these pages is a complete file you can copy, with example.com and /var/www/example.com to replace. Each one implements the same list, in this order:

  1. a dot file or dot directory (.git, .env, .htaccess) answers 404 anywhere; .well-known is exempt;
  2. an existing .php, .phtml or .phar below the root answers 404: no script runs because its path was asked for;
  3. /api/... and /index_rest.php go to index_rest.php, /content/treemenu... (with or without a siteaccess in front) to index_treemenu.php;
  4. the asset list is sent as files: design and extension design directories, share/icons, the icon themes of extensions (extension/<name>/icons/: SVG, PNG and GIF images with exactly one extension), stored images, the image originals, stored PDF exports, the public caches, package previews, favicon.ico, robots.txt, index.js, sw.js and w3c/p3p.xml;
  5. everything else goes to index.php.

Which one

ServerPageRaw file to copyHow it was checked
Velocity (recommended)Velocityvelocity.ini.append.php.example, exponential-velocity.serviceevery setting exists in settings/velocity.ini; systemd-analyze verify
Apache, .htaccessApache .htaccess../htaccess (= .htaccess_root + optional blocks)httpd -t; a throwaway Apache answered every test request as expected
Apache, virtual hostApache virtual host../ezpublish.confhttpd -t; a throwaway Apache, HTTP and HTTPS, answered every test request as expected
nginxnginxnginx.confnginx -t; a throwaway nginx, HTTP and HTTPS, answered every test request as expected
CaddyCaddyCaddyfile.examplefrankenphp validate (Caddy 2.11 inside FrankenPHP 1.12.7)
FrankenPHPFrankenPHPfrankenphp.Caddyfile.examplefrankenphp validate
LiteSpeed, OpenLiteSpeedLiteSpeedopenlitespeed-vhost.confnot run on LiteSpeed; its rewrite rules answered every test request as expected in Apache's mod_rewrite
LiteSpeed, OpenLiteSpeed: page cachePage caching with LiteSpeed and OpenLiteSpeedlitespeed-page-cache.conf (and commented blocks in .htaccess_root and openlitespeed-vhost.conf)not run on LiteSpeed; the address condition was checked with PCRE against sample addresses (cached, and excluded: the administration, user/, shop/, content/ views other than view/)
IISIISweb.configwell-formed XML (xmllint) only; not run on IIS
PHP-FPM (behind Apache, nginx, Caddy)PHP-FPM poolphp-fpm-pool.confphp-fpm -t

The test requests: /.git/config, /.env, scripts below the root (in extension/, kernel/, vendor/, the package store, an asset directory) and a dot file in an asset directory must answer 404 without their content; /settings/site.ini, /composer.json, /config.php, /var/log/error.log and a stored non-image original must reach index.php and never be sent; /api/... must reach index_rest.php and /content/treemenu/... index_treemenu.php; each kind of listed asset must be sent (200), and an uploaded SVG must carry the sandbox content security policy. Run the same requests against your own server with the commands in chapter 13, section 13.2.

Two things every setup shares

  • Never use a generic "serve the file if it exists, else index.php" configuration (nginx try_files $uri /index.php, Caddy's php_fastcgi or php_server): it hands out every file that exists, settings/*.ini included.
  • .well-known is reachable but not on the asset list. The dot rule leaves it alone, then the request goes to index.php like any other. A certificate client that places challenge files there (certbot --webroot) needs the plain-HTTP host to serve them, as the port 80 hosts of the Apache and nginx examples do; Caddy, FrankenPHP and Velocity's qbix engine answer ACME challenges themselves.

Which servers read .htaccess. Apache (with AllowOverride All) and LiteSpeed Enterprise read it on the next request: there, ./console exp:setup:htaccess --apply copies .htaccess_root into place (--static copies .htaccess_root_static) and nothing else is needed. OpenLiteSpeed reads only its rewrite rules, only with autoLoadHtaccess on and only after a restart. nginx, Caddy, FrankenPHP and IIS never read it: their rules are in the configurations on these pages. Velocity has the rules of .htaccess_root built in; copy the file anyway when Apache may serve the same tree. See Setting up .htaccess and config.php from the console.

WebDAV is not routed by any of these examples: it is off by default. Since 6.0.15 its entry script is index_webdav.php (webdav.php only forwards to it until a later major version). To serve it, add a rule for index_webdav.php on Apache, nginx or IIS, or a WebDAV host of its own; Velocity, Caddy and FrankenPHP do not run it. Before/after rules for every server, and how to test them: The WebDAV entry script is now index_webdav.php.

Also in this directory

  • ../staticcache_offload.conf: Apache rules that serve a page generated by the static content cache without starting PHP (.htaccess_root_static is .htaccess_root with them already in place).
  • ../README.md: every example of the documentation.

Public demos. The settings that switch demo mode on for each of these servers (EXP_DEMO_MODE=1) are in Demo mode examples.

Something wrong on this page? Report an error

Documentation license

This documentation is free documentation, licensed under the GNU Free Documentation License 1.3 or later.

Exponential Copyright © 1998-2026 Exponential Foundation and 7x