Virtual host setup
How to serve an Exponential 6 installation. The document root is always the installation root, the directory that holds index.php. Pick one of the options below; the setup wizard needs one of them during the install, exp:install and the kickstarter do not.
| Exponential Velocity | Apache or nginx with PHP-FPM | |
|---|---|---|
| Other web server needed | no | yes |
| HTTPS | built in: your certificate, Let's Encrypt or any ACME CA, self-signed fallback | the web server's, with a certificate from your own tool |
| Role | recommended, from development to production | the classic setup, shared hosting |
Exponential Velocity (recommended)
Velocity is the application server of Exponential, installed with it by Composer. It loads the application once, keeps it in persistent workers, has its own response cache and serves HTTP and HTTPS itself. The shipped engine is php (PHP's built-in server, for development); set qbix for every real site:
php bin/php/console exp:velocity config set --apply ServerSettings Engine qbix php bin/php/console exp:velocity start php bin/php/console exp:velocity status
The qbix engine serves plain HTTP on port 8088 and HTTPS on port 8080, bound to 127.0.0.1. To serve the network on the standard ports (ports below 1024 need root; the workers still run as the installation's user):
php bin/php/console exp:velocity config set --apply ServerSettings Host 0.0.0.0 php bin/php/console exp:velocity config set --apply ServerSettings Port 80 php bin/php/console exp:velocity config set --apply ServerSettings HTTPSPort 443 php bin/php/console exp:velocity restart
HTTPS with a certificate you have (one PEM file may hold both):
php bin/php/console exp:velocity config set --apply HTTPSSettings Certificate /etc/ssl/example.com/fullchain.pem php bin/php/console exp:velocity config set --apply HTTPSSettings Key /etc/ssl/example.com/privkey.pem php bin/php/console exp:velocity config set --apply HTTPSSettings Enabled true php bin/php/console exp:velocity restart php bin/php/console exp:velocity ssl show
config set writes settings/override/velocity.ini.append.php; the shipped defaults stay in settings/velocity.ini. Without --apply it only shows the change. Velocity's own configuration follows Debian's /etc/apache2 layout under /etc/vc (vc.conf, ports.conf, envvars, sites-available and sites-enabled); exp:velocity layout shows every file it uses.
Day to day: exp:velocity deploy after a PHP, INI or class change (autoloads, caches, PHP-FPM reload and Velocity restart in the right order; --dry-run shows the steps), exp:velocity graceful for a restart without dropped requests, and exp:velocity cache clear --apply for the response cache. Workers keep the application in memory, so clearing caches alone does not reach a code change. A systemd unit to start Velocity at boot is in the Velocity example.
Apache with PHP-FPM
Copy the shipped rewrite rules into place, then add a virtual host:
./console exp:setup:htaccess # shows what would be copied ./console exp:setup:htaccess --apply # copies .htaccess_root to .htaccess
mod_rewrite, mod_proxy and mod_proxy_fcgi must be loaded, and mod_ssl for HTTPS. A minimal virtual host and the faster variant without .htaccess are on Virtual host example; what the rules do is on htaccess example. Check with apachectl configtest and reload Apache.
.htaccess slows down every request. When AllowOverride is anything but None, Apache reads and evaluates .htaccess files on every request, in every directory of the path. For production, put the rules into the virtual host itself and set AllowOverride None: the example HTTPS virtual host carries them.
nginx with PHP-FPM
nginx does not read .htaccess; its server block carries the same rules. This one passes nginx -t (nginx 1.28); replace example.com, /var/www/example.com, the PHP-FPM socket and the certificate paths, then run nginx -t and systemctl reload nginx:
server {
listen 80;
server_name example.com www.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
http2 on;
server_name example.com www.example.com;
ssl_certificate /etc/ssl/example.com/fullchain.pem;
ssl_certificate_key /etc/ssl/example.com/privkey.pem;
root /var/www/example.com;
index index.php;
client_max_body_size 64m;
# No dot file or dot directory; .well-known stays reachable
location ~ (^|/)\.(?!well-known(/|$)) { return 404; }
# No script below the root runs because its path was asked for
location ~ ^/.+/[^/]+\.(php[0-9]?|phtml|phar)$ { return 404; }
# Front controllers
location ^~ /api/ {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root/index_rest.php;
fastcgi_param SCRIPT_NAME /index_rest.php;
fastcgi_pass unix:/run/php-fpm/www.sock;
}
location ~ ^/([^/]+/)?content/treemenu {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root/index_treemenu.php;
fastcgi_param SCRIPT_NAME /index_treemenu.php;
fastcgi_pass unix:/run/php-fpm/www.sock;
}
# Files served as they are
location ~ ^/var/([^/]+/)?storage/images(-versioned)?/ { try_files $uri =404; }
location ~ ^/var/([^/]+/)?storage/original/image/.+\.(png|jpe?g|gif|webp|svg)$ { try_files $uri =404; }
location ~ ^/var/([^/]+/)?cache/(texttoimage|public)/ { try_files $uri =404; }
location ~ ^/design/[^/]+/(stylesheets|images|javascript|fonts)/ { try_files $uri =404; }
location ~ ^/share/icons/ { try_files $uri =404; }
location ~ ^/extension/[^/]+/design/[^/]+/(stylesheets|flash|images|lib|javascripts?|fonts|vendor|media)/ { try_files $uri =404; }
location = /favicon.ico { try_files $uri =404; }
location = /robots.txt { try_files $uri =404; }
# Everything else goes to index.php
location / {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root/index.php;
fastcgi_param SCRIPT_NAME /index.php;
fastcgi_pass unix:/run/php-fpm/www.sock;
}
}
This is the core of the rules. The complete nginx example adds the security headers, the sandbox for uploaded SVG images, the PDF and package files, the ACME challenge and the SOAP server.
Other servers and control panels
The same rules for LiteSpeed, Caddy, IIS and FrankenPHP, and an overview of all of them: Web server examples.
Behind a reverse proxy or load balancer
Forwarded headers (X-Forwarded-For, X-Forwarded-Proto, X-Forwarded-Host) are believed only from the addresses in site.ini [HTTPHeaderSettings] TrustedProxies[], by default 127.0.0.1 and ::1. Add a proxy on another machine in settings/override/site.ini.append.php:
[HTTPHeaderSettings] TrustedProxies[]=10.0.0.0/8
The complete chapter, with FrankenPHP, permissions and HTTPS in depth: Serving the site.
In this section
- Virtual host example Apache virtual host examples for Exponential 6 with PHP-FPM and HTTPS, with .htaccess or with the rules in the virtual host.
- htaccess example The Apache rewrite rules of Exponential 6: .htaccess_root, exp:setup:htaccess, and what each rule does.
- eZ JS Core rewrite rules ezjscore needs no extra rewrite rules in Exponential 6: how its calls and packed files are served, and how to check.
Contributors
- Geir Arne Waaler
- Ricardo Correia Maintainer
- André Rømcke Maintainer
- Andrea Melo Maintainer
- Bertrand Dunogier Maintainer
- Mahmoud Abu-Wardeh Commenter
- Graham Brookins Updated Maintainer
Comments (2 historical)
Written by readers of the earlier documentation sites, kept as they were.
Mistake in last rewrite rule
Mahmoud Abu-Wardeh ·
When I tried the rewrite rules above, Apache (2.0.54) complained with "mod_rewrite: maximum number of internal redirects reached", resulting in a 500 error.
The solution is that the last rewrite rule should read:
RewriteRule .* index.php # no leading slash
See http://www.sitepoint.com/print/mod_rewrite-no-endless-loops for an explanation.
By the way, this VirtualHost setup is quite differet to those in the .htaccess_root file that shops with ez Publish 3.7.2 - would you recommend a selective merge of the two or to stick to this example?
RE: Mistake in last rewrite rule
André R. ·
Not correct, I suspect you are talking about .htaccess.
These pages does not cover .htaccess, but vhost settings.