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

Apache with PHP-FPM

How a host serves Exponential with Apache httpd 2.4 and a PHP-FPM pool per site: the shipped rewrite rules, the virtual host, HTTPS, the right FPM master to reload, Plesk, and the checks before go-live.

Download as PDF

Address: https://doc.exponential.earth/exphelp/viewer/help/hosting/servers/apache-with-php-fpm.md

On this page

Apache with PHP-FPM

This page is for system administrators at hosting companies who serve Exponential with Apache httpd 2.4 and PHP-FPM, the classic setup and the usual one on shared hosting and control panels. It answers: which modules and rules are needed, how the virtual host looks, how HTTPS and the PHP-FPM pool fit in, which FPM master to reload after a change, and how to check the result. The source is Chapter 8, Apache with PHP-FPM.

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.

Contents

  1. Why Apache
  2. Step by step
  3. Rules in .htaccess or in the virtual host
  4. The PHP-FPM pool
  5. Reloading the right PHP-FPM
  6. Plesk
  7. Static cache offload
  8. What can go wrong
  9. Checklist

Why Apache

  • It needs no long-running process of the customer's own, so it fits shared hosting.
  • The rewrite rules ship with Exponential as .htaccess_root; Apache (and LiteSpeed) read them directly.
  • Operating system support lists Apache httpd 2.4 with PHP-FPM (or mod_php) as tier 1. PHP-FPM is preferred over mod_php, which "ties PHP to Apache's prefork model" (PHP SAPIs).
  • It runs Exponential on PHP 8.0 and later (PHP 7.4 usable without support), so it is the answer on machines with the stock PHP 8.0 of Red Hat Enterprise Linux 9 and its rebuilds.

Step by step

  1. Enable the rewrite rules. Copy, do not move, so an update can bring a new version:

    cp .htaccess_root .htaccess

    Or ./console exp:setup:htaccess --apply, run as the site's user: it keeps the template's mode, refuses to replace a .htaccess that differs unless you add --force (backup first), and shows what it would do when --apply is left out (Setting up .htaccess and config.php from the console). Use .htaccess_root_static instead (exp:setup:htaccess --static --apply) only when the site serves a generated static cache (Static cache).

  2. Load the modules: mod_rewrite, mod_proxy and mod_proxy_fcgi (Debian: a2enmod rewrite proxy_fcgi); for HTTPS mod_ssl, for HTTP/2 mod_http2.

  3. Create the virtual host (adjust paths and the PHP-FPM socket):

    <VirtualHost *:80>
        ServerName example.com
        ServerAlias www.example.com
        # The installation root, where index.php is
        DocumentRoot /var/www/vhosts/example.com/httpdocs
        DirectoryIndex index.php
    
        <Directory /var/www/vhosts/example.com/httpdocs>
            Options FollowSymLinks
            # Lets Apache read the .htaccess created in step 1
            AllowOverride All
            Require all granted
        </Directory>
    
        # Every PHP script goes to the PHP-FPM pool of this site
        <FilesMatch \.php$>
            SetHandler "proxy:unix:/run/php-fpm/example.com.sock|fcgi://localhost"
        </FilesMatch>
    </VirtualHost>
  4. HTTPS. Add a *:443 virtual host with the same content plus:

        SSLEngine on
        SSLCertificateFile    /etc/ssl/example.com/fullchain.pem
        SSLCertificateKeyFile /etc/ssl/example.com/privkey.pem
        Protocols h2 http/1.1

    Obtain the certificate with certbot or the panel. Once HTTPS works, redirect port 80 in the *:80 host (Redirect permanent / https://example.com/).

  5. Check and reload:

    apachectl configtest           # Syntax OK
    systemctl reload apache2       # httpd on Red Hat style systems
    curl -sI https://example.com/ | head -1
  6. Security headers. The kernel sends them on its pages (site.ini [HTTPHeaderSettings] SecurityHeaders[]). For static files add the same with mod_headers if you want them there too (Chapter 13).

Rules in .htaccess or in the virtual host

.htaccessrules in the virtual host
NeedsAllowOverride AllAllowOverride None
Costa file lookup per directoryAllowOverride None saves that lookup
Customer can change ityes, which suits shared hostingno, only the host
Upgradecopy the new .htaccess_root over .htaccess (exp:setup:htaccess shows the diff, --force --apply copies)copy the changed rules into the vhost

Inside <Directory> the rules of .htaccess_root keep their form. In server context (outside <Directory>) every pattern needs a leading slash, as in doc/eng-us/examples/ezpublish.conf. That example's rule list predates the current .htaccess_root, so take the rules from .htaccess_root itself (Chapter 8, step 3).

Warning

After every upgrade, compare your copied rules with the new .htaccess_root. A rule that is missing can expose files that should never be sent; a rule that is added can be the fix for exactly that. ./console exp:setup:htaccess prints that comparison as a diff and exits 1 while .htaccess differs, which also makes it a drift check for monitoring.

The PHP-FPM pool

The pool runs PHP as the site's user. The settings chapter 8 names for Exponential (in the pool file or php.ini):

SettingGuidance from the sources
memory_limitat least 256M in production; more for large imports. The setup wizard's floor is 64M (Chapter 2)
max_execution_timethe wizard's floor is 30; chapter 2's production example uses 60
upload_max_filesize, post_max_sizethe customer's largest upload
date.timezoneset it; a missing value fails the wizard's critical test
OPcacheon, with timestamp checks on (OPcache)

One pool per customer, running as that customer's user, is the isolation unit on a shared machine. Sizing the pool (process manager, child counts, timeouts) is on PHP-FPM tuning; panels and pools on PHP selection and FPM pools.

Reloading the right PHP-FPM

After a PHP class, operator or INI change, reload the FPM master that serves the site. On machines with several PHP versions it is often not the one called php-fpm.

systemctl reload php-fpm                                                   # the distribution's single PHP
php bin/php/console exp:velocity deploy --no-velocity --allow-root-user    # finds the right one, clears caches in order
php bin/php/console exp:velocity deploy --no-velocity --dry-run --allow-root-user   # shows what it found and why

exp:velocity deploy works on Apache-only sites too: --no-velocity skips the Velocity steps. [DeploySettings] PhpFpmService=auto (in settings/velocity.ini) looks for the pool named after the installation's hosting domain, or one that names its directory, in /opt/plesk/php/*/etc/php-fpm.d, /etc/php-fpm.d, /etc/php/*/fpm/pool.d and /etc/opt/remi/php*/php-fpm.d (Velocity engines, Which PHP-FPM).

Note

A reload is not confined to one site. The master asks every child of every pool to finish, and requests on other sites of the same PHP version wait meanwhile. That is why [DeploySettings] PhpFpmReload=auto waits for OPcache to revalidate the changed files instead of reloading, when the pool's OPcache settings allow it (Velocity engines).

Plesk

Plesk generates the virtual host itself; do not edit its files (Chapter 8, Plesk):

  • point the domain's document root at the installation root;
  • choose "FPM application served by Apache" in the PHP settings, and the PHP version;
  • keep .htaccess (copied from .htaccess_root); Plesk's Apache reads it;
  • install the certificate in Plesk and switch on the redirect to HTTPS.

In Plesk's SSH terminal, as the subscription's system user and with the domain's PHP, /opt/plesk/php/<version>/bin/php bin/php/console exp:setup:htaccess --apply makes the copy. As root, add --allow-root-user and, when needed, --owner=<subscription-user>:psacln (Plesk).

Plesk names each pool after the domain in /opt/plesk/php/<version>/etc/php-fpm.d/<domain>.conf, served by the unit plesk-php<XY>-fpm (for example plesk-php85-fpm). systemctl restart php-fpm restarts a different master that no Plesk site uses. More on Plesk.

Static cache offload

With .htaccess_root_static, or the rules of doc/eng-us/examples/staticcache_offload.conf in the vhost of the public site, Apache answers a generated static page from its file without starting PHP. Never add those rules to the administration vhost. See Static cache.

What can go wrong

SymptomCauseFix
404 for every page.htaccess not read (AllowOverride) or mod_rewrite offallow overrides, load mod_rewrite
404 for every asset under design/the document root is not the installation rootpoint DocumentRoot at the directory with index.php
500a PHP or permission errorread the Apache and PHP-FPM error logs, then var/log/error.log
200 for /.git/config or a kernel .php pathrules not activefix before the site is public
A change "does not work"the reloaded FPM master is not the one that serves the siteexp:velocity deploy --no-velocity --dry-run
Files in var/ owned by roota console script run as rootrun scripts as the site user (Chapter 8, One user, or one group)

Checklist

  • To do: .htaccess copied from .htaccess_root (or the rules in the vhost), mod_rewrite and mod_proxy_fcgi loaded.
  • To do: Document root is the installation root.
  • To do: One PHP-FPM pool per site, running as the site's user; OPcache on.
  • To do: HTTPS with a CA certificate; port 80 redirected once HTTPS works.
  • To do: The four routing checks of Web servers and engines pass.
  • To do: Support knows which FPM unit serves the site (exp:velocity deploy --no-velocity --dry-run).

Demo mode with Apache and PHP-FPM. For a public demo, SetEnv EXP_DEMO_MODE 1 in its virtual host or .htaccess reaches PHP-FPM as a FastCGI parameter through mod_proxy_fcgi, which getenv() reads; env[EXP_DEMO_MODE] = 1 in the demo's pool does the same. Demo mode examples, Demo mode for hosts.

Become an Exponential Partner

Partners share their information, provide funding, contribute back and develop the products with us, and that is how Exponential grows. A partner website and dashboard are planned for mid-2027: please become a partner today to speed up our growth rate and land new features faster.

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