Requirements and Hosting
|
This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production. This sub-section’s WordPress bibliography lists the reference material consulted while preparing these pages. |
This page was written against WordPress 7.1.3 (released 2026-10-06; 7.1.4, a security release of 2026-10-28, is the version to run in production), with WordPress 7.2 in beta and planned for 2026-12-08, WP-CLI 2.12.0, and checked on 2026-10-28. WordPress 7.x needs PHP 7.4 or later and recommends PHP 8.3 or later. It needs a MySQL-compatible database and, in practice, HTTPS. The page lists each requirement and the PHP extensions and settings behind it. It also records where the three official requirement pages disagree and gives a recommendation for each disagreement. The second half covers choosing a host for the Lumen Press site: hosting types, how to evaluate them, what an uptime percentage means in minutes, and the DNS records a WordPress site needs.
It is written for site owners choosing a host and for administrators preparing a server. Installing WordPress itself is covered in Installation, and running it on a laptop in Local Development Environments.
The requirements at a glance
| Component | Recommended (new installations) | Still works, but not recommended |
|---|---|---|
PHP |
8.3 or later (wordpress.org); 8.4 or later (Hosting Handbook) |
7.4 to 8.2. 7.4, 8.0 and 8.1 are end-of-life upstream and are supported by WordPress for backward compatibility only |
Database |
MySQL 8.4 LTS, or MariaDB 11.8, 11.4 or 10.11 LTS |
MySQL 5.5.5 or later. The requirements page calls those older versions end-of-life |
Web server |
Apache HTTPD 2.4 or nginx 1.30/1.31 |
Any server that runs PHP. Angie, LiteSpeed and OpenLiteSpeed are known to work well |
HTTPS |
A TLS certificate on every host name |
Plain HTTP works, but application passwords and many browser features need HTTPS |
Memory ( |
256M; 512M or more for e-commerce and page builders |
128M for a bare install |
WordPress 7.0 raised the minimum PHP version from 7.2.24 to 7.4 and dropped PHP 7.2 and 7.3. WordPress 7.1 kept the same minimum. A site on PHP 7.2 or 7.3 cannot run 7.x and must upgrade PHP first. See Versions and Release Cycle for the PHP compatibility table across releases.
PHP
All of WordPress core, its themes and its plugins run on PHP, so the PHP version decides both security and speed. The Hosting Handbook lists WordPress 7.1 as fully compatible with PHP 7.4, 8.0, 8.1, 8.2, 8.3, 8.4 and 8.5. The Core team has retired the "compatible with exceptions" label (April 2025) and the "beta support" label (May 2026), so a PHP version is now either supported or not.
The upstream PHP support status at the check date:
| PHP | End of life | Status on 2026-10-28 |
|---|---|---|
8.5 |
2029-12-31 |
Active support |
8.4 |
2028-12-31 |
Active support. The Hosting Handbook recommends it for production |
8.3 |
2027-12-31 |
Security fixes only (since 2025-12-31). The wordpress.org recommended minimum |
8.2 |
2026-12-31 |
Security fixes only; reaches end of life in two months |
8.1 and older |
Past |
Unsupported upstream. Some Linux distributions still backport fixes |
A known regression affects two of the 21 October 2026 security releases. PHP 8.4.27 and 8.5.12 can crash when the
garbage collector frees a SimpleXML object whose properties were read as a whole. Reading the properties as a whole
means calling get_object_vars(), casting with (array) or calling json_encode() on the object. PHP-FPM then logs
that a child exited on a signal, such as SIGABRT. The fix ships in 8.4.28 and 8.5.13. The Hosting Handbook advises
against downgrading, because 8.4.26, 8.5.11 and earlier releases have the vulnerabilities that the October releases
fix. If a site cannot wait for 8.4.28 or 8.5.13, the handbook suggests PHP 8.3.36, which has the security fixes
without the regression. At the check date, the official wordpress:cli-php8.4 Docker image reported PHP 8.4.27, so
container users are affected too.
Upgrade PHP on staging first. WordPress core is compatible with each listed version, but older plugins and themes are
often not. PHP 8 turns many old warnings into TypeError exceptions, and PHP 8.2 deprecated dynamic properties. Hosts
should let each environment choose its PHP version separately, so that a newer version can be tested on staging
before production. PHP: What’s New and Migration covers
the language changes.
PHP extensions
WordPress uses PHP extensions when they are available. When a preferred extension is missing, WordPress either uses a slower fallback or turns the feature off.
| Group | Extensions (Hosting Handbook) |
|---|---|
Required |
|
Highly recommended |
|
For caching (one of |
|
Optional |
|
Fallbacks |
|
File changes when files are not writable |
|
The extensions are only part of what the server needs. The handbook also recommends ImageMagick 7.1 or later, which
the imagick extension requires, and Ghostscript 10 or later, which PDF thumbnails need. Image uploads in WebP and
AVIF need libraries that support those formats, and curl should be 8.4 or later. It recommends OpenSSL 3.5 LTS,
because upstream support for OpenSSL 3.0 ended on 2026-09-07. On Ubuntu 24.04 and later and on Debian 13, the
tzdata-legacy package is needed when a site’s time zone uses a deprecated name such as Europe/Kiev. Without it, the
site fails with a fatal error. PHP: Configuration and
Extensions explains how extensions are loaded.
PHP settings
PHP reads its settings from php.ini. Most hosts also read a per-directory .user.ini file (with PHP-FPM or CGI), or
php_value lines in .htaccess (with mod_php). The settings that matter most for WordPress are:
-
memory_limit, the most memory one request may use. WordPress raises it at runtime withini_set(), toWP_MEMORY_LIMITon load and throughwp_raise_memory_limit()for admin, cron and image work. It never lowers a higherphp.inivalue.WP_MEMORY_LIMITdefaults to 40M (64M on Multisite) andWP_MAX_MEMORY_LIMITto 256M. Both constants only work where the host lets PHP change the limit at runtime; otherwise thephp.inivalue is the limit. WordPress core documents no minimum, but the Hosting Handbook suggests 128M at least, 256M as the default and 512M or more for heavy sites. -
upload_max_filesizeandpost_max_sizelimit a single file and a whole request.post_max_sizemust be at leastupload_max_filesize, and it applies to every request, not only uploads. The Media Library shows the smaller of the two values as "Maximum upload file size" (wp_max_upload_size()). In front of PHP, the web server has its own limit, such asclient_max_body_sizein nginx, which defaults to 1m. -
max_execution_timelimits the PHP execution time, andmax_input_timelimits the time spent receiving the request. Both must fit with the web server and proxy timeouts. A 300-second PHP limit is pointless behind a 60-second proxy timeout. -
OPcache, which keeps compiled PHP bytecode in shared memory. It is the single cheapest performance win and is recommended for every production site. The settings to size are
opcache.memory_consumption,opcache.interned_strings_bufferandopcache.max_accelerated_files.opcache.validate_timestampsandopcache.revalidate_freqdecide when changed files are picked up. With timestamp validation off, every deployment and every core, plugin or theme update must reset OPcache, or the old code keeps running. Since WordPress 7.0, Site Health reports the opcode cache status.
The Lumen Press servers load this file after the distribution defaults:
; /usr/local/etc/php/conf.d/zz-lumen.ini (Lumen Press PHP settings)
memory_limit = 256M
upload_max_filesize = 64M
post_max_size = 72M
max_execution_time = 60
max_input_time = 60
; OPcache: on for web requests, sized for core plus a handful of plugins
opcache.enable = 1
opcache.memory_consumption = 192
opcache.interned_strings_buffer = 16
opcache.max_accelerated_files = 20000
opcache.validate_timestamps = 1
opcache.revalidate_freq = 60
expose_php = Off
revalidate_freq = 60 means that a changed file can take up to a minute to take effect. For comparison, the official
wordpress Docker image sets opcache.memory_consumption=128, opcache.interned_strings_buffer=8,
opcache.max_accelerated_files=4000 and opcache.revalidate_freq=2. Those values are tuned for development; a
production site with many plugins can exceed the 4000-file limit.
PHP: OPcache, JIT and Performance covers OPcache
in depth, and Performance and Caching covers the WordPress caching
layers.
Database: MySQL and MariaDB
WordPress stores everything except files in a MySQL-compatible database, which it reaches through the mysqli
extension and the wpdb class. The Hosting Handbook recommends LTS releases only. MySQL and MariaDB also publish
innovation or rolling releases, which have short support windows and are not recommended for production. Managed
services such as Amazon RDS and Aurora, Azure Database for MySQL, Google Cloud SQL, DigitalOcean and Percona Server
are not tested regularly, but are known to work well. Use utf8mb4 with a current collation. A new MariaDB 11.8
server defaults to utf8mb4_uca1400_ai_ci, as the check below shows.
Database Schema describes the tables.
Where the official pages disagree
Three official pages state the requirements, and on the check date they disagreed:
| Page | PHP | Database |
|---|---|---|
wordpress.org/about/requirements (last modified 2026-05-07) |
8.3 or greater; "also works" with 7.4+ |
MySQL 8.0+ or MariaDB 10.11+; "also works" with MySQL 5.5.5+ |
Advanced Administration Handbook, "Before You Install" |
7.4 or greater |
MySQL 5.7 or MariaDB 10.3 or greater |
Advanced Administration Handbook, "PHP" (performance) |
7.4 is "officially supported", 8.0/8.1 "compatible with exceptions", 8.2 "beta support" |
(not covered) |
Hosting Handbook, "Server Environment" |
8.4 or later for production |
MySQL 8.4 or 8.0 LTS; MariaDB 11.8, 11.4, 10.11 or 10.6 LTS |
Hosting Handbook, "WordPress 7.1 Server Compatibility" |
8.4.x or 8.5.x for new installs; 7.4+ absolute minimum |
MySQL 8.4.x; MariaDB 10.11.x, 11.4.x or 11.8.x. Lists MySQL 9.7 and MariaDB 12.3 as LTS. Absolute minimum MySQL or MariaDB 5.5.5 |
The disagreements go beyond the headline numbers:
-
The "Before You Install" database line is outdated. MySQL 5.7 reached end of life in October 2023 and MariaDB 10.3 in May 2023, and both are below the 8.0 and 10.11 that the requirements page names.
-
The Advanced Administration "PHP" page still uses support labels that the Core team retired in 2025 and 2026. Its statement that 7.4 is the officially supported version predates the PHP 8.x compatibility work.
-
The "Server Environment" page still lists MySQL 8.0 as recommended, although its own table gives April 2026 as the end-of-life date. It also still lists MariaDB 10.6, which reached end of life on 2026-07-06. The 7.1 compatibility post says MySQL 8.0 "should no longer be used" and no longer lists MariaDB 10.6.
-
The two Hosting Handbook pages give different end-of-life dates for MariaDB 11.8: June 2030 on "Server Environment" and 2028-06-04 in the 7.1 post.
-
The extension list on "Server Environment" says it assumes PHP 7.2, the minimum at the time it was written.
-
The legacy minimum on the requirements page names MySQL 5.5.5 but not MariaDB; the 7.1 post gives 5.5.5 for both.
The recommendation for Lumen Press, and for any new site, is to follow the newest of the pages. Use PHP 8.4, or 8.5 once the plugins in use support it, and MySQL 8.4 LTS or MariaDB 11.8 LTS. Treat MySQL 8.0, MariaDB 10.6 and PHP 8.2 as migrations to plan now. The lower numbers only describe what WordPress still runs on; they are not a target.
SQLite
Core supports only MySQL and MariaDB in production. SQLite is available through the SQLite Database Integration feature plugin (version 3.1.2 at the check date). The plugin requires WordPress 6.4 or later, PHP 7.2 or later, the PDO SQLite extension and SQLite 3.37.0 or newer. It is a community feature plugin meant to collect feedback for a possible core merge, and the Hosting Handbook calls it opt-in and experimental. WordPress Playground runs on it, which is the main place most people meet it. See Playground and Blueprints.
The plugin’s limits matter before trying it on a real site:
-
SQLite allows one writer at a time, so a site with many concurrent writes is better served by MySQL or MariaDB.
-
Activating it starts a new, empty database. Existing content is not migrated, and content created in SQLite does not move back when the plugin is turned off.
-
The database file lives in a randomized path under
wp-content/database/, exposed at runtime as theDB_PATHconstant. The plugin page recommends definingDB_PATHinwp-config.phpas an absolute path outside the web root. The olderDB_DIRandDB_FILEconstants are deprecated. -
WAL mode is the default, so backups must also copy the
-waland-shmside files, or be taken with SQLite’s own backup tooling.
Web server
Any web server that runs PHP can run WordPress. The Hosting Handbook recommends Apache HTTPD 2.4 and nginx 1.30
(stable) or 1.31 (mainline). It lists Angie 1.12, LiteSpeed Web Server 6.3 and OpenLiteSpeed 1.8 or 1.9 as known to
work well. Apache reads the rewrite rules that WordPress writes into .htaccess (mod_rewrite). nginx ignores
.htaccess, so its server block needs a try_files rule instead. Configuration details, including Apache 2.4 access
syntax, are in Web Servers: Apache and nginx.
Upload limits are the setting that most often conflicts between PHP and the web server. The Lumen Press nginx server
block raises client_max_body_size to match post_max_size, redirects HTTP to HTTPS, and tells PHP that the request
was secure:
server {
listen 80;
server_name lumenpress.example www.lumenpress.example;
return 301 https://lumenpress.example$request_uri;
}
server {
listen 443 ssl;
http2 on;
server_name lumenpress.example;
ssl_certificate /etc/nginx/tls/lumenpress.example.crt;
ssl_certificate_key /etc/nginx/tls/lumenpress.example.key;
root /var/www/lumen;
index index.php;
# Must be at least PHP's post_max_size, or nginx answers 413 first.
client_max_body_size 72m;
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param HTTPS on;
fastcgi_read_timeout 60s;
fastcgi_pass 127.0.0.1:9000;
}
}
When the upload is larger than client_max_body_size, nginx answers 413 Request Entity Too Large before PHP sees
the request. When it is larger than post_max_size, PHP discards the body and WordPress reports a generic upload
failure. When it exceeds only upload_max_filesize, the Media Library shows the file-size error.
HTTPS
The requirements page lists HTTPS support as a requirement. WordPress is fully compatible with HTTPS once a TLS certificate is installed, and several features depend on it. Application passwords are offered only over HTTPS by default. Browsers restrict service workers, geolocation and other APIs to secure origins. Search engines and browsers also flag plain-HTTP pages. Certificates are free from ACME certificate authorities, and most hosts automate them.
Three things must agree for a site to work over HTTPS:
-
the site URLs (Settings > General, or
WP_HOMEandWP_SITEURLinwp-config.php) start withhttps:// -
the web server redirects HTTP to HTTPS, so there is one canonical address
-
PHP knows that the request was secure.
is_ssl()checks$_SERVER['HTTPS']and the port, so when TLS ends at a load balancer or CDN, PHP sees plain HTTP and the dashboard enters a redirect loop
FORCE_SSL_ADMIN forces the login screen and the dashboard over HTTPS (the older FORCE_SSL_LOGIN was deprecated in
WordPress 4.0). Behind a proxy, wp-config.php must translate the proxy’s X-Forwarded-Proto header:
<?php
// Excerpt of wp-config.php, above the "That's all, stop editing!" line.
// Lumen Press production: TLS ends at the load balancer, PHP sees plain HTTP.
define( 'WP_HOME', 'https://lumenpress.example' );
define( 'WP_SITEURL', 'https://lumenpress.example' );
define( 'FORCE_SSL_ADMIN', true );
// Trust X-Forwarded-Proto only because the origin accepts traffic from the load balancer alone.
if ( isset( $_SERVER['HTTP_X_FORWARDED_PROTO'] )
&& false !== strpos( $_SERVER['HTTP_X_FORWARDED_PROTO'], 'https' ) ) {
$_SERVER['HTTPS'] = 'on';
}
// Ask PHP for more memory where the host allows runtime changes.
define( 'WP_MEMORY_LIMIT', '128M' );
define( 'WP_MAX_MEMORY_LIMIT', '256M' );
strpos() rather than str_contains() keeps the file valid on PHP 7.4, because wp-config.php runs before the
WordPress polyfills load. The header can hold a list such as http,https, which is why the code searches for
https instead of comparing the whole value. Trusting the header is safe only when clients cannot reach the origin
directly. Otherwise any client can claim to be on HTTPS. Moving an existing site from HTTP to HTTPS also means
rewriting the stored http:// URLs, which Importing,
Exporting and Migrating does with wp search-replace. HSTS and the other security headers are covered in
Security Hardening.
Checking a server
Site Health (Tools > Site Health, WordPress 5.2 and later) reports the PHP version, the database server, missing
extensions, the memory and upload limits and the HTTPS status, and flags anything below the recommendations. The same
data is available from the command line, which is useful before a site exists or in a deployment pipeline. Lumen Press
keeps this check in its operations repository and runs it with wp eval-file:
<?php
/**
* Lumen Press environment check.
*
* Run with: wp eval-file lumen-env-check.php
* Compares the server against the WordPress requirements and the
* Hosting Handbook recommendations. Exits with status 1 on a hard failure.
*/
$failures = 0;
$report = static function ( string $status, string $label, string $detail ) use ( &$failures ): void {
if ( 'FAIL' === $status ) {
++$failures;
}
WP_CLI::line( sprintf( '[%-4s] %-22s %s', $status, $label, $detail ) );
};
// PHP: 7.4 is the hard minimum, 8.3 is the recommendation on wordpress.org.
$php = PHP_VERSION;
if ( version_compare( $php, '7.4', '<' ) ) {
$report( 'FAIL', 'PHP version', "$php (WordPress 7.x needs 7.4 or later)" );
} elseif ( version_compare( $php, '8.3', '<' ) ) {
$report( 'WARN', 'PHP version', "$php (8.3 or later is recommended)" );
} else {
$report( 'OK', 'PHP version', $php );
}
// Database: MySQL 8.0+ or MariaDB 10.11+ is recommended.
global $wpdb;
$server_info = $wpdb->db_server_info();
$is_mariadb = false !== stripos( $server_info, 'mariadb' );
$db_version = $wpdb->db_version();
$wanted = $is_mariadb ? '10.11' : '8.0';
$engine = $is_mariadb ? 'MariaDB' : 'MySQL';
$report(
version_compare( $db_version, $wanted, '>=' ) ? 'OK' : 'WARN',
'Database',
"$engine $db_version (recommended $wanted or later)"
);
// PHP extensions.
foreach ( array( 'json', 'hash', 'mysqli' ) as $ext ) {
$report( extension_loaded( $ext ) ? 'OK' : 'FAIL', "ext/$ext", 'required' );
}
$recommended = array( 'curl', 'dom', 'exif', 'fileinfo', 'igbinary', 'imagick', 'intl', 'mbstring', 'openssl', 'xml', 'zip' );
$missing = array_values( array_filter( $recommended, static fn ( $ext ) => ! extension_loaded( $ext ) ) );
$report(
$missing ? 'WARN' : 'OK',
'Recommended exts',
$missing ? 'missing: ' . implode( ', ', $missing ) : 'all loaded'
);
// Memory and uploads.
$memory = wp_convert_hr_to_bytes( ini_get( 'memory_limit' ) );
$report(
( -1 === $memory || $memory >= 256 * MB_IN_BYTES ) ? 'OK' : 'WARN',
'memory_limit',
ini_get( 'memory_limit' ) . ' (256M recommended)'
);
$report( 'INFO', 'WP_MEMORY_LIMIT', WP_MEMORY_LIMIT . ' / WP_MAX_MEMORY_LIMIT ' . WP_MAX_MEMORY_LIMIT );
$report( 'INFO', 'Max upload size', size_format( wp_max_upload_size() ) );
// OPcache (the CLI usually has it off; check the web SAPI too).
$opcache = function_exists( 'opcache_get_status' ) && is_array( @opcache_get_status( false ) );
$report( $opcache ? 'OK' : 'INFO', 'OPcache (this SAPI)', $opcache ? 'enabled' : 'not active for ' . PHP_SAPI );
// HTTPS.
$home = home_url();
$report( str_starts_with( $home, 'https://' ) ? 'OK' : 'WARN', 'Home URL scheme', $home );
if ( $failures > 0 ) {
WP_CLI::error( "$failures hard requirement(s) not met." );
}
WP_CLI::success( 'Environment check finished.' );
Run against the local stack described below (the wordpress:cli-php8.4 image, the zz-lumen.ini file and MariaDB
11.8), the script printed:
$ wp eval-file lumen-env-check.php
[OK ] PHP version 8.4.27
[OK ] Database MariaDB 11.8.9 (recommended 10.11 or later)
[OK ] ext/json required
[OK ] ext/hash required
[OK ] ext/mysqli required
[WARN] Recommended exts missing: igbinary
[OK ] memory_limit -1 (256M recommended)
[INFO] WP_MEMORY_LIMIT 128M / WP_MAX_MEMORY_LIMIT 256M
[INFO] Max upload size 64 MB
[INFO] OPcache (this SAPI) not active for cli
[WARN] Home URL scheme http://localhost:8080
Success: Environment check finished.
Source: WP-CLI Commands: wp eval-file
Three results need care when reading the output. memory_limit reads -1 inside WP-CLI once WordPress has loaded,
although the same php.ini gives 256M with --skip-wordpress. The web value must therefore be read from Site Health
or from a phpinfo() page. OPcache is normally off for the command-line SAPI (opcache.enable_cli), which says
nothing about PHP-FPM. The PHP version, 8.4.27, is the release with the SimpleXML regression described above. str_starts_with() is safe here on PHP 7.4, because WordPress has
polyfilled it since 5.9.
The database version and the WP-CLI environment can also be read directly:
wp core version --extra
wp db query "SELECT VERSION() AS server, @@character_set_server AS charset, @@collation_server AS collation;"
wp cli info
Source: WP-CLI Commands: wp db query
On the test stack, wp db query returned 11.8.9-MariaDB-ubu2404, utf8mb4 and utf8mb4_uca1400_ai_ci.
A local stack with the recommended versions
The Compose file below runs WordPress 7.1.3 on PHP 8.4 with Apache, on MariaDB 11.8, with the Lumen Press PHP settings mounted. The WP-CLI service is used for the checks above. The database password comes from the environment and is never written in the file.
# compose.yaml (start with: LUMEN_DB_PASSWORD=<choose-one> docker compose up -d)
name: lumen-press-requirements
services:
db:
image: mariadb:11.8
environment:
MARIADB_DATABASE: lumen
MARIADB_USER: lumen
MARIADB_PASSWORD: ${LUMEN_DB_PASSWORD:?set LUMEN_DB_PASSWORD}
MARIADB_RANDOM_ROOT_PASSWORD: "1"
volumes:
- db-data:/var/lib/mysql
healthcheck:
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
interval: 5s
retries: 20
wordpress:
image: wordpress:7.1.3-php8.4-apache
depends_on:
db:
condition: service_healthy
ports:
- "8080:80"
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_NAME: lumen
WORDPRESS_DB_USER: lumen
WORDPRESS_DB_PASSWORD: ${LUMEN_DB_PASSWORD}
WORDPRESS_CONFIG_EXTRA: |
define( 'WP_ENVIRONMENT_TYPE', 'local' );
define( 'WP_MEMORY_LIMIT', '128M' );
define( 'WP_MAX_MEMORY_LIMIT', '256M' );
volumes:
- wp-data:/var/www/html
- ./php/zz-lumen.ini:/usr/local/etc/php/conf.d/zz-lumen.ini:ro
cli:
image: wordpress:cli-2.12.0-php8.4
profiles: ["tools"]
user: "33:33"
depends_on:
- wordpress
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_NAME: lumen
WORDPRESS_DB_USER: lumen
WORDPRESS_DB_PASSWORD: ${LUMEN_DB_PASSWORD}
volumes:
- wp-data:/var/www/html
- ./php/zz-lumen.ini:/usr/local/etc/php/conf.d/zz-lumen.ini:ro
- ./tools:/tools:ro
volumes:
db-data:
wp-data:
After docker compose up -d, run docker compose run --rm cli wp eval-file /tools/lumen-env-check.php once the
installer has been completed. Tear the stack down with docker compose down -v. The cli service runs as user
33:33, the www-data user of the Debian-based Apache image, so files that WP-CLI writes stay writable by Apache. The
Alpine-based CLI image’s own www-data user has the ID 82.
Local Development Environments compares this setup with
wp-env and Playground, and Docker: Compose Fundamentals explains the
Compose file format.
Hosting types
Self-hosted WordPress runs anywhere the requirements above are met. The hosting choice decides who maintains the operating system, PHP, the database, backups and caching. The trade-off is between control on one side and less work and cost on the other.
| Type | What is shared or managed | Good for | Watch for |
|---|---|---|---|
Shared hosting |
One server and one PHP pool shared by many customers; the host runs everything |
Small sites with low traffic and a small budget |
Old PHP versions, low |
VPS or dedicated server |
A virtual or physical machine; the customer runs the OS, PHP, database and web server |
Teams that can administer Linux and want full control |
Security updates, backups, monitoring and TLS renewal are the customer’s job |
Managed WordPress hosting |
A platform tuned for WordPress: PHP, database, page cache, backups, staging and often core updates are managed |
Content teams that want little server work |
Plugin restrictions, custom caching layers, price per site or per visit, export and lock-in terms |
Cloud platform (IaaS or PaaS) |
Building blocks such as virtual machines, managed MySQL, object storage and CDN, combined by the customer |
Sites that must scale or need high availability |
Design and cost complexity, shared uploads across servers, egress fees |
Containers (Docker, Kubernetes) |
An image per release, with a database and uploads on persistent storage |
Repeatable deployments and many environments |
|
WordPress.org keeps a page of hosts that sponsor the project. The Advanced Administration Handbook also has a page of install guides from cloud providers. Neither page is a requirement, and this sub-section does not endorse any host. Running WordPress in containers is covered in Containers, Docker and Kubernetes, and multi-server designs are covered in Scaling and High Availability. The cloud-platform row of the table below, built as a managed database plus stateless containers on several Kubernetes nodes, is described in Cloud Reference Architecture.
Lumen Press runs its staging and production environments on two virtual machines. Each has nginx and PHP-FPM 8.4, and production uses a managed MariaDB 11.8 database. A Redis object cache and a CDN for media sit in front, and the backups are stored off-site. Staging uses the same versions as production, so a PHP or database upgrade is always rehearsed there first.
Evaluating a host
These questions separate hosts better than marketing pages do:
-
Versions: which PHP versions can be selected per site, how fast new PHP minor releases are applied (for example 8.4.28 after the regression above), which MySQL or MariaDB version runs, and whether it is an LTS release.
-
Limits:
memory_limit,upload_max_filesizeandpost_max_size, PHP worker count, CPU and inode quotas, and whether the limits can be raised. -
Access: SSH, WP-CLI, Git or SFTP deployment, and database access. Check whether PHP runs as the account’s own user. The requirements page recommends that, because it keeps one site from reading another’s files.
-
Security: free automated TLS, isolation between accounts, a web application firewall, malware scanning, and how compromised sites are handled.
-
Operations: daily off-site backups with tested restores and a retention period, one-click staging, server-level page caching and a persistent object cache (Redis or Memcached), and whether WordPress cron can be driven by a system cron.
-
Exit: whether a full export (files plus database) is possible at any time, and with no proprietary plugins that the site will depend on.
-
Support and service level: the uptime percentage in the contract and what compensation it gives, support hours, and the status page.
Uptime arithmetic
An uptime guarantee is easier to judge as minutes of allowed downtime. The figures use a 365.25-day year and an average month of one twelfth of a year:
| Uptime | Downtime per year | Per month | Per week |
|---|---|---|---|
99% |
87.7 hours (3.65 days) |
7.3 hours |
1.7 hours |
99.5% |
43.8 hours |
3.7 hours |
50.4 minutes |
99.9% |
8.77 hours |
43.8 minutes |
10.1 minutes |
99.95% |
4.38 hours |
21.9 minutes |
5.0 minutes |
99.99% |
52.6 minutes |
4.4 minutes |
1.0 minute |
99.999% |
5.3 minutes |
26 seconds |
6 seconds |
The formula is downtime = (1 - uptime) x period. Two details matter more than the headline number. The first is what the contract excludes, such as scheduled maintenance and "network" outages. The second is how availability is measured. A host can be "up" while PHP returns errors, so Lumen Press checks a real page with an external monitor. Availability also multiplies across dependencies. A site that needs the host (99.9%) and an external database (99.9%) is at best about 99.8% available, which is roughly 17.5 hours of downtime a year.
Domains and DNS basics
A domain is registered through a registrar, and its DNS records are served by name servers. The name servers can be the registrar’s, the host’s or a DNS provider’s. A WordPress site needs only a few record types:
| Record | Use |
|---|---|
|
Map a name to the server’s IPv4 or IPv6 address. Used for the apex domain ( |
|
Make a name an alias of another name ( |
|
Mail delivery, and SPF, DKIM and DMARC records for the mail that WordPress sends. See Email Delivery |
|
Limits which certificate authorities may issue certificates for the domain |
|
Delegate the zone, or a subdomain, to name servers |
The Lumen Press zone uses the documentation address ranges reserved for examples:
$ORIGIN lumenpress.example.
$TTL 3600
@ IN A 192.0.2.10
@ IN AAAA 2001:db8::10
www IN CNAME lumenpress.example.
staging IN A 192.0.2.20
media IN CNAME lumen-media.cdn.example.
@ IN MX 10 mail.lumenpress.example.
@ IN TXT "v=spf1 include:_spf.mail-provider.example -all"
@ IN CAA 0 issue "letsencrypt.org"
Lower the TTL (for example to 300 seconds) a day before moving a site to a new server. The old records then expire
from resolvers quickly, and the TTL can be raised again after the move. WordPress stores its own address in the
siteurl and home options, so changing the domain also means updating those options and the stored URLs. The DNS
change alone is not enough; see Importing, Exporting and
Migrating. A Multisite network that uses subdomains also needs a wildcard record (*.lumenpress.example), described
in Multisite Networks.
Where older books are outdated
The three books consulted for this sub-section were written for WordPress 6.2 to 6.6, and several of their requirement and hosting statements no longer hold:
-
WordPress All-in-One For Dummies gives PHP 7.4+, MySQL 5.7+ and MariaDB 10.4+ as the baseline. PHP 7.4 is still the absolute minimum, but the recommendation is now 8.3 (wordpress.org) or 8.4 (Hosting Handbook). MySQL 5.7 and MariaDB 10.4 are end-of-life; the recommendation is MySQL 8.4 LTS or MariaDB 10.11 or later.
-
Ultimate WordPress Handbook says that most themes require PHP 8.2 or later. Themes declare their own minimum with the
Requires PHPheader, and WordPress itself requires 7.4. PHP 8.2 reaches end of life at the end of 2026, so it is no longer a sensible target either way. -
Pro WordPress recommends tuning the MySQL query cache. MySQL 8.0 removed the query cache, and MariaDB disables it by default. The book also describes caching and minification as built into WordPress. Core has neither a page cache nor CSS and JavaScript concatenation or minification. It relies on OPcache, a persistent object cache drop-in and server or plugin page caching.
-
Advice to enable HTTP/2 Server Push for WordPress assets is obsolete, because browsers have removed support for it. HTTP/2 and HTTP/3 themselves remain worth enabling.
The complete list is in Where Older Books and Tutorials Are Outdated.