{"id":1785,"date":"2025-11-13T18:42:53","date_gmt":"2025-11-13T15:42:53","guid":{"rendered":"https:\/\/www.dchost.com\/blog\/the-calm-guide-to-linux-tcp-tuning-for-high%e2%80%91traffic-wordpress-laravel-without-the-drama\/"},"modified":"2025-11-13T18:42:53","modified_gmt":"2025-11-13T15:42:53","slug":"the-calm-guide-to-linux-tcp-tuning-for-high%e2%80%91traffic-wordpress-laravel-without-the-drama","status":"publish","type":"post","link":"https:\/\/www.dchost.com\/blog\/en\/the-calm-guide-to-linux-tcp-tuning-for-high%e2%80%91traffic-wordpress-laravel-without-the-drama\/","title":{"rendered":"The Calm Guide to Linux TCP Tuning for High\u2011Traffic WordPress &amp; Laravel (Without the Drama)"},"content":{"rendered":"<div class=\"dchost-blog-content-wrapper\"><p>So there I was, staring at a graph that looked like a heartbeat monitor during a sprint. A client had just pushed a flash sale on their WooCommerce store, and traffic surged like a wave. Pages started to crawl. Checkout lagged. Everyone blamed the database. But the database was fine. Nginx was fine. PHP\u2011FPM was breathing hard, sure, but not out of air. The quiet culprit? The Linux network stack\u2014the pipes carrying all the tiny packets that make the web dance. The defaults weren\u2019t built for a stampede.<\/p>\n<p>Ever had that moment when everything \u201clooks normal\u201d but your site still feels slow under load? That\u2019s often the TCP\/IP layer raising a hand and whispering, \u201cHey, I need bigger buffers, a wider door, and a line system that actually moves.\u201d In this post, I\u2019ll walk you through practical Linux TCP tuning for high\u2011traffic WordPress and Laravel apps: sysctl settings that actually matter, sensible UDP buffer sizing (especially if you\u2019re playing with HTTP\/3), and the calm way to defend against SYN floods without kneecapping real users. All in a friendly, human way\u2014no wall of jargon, no magic numbers with zero context.<\/p>\n<div id=\"toc_container\" class=\"toc_transparent no_bullets\"><p class=\"toc_title\">\u0130&ccedil;indekiler<\/p><ul class=\"toc_list\"><li><a href=\"#Why_Your_WordPressLaravel_Site_Feels_Slow_When_The_Network_Stack_Cant_Breathe\"><span class=\"toc_number toc_depth_1\">1<\/span> Why Your WordPress\/Laravel Site Feels Slow When The Network Stack Can\u2019t Breathe<\/a><\/li><li><a href=\"#A_Calm_Rollout_Plan_Measure_Change_Verify_Repeat\"><span class=\"toc_number toc_depth_1\">2<\/span> A Calm Rollout Plan: Measure, Change, Verify, Repeat<\/a><\/li><li><a href=\"#The_Core_sysctl_Moves_That_Make_HighTraffic_HTTP_Feel_Easy\"><span class=\"toc_number toc_depth_1\">3<\/span> The Core sysctl Moves That Make High\u2011Traffic HTTP Feel Easy<\/a><ul><li><a href=\"#Front_door_wider_listen_backlog_and_accept_queues\"><span class=\"toc_number toc_depth_2\">3.1<\/span> Front door wider: listen backlog and accept queues<\/a><\/li><li><a href=\"#Buffers_that_fit_modern_bandwidth\"><span class=\"toc_number toc_depth_2\">3.2<\/span> Buffers that fit modern bandwidth<\/a><\/li><li><a href=\"#Modern_congestion_control\"><span class=\"toc_number toc_depth_2\">3.3<\/span> Modern congestion control<\/a><\/li><li><a href=\"#Graceful_timewait_and_port_range\"><span class=\"toc_number toc_depth_2\">3.4<\/span> Graceful timewait and port range<\/a><\/li><li><a href=\"#Keepalives_and_probing\"><span class=\"toc_number toc_depth_2\">3.5<\/span> Keepalives and probing<\/a><\/li><li><a href=\"#A_sensible_starting_block\"><span class=\"toc_number toc_depth_2\">3.6<\/span> A sensible starting block<\/a><\/li><\/ul><\/li><li><a href=\"#UDP_Buffers_That_Dont_Panic_DNS_Logs_and_HTTP3QUIC\"><span class=\"toc_number toc_depth_1\">4<\/span> UDP Buffers That Don\u2019t Panic: DNS, Logs, and HTTP\/3\/QUIC<\/a><\/li><li><a href=\"#SYN_Flood_Defense_That_Doesnt_Punish_Real_Users\"><span class=\"toc_number toc_depth_1\">5<\/span> SYN Flood Defense That Doesn\u2019t Punish Real Users<\/a><ul><li><a href=\"#Start_with_kernel_defenses\"><span class=\"toc_number toc_depth_2\">5.1<\/span> Start with kernel defenses<\/a><\/li><li><a href=\"#SYNPROXY_when_things_get_serious\"><span class=\"toc_number toc_depth_2\">5.2<\/span> SYNPROXY when things get serious<\/a><\/li><\/ul><\/li><li><a href=\"#AppLayer_Settings_That_Play_Nice_With_the_Kernel\"><span class=\"toc_number toc_depth_1\">6<\/span> App\u2011Layer Settings That Play Nice With the Kernel<\/a><ul><li><a href=\"#Nginx_the_great_traffic_translator\"><span class=\"toc_number toc_depth_2\">6.1<\/span> Nginx: the great traffic translator<\/a><\/li><li><a href=\"#PHPFPM_dont_starve_the_kitchen\"><span class=\"toc_number toc_depth_2\">6.2<\/span> PHP\u2011FPM: don\u2019t starve the kitchen<\/a><\/li><li><a href=\"#Database_use_a_pooler_and_stop_playing_whackamole\"><span class=\"toc_number toc_depth_2\">6.3<\/span> Database: use a pooler and stop playing whack\u2011a\u2011mole<\/a><\/li><li><a href=\"#Load_balancer_tier_health_checks_that_matter\"><span class=\"toc_number toc_depth_2\">6.4<\/span> Load balancer tier: health checks that matter<\/a><\/li><\/ul><\/li><li><a href=\"#RealWorld_Debug_Stories_What_I_Watch_Under_Load\"><span class=\"toc_number toc_depth_1\">7<\/span> Real\u2011World Debug Stories: What I Watch Under Load<\/a><\/li><li><a href=\"#A_Thought_on_Certificates_Ports_and_the_Everything_Is_Fine_Lie\"><span class=\"toc_number toc_depth_1\">8<\/span> A Thought on Certificates, Ports, and the \u201cEverything Is Fine\u201d Lie<\/a><\/li><li><a href=\"#Automation_and_Safe_Defaults_Make_It_Boring\"><span class=\"toc_number toc_depth_1\">9<\/span> Automation and Safe Defaults: Make It Boring<\/a><\/li><li><a href=\"#Extra_Knobs_Use_Gently_Fast_Open_GRO_and_NIC_Queues\"><span class=\"toc_number toc_depth_1\">10<\/span> Extra Knobs (Use Gently): Fast Open, GRO, and NIC Queues<\/a><\/li><li><a href=\"#Rollback_Observability_and_The_Human_Bits\"><span class=\"toc_number toc_depth_1\">11<\/span> Rollback, Observability, and The Human Bits<\/a><\/li><li><a href=\"#WrapUp_A_Calm_Fast_and_Resilient_Stack\"><span class=\"toc_number toc_depth_1\">12<\/span> Wrap\u2011Up: A Calm, Fast, and Resilient Stack<\/a><\/li><\/ul><\/div>\n<h2 id=\"section-1\"><span id=\"Why_Your_WordPressLaravel_Site_Feels_Slow_When_The_Network_Stack_Cant_Breathe\">Why Your WordPress\/Laravel Site Feels Slow When The Network Stack Can\u2019t Breathe<\/span><\/h2>\n<p>Here\u2019s the thing about PHP apps: they\u2019re usually blamed last for network hiccups and first for everything else. But WordPress and Laravel don\u2019t live in a vacuum; they sit behind Nginx or Apache, often behind a load balancer, and every single dynamic request is a little conversation\u2014TCP handshake, TLS handshake, request, response, maybe a few keep\u2011alive hops, and then the connection is parked or retired. When your kernel\u2019s defaults are tuned for a quiet Sunday, a Friday night campaign feels like stuffing a stadium through a single turnstile.<\/p>\n<p>Think of your server like a popular coffee shop. The baristas (PHP\u2011FPM\/your app) can crank out drinks fast, but if the front door is too narrow (accept queue too small), the hallway is clogged (backlog too short), and the cups are tiny (socket buffers too small), the line spills into the street and everyone blames the coffee. I\u2019ve seen this dozens of times: CPU looks fine, RAM fine, even disk okay. But the TCP queues are screaming, SYN packets are retried, and users start hitting refresh like it\u2019s a game.<\/p>\n<p>In my experience, the biggest wins come from widening that front door, giving each customer a bigger cup, and teaching staff to move with the flow. In kernel terms: adjust somaxconn and backlog, increase buffer ceilings, pick a modern congestion control, and give UDP some love if you\u2019ve added HTTP\/3 or chatty services. And when traffic turns hostile\u2014accidental thundering herds or real SYN floods\u2014you need controls that protect capacity without tripping real buyers.<\/p>\n<h2 id=\"section-2\"><span id=\"A_Calm_Rollout_Plan_Measure_Change_Verify_Repeat\">A Calm Rollout Plan: Measure, Change, Verify, Repeat<\/span><\/h2>\n<p>Before we touch sysctl, I always take a snapshot of reality. It doesn\u2019t have to be fancy. I\u2019ll run a quick set of commands while the app is under normal traffic (and again under load if I can simulate safely):<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">ss -s\nss -ltnp | head -n 20\nss -n state syn-recv '( sport = :80 or sport = :443 )'\nnetstat -s | egrep 'listen|SYN|retransmit|pruned'\ncat \/proc\/sys\/net\/core\/somaxconn\ncat \/proc\/sys\/net\/core\/netdev_max_backlog\ncat \/proc\/sys\/net\/ipv4\/tcp_max_syn_backlog\n<\/code><\/pre>\n<p>This quick peek tells me if the listen queues are overflowing, whether SYN\u2011RECV is piling up, and whether the server is shedding packets before they even reach Nginx. I also like to keep an eye on dmesg during tests\u2014if the kernel\u2019s complaining about backlog drops or memory pressure, it\u2019s rarely shy.<\/p>\n<p>Now for the \u201cI learned this the hard way\u201d part: never paste a giant sysctl block into production and call it a day. Make incremental changes, apply them with <strong>sysctl -p<\/strong> or by dropping a file into <strong>\/etc\/sysctl.d\/<\/strong>, and verify. Propagate slowly across a cluster. And keep a rollback file handy. If you\u2019ve got automation, even better\u2014I often bake these settings into first\u2011boot playbooks. If you like clean, repeatable setups, I\u2019ve shared how I scaffold fresh <a href=\"https:\/\/www.dchost.com\/vps\">VPS<\/a>es with <a href=\"https:\/\/www.dchost.com\/blog\/en\/bulutun-ilk-nefesi-cloud%e2%80%91init-ve-ansible-ile-tekrar-uretilebilir-vps-nasil-kurulur\/\">cloud\u2011init + Ansible for users, security, and services on first boot<\/a>. It\u2019s a great home for sysctl too.<\/p>\n<h2 id=\"section-3\"><span id=\"The_Core_sysctl_Moves_That_Make_HighTraffic_HTTP_Feel_Easy\">The Core sysctl Moves That Make High\u2011Traffic HTTP Feel Easy<\/span><\/h2>\n<p>Let\u2019s talk about the heartbeat of it all. The goal is simple: accept connections quickly, give each socket enough room to breathe, and keep the kernel from tripping over its own shoelaces under bursty traffic. These are the settings I reach for most often, with a few notes on why they matter.<\/p>\n<h3><span id=\"Front_door_wider_listen_backlog_and_accept_queues\">Front door wider: listen backlog and accept queues<\/span><\/h3>\n<p>Two settings almost always help right away: <strong>net.core.somaxconn<\/strong> and <strong>net.ipv4.tcp_max_syn_backlog<\/strong>. The first caps the maximum length of the socket listen queue; the second controls how many connections in SYN\u2011RECV can be queued before the kernel starts dropping. When traffic spikes, a bigger queue buys your app time to accept connections. Pair this with your app server\u2019s own backlog settings. For Nginx, the <strong>listen<\/strong> directive has a backlog parameter you can tweak; their docs on the <a href=\"https:\/\/nginx.org\/en\/docs\/http\/ngx_http_core_module.html#listen\" rel=\"nofollow noopener\" target=\"_blank\">listen directive and backlog<\/a> are worth a quick skim.<\/p>\n<h3><span id=\"Buffers_that_fit_modern_bandwidth\">Buffers that fit modern bandwidth<\/span><\/h3>\n<p>You\u2019ll see four important knobs: <strong>net.core.rmem_max<\/strong>, <strong>net.core.wmem_max<\/strong>, and per\u2011protocol triplets <strong>net.ipv4.tcp_rmem<\/strong> and <strong>net.ipv4.tcp_wmem<\/strong>. The triplets set minimum, default, and maximum auto\u2011tuned buffer sizes. Bigger ceilings help long\u2011fat pipes (high bandwidth, higher latency) and bursty workloads under TLS. Don\u2019t set them to cartoonish values, but do lift them beyond decade\u2011old defaults.<\/p>\n<h3><span id=\"Modern_congestion_control\">Modern congestion control<\/span><\/h3>\n<p>CUBIC is a solid default. BBR can be a real win for web delivery by keeping queues shallow while pushing throughput. If your kernel supports it, try BBR in a controlled rollout. The official <a href=\"https:\/\/github.com\/google\/bbr\" rel=\"nofollow noopener\" target=\"_blank\">BBR repository<\/a> has background and links, but what matters in practice is watching your retransmits, tail latency, and 95th percentile request times before and after.<\/p>\n<h3><span id=\"Graceful_timewait_and_port_range\">Graceful timewait and port range<\/span><\/h3>\n<p>Under load testing, you\u2019ll often run out of ephemeral ports from the client side, but servers with reverse proxies can also benefit from a healthy <strong>ip_local_port_range<\/strong>. I usually open it up. I also set a reasonable <strong>tcp_fin_timeout<\/strong> so closed connections don\u2019t linger forever. <strong>tcp_tw_reuse<\/strong> can help on boxes that initiate lots of outbound connections, but don\u2019t bring back the ancient <strong>tcp_tw_recycle<\/strong>\u2014it\u2019s gone for good reason.<\/p>\n<h3><span id=\"Keepalives_and_probing\">Keepalives and probing<\/span><\/h3>\n<p>Long\u2011lived connections are great for HTTP\/2 and gRPC. Lowering <strong>tcp_keepalive_time<\/strong> and enabling <strong>tcp_mtu_probing<\/strong> can reduce stalls when paths are weird. For most web stacks, I leave SACK and timestamps on.<\/p>\n<h3><span id=\"A_sensible_starting_block\">A sensible starting block<\/span><\/h3>\n<p>Here\u2019s a sample sysctl file I\u2019ve used as a base on busy web nodes. It\u2019s not a magic recipe\u2014tune to your capacity, kernel version, and traffic pattern\u2014but it\u2019s a friendly place to start.<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\"># \/etc\/sysctl.d\/99-web-tuning.conf\n\n# 1) Bigger door for bursts\nnet.core.somaxconn = 65535\nnet.ipv4.tcp_max_syn_backlog = 8192\nnet.core.netdev_max_backlog = 16384\n\n# 2) Buffer ceilings (TCP)\nnet.core.rmem_default = 262144\nnet.core.wmem_default = 262144\nnet.core.rmem_max = 8388608\nnet.core.wmem_max = 8388608\nnet.ipv4.tcp_rmem = 4096 1048576 8388608\nnet.ipv4.tcp_wmem = 4096 1048576 8388608\n\n# 3) Keep the flow modern\nnet.core.default_qdisc = fq\nnet.ipv4.tcp_congestion_control = bbr\n\n# 4) Handshake sanity and timeouts\nnet.ipv4.tcp_synack_retries = 4\nnet.ipv4.tcp_fin_timeout = 15\nnet.ipv4.tcp_keepalive_time = 300\nnet.ipv4.tcp_keepalive_intvl = 30\nnet.ipv4.tcp_keepalive_probes = 5\n\n# 5) Ephemeral ports &amp; TIME-WAIT behavior\nnet.ipv4.ip_local_port_range = 1024 65535\nnet.ipv4.tcp_tw_reuse = 1\n\n# 6) Don\u2019t break modern TCP features\nnet.ipv4.tcp_sack = 1\nnet.ipv4.tcp_timestamps = 1\nnet.ipv4.tcp_mtu_probing = 1\n\n# 7) SYN flood baseline defense (more below)\nnet.ipv4.tcp_syncookies = 1\n<\/code><\/pre>\n<p>Apply with:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">sudo sysctl --system\n# or\nsudo sysctl -p \/etc\/sysctl.d\/99-web-tuning.conf\n<\/code><\/pre>\n<p>Then verify:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">ss -s\ncat \/proc\/sys\/net\/ipv4\/tcp_congestion_control\ncat \/proc\/sys\/net\/core\/somaxconn\n<\/code><\/pre>\n<p>And don\u2019t forget your app layer. For Nginx, bump the backlog on your HTTPS listeners and enable reuseport on multi\u2011core boxes. On the load balancer layer, I\u2019ve shared ways to keep traffic flowing cleanly in <a href=\"https:\/\/www.dchost.com\/blog\/en\/haproxy-ile-l4-l7-yuk-dengeleme-nasil-sifir-kesinti-sunar-health-check-sticky-sessions-ve-tls-passthroughu-sade-sade-konusalim\/\">my zero\u2011downtime HAProxy guide for L4\/7 load balancing<\/a>. It ties in beautifully with these kernel settings.<\/p>\n<h2 id=\"section-4\"><span id=\"UDP_Buffers_That_Dont_Panic_DNS_Logs_and_HTTP3QUIC\">UDP Buffers That Don\u2019t Panic: DNS, Logs, and HTTP\/3\/QUIC<\/span><\/h2>\n<p>Once upon a time, I barely cared about UDP buffers on web nodes. DNS queries were tiny, syslog was tame, and the heavy lifting was TCP. Then QUIC\/HTTP\/3 rolled in, CDNs started speaking UDP in earnest, and suddenly that part of the stack mattered again. If your edge or reverse proxy handles HTTP\/3, or you\u2019re pushing logs\/metrics over UDP, you want to make sure those packets aren\u2019t fighting for crumbs.<\/p>\n<p>UDP is not TCP. There\u2019s no handshake, no retransmit logic in the kernel. That means buffers are your shock absorbers. If they\u2019re too small, bursts lead to drops\u2014fast. The good news is the fixes are straightforward: raise the global rmem\/wmem ceilings and set sensible UDP\u2011specific minimums. Paired with a reasonable <strong>netdev_max_backlog<\/strong>, this helps your NIC and kernel move bursting flows to user space without losing their lunch.<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\"># UDP buffer tuning (add alongside TCP block)\nnet.core.rmem_max = 134217728   # 128M ceiling for receive\nnet.core.wmem_max = 134217728   # 128M ceiling for send\n\n# System-wide defaults (not too big; apps can request more)\nnet.core.rmem_default = 1048576  # 1M\nnet.core.wmem_default = 1048576  # 1M\n\n# UDP specific mins and memory pressure triplets\nnet.ipv4.udp_rmem_min = 8192\nnet.ipv4.udp_wmem_min = 8192\n# udp_mem: pages; kernel scales per 4K page on most distros\n# Roughly: low pressure, pressure, and hard limit\nnet.ipv4.udp_mem = 98304 262144 393216\n<\/code><\/pre>\n<p>I keep defaults conservative and let applications (like a QUIC\u2011enabled proxy) request larger buffers with <strong>SO_RCVBUF<\/strong> and <strong>SO_SNDBUF<\/strong>. You can monitor UDP drops with:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">netstat -su | egrep 'packet receive errors|receive buffer errors|send buffer errors'\nss -u -a | head -n 20\n<\/code><\/pre>\n<p>If you\u2019re experimenting with HTTP\/3 on Nginx, HAProxy, or Caddy, track UDP receive errors during traffic spikes. A small bump in defaults can make a big difference without wasting RAM. And don\u2019t forget that DNS and NTP live here too\u2014if your instance is both resolver and web node, give those daemons a little headroom. For deeper dives into how to keep persistent connections happy at the edge, I shared some timeout and keep\u2011alive notes in <a href=\"https:\/\/www.dchost.com\/blog\/en\/cloudflare-ile-websocket-ve-grpc-yayini-nasil-hep-canli-kalir-nginx-timeout-keep%e2%80%91alive-ve-kesintisiz-dagitimun-sirlari\/\">my guide to WebSockets and gRPC behind Cloudflare<\/a>\u2014the mindset is similar for QUIC.<\/p>\n<h2 id=\"section-5\"><span id=\"SYN_Flood_Defense_That_Doesnt_Punish_Real_Users\">SYN Flood Defense That Doesn\u2019t Punish Real Users<\/span><\/h2>\n<p>A SYN flood is that annoying crowd that pretends to line up for coffee but never actually orders. Your server spends time and memory tracking the half\u2011open handshakes until it can\u2019t accept real customers. The trick is to make these fakes as cheap as possible while keeping legitimate users moving.<\/p>\n<h3><span id=\"Start_with_kernel_defenses\">Start with kernel defenses<\/span><\/h3>\n<p>Turn on syncookies, increase the max SYN backlog, and keep retries sane. It\u2019s not heroic, but it works surprisingly well during short spikes and accidental thundering herds.<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">net.ipv4.tcp_syncookies = 1\nnet.ipv4.tcp_max_syn_backlog = 8192\nnet.ipv4.tcp_synack_retries = 4\nnet.core.somaxconn = 65535\n<\/code><\/pre>\n<p>Then make sure your app\u2019s backlog isn\u2019t the weak link. On Nginx, raise the listener backlog and consider enabling <strong>reuseport<\/strong> on multi\u2011core machines so each worker has its own accept queue. The Nginx docs on the <a href=\"https:\/\/nginx.org\/en\/docs\/http\/ngx_http_core_module.html#listen\" rel=\"nofollow noopener\" target=\"_blank\">listen directive<\/a> cover both backlog and reuseport parameters.<\/p>\n<h3><span id=\"SYNPROXY_when_things_get_serious\">SYNPROXY when things get serious<\/span><\/h3>\n<p>When you\u2019re under sustained SYN flood from spoofed addresses, or you need to protect a thin app tier, a kernel\u2011level SYNPROXY can be a lifesaver. The idea is simple: your firewall completes the SYN\/SYN\u2011ACK\/ACK handshake on behalf of your app. Only once the client proves it\u2019s real does the proxy pass the connection upstream. You can do this with iptables or nftables. The nftables docs have a good primer on <a href=\"https:\/\/wiki.nftables.org\/wiki-nftables\/index.php\/SYN_proxy\" rel=\"nofollow noopener\" target=\"_blank\">SYN proxy<\/a>.<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\"># Example nftables snippet (simplified; adjust to your setup)\n\ntable inet filter {\n  chain input {\n    type filter hook input priority 0;\n    ct state established,related accept\n    iif lo accept\n\n    tcp flags syn tcp option maxseg size 0 counter drop\n\n    # Protect ports 80 and 443 with synproxy\n    tcp dport {80, 443} ct state new,untracked syn proxy mss 1460 wscale 7 sack-perm timestamp\n    tcp dport {80, 443} ct state invalid drop\n\n    # Allow the validated handshake to app\n    tcp dport {80, 443} accept\n  }\n}\n<\/code><\/pre>\n<p>You can also build this with iptables and the SYNPROXY target. The key is placement and not breaking established flows. Test on a canary, watch your error rates, and keep an eye on CPU\u2014SYNPROXY is efficient, but it\u2019s not free.<\/p>\n<p>If you\u2019re fronted by a load balancer or DDoS\u2011capable CDN, let them take the first punch. I\u2019ve had great results pairing kernel hardening with a smart L4\/L7 tier; for tips on balancing, health checks, and graceful restarts, here\u2019s how I run <a href=\"https:\/\/www.dchost.com\/blog\/en\/haproxy-ile-l4-l7-yuk-dengeleme-nasil-sifir-kesinti-sunar-health-check-sticky-sessions-ve-tls-passthroughu-sade-sade-konusalim\/\">zero\u2011downtime HAProxy<\/a> in front of busy PHP stacks.<\/p>\n<h2 id=\"section-6\"><span id=\"AppLayer_Settings_That_Play_Nice_With_the_Kernel\">App\u2011Layer Settings That Play Nice With the Kernel<\/span><\/h2>\n<p>Kernel tuning makes room. Your app needs to use it. Here\u2019s how I connect the dots for WordPress and Laravel without turning it into a 500\u2011line checklist.<\/p>\n<h3><span id=\"Nginx_the_great_traffic_translator\">Nginx: the great traffic translator<\/span><\/h3>\n<p>I set <strong>worker_processes auto;<\/strong> so it matches CPU cores and pair it with <strong>worker_connections<\/strong> high enough to cover peak concurrency. On busy sites, I raise the <strong>listen &#8230; backlog=65535 reuseport;<\/strong> on ports 80\/443 to match kernel somaxconn. For TLS handshakes, session reuse and HTTP\/2 help a lot\u2014and if you\u2019re curious about balancing speed and compatibility on certificates, I\u2019ve shared an approach for <a href=\"https:\/\/www.dchost.com\/blog\/en\/nginx-apachede-ecdsa-rsa-ikili-ssl-uyumluluk-mu-hiz-mi-ikisini-birden-nasil-alirsin\/\">serving dual ECDSA + RSA certificates<\/a> that keeps old clients happy without slowing down the new ones.<\/p>\n<p>Keep\u2011alive is a friend. I like a <strong>keepalive_requests<\/strong> limit that prevents one connection from living forever, with a keep\u2011alive timeout that fits your CDN and app patterns. For HTTP\/3, I monitor UDP errors while rolling out and bump buffers in small steps.<\/p>\n<h3><span id=\"PHPFPM_dont_starve_the_kitchen\">PHP\u2011FPM: don\u2019t starve the kitchen<\/span><\/h3>\n<p>Most of the time, I run <strong>pm = dynamic<\/strong> or <strong>pm = static<\/strong> with counts based on CPU and memory, and I make sure the <strong>listen.backlog<\/strong> in the pool config isn\u2019t the bottleneck. If you\u2019ve got a reverse proxy tier, give FPM a backlog that matches Nginx and kernel expectations, and make sure your <strong>rlimit_files<\/strong> and system <strong>nofile<\/strong> ulimit are high enough. Nothing is sadder than a server with room to run that can\u2019t open more sockets.<\/p>\n<h3><span id=\"Database_use_a_pooler_and_stop_playing_whackamole\">Database: use a pooler and stop playing whack\u2011a\u2011mole<\/span><\/h3>\n<p>WordPress and Laravel apps love to open many short\u2011lived connections. On MySQL, connection storms can be brutal under flash sales. Using a pooler or proxy that keeps backend connections stable makes a world of difference. I wrote down my favorite patterns for WooCommerce and Laravel in <a href=\"https:\/\/www.dchost.com\/blog\/en\/proxysql-ile-mysql-read-write-split-ve-baglanti-havuzu-woocommerce-laravel-icin-gercek-dunya-rehberi\/\">ProxySQL with read\/write split and pooling<\/a>. Kernel tuning keeps the highway clear, but the pooler makes sure you don\u2019t park a truck in every lane.<\/p>\n<h3><span id=\"Load_balancer_tier_health_checks_that_matter\">Load balancer tier: health checks that matter<\/span><\/h3>\n<p>If you\u2019re running your own L4\/L7 tier, keep health checks lightweight but meaningful, and make failover polite. The right checks reduce flapping and save you from false positives when the kernel is working hard. My playbook for <a href=\"https:\/\/www.dchost.com\/blog\/en\/haproxy-ile-l4-l7-yuk-dengeleme-nasil-sifir-kesinti-sunar-health-check-sticky-sessions-ve-tls-passthroughu-sade-sade-konusalim\/\">HAProxy zero\u2011downtime upgrades and sticky sessions<\/a> pairs nicely with the TCP settings here.<\/p>\n<h2 id=\"section-7\"><span id=\"RealWorld_Debug_Stories_What_I_Watch_Under_Load\">Real\u2011World Debug Stories: What I Watch Under Load<\/span><\/h2>\n<p>On a busy WooCommerce sale, my checklist is simple and fast. If checkout feels sticky, I look at SYN\u2011RECV counts and listen queue overflows. If those climb, I bump backlog and confirm Nginx is allowed to use it. Then I watch retransmits. If they spike, I\u2019ll test BBR on one node, compare tail latencies, and watch error budgets for a few hours.<\/p>\n<p>If HTTP\/3 is enabled and errors creep up only when traffic goes big, I inspect UDP receive errors and server CPU in softirq. Sometimes the fix is as simple as lifting <strong>net.core.rmem_max<\/strong> from 8M to 32M, raising <strong>rmem_default<\/strong> a notch, and nudging <strong>net.core.netdev_max_backlog<\/strong>. Other times, moving QUIC to a different node helps spread the interrupt load.<\/p>\n<p>And when traffic smells malicious? I turn on verbose logging for a few minutes, sample packet captures, and check the geographic fingerprint. If it\u2019s a classic spoofed SYN flood, I\u2019ll enable SYNPROXY on the edge and relax. It\u2019s oddly satisfying to watch a CPU graph go from panic to quiet in seconds.<\/p>\n<h2 id=\"section-8\"><span id=\"A_Thought_on_Certificates_Ports_and_the_Everything_Is_Fine_Lie\">A Thought on Certificates, Ports, and the \u201cEverything Is Fine\u201d Lie<\/span><\/h2>\n<p>Once, the team kept insisting, \u201cEverything is fine, we just need more PHP workers.\u201d The truth? TLS handshakes were piling up and the kernel was politely dropping new connections when the listen queue overflowed. Users hammered refresh, creating even more SYNs. We increased <strong>somaxconn<\/strong>, matched Nginx backlog, enabled session resumption, and moved to a faster cert combo. Request latency fell without changing a single line of PHP. If you want to squeeze every millisecond out of TLS without breaking old devices, take a look at that piece on <a href=\"https:\/\/www.dchost.com\/blog\/en\/nginx-apachede-ecdsa-rsa-ikili-ssl-uyumluluk-mu-hiz-mi-ikisini-birden-nasil-alirsin\/\">serving dual ECDSA and RSA certificates<\/a>. It\u2019s one of those underappreciated tweaks that makes your users feel the difference.<\/p>\n<h2 id=\"section-9\"><span id=\"Automation_and_Safe_Defaults_Make_It_Boring\">Automation and Safe Defaults: Make It Boring<\/span><\/h2>\n<p>The best compliment for a production network stack is \u201cboring.\u201d I aim for configurations that survive Friday night traffic and Sunday maintenance windows without surprises. The way to get there is to capture your tuned sysctl, app backlogs, and ulimits in code. I like to bake them into first\u2011boot routines and version them right next to app config. If you want a comfortable starting point, I shared how I standardize a new host with <a href=\"https:\/\/www.dchost.com\/blog\/en\/bulutun-ilk-nefesi-cloud%e2%80%91init-ve-ansible-ile-tekrar-uretilebilir-vps-nasil-kurulur\/\">cloud\u2011init + Ansible on first boot<\/a>. It keeps drift low and rollbacks easy.<\/p>\n<p>For teams deploying multi\u2011node stacks, putting the load balancer in a controlled pipeline helps you scale changes gradually and avoid brownouts. It pairs nicely with the kernel tuning we\u2019ve covered, and honestly, it saves arguments during incident calls.<\/p>\n<h2 id=\"section-10\"><span id=\"Extra_Knobs_Use_Gently_Fast_Open_GRO_and_NIC_Queues\">Extra Knobs (Use Gently): Fast Open, GRO, and NIC Queues<\/span><\/h2>\n<p>There are a few more dials you can explore as your traffic grows.<\/p>\n<p><strong>TCP Fast Open<\/strong> can shave a bit off the first request if your reverse proxy supports it. On Linux, enable server\/client bits via <strong>net.ipv4.tcp_fastopen<\/strong> and turn it on in your edge proxy. Measure carefully; gains vary, and middleboxes can get twitchy.<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\"># Enable server and client Fast Open\nnet.ipv4.tcp_fastopen = 3\n<\/code><\/pre>\n<p><strong>GRO\/LRO and IRQ affinity<\/strong> are more about NIC and driver tuning than sysctl, but I\u2019ve seen them matter at very high pps. Pinning interrupts, spreading queues, and making sure RSS is doing its job keep softirq from spiking one core while others nap. If you reach that stage, you\u2019re well into \u201cfun with drivers\u201d territory\u2014do it on a staging node first.<\/p>\n<h2 id=\"section-11\"><span id=\"Rollback_Observability_and_The_Human_Bits\">Rollback, Observability, and The Human Bits<\/span><\/h2>\n<p>Big lesson from the trenches: a good rollback plan is as important as a good tuning plan. Keep a copy of your old sysctl file, push changes to a single node, and roll forward only after watching request latency, error rates, and queue lengths for a while. On peak traffic days, resist the temptation to \u201cjust tweak one more thing.\u201d It\u2019s easy to confuse correlation with causation when graphs are dancing.<\/p>\n<p>Make observability your quiet partner. Even simple metrics like accept queue size, SYN\u2011RECV counts, retransmits, and UDP drops tell a clear story. When something looks off, take a breath, grab a tiny packet capture, and validate your assumptions. The network stack is honest if you ask the right questions.<\/p>\n<h2 id=\"section-12\"><span id=\"WrapUp_A_Calm_Fast_and_Resilient_Stack\">Wrap\u2011Up: A Calm, Fast, and Resilient Stack<\/span><\/h2>\n<p>Alright\u2014let\u2019s land the plane. High\u2011traffic WordPress and Laravel sites don\u2019t have to feel fragile. With a few focused kernel tweaks, you widen the front door, give sockets room to breathe, and make handshakes cheaper. On the UDP side, you cushion bursts so QUIC, DNS, and logs don\u2019t spill packets at the worst moments. And when the crowd turns rowdy, syncookies and SYNPROXY stand quietly at the door, letting the real customers in and showing the fakes out.<\/p>\n<p>Start small: snapshot your current state, apply a tight sysctl block, match app backlogs, and verify. If you\u2019re curious, test BBR on one node and watch tail latencies. If you\u2019re moving into HTTP\/3 country, lift UDP buffers sensibly and keep an eye on receive errors. And please\u2014put it all into automation so the next server gets the same calm defaults. If your stack includes a pooler, a smart load balancer, and sane TLS, you\u2019ll feel the difference on a real sale day. Hope this was helpful! If you try these settings, I\u2019d love to hear how it goes. See you in the next post.<\/p>\n<\/div>","protected":false},"excerpt":{"rendered":"<p>So there I was, staring at a graph that looked like a heartbeat monitor during a sprint. A client had just pushed a flash sale on their WooCommerce store, and traffic surged like a wave. Pages started to crawl. Checkout lagged. Everyone blamed the database. But the database was fine. Nginx was fine. PHP\u2011FPM was [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":1786,"comment_status":"","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[26],"tags":[],"class_list":["post-1785","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-teknoloji"],"_links":{"self":[{"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/posts\/1785","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/comments?post=1785"}],"version-history":[{"count":0,"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/posts\/1785\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/media\/1786"}],"wp:attachment":[{"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/media?parent=1785"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/categories?post=1785"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/tags?post=1785"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}