
The biggest mistake teams make ahead of a known traffic event is guessing at capacity instead of measuring it. If you do not know the exact concurrency your server fails at, every other decision — how far to raise pm.max_children, whether you need a bigger box, whether Redis can keep up — is a guess dressed up as a plan. Clone the production site onto a staging server with the same PHP-FPM pool size, database tier, and plugin set, then throw synthetic load at it with a real tool until it breaks.
Ramp concurrency in steps (50, 100, 200, 400 virtual users) rather than firing one huge run, and watch for the point where p99 latency spikes and 502/504 errors start appearing — that is your actual breaking point, not the number on the droplet's spec sheet. Write down the request rate and concurrency where things started degrading; that number drives every limit you raise in the next step.
Run the load test against a staging clone first — never let real concurrent users on production be your first test of a config change. Confirm the staging box mirrors production's PHP-FPM pool count, MySQL tier, plugin set, and cache configuration before you trust any number the test gives you; a staging server that is quietly more powerful than production will report a ceiling that does not exist.
Using the ceiling you just found, raise pm.max_children and MySQL's max_connections before the event starts, not reactively while it is already underway. Editing a config file and reloading a service while checkout traffic is live is how a bad afternoon turns into a bad week.
Size pm.max_children against actual RAM, not ambition: divide the memory you can spare for PHP by the average resident size of one PHP-FPM worker under load (check with ps_mem or `ps -ylC php-fpm --sort:rss`), and set max_children below that so the kernel never has to start killing processes under memory pressure. Do the same math for max_connections — every open connection holds memory on the MySQL side, so pairing a huge PHP-FPM pool with a MySQL server still capped at 151 connections just moves the bottleneck one layer deeper and produces a wall of "Too many connections" errors instead of 502s. Plan to lower both back to their normal values once the event window closes; oversized pools sitting idle for weeks waste RAM and can mask a real leak.
A cold cache means your first real visitors are the ones paying the cost of filling it — and on launch day, those are the visitors you can least afford to give a slow first page load. Walk every important URL yourself, in a loop, before the doors open, so page cache, object cache, and OPcache are all populated ahead of the crowd.
Build launch-urls.txt from your sitemap plus the specific product, checkout, and category pages the launch will actually drive traffic to — the homepage warming itself is not the point. OPcache compiles and caches PHP bytecode after the first hit per file, and object cache backends like Redis fill the same way, so one full pass through the real URLs primes both automatically; there is no separate "warm OPcache" command needed beyond making sure `opcache.enable` is on and the request actually happened once before real traffic does.
Every request the origin server never sees is a request that cannot hurt your load test numbers. Images, CSS, JS, fonts, and as much full-page HTML as your product allows should be served from the edge, not re-generated on your box for every visitor.
CloudStick's built-in Cloudflare integration lets you turn on edge caching and DDoS protection for a site directly from the dashboard, ahead of a known event, without touching DNS records by hand. Purge the cache once right before launch if you have made last-minute content changes, then immediately run your cache-warming pass again — a purge followed by silence just means the first wave of real visitors refills the edge cache for you, which defeats the point of warming it in the first place.
Every CPU cycle and database connection spent on something that is not serving a customer during the launch window is a cycle you needed for the actual traffic. Pause anything heavy that can wait a few hours.
Reschedule or comment out cron jobs that run backups, full-catalog re-indexing, image regeneration, security scans, or analytics rollups so none of them fire during the window — a scheduled backup that kicks off mid-launch and locks database tables is a self-inflicted outage. Deactivate plugins that are not required for the launch flow itself (heavy SEO analyzers, related-post recommendation engines, marketing pixels that queue synchronous requests), and turn them back on once traffic has settled. If any of these jobs must run, move them to well before or well after the window, not "sometime during."
You want to know about a problem in the first minute, not the first hour a customer complains on social media. Set up real-time monitoring and alerting before the event, and decide in advance who is watching it and what they do if a threshold is crossed.
CloudStick's dashboard runs Zabbix Agent 2 under the hood to show live CPU, RAM, and disk graphs alongside per-site Web Application Logs, so you can watch the launch unfold in real time and see the actual error behind a spike before a customer even reports it. Keep that dashboard open on a second screen for the whole window rather than checking it every twenty minutes.
Have a rollback plan written down before launch, not improvised during it: a tested maintenance-mode page you can flip on in seconds, a known-good backup or snapshot you can restore without debate over whether it is recent enough, and a clear owner who is authorized to pull that trigger without waiting for a group decision mid-incident. The checklist below is what should be true before the first real visitor hits the site, not something you are still working through as traffic climbs:

