<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Opservo</title>
    <description>The latest articles on DEV Community by Opservo (@opservo).</description>
    <link>https://dev.to/opservo</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4086465%2F6fe9497d-2c67-4b0b-887f-0bbb8cad52dc.PNG</url>
      <title>DEV Community: Opservo</title>
      <link>https://dev.to/opservo</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/opservo"/>
    <language>en</language>
    <item>
      <title>How to Reduce Nginx 502 and 504 Gateway Errors</title>
      <dc:creator>Opservo</dc:creator>
      <pubDate>Tue, 25 Aug 2026 10:50:00 +0000</pubDate>
      <link>https://dev.to/opservo/how-to-reduce-nginx-502-and-504-gateway-errors-3m6i</link>
      <guid>https://dev.to/opservo/how-to-reduce-nginx-502-and-504-gateway-errors-3m6i</guid>
      <description>&lt;p&gt;Practical steps to diagnose and fix nginx 502 and 504 errors — from upstream timeouts to worker limits — before they wake you up at 3am.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understand the Difference First
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;Run this to see the last 50 upstream errors in real time: &lt;code&gt;sudo tail -n 50 /var/log/nginx/error.log | grep upstream&lt;/code&gt;. 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).&lt;/p&gt;

&lt;h2&gt;
  
  
  Fix the Most Common 502 Causes
&lt;/h2&gt;

&lt;p&gt;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:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Check the upstream process is running: &lt;code&gt;systemctl status gunicorn&lt;/code&gt; or &lt;code&gt;pm2 list&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Confirm it's accepting connections on the expected socket or port: &lt;code&gt;ss -tlnp | grep 8000&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Look at the upstream's own logs for uncaught exceptions or OOM kills: &lt;code&gt;journalctl -u gunicorn --since '10 minutes ago'&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;If using PHP-FPM, check the pool's &lt;code&gt;pm.max_children&lt;/code&gt; setting — a common cause of 502 spikes under load&lt;/li&gt;
&lt;li&gt;Verify file descriptor limits aren't exhausted: &lt;code&gt;cat /proc/$(pgrep gunicorn | head -1)/limits | grep 'open files'
&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For PHP-FPM specifically, edit &lt;code&gt;/etc/php/8.x/fpm/pool.d/www.conf&lt;/code&gt; and increase &lt;code&gt;pm.max_children&lt;/code&gt; to a value your RAM can support. A rough formula: divide available RAM (in MB) by the average PHP process size (check with &lt;code&gt;ps --no-headers -o rss -C php-fpm8.2 | awk '{sum+=$1} END {print sum/NR/1024" MB"}'&lt;/code&gt;). Restart FPM after changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fix the Most Common 504 Causes
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;In your nginx upstream or server block, tune these three directives:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;proxy_connect_timeout 10s;&lt;/code&gt; — how long nginx waits to establish a connection to the upstream&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;proxy_read_timeout 60s;&lt;/code&gt; — how long nginx waits for the upstream to send a response body (the most common culprit)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;proxy_send_timeout 60s;&lt;/code&gt; — how long nginx waits while transmitting a request to the upstream&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;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 &lt;code&gt;slow_query_log = 1&lt;/code&gt; and &lt;code&gt;long_query_time = 1&lt;/code&gt; in &lt;code&gt;/etc/mysql/mysql.conf.d/mysqld.cnf&lt;/code&gt;, then watch &lt;code&gt;/var/log/mysql/mysql-slow.log&lt;/code&gt;. Fix the query, add an index, or move the work to a background job.&lt;/p&gt;

&lt;h2&gt;
  
  
  Add Upstream Health Checks and Retry Logic
&lt;/h2&gt;

&lt;p&gt;If you run multiple upstream instances, nginx can automatically stop sending traffic to a failing one. In your upstream block, add failure detection:&lt;/p&gt;

&lt;p&gt;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; }&lt;br&gt;
This marks a server as unavailable after 3 failed attempts within 30 seconds, then retries it after 30 seconds. You can also add &lt;code&gt;proxy_next_upstream error timeout http_502 http_504;&lt;/code&gt; 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.&lt;/p&gt;

&lt;h3&gt;
  
  
  Keep Buffer and Queue Settings Realistic
&lt;/h3&gt;

&lt;p&gt;Misconfigured buffers cause a surprising number of 502 errors. If your upstream sends a large response header and &lt;code&gt;proxy_buffer_size&lt;/code&gt; 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:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;proxy_buffer_size 16k;&lt;/code&gt; — for large response headers&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;proxy_buffers 4 16k;&lt;/code&gt; — total buffer pool for response body&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;proxy_busy_buffers_size 24k;&lt;/code&gt; — max data sent to client while response is still being read&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After any nginx config change, always run &lt;code&gt;nginx -t&lt;/code&gt; before reloading. A broken config will take down your whole server on reload. Once tests pass, use &lt;code&gt;systemctl reload nginx&lt;/code&gt; rather than restart — reload is graceful and keeps existing connections alive.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The core takeaway:&lt;/strong&gt; 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.&lt;/p&gt;

&lt;p&gt;Originally published on the Opservo blog — Opservo is the AI ops engineer for teams without an SRE. Free for 2 servers → &lt;a href="https://getopservo.com/welcome" rel="noopener noreferrer"&gt;https://getopservo.com/welcome&lt;/a&gt;&lt;/p&gt;

</description>
      <category>backend</category>
      <category>debugging</category>
      <category>devops</category>
      <category>infrastructure</category>
    </item>
    <item>
      <title>Why is my Linux server slow? A practical checklist</title>
      <dc:creator>Opservo</dc:creator>
      <pubDate>Thu, 20 Aug 2026 12:30:00 +0000</pubDate>
      <link>https://dev.to/opservo/why-is-my-linux-server-slow-a-practical-checklist-225e</link>
      <guid>https://dev.to/opservo/why-is-my-linux-server-slow-a-practical-checklist-225e</guid>
      <description>&lt;p&gt;A no-nonsense order of operations for finding what’s actually slowing a Linux box down — CPU, memory, disk, I/O, or something noisier.&lt;/p&gt;

&lt;p&gt;“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.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Is it CPU, memory, disk, or I/O?&lt;/strong&gt;&lt;br&gt;
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.&lt;/p&gt;

&lt;p&gt;Load average vs cores: &amp;gt; 1× per core means saturation, &amp;gt; 2× means overloaded.&lt;br&gt;
Memory: high swap usage means you’re out of RAM and paging to disk — everything gets slow.&lt;br&gt;
Disk: a full disk (or one stuck in I/O wait) stalls writes for every process on the box.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Which process is responsible?&lt;/strong&gt;&lt;br&gt;
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.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Did something change?&lt;/strong&gt;&lt;br&gt;
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.&lt;/p&gt;

&lt;p&gt;The fastest path to a fix is almost always “what changed?” — not “what’s the metric?”&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. The shortcut&lt;/strong&gt;&lt;br&gt;
This is exactly the loop Opservo automates. It watches 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.&lt;/p&gt;

&lt;p&gt;Originally published on the Opservo blog — Opservo is the AI ops engineer for teams without an SRE. Free for 2 servers → &lt;a href="https://getopservo.com/welcome" rel="noopener noreferrer"&gt;https://getopservo.com/welcome&lt;/a&gt;&lt;/p&gt;

</description>
      <category>linux</category>
      <category>devops</category>
      <category>sysadmin</category>
      <category>monitoring</category>
    </item>
  </channel>
</rss>
