
High traffic is not a page-views-per-month number — it is concurrent connections and requests per second hitting your server at the same moment. A site with 500,000 monthly visitors spread evenly generates almost no load; the same 500,000 visitors arriving in a two-hour flash sale window can push hundreds of simultaneous connections and dozens of requests per second, and that concurrency is what breaks servers, not the monthly total.
Every layer of a web stack has a concurrency ceiling: the web server has a worker connection limit, PHP-FPM has a maximum number of child processes, MariaDB has a maximum connection count, and the OS has a file-descriptor limit. When traffic exceeds any one of those ceilings, requests queue, then time out, while the other layers may still have headroom to spare. Building a stack for high traffic means raising and balancing those ceilings together, not just throwing more CPU at the box.
Which server handles the public-facing connection matters more than which one executes PHP. Apache's traditional worker model spawns a thread or process per connection, so memory usage climbs directly with concurrent visitors; Nginx uses an event-driven, non-blocking model that handles thousands of idle or slow connections on a handful of worker processes, which is why almost every high-traffic stack puts Nginx at the edge regardless of what executes the application code behind it.
That does not mean Apache disappears — it can still sit behind Nginx as the PHP execution layer, reached only over an internal, non-public port, with Nginx acting purely as the reverse proxy handler that absorbs slow clients, keep-alive connections, and static asset delivery before anything reaches PHP. The reverse proxy is what protects the execution layer: it terminates thousands of noisy, slow, or malicious client connections up front so PHP-FPM only ever sees clean, fast internal requests, which is the difference between a server that queues gracefully and one that runs out of workers under load.
CloudStick's nginx-cs stack ships with exactly these defaults out of the box — worker_processes set to auto so it scales to the CPU core count, worker_connections at 65535, and the epoll event method active — so a server provisioned through CloudStick already has the concurrency ceiling raised before a single line of application traffic hits it.
PHP-FPM's process manager mode decides how many workers sit idle versus how fast new ones spin up under a traffic spike. pm = ondemand keeps zero idle children when the site is quiet and spawns new ones only as requests arrive, which is memory-efficient on servers hosting many low-traffic sites; pm = dynamic keeps a configurable minimum of idle children always warm, ready to absorb a burst instantly without the small delay of forking a fresh process, which is usually the better choice for a single site expecting sustained high concurrency.
pm.max_children is a hard ceiling, not a suggestion — every request beyond that count queues until a child frees up, and a queue that never drains is what shows up to visitors as a stalled or blank page. Size it against available RAM divided by the average memory a single PHP process consumes, not against an arbitrary round number, or you risk either starving the site of workers or letting PHP exhaust server memory and trigger the OOM killer.
Each site on a CloudStick server already runs in its own isolated PHP-FPM pool, with its own socket, its own system user, and its own max_children ceiling, so raising the limit for a high-traffic site never eats into the headroom reserved for other sites sharing the same box.
The fastest request is the one that never reaches PHP at all, which is why a full-page cache sitting in front of the application is the single highest-leverage change for a high-traffic site: it serves a static, pre-rendered copy of a page directly from Nginx for anonymous visitors, bypassing PHP-FPM, the database, and every plugin hook a normal request would trigger.
Below the page cache sits the object cache — Redis is the standard choice, storing database query results, session data, and computed fragments in memory so repeat lookups skip MariaDB entirely. For logged-in traffic, personalized content, or WooCommerce carts where a full-page cache cannot apply, an object cache backed by Redis is what keeps response times flat even as concurrent logged-in sessions climb, since it turns repeated database round-trips into sub-millisecond memory reads.
Redis runs as a standard system service alongside MariaDB on a CloudStick server, so enabling object caching for WordPress or a custom PHP application is a matter of pointing the app at the local Redis instance rather than installing and configuring a separate caching service from scratch.
MariaDB has its own connection ceiling, and it is easy to size PHP-FPM's max_children higher than the database can actually accept — if fifty PHP workers can each open a connection but MariaDB is capped lower, the overflow connections fail outright instead of queueing gracefully. The connection limit and the PHP-FPM pool size need to be planned together, with the database ceiling set comfortably above the peak number of concurrent PHP workers across every site sharing that database server.
Beyond connection limits, the query cache and slow query log are the two levers worth checking first: a handful of unindexed, repeatedly-run queries is a far more common cause of a high-traffic site slowing down than raw connection volume, and an object cache in front of MariaDB (see the caching layer above) reduces how often those queries need to run at all. Each website on CloudStick gets its own MySQL database and user with restricted privileges, and the visual database manager in the dashboard makes it straightforward to inspect and manage that database without touching phpMyAdmin or the command line.
Five things to confirm before a traffic spike hits, not during one: Nginx sits at the public edge with worker_connections raised well above default, PHP-FPM's pm mode and max_children are sized against actual available RAM per process, a page cache is active for anonymous traffic and an object cache like Redis is active for everything else, MariaDB's connection limit is set above the peak concurrent PHP-FPM workers that can reach it, and something is actually watching CPU, memory, and disk in real time so a slow leak or spike shows up before it becomes downtime.
CloudStick covers most of this by default rather than leaving it to manual configuration: the nginx-cs stack ships with worker_connections 65535 and epoll active out of the box, every site gets its own isolated PHP-FPM pool so tuning one site's max_children never starves another, and Zabbix Agent 2 reports real-time CPU, memory, and disk metrics straight to the dashboard so a load spike is visible the moment it starts rather than after visitors already noticed. Get the stack right ahead of the spike, and the traffic event becomes a graph you watch instead of an incident you respond to.

