Chapter 3: Architecting the Multi-Site Environment

Introduction: One Codebase, Many Sites

The foundation of our multi-site platform isn't in PHP, but a level below it: the web server. Before a single line of PHP is executed, the server must recognise an incoming request for one domain and route it to our single application, specifying which site it needs to be. This chapter provides the blueprint for that environment.

The Virtual Host Configuration

Our architecture relies on a single, comprehensive Virtual Host file for each site. This file contains all the directives needed to manage traffic, performance, security, and routing for that specific domain. By keeping all rules within this single file and disabling .htaccess overrides, we achieve the best possible performance.

Here is the complete, production-ready virtual host file for our book's sample site, oophp.uk.

# /etc/apache2/sites-available/oophp.uk.conf

# --- HTTP to HTTPS Redirect ---
<VirtualHost *:80>
    ServerName oophp.uk
    ServerAlias www.oophp.uk
    Redirect permanent / [https://oophp.uk/](https://oophp.uk/)
</VirtualHost>

# --- Main SSL-enabled Virtual Host ---
<VirtualHost *:443>
    # --- Core Settings ---
    ServerName oophp.uk
    ServerAlias www.oophp.uk
    DocumentRoot "/var/www/oophp.uk"
    ServerAdmin author@oophp.uk
    Protocols h2 http/1.1

    # --- Application Configuration (Variables for PHP) ---
    Include /var/www/siteEnVars/common
    Include /var/www/siteEnVars/oophp.uk

    # --- Logging ---
    ErrorLog "/var/www/siteLogs/errorLogs/oophp.uk.log"
    CustomLog "/var/www/siteLogs/accessLogs/oophp.log" common

    # --- Security Headers ---
    Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains"

    # --- Performance & Caching ---
    <IfModule mod_deflate.c>
        AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css application/javascript
    </IfModule>
    <IfModule mod_expires.c>
        ExpiresActive On
        ExpiresDefault "access plus 5 days"
        ExpiresByType text/html "access plus 1 day"
        ExpiresByType image/jpeg "access plus 60 days"
        ExpiresByType image/png "access plus 60 days"
        ExpiresByType image/gif "access plus 60 days"
        ExpiresByType text/javascript "access plus 1 day"
        ExpiresByType text/css "access plus 1 day"
    </IfModule>

    # --- Custom Error Pages ---
    ErrorDocument 403 /error_pages/403.html
    ErrorDocument 404 /error_pages/404.html
    ErrorDocument 500 /error_pages/500.html

    # --- Routing & Security Rules ---
    RewriteEngine On

    # Rule 1: Redirect www to non-www
    RewriteCond %{HTTP_HOST} ^www\.oophp\.uk [NC]
    RewriteRule ^(.*)$ [https://oophp.uk/$1](https://oophp.uk/$1) [L,R=301]

    # Rule 2: Block bad bots
    RewriteCond %{HTTP_USER_AGENT} "Mb2345Browser|LieBaoFast|zh-CN|MicroMessenger|zh_CN|Kinza|Datanyze|serpstatbot|spaziodati|OPPO\sA33|AspiegelBot|aspiegel|PetalBot|Bytespider|Amazonbot" [NC]
    RewriteRule .* - [F,L]

    # Rule 3: Front Controller
    RewriteCond %{REQUEST_URI} !/index.php
    RewriteCond %{REQUEST_URI} !/favicon.ico
    RewriteCond %{REQUEST_URI} !/_r
    RewriteCond %{REQUEST_URI} !/robots.txt
    RewriteCond %{REQUEST_URI} !/ads.txt
    RewriteCond %{REQUEST_URI} !/manifest.json
    RewriteCond %{REQUEST_URI} !/sw.js
    RewriteCond %{REQUEST_URI} !/sitemaps
    RewriteCond %{REQUEST_URI} !/sitemap.xml
    RewriteCond %{REQUEST_URI} !/fileUpload
    RewriteCond %{REQUEST_URI} !/program.log
    RewriteCond %{REQUEST_URI} !/stripeEndPoint
    RewriteRule ^(.*)$ /index.php [L,QSA]

    # --- SSL Configuration ---
    SSLCertificateFile /etc/letsencrypt/live/oophp.uk/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/oophp.uk/privkey.pem
    Include /etc/letsencrypt/options-ssl-apache.conf

    # --- Directory Permissions ---
    <Directory "/var/www/oophp.uk">
        AllowOverride None
        Require all granted
        AddDefaultCharset UTF-8
        AddType image/x-icon .ico
        Include /var/www/siteEnVars/cors-whitelist.conf
    </Directory>

    <Directory "/var/www/oophp.uk/_r">
        Options -Indexes
    </Directory>
</VirtualHost>

Conclusion: A Solid Foundation

This server-level architecture is the bedrock of our integrated application. By handling site identification and all major rules within Apache, our PHP code remains clean, generic, and decoupled from the domains it serves. This approach is not only performant and secure, but it makes adding a new site to the platform a trivial task: create a new database, add a new environment file, and enable a new virtual host. The core application requires no changes.

Shopping summary

Item

SubTotal: £

Empty Basket

this is a hidden panel

Completed in 43 milliseconds

Completed in 43 milliseconds

This is the top Panel

This is the bottom Panel