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.