<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Opservo]]></title><description><![CDATA[Opservo]]></description><link>https://opservo.hashnode.dev</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1593680282896/kNC7E8IR4.png</url><title>Opservo</title><link>https://opservo.hashnode.dev</link></image><generator>RSS for Node</generator><lastBuildDate>Tue, 08 Sep 2026 20:56:14 GMT</lastBuildDate><atom:link href="https://opservo.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[How to Find What Is Filling Up Disk Space on a Linux Server]]></title><description><![CDATA[Disk full alerts at 2am? Learn the exact commands to find what's eating your Linux server's disk space and fix it fast.
You get the alert: disk usage at 94%. Your app starts throwing errors, logs stop]]></description><link>https://opservo.hashnode.dev/how-to-find-what-is-filling-up-disk-space-on-a-linux-server</link><guid isPermaLink="true">https://opservo.hashnode.dev/how-to-find-what-is-filling-up-disk-space-on-a-linux-server</guid><dc:creator><![CDATA[getopservo]]></dc:creator><pubDate>Tue, 08 Sep 2026 05:29:17 GMT</pubDate><content:encoded><![CDATA[<p>Disk full alerts at 2am? Learn the exact commands to find what's eating your Linux server's disk space and fix it fast.</p>
<p>You get the alert: disk usage at 94%. Your app starts throwing errors, logs stop writing, and databases refuse to accept new rows. Finding the culprit fast matters — but on a server with millions of files, knowing where to look is half the battle. Here's a systematic approach to track down disk hogs in minutes, not hours.</p>
<h2><strong>Start With the Big Picture: df</strong></h2>
<p>Before you dig into directories, confirm which filesystem is actually full. Run:</p>
<ul>
<li><p>df -h — shows all mounted filesystems with human-readable sizes</p>
</li>
<li><p>df -h / — focus on the root filesystem</p>
</li>
<li><p>df -i — check inode usage (a filesystem can be 'full' even with free space if inodes are exhausted)</p>
</li>
</ul>
<p>Pay attention to the 'Use%' column. If you see 100% on /var or /home but not /, that tells you exactly which mount point to investigate. Inode exhaustion — df -i showing 100% — is easy to miss and causes the same symptoms as a full disk, so always check both.</p>
<h2><strong>Drill Down With du</strong></h2>
<p>Once you know which mount point is full, use du to find the largest directories. Start from the top of that mount point and work down:</p>
<ul>
<li><p>du -sh /* 2&gt;/dev/null — sizes of every top-level directory, errors suppressed</p>
</li>
<li><p>du -sh /var/* 2&gt;/dev/null — drill into /var if that's the culprit</p>
</li>
<li><p>du -ah /var | sort -rh | head -20 — list the 20 largest files and folders inside /var</p>
</li>
</ul>
<p>The pattern is always the same: run du -sh on the suspicious directory, find the largest subdirectory, repeat one level deeper. You'll usually hit the real culprit within three or four iterations. Common offenders are /var/log (runaway logs), /var/lib/docker (unused images and volumes), and /tmp (applications that don't clean up after themselves).</p>
<h2><strong>Find Large Files Directly With find</strong></h2>
<p>Sometimes a single enormous file is the problem — a core dump, a forgotten database export, or a log that rotated incorrectly. Use find to surface files above a size threshold:</p>
<ul>
<li><p>find / -xdev -size +500M -ls 2&gt;/dev/null — files over 500 MB on the current filesystem only (-xdev stops it crossing into other mount points)</p>
</li>
<li><p>find /var/log -name '*.log' -size +100M — large log files specifically</p>
</li>
<li><p>find / -xdev -name 'core' -o -name '*.dump' 2&gt;/dev/null — core dumps that can appear silently after crashes</p>
</li>
</ul>
<blockquote>
<p><em>Always use -xdev with find when searching from / — without it, find will cross into other mount points and give you confusing results about space that belongs elsewhere.</em></p>
</blockquote>
<h2><strong>Track Down Deleted Files Still Holding Space</strong></h2>
<p>One of the most frustrating disk space mysteries on Linux: a file gets deleted but disk usage doesn't drop. This happens when a process still has the file open — the space isn't reclaimed until that process closes or releases the file. To find these ghost files:</p>
<ul>
<li><p>lsof +L1 — lists all open files where the link count has dropped to zero (i.e., deleted but still held open)</p>
</li>
<li><p>lsof +L1 | awk 'NR&gt;1 {print $7, $1, $2}' | sort -rn | head -10 — sort by file size descending</p>
</li>
<li><p>sudo lsof +L1 | grep deleted — simpler alternative if you just want to see what's deleted but open</p>
</li>
</ul>
<p>The fix is usually to restart the process holding the file. If it's a log file held open by a service like nginx or a Java app, restarting the service releases it. Alternatively, if restarting isn't an option immediately, you can truncate the file: &gt; /proc//fd/ — but a restart is cleaner.</p>
<h2><strong>Clean Up Common Space Wasters</strong></h2>
<p>Once you've identified the culprit, here are targeted cleanup commands for the most frequent offenders:</p>
<ul>
<li><p>Docker: docker system prune -a --volumes — removes stopped containers, unused images, and orphaned volumes. Be sure you actually want this in production.</p>
</li>
<li><p>Old journals: journalctl --vacuum-size=200M or journalctl --vacuum-time=7d — caps systemd journal size</p>
</li>
<li><p>Package manager leftovers: apt autoremove &amp;&amp; apt clean on Debian/Ubuntu; dnf autoremove on RHEL-based systems</p>
</li>
<li><p>Rotated logs not cleaning up: check /etc/logrotate.conf and run logrotate -f /etc/logrotate.conf to force a rotation cycle</p>
</li>
<li><p>Core dumps: check /proc/sys/kernel/core_pattern to see where they go, then remove them — consider setting kernel.core_pattern=/dev/null in /etc/sysctl.conf if you don't need them</p>
</li>
</ul>
<p>For Docker specifically, it's worth making prune a scheduled task rather than a reactive one. A weekly cron job running docker system prune -f prevents volumes from silently accumulating over months.</p>
<h2><strong>Make Disk Pressure Visible Before It Becomes a Crisis</strong></h2>
<p>Tracking down disk usage reactively works, but the real fix is knowing about gradual disk growth before it hits 100%. Set up alerts at 75% and 85% so you have time to investigate calmly rather than under pressure. Trend data matters too — a disk filling at 1 GB per day needs a different response than one that jumped 20 GB overnight.</p>
<p>This is where Opservo helps: it monitors disk usage across your servers, surfaces which directories are growing fastest, and flags anomalies like a log file that suddenly triples in size — before you get the 2 am alert. If you're managing production servers without a dedicated SRE, having that context surfaced automatically means you spend time fixing problems, not hunting for them.</p>
<p>The commands above will get you out of trouble today. The longer-term win is building visibility so slow-growing disk issues never become emergencies in the first place.</p>
<p>Originally published on the Opservo blog — Opservo is the AI ops engineer for teams without an SRE. Free for 2 servers → <a href="https://getopservo.com/welcome">https://getopservo.com/welcome</a></p>
]]></content:encoded></item><item><title><![CDATA[Server monitoring without an SRE: the signals that actually matter]]></title><description><![CDATA[You don’t need a full observability stack to keep a few servers healthy — just the handful of signals that actually predict trouble, and what they mean.
Enterprise observability platforms assume you h]]></description><link>https://opservo.hashnode.dev/server-monitoring-without-an-sre-the-signals-that-actually-matter</link><guid isPermaLink="true">https://opservo.hashnode.dev/server-monitoring-without-an-sre-the-signals-that-actually-matter</guid><category><![CDATA[Devops]]></category><category><![CDATA[Linux]]></category><category><![CDATA[sysadmin]]></category><category><![CDATA[nginx]]></category><dc:creator><![CDATA[getopservo]]></dc:creator><pubDate>Fri, 04 Sep 2026 06:42:04 GMT</pubDate><content:encoded><![CDATA[<p>You don’t need a full observability stack to keep a few servers healthy — just the handful of signals that actually predict trouble, and what they mean.</p>
<p>Enterprise observability platforms assume you have a team to run them. If you’re keeping a handful of production servers alive without a dedicated SRE, most of that machinery is overkill — dashboards you never open, alerts you learn to ignore. What you actually need is to watch a small number of high-signal things and know what to do when one of them moves.</p>
<h2><strong>The signals that predict real trouble</strong></h2>
<ul>
<li><p>Disk headroom + trend: not just “85% full,” but “filling — full in ~3 days.” A full disk takes everything down.</p>
</li>
<li><p>Memory pressure + swap: once you’re paging to disk, every process on the box gets slow. Watch for the leak, not just the level.</p>
</li>
<li><p>Load relative to cores: load 8 on an 8-core box is saturated; the same number on a 2-core box is an emergency.</p>
</li>
<li><p>Error rate on your web tier: a rising 5xx rate is the earliest sign something broke, often before users complain.</p>
</li>
<li><p>Service liveness: is each thing that should be running actually up — or crash-looping? (And if you auto-restart it, <a href="https://getopservo.com/blog/auto-restart-a-downed-service-safely">do it safely</a>.)</p>
</li>
<li><p>Certificate + domain expiry: boring, silent, and <a href="https://getopservo.com/blog/monitor-ssl-certificate-expiry">a guaranteed outage if missed</a>.</p>
</li>
</ul>
<h2><strong>Levels are lagging indicators. Trends are leading ones.</strong></h2>
<p>A threshold alarm (“disk &gt; 90%”) tells you you’re already in trouble. The more useful question is “where is this heading, and when will it become a problem?” A disk climbing 2% a day is worth a calm ticket today; the same disk at 90% and flat may be fine for months. Watch the slope, not just the value — and, ideally, learn what’s normal for each server so you can tell a real anomaly from a nightly backup.</p>
<h2><strong>The part most tools skip: what to do</strong></h2>
<p>Knowing a disk is filling is only half the job. The other half — find what’s eating the space, safely reclaim it, and make sure it doesn’t recur (we walk the diagnosis order in <a href="https://getopservo.com/blog/why-is-my-linux-server-slow">Why is my Linux server slow?</a>) — is where a good ops engineer earns their keep, and where most monitoring tools shrug. That gap is exactly why we built Opservo: it watches the signals above, forecasts the ones that are trending wrong, explains what’s happening in plain English, and can run the fix with you. For a small team, that’s the difference between monitoring and actually being covered.</p>
<p>Originally published on the Opservo blog — Opservo is the AI ops engineer for teams without an SRE. Free for 2 servers → <a href="https://getopservo.com/welcome">https://getopservo.com/welcome</a></p>
]]></content:encoded></item><item><title><![CDATA[How to Monitor a Docker Container's CPU and Memory Usage]]></title><description><![CDATA[Learn how to track Docker container CPU and memory usage with built-in tools and practical commands — no dedicated SRE required.
Your app slows to a crawl at 2 a.m., and you have no idea which contain]]></description><link>https://opservo.hashnode.dev/how-to-monitor-a-docker-container-s-cpu-and-memory-usage</link><guid isPermaLink="true">https://opservo.hashnode.dev/how-to-monitor-a-docker-container-s-cpu-and-memory-usage</guid><dc:creator><![CDATA[getopservo]]></dc:creator><pubDate>Mon, 31 Aug 2026 12:47:23 GMT</pubDate><content:encoded><![CDATA[<p>Learn how to track Docker container CPU and memory usage with built-in tools and practical commands — no dedicated SRE required.</p>
<p>Your app slows to a crawl at 2 a.m., and you have no idea which container is eating all the CPU. By morning the problem has vanished, but you're left with zero evidence and a vague sense of dread. If you're running Docker in production without dedicated monitoring, that scenario is only a matter of time. The good news: Docker exposes a surprising amount of resource data out of the box — you just need to know where to look.</p>
<h2>The Quickest Starting Point: docker stats</h2>
<p>Docker ships with a live stats command that works immediately, no extra software required. Run it and you get a continuously refreshing table of every running container:</p>
<p>docker stats — streams live CPU %, memory usage vs. limit, network I/O, and block I/O for all running containers</p>
<p>docker stats &lt;container_name_or_id&gt; — scope it to one container</p>
<p>docker stats --no-stream — prints a single snapshot and exits, useful in scripts or cron jobs</p>
<p>docker stats --format 'table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}' — trim the output to only the columns you care about</p>
<p>The CPU percentage shown is relative to a single core. On a 4-core host, 100% means one full core is saturated. Keep that in mind when reading numbers above 100% — your container is consuming more than one core, not breaking mathematics.</p>
<h2>Reading the Memory Numbers Correctly</h2>
<p>Memory output looks like '210MiB / 1.95GiB'. The first number is the container's current RSS-style usage; the second is its limit (or the host's total RAM if no limit is set). A container with no memory limit will happily consume all available RAM before the kernel OOM-killer starts terminating processes — usually the worst possible time to discover this.</p>
<p>Always set memory limits on production containers. Without them, a single runaway process can starve every other service on the host. Set a hard limit at run time with --memory and a soft warning threshold with --memory-reservation:</p>
<p>docker run --memory='512m' --memory-reservation='400m' your-image — container gets a hard 512 MB ceiling</p>
<p>docker inspect | grep -i memory — verify limits on an already-running container cat /sys/fs/cgroup/memory/docker/&lt;container_id&gt;/memory.usage_in_bytes — read raw cgroup data directly if you need it in a script</p>
<h2>Capturing Historical Data with docker stats and Simple Scripts</h2>
<p>docker stats is great for real-time debugging but terrible for answering 'what was happening at 2 a.m.?' For historical data without standing up a full monitoring stack, a small shell loop written to a log file is often enough to start:</p>
<p>while true; do docker stats --no-stream --format '{{.Name}},{{.CPUPerc}},{{.MemUsage}}' &gt;&gt; /var/log/container-stats.csv; sleep 30; done — logs a CSV snapshot every 30 seconds</p>
<p>Run it inside a tmux or screen session, or as a systemd service, so it survives SSH disconnects</p>
<p>Pipe output to grep or awk to filter for specific containers in high-container-count environments</p>
<p>This is not a replacement for proper time-series storage, but it gives you a simple audit trail you can grep through when something goes wrong.</p>
<h2>Going Deeper: cAdvisor and Prometheus</h2>
<p>If your team is ready for a more complete solution, Google's cAdvisor (Container Advisor) is the standard open-source exporter for Docker metrics. It runs as a container itself, scrapes cgroup data, and exposes a Prometheus-compatible endpoint:</p>
<p>docker run --volume=/var/run:/var/run:ro --volume=/sys:/sys:ro --volume=/var/lib/docker/:/var/lib/docker:ro --publish=8080:8080 --detach=true --name=cadvisor gcr.io/cadvisor/cadvisor — starts cAdvisor with read-only host access</p>
<p>Browse <a href="http://localhost:8080/containers/">http://localhost:8080/containers/</a> for a built-in web UI with CPU and memory graphs</p>
<p>Scrape <a href="http://localhost:8080/metrics">http://localhost:8080/metrics</a> from Prometheus for long-term storage and alerting</p>
<p>Key metrics to watch: container_cpu_usage_seconds_total, container_memory_usage_bytes, container_memory_working_set_bytes (working set is usually more meaningful than raw usage)</p>
<p>Pair cAdvisor with Grafana and you have a full dashboard. The setup takes an afternoon but pays for itself the first time you need to correlate a deploy with a memory spike hours later.</p>
<h2>What to Actually Alert On</h2>
<p>Collecting data is only half the job — you need to know when to wake someone up. Focus on these thresholds as a practical starting point:</p>
<p>CPU sustained above 80% for more than 5 minutes — a brief spike is normal; sustained high CPU usually signals a stuck process or traffic anomaly</p>
<p>Memory usage above 90% of the container limit — at this point OOM-kills are close; investigate before the kernel does it for you</p>
<p>Memory usage growing steadily over hours with no plateau — classic memory leak signature</p>
<p>Container restart count increasing — docker inspect | grep RestartCount will show you; repeated restarts mean something is crashing silently</p>
<p>If managing these thresholds across multiple containers sounds tedious, that's exactly the gap tools like Opservo are built to fill — it watches your containers continuously, surfaces anomalies in plain English, and flags the signals that actually matter before they become incidents. For small teams without a dedicated ops person, that kind of automated context can be the difference between catching a problem at 9 a.m. and getting paged at 2 a.m.</p>
<p>Start with docker stats today. Add cgroup limits to every production container this week. When you're ready for historical data and intelligent alerting, build from there — the foundation you lay now makes every future improvement much easier.</p>
<p>Originally published on the Opservo blog — Opservo is the AI ops engineer for teams without an SRE. Free for 2 servers → <a href="https://getopservo.com/welcome">https://getopservo.com/welcome</a></p>
]]></content:encoded></item><item><title><![CDATA[Why is my Linux server slow? A practical checklist]]></title><description><![CDATA[A no-nonsense order of operations for finding what’s actually slowing a Linux box down — CPU, memory, disk, I/O, or something noisier.
“The server is slow” is a symptom, not a diagnosis. The trick is ]]></description><link>https://opservo.hashnode.dev/why-is-my-linux-server-slow-a-practical-checklist</link><guid isPermaLink="true">https://opservo.hashnode.dev/why-is-my-linux-server-slow-a-practical-checklist</guid><category><![CDATA[Linux]]></category><category><![CDATA[sysadmin]]></category><category><![CDATA[monitor]]></category><category><![CDATA[Devops]]></category><dc:creator><![CDATA[getopservo]]></dc:creator><pubDate>Thu, 27 Aug 2026 12:34:18 GMT</pubDate><content:encoded><![CDATA[<p>A no-nonsense order of operations for finding what’s actually slowing a Linux box down — CPU, memory, disk, I/O, or something noisier.</p>
<p>“The server is slow” is a symptom, not a diagnosis. The trick is to narrow it down in the right order so you don’t waste an hour chasing the wrong resource. Here’s the checklist we actually use.</p>
<ol>
<li>Is it CPU, memory, disk, or I/O? Start broad. Look at load average relative to core count — a load of 8 on an 8-core box is fully saturated; on a 2-core box it’s an emergency. Then check whether memory pressure is forcing swap, and whether a disk is near full or saturated with I/O wait.</li>
</ol>
<p>Load average vs cores: &gt; 1× per core means saturation, &gt; 2× means overloaded. Memory: high swap usage means you’re out of RAM and paging to disk — everything gets slow. Disk: a full disk (or one stuck in I/O wait) stalls writes for every process on the box.</p>
<p>2. Which process is responsible? Once you know the resource, find the culprit. Sort processes by the resource that’s saturated — CPU or memory — and look at the top few. A runaway worker, a stuck cron job, or a memory-leaking app usually stands out immediately.</p>
<p>3.Did something change? Most “sudden” slowness has a cause: a deploy, a traffic spike, a log file that stopped rotating and filled the disk, or a service that crashed and is restarting in a loop. Correlate the slowdown with what happened around the same time.</p>
<p>The fastest path to a fix is almost always “what changed?” — not “what’s the metric?”</p>
<p>4. The shortcut This is exactly the loop Opservo automates. It watches the signals that actually matter — CPU, memory, disk, load and I/O — on every server, tells you in plain English which one is the problem and which process is responsible, and ties the slowdown to what changed — a deploy, a crash, a log that stopped rotating. Instead of running this checklist by hand at 3am, you open the server and it’s already on the screen.</p>
<p>Originally published on the Opservo blog — Opservo is the AI ops engineer for teams without an SRE. Free for 2 servers → <a href="https://getopservo.com/welcome">https://getopservo.com/welcome</a></p>
]]></content:encoded></item><item><title><![CDATA[How to Fix High Memory Usage on a Linux Server]]></title><description><![CDATA[Linux server running out of memory? Learn how to diagnose and fix high memory usage with real commands — before it takes down your app.
Your app starts slowing down, the OOM killer fires, or your moni]]></description><link>https://opservo.hashnode.dev/how-to-fix-high-memory-usage-on-a-linux-server</link><guid isPermaLink="true">https://opservo.hashnode.dev/how-to-fix-high-memory-usage-on-a-linux-server</guid><category><![CDATA[Linux]]></category><category><![CDATA[Devops]]></category><category><![CDATA[sysadmin]]></category><dc:creator><![CDATA[getopservo]]></dc:creator><pubDate>Tue, 25 Aug 2026 10:31:02 GMT</pubDate><content:encoded><![CDATA[<p>Linux server running out of memory? Learn how to diagnose and fix high memory usage with real commands — before it takes down your app.</p>
<p>Your app starts slowing down, the OOM killer fires, or your monitoring page turns red — and the culprit is memory. High memory usage on a Linux server is one of the most common production crises for small teams, and it's easy to misread. Linux intentionally uses most of your RAM for caching, so a server showing 95% memory used isn't necessarily in trouble. But one that's exhausting real working memory and swapping is. Here's how to tell the difference and actually fix it.</p>
<h2><strong>Step 1: Get a Clear Picture of What's Using Memory</strong></h2>
<p>Start with the basics. Run 'free -h' to see total, used, free, and available memory. Focus on the 'available' column — that's the real number. It accounts for reclaimable cache and is far more useful than 'free'.</p>
<ul>
<li><p>free -h — quick overview of RAM and swap usage</p>
</li>
<li><p>vmstat 1 5 — five one-second snapshots; watch the 'si' and 'so' columns for swap-in and swap-out activity</p>
</li>
<li><p>cat /proc/meminfo — full breakdown including Slab, PageTables, and AnonPages</p>
</li>
</ul>
<p>If swap is actively being used (si/so values above zero consistently), your server is genuinely memory-constrained. That's different from swap space existing but sitting idle.</p>
<h2><strong>Step 2: Find the Processes Eating Your RAM</strong></h2>
<p>Once you know memory is tight, you need to know what's consuming it. Run 'ps aux --sort=-%mem | head -20' to list the top 20 processes by memory percentage. For more detail on actual RSS (resident set size) in human-readable form:</p>
<blockquote>
<p><em>ps -eo pid,ppid,cmd,%mem,rss --sort=-%mem | head -20</em></p>
</blockquote>
<p>RSS is the memory a process actually holds in RAM — not virtual memory, which is often misleadingly large. Another useful tool is 'smem', which calculates PSS (proportional set size) and gives a fairer view when processes share memory libraries. Install it with 'apt install smem' or 'yum install smem', then run 'smem -r -k | head -20'.</p>
<p>Look for processes with unexpectedly high RSS. A Node.js app sitting at 2 GB when it should use 400 MB is a red flag. A MySQL instance using 4 GB is probably just doing its job.</p>
<h2><strong>Step 3: Diagnose the Root Cause</strong></h2>
<p>Not all memory problems are the same. Here are the most common causes and how to confirm each:</p>
<ul>
<li><p>Memory leak — process RSS grows continuously over hours or days; restart the process and watch it climb again. Use 'watch -n 5 ps -p  -o rss=' to monitor a specific process.</p>
</li>
<li><p>Misconfigured heap limits — Java apps, Node.js, or Elasticsearch configured with heap sizes too close to total available RAM. Check startup flags for -Xmx (Java) or --max-old-space-size (Node).</p>
</li>
<li><p>Too many processes — dozens of PHP-FPM or Unicorn workers each holding memory; check your pool/worker count configuration against actual server RAM.</p>
</li>
<li><p>Kernel slab cache — run 'slabtop' to see if kernel object caches (like dentries or inodes) are unusually large; this is common on servers handling millions of small files.</p>
</li>
<li><p>Huge log or data buffers — apps buffering large amounts of data in memory before flushing to disk.</p>
</li>
</ul>
<h2><strong>Step 4: Free Memory and Reduce Pressure</strong></h2>
<p>If you need to recover memory right now, here are safe options in order of preference:</p>
<ul>
<li><p>Restart the leaking or bloated process — this is usually the fastest path if you've identified a culprit.</p>
</li>
<li><p>Drop page cache — 'echo 1 &gt; /proc/sys/vm/drop_caches' releases cached file data Linux is holding speculatively. It's safe and the cache refills automatically. Use '2' to free dentries/inodes, '3' for both.</p>
</li>
<li><p>Reduce worker counts — lower PHP-FPM pm.max_children, Unicorn workers, or similar settings to reflect your actual RAM budget.</p>
</li>
<li><p>Increase swap temporarily — if you're on a VPS with no extra RAM, a swap file buys breathing room: 'fallocate -l 2G /swapfile &amp;&amp; chmod 600 /swapfile &amp;&amp; mkswap /swapfile &amp;&amp; swapon /swapfile'. Add it to /etc/fstab to persist across reboots.</p>
</li>
<li><p>Tune vm.swappiness — set it to 10 (echo 10 &gt; /proc/sys/vm/swappiness) so the kernel prefers keeping processes in RAM over aggressively swapping.</p>
</li>
</ul>
<h2><strong>Step 5: Prevent It From Happening Again</strong></h2>
<p>Fixing a memory spike once isn't enough. You need guardrails so the next one doesn't catch you off guard at 2 AM.</p>
<ul>
<li><p>Set per-process memory limits using systemd's MemoryMax= in a service unit file, or use cgroups directly. This stops one bad process from starving everything else.</p>
</li>
<li><p>Add alerting on available memory, not just used memory — alert when available drops below 15–20% of total RAM.</p>
</li>
<li><p>Schedule regular restarts for known-leaky long-running processes using systemd timers or cron, as a pragmatic interim fix.</p>
</li>
<li><p>Profile your app under realistic load before sizing your server — tools like Valgrind (C/C++), memory_profiler (Python), or clinic.js (Node.js) can catch leaks before production.</p>
</li>
</ul>
<p>If you're running multiple services and want to understand memory trends over time without manually SSHing in and running commands, this is exactly where Opservo helps — it continuously tracks per-process memory, surfaces anomalies in plain English, and can alert you before available memory hits a critical threshold.</p>
<p>Memory problems are almost always diagnosable if you know where to look. The key is distinguishing Linux's normal aggressive caching from genuine memory pressure, finding the process responsible, and either fixing the root cause or putting hard limits in place so one misbehaving service can't take down everything else.</p>
<p>Originally published on the Opservo blog — Opservo is the AI ops engineer for teams without an SRE. Free for 2 servers → <a href="https://getopservo.com/welcome">https://getopservo.com/welcome</a></p>
]]></content:encoded></item><item><title><![CDATA[How to Reduce Nginx 502 and 504 Gateway Errors]]></title><description><![CDATA[Practical steps to diagnose and fix nginx 502 and 504 errors — from upstream timeouts to worker limits — before they wake you up at 3am.
A wave of 502 and 504 errors is one of the most frustrating thi]]></description><link>https://opservo.hashnode.dev/how-to-reduce-nginx-502-and-504-gateway-errors</link><guid isPermaLink="true">https://opservo.hashnode.dev/how-to-reduce-nginx-502-and-504-gateway-errors</guid><category><![CDATA[Linux]]></category><category><![CDATA[Devops]]></category><category><![CDATA[sysadmin]]></category><category><![CDATA[Docker]]></category><dc:creator><![CDATA[getopservo]]></dc:creator><pubDate>Thu, 20 Aug 2026 12:06:33 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6a86e9f22bd7d7286dc29aab/df3f9f34-217f-4e78-838b-e12b3df84ba7.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Practical steps to diagnose and fix nginx 502 and 504 errors — from upstream timeouts to worker limits — before they wake you up at 3am.</p>
<p>A wave of 502 and 504 errors is one of the most frustrating things to debug under pressure. Your nginx is running fine, your app server appears to be up, yet users are getting gateway errors. The problem almost never lives in nginx itself — it lives in the conversation between nginx and whatever is sitting behind it. Here's how to find the real cause and stop it from happening again.</p>
<h2>Understand the Difference First</h2>
<p>502 Bad Gateway means nginx got a response from the upstream — but the response was invalid, incomplete, or came from a crashed process. 504 Gateway Timeout means nginx gave up waiting because the upstream took too long to respond at all. They look the same to users but point to different root causes, so checking your nginx error log is step one.</p>
<p>Run this to see the last 50 upstream errors in real time: <code>sudo tail -n 50 /var/log/nginx/error.log | grep upstream</code>. Look for phrases like "connect() failed", "upstream timed out", or "no live upstreams". These strings tell you immediately whether you're dealing with a process crash (502 territory) or a slow backend (504 territory).</p>
<h2>Fix the Most Common 502 Causes</h2>
<p>A 502 usually means the upstream process — your Node app, Python/gunicorn, PHP-FPM, or whatever — is either dead, crashing on certain requests, or running out of worker slots. Start by confirming the upstream is actually listening:</p>
<p>Check the upstream process is running: <code>systemctl status gunicorn</code> or <code>pm2 list</code></p>
<p>Confirm it's accepting connections on the expected socket or port: <code>ss -tlnp | grep 8000</code></p>
<p>Look at the upstream's own logs for uncaught exceptions or OOM kills: <code>journalctl -u gunicorn --since '10 minutes ago'</code></p>
<p>If using PHP-FPM, check the pool's <code>pm.max_children</code> setting — a common cause of 502 spikes under load</p>
<p>Verify file descriptor limits aren't exhausted: <code>cat /proc/$(pgrep gunicorn | head -1)/limits | grep 'open files'</code></p>
<p>For PHP-FPM specifically, edit <code>/etc/php/8.x/fpm/pool.d/www.conf</code> and increase <code>pm.max_children</code> to a value your RAM can support. A rough formula: divide available RAM (in MB) by the average PHP process size (check with <code>ps --no-headers -o rss -C php-fpm8.2 | awk '{sum+=$1} END {print sum/NR/1024" MB"}'</code>). Restart FPM after changes.</p>
<h2>Fix the Most Common 504 Causes</h2>
<p>A 504 means nginx is waiting and eventually giving up. The upstream is alive but responding too slowly — usually due to a slow database query, an external API call, or a CPU-bound task. The first thing to check is whether your nginx timeout values are set too aggressively short.</p>
<p>In your nginx upstream or server block, tune these three directives:</p>
<p><code>proxy_connect_timeout 10s;</code> — how long nginx waits to establish a connection to the upstream</p>
<p><code>proxy_read_timeout 60s;</code> — how long nginx waits for the upstream to send a response body (the most common culprit)</p>
<p><code>proxy_send_timeout 60s;</code> — how long nginx waits while transmitting a request to the upstream</p>
<p>Don't blindly raise these to 300s and call it done — that just hides slow queries behind a longer wait. Instead, profile what's actually slow. For slow database queries, enable slow query logging: in MySQL, set <code>slow_query_log = 1</code> and <code>long_query_time = 1</code> in <code>/etc/mysql/mysql.conf.d/mysqld.cnf</code>, then watch <code>/var/log/mysql/mysql-slow.log</code>. Fix the query, add an index, or move the work to a background job.</p>
<h2>Add Upstream Health Checks and Retry Logic</h2>
<p>If you run multiple upstream instances, nginx can automatically stop sending traffic to a failing one. In your upstream block, add failure detection:</p>
<p>upstream app_servers { server 127.0.0.1:8001 max_fails=3 fail_timeout=30s; server 127.0.0.1:8002 max_fails=3 fail_timeout=30s; }</p>
<p>This marks a server as unavailable after 3 failed attempts within 30 seconds, then retries it after 30 seconds. You can also add <code>proxy_next_upstream error timeout http_502 http_504;</code> in your location block so nginx automatically retries a failed request against the next upstream before returning an error to the user. Be careful with this on non-idempotent requests — you don't want POST requests retried blindly.</p>
<h2>Keep Buffer and Queue Settings Realistic</h2>
<p>Misconfigured buffers cause a surprising number of 502 errors. If your upstream sends a large response header and <code>proxy_buffer_size</code> is too small, nginx will return a 502. The default is usually 4k or 8k — if you use frameworks that set many cookies or JWT tokens in headers, bump it:</p>
<p><code>proxy_buffer_size 16k;</code> — for large response headers</p>
<p><code>proxy_buffers 4 16k;</code> — total buffer pool for response body <code>proxy_busy_buffers_size 24k;</code> — max data sent to client while response is still being read</p>
<p>After any nginx config change, always run <code>nginx -t</code> before reloading. A broken config will take down your whole server on reload. Once tests pass, use <code>systemctl reload nginx</code> rather than restart — reload is graceful and keeps existing connections alive.</p>
<p>Catching these errors before they spike is where tooling earns its keep. Opservo monitors your nginx error rate and upstream response times continuously, surfaces the likely cause in plain language, and can alert you the moment a pattern emerges — before it becomes a 3am incident. If you're managing production without a dedicated SRE, having that layer of interpretation between raw logs and a decision is genuinely useful.</p>
<p>The core takeaway: 502s and 504s are almost always symptoms of an unhealthy upstream or mismatched expectations between nginx and your app. Fix the underlying slowness or instability first, use nginx's retry and health-check features as a safety net, and tune your timeouts to reflect reality rather than hope.</p>
<p>Originally published on the Opservo blog. Opservo is the AI ops engineer for teams without an SRE. Free for 2 servers → <a href="https://getopservo.com/welcome">https://getopservo.com/welcome</a></p>
]]></content:encoded></item></channel></rss>