<?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: Shams Ali Shaikh</title>
    <description>The latest articles on DEV Community by Shams Ali Shaikh (@shamsalishaikh).</description>
    <link>https://dev.to/shamsalishaikh</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%2F4104387%2F2a225a63-6b6a-4e95-be12-fc4b1344b356.jpg</url>
      <title>DEV Community: Shams Ali Shaikh</title>
      <link>https://dev.to/shamsalishaikh</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/shamsalishaikh"/>
    <language>en</language>
    <item>
      <title>When Your Next.js App Works on Port 3000 but Production Says Nope</title>
      <dc:creator>Shams Ali Shaikh</dc:creator>
      <pubDate>Thu, 10 Sep 2026 17:57:01 +0000</pubDate>
      <link>https://dev.to/shamsalishaikh/when-your-nextjs-app-works-on-port-3000-but-production-says-nope-3f4h</link>
      <guid>https://dev.to/shamsalishaikh/when-your-nextjs-app-works-on-port-3000-but-production-says-nope-3f4h</guid>
      <description>&lt;p&gt;When Your Next.js App Works on Port 3000 but Production Says Nope &lt;/p&gt;

&lt;p&gt;If you've ever deployed a Next.js application, you've probably experienced this:&lt;/p&gt;

&lt;p&gt;Localhost: Works perfectly. Production: 502 Bad Gateway. &lt;/p&gt;

&lt;p&gt;Your application is running.&lt;/p&gt;

&lt;p&gt;Your process manager says it's online.&lt;/p&gt;

&lt;p&gt;The server looks healthy.&lt;/p&gt;

&lt;p&gt;And somehow, the browser still says:&lt;/p&gt;

&lt;p&gt;"Nope."&lt;/p&gt;

&lt;p&gt;This is where understanding Nginx reverse proxying becomes extremely useful.&lt;/p&gt;

&lt;p&gt;I'm Shams Ali Shaikh, and in this post, I'll walk through one of the most common patterns I use when deploying Next.js and Node.js applications to a production server.&lt;/p&gt;

&lt;p&gt;The Basic Problem &lt;/p&gt;

&lt;p&gt;When running a Next.js application locally, you might use:&lt;/p&gt;

&lt;p&gt;npm run dev &lt;/p&gt;

&lt;p&gt;and access it through:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://localhost:3000" rel="noopener noreferrer"&gt;http://localhost:3000&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;In production, you might instead run:&lt;/p&gt;

&lt;p&gt;npm run build npm run start &lt;/p&gt;

&lt;p&gt;Your application is now listening on a port such as:&lt;/p&gt;

&lt;p&gt;127.0.0.1:3000 &lt;/p&gt;

&lt;p&gt;But your users aren't going to visit:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://your-server-ip:3000" rel="noopener noreferrer"&gt;http://your-server-ip:3000&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;They expect:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://example.com" rel="noopener noreferrer"&gt;https://example.com&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;That's where Nginx comes in.&lt;/p&gt;

&lt;p&gt;What Is Nginx Doing Here? &lt;/p&gt;

&lt;p&gt;Think of Nginx as the receptionist sitting in front of your application.&lt;/p&gt;

&lt;p&gt;The user talks to Nginx.&lt;/p&gt;

&lt;p&gt;Nginx talks to your application.&lt;/p&gt;

&lt;p&gt;The application doesn't need to be directly exposed to the internet.&lt;/p&gt;

&lt;p&gt;The architecture looks like this:&lt;/p&gt;

&lt;p&gt;Internet | v &lt;a href="https://example.com" rel="noopener noreferrer"&gt;https://example.com&lt;/a&gt; | v +---------+ | Nginx | +---------+ | Reverse Proxy | v 127.0.0.1:3000 | v Next.js &lt;/p&gt;

&lt;p&gt;This simple architecture solves a lot of deployment problems.&lt;/p&gt;

&lt;p&gt;Basic Nginx Configuration &lt;/p&gt;

&lt;p&gt;A basic configuration can look like this:&lt;/p&gt;

&lt;p&gt;server { listen 80; server_name example.com &lt;a href="http://www.example.com" rel="noopener noreferrer"&gt;www.example.com&lt;/a&gt;; location / { proxy_pass &lt;a href="http://127.0.0.1:3000" rel="noopener noreferrer"&gt;http://127.0.0.1:3000&lt;/a&gt;; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } } &lt;/p&gt;

&lt;p&gt;The important part is:&lt;/p&gt;

&lt;p&gt;proxy_pass &lt;a href="http://127.0.0.1:3000" rel="noopener noreferrer"&gt;http://127.0.0.1:3000&lt;/a&gt;; &lt;/p&gt;

&lt;p&gt;This tells Nginx:&lt;/p&gt;

&lt;p&gt;"When someone requests this domain, forward the request to the application running on port 3000."&lt;/p&gt;

&lt;p&gt;Testing the Configuration &lt;/p&gt;

&lt;p&gt;After changing the Nginx configuration, don't immediately restart everything.&lt;/p&gt;

&lt;p&gt;First test the configuration:&lt;/p&gt;

&lt;p&gt;sudo nginx -t &lt;/p&gt;

&lt;p&gt;If the configuration is valid, reload Nginx:&lt;/p&gt;

&lt;p&gt;sudo systemctl reload nginx &lt;/p&gt;

&lt;p&gt;This is a small habit that can save you from turning a configuration change into a production incident.&lt;/p&gt;

&lt;p&gt;What If You Get a 502? &lt;/p&gt;

&lt;p&gt;This is where things become interesting.&lt;/p&gt;

&lt;p&gt;If Nginx returns:&lt;/p&gt;

&lt;p&gt;502 Bad Gateway &lt;/p&gt;

&lt;p&gt;don't immediately start changing random Nginx settings.&lt;/p&gt;

&lt;p&gt;First check whether your application is actually running.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;pm2 status &lt;/p&gt;

&lt;p&gt;Then test the application directly:&lt;/p&gt;

&lt;p&gt;curl &lt;a href="http://127.0.0.1:3000" rel="noopener noreferrer"&gt;http://127.0.0.1:3000&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;If this doesn't respond, the problem probably isn't Nginx.&lt;/p&gt;

&lt;p&gt;Your application might have:&lt;/p&gt;

&lt;p&gt;Crashed Failed to start Started on another port Failed because of environment variables Failed during the production build Been stopped by PM2 or another process manager &lt;/p&gt;

&lt;p&gt;If curl works but the domain doesn't, then investigate the Nginx configuration, DNS, SSL, firewall, or networking.&lt;/p&gt;

&lt;p&gt;Checking Nginx Logs &lt;/p&gt;

&lt;p&gt;When things still aren't clear, logs become your best friend.&lt;/p&gt;

&lt;p&gt;Check the Nginx error log:&lt;/p&gt;

&lt;p&gt;sudo tail -f /var/log/nginx/error.log &lt;/p&gt;

&lt;p&gt;You can also inspect the access log:&lt;/p&gt;

&lt;p&gt;sudo tail -f /var/log/nginx/access.log &lt;/p&gt;

&lt;p&gt;Logs usually give you a much better answer than repeatedly refreshing the browser and hoping for a miracle.&lt;/p&gt;

&lt;p&gt;One Server, Multiple Applications &lt;/p&gt;

&lt;p&gt;One of the reasons I like this architecture is that you can run multiple applications on the same server.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;app.example.com | v Nginx | v 127.0.0.1:3000 Next.js api.example.com | v Nginx | v 127.0.0.1:5000 Node.js admin.example.com | v Nginx | v 127.0.0.1:4000 Next.js &lt;/p&gt;

&lt;p&gt;Nginx becomes the traffic controller.&lt;/p&gt;

&lt;p&gt;Different domains can point to different applications and ports.&lt;/p&gt;

&lt;p&gt;Adding HTTPS &lt;/p&gt;

&lt;p&gt;In a real production environment, you generally don't want users accessing your application through plain HTTP.&lt;/p&gt;

&lt;p&gt;The production flow becomes:&lt;/p&gt;

&lt;p&gt;User | | HTTPS :443 v Nginx | | HTTP v 127.0.0.1:3000 | v Next.js &lt;/p&gt;

&lt;p&gt;Nginx can terminate the TLS connection while your application continues running internally.&lt;/p&gt;

&lt;p&gt;This also means your application doesn't necessarily need to manage the public SSL connection itself.&lt;/p&gt;

&lt;p&gt;My Production Debugging Checklist &lt;/p&gt;

&lt;p&gt;When a deployed Next.js application isn't working, I usually go layer by layer:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Is the application running? pm2 status 2. Is the application responding? curl &lt;a href="http://127.0.0.1:3000" rel="noopener noreferrer"&gt;http://127.0.0.1:3000&lt;/a&gt; 3. Is Nginx running? sudo systemctl status nginx 4. Is the configuration valid? sudo nginx -t 5. What does Nginx say? sudo tail -f /var/log/nginx/error.log 6. Is DNS pointing to the correct server? &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Check the domain's DNS records.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Is HTTPS configured correctly? &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Check the certificate and TLS configuration.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Is the required port accessible? &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Check your firewall and server networking rules.&lt;/p&gt;

&lt;p&gt;The important part is not to troubleshoot everything at once.&lt;/p&gt;

&lt;p&gt;Start from the application and move outward.&lt;/p&gt;

&lt;p&gt;Application ↓ Port ↓ Process ↓ Nginx ↓ HTTPS ↓ DNS ↓ Internet The Bigger Lesson &lt;/p&gt;

&lt;p&gt;Deployment is not simply:&lt;/p&gt;

&lt;p&gt;git push → website &lt;/p&gt;

&lt;p&gt;A production application is a collection of interconnected layers.&lt;/p&gt;

&lt;p&gt;Developer ↓ GitHub ↓ CI/CD ↓ Production Server ↓ Docker / PM2 ↓ Next.js / Node.js ↓ Nginx ↓ HTTPS ↓ Domain ↓ Users &lt;/p&gt;

&lt;p&gt;When you understand each layer, debugging becomes much easier.&lt;/p&gt;

&lt;p&gt;You stop asking:&lt;/p&gt;

&lt;p&gt;"Why isn't my website working?"&lt;/p&gt;

&lt;p&gt;And start asking:&lt;/p&gt;

&lt;p&gt;"Which layer is failing?"&lt;/p&gt;

&lt;p&gt;That change in thinking is one of the most useful things I've learned while working with production deployments.&lt;/p&gt;

&lt;p&gt;Because "it works on my machine" might be a perfectly valid development statement.&lt;/p&gt;

&lt;p&gt;It just isn't a very convincing production strategy.&lt;/p&gt;

&lt;p&gt;I'm documenting what I learn while building and deploying real applications, from localhost to production.&lt;/p&gt;

&lt;p&gt;More deployment and DevOps guides coming soon.&lt;/p&gt;

&lt;p&gt;— Shams Ali Shaikh&lt;/p&gt;

&lt;p&gt;Software Engineer | MERN Stack | Next.js | Node.js | DevOps | Deployment&lt;/p&gt;

</description>
      <category>deployment</category>
      <category>devops</category>
      <category>nextjs</category>
    </item>
    <item>
      <title>From “It Works on My Machine” to Production: My DevOps Journey</title>
      <dc:creator>Shams Ali Shaikh</dc:creator>
      <pubDate>Tue, 01 Sep 2026 13:13:00 +0000</pubDate>
      <link>https://dev.to/shamsalishaikh/from-it-works-on-my-machine-to-production-my-devops-journey-2kk1</link>
      <guid>https://dev.to/shamsalishaikh/from-it-works-on-my-machine-to-production-my-devops-journey-2kk1</guid>
      <description>&lt;h1&gt;
  
  
  From “It Works on My Machine” to “Why Is Production Down?”
&lt;/h1&gt;

&lt;p&gt;Hi, I’m Shams Ali Shaikh, a Software Engineer passionate about building applications and figuring out how to make them actually work in production.&lt;/p&gt;

&lt;p&gt;Writing code is one thing.&lt;/p&gt;

&lt;p&gt;Deploying it without breaking the server is a completely different adventure.&lt;/p&gt;

&lt;p&gt;Over the past few projects, I’ve been exploring application deployment, servers, DevOps, infrastructure automation, and production architecture.&lt;/p&gt;

&lt;p&gt;Here are some of the topics I’ll be sharing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How I Deploy Next.js Applications Using Nginx&lt;/li&gt;
&lt;li&gt;Complete Docker Deployment Guide for Node.js&lt;/li&gt;
&lt;li&gt;CI/CD Pipeline Using GitHub Actions&lt;/li&gt;
&lt;li&gt;Terraform for Beginners: Infrastructure Automation&lt;/li&gt;
&lt;li&gt;How I Configure Production Servers&lt;/li&gt;
&lt;li&gt;MERN Application Deployment Architecture&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because building an application is only half the job.&lt;/p&gt;

&lt;p&gt;The real challenge starts when you hear:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"It works perfectly on my local machine."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Then production introduces you to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Nginx configuration issues&lt;/li&gt;
&lt;li&gt;Docker containers that suddenly stop&lt;/li&gt;
&lt;li&gt;Missing environment variables&lt;/li&gt;
&lt;li&gt;SSL certificate problems&lt;/li&gt;
&lt;li&gt;Firewall rules&lt;/li&gt;
&lt;li&gt;Port conflicts&lt;/li&gt;
&lt;li&gt;PM2 processes&lt;/li&gt;
&lt;li&gt;CI/CD pipeline failures&lt;/li&gt;
&lt;li&gt;And, of course, the legendary 502 Bad Gateway&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;My goal is to document everything I learn while building, deploying, breaking, fixing, and optimizing modern web applications.&lt;/p&gt;

&lt;p&gt;I’ll be sharing practical experiences around:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;MERN Stack Development&lt;/li&gt;
&lt;li&gt;Next.js&lt;/li&gt;
&lt;li&gt;Node.js&lt;/li&gt;
&lt;li&gt;Docker&lt;/li&gt;
&lt;li&gt;Nginx&lt;/li&gt;
&lt;li&gt;GitHub Actions&lt;/li&gt;
&lt;li&gt;CI/CD&lt;/li&gt;
&lt;li&gt;VPS Deployment&lt;/li&gt;
&lt;li&gt;Terraform&lt;/li&gt;
&lt;li&gt;DevOps&lt;/li&gt;
&lt;li&gt;Production Infrastructure&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No unnecessary theory. No overcomplicated tutorials.&lt;/p&gt;

&lt;p&gt;Just practical development, real deployment problems, infrastructure challenges, and solutions discovered along the way.&lt;/p&gt;

&lt;p&gt;If you're interested in building applications and taking them from localhost to production, follow along.&lt;/p&gt;

&lt;p&gt;Because writing the code is easy.&lt;/p&gt;

&lt;p&gt;Finding out why it works locally but not in production is where the real character development begins.&lt;/p&gt;

&lt;p&gt;— Shams Ali Shaikh&lt;br&gt;
Software Engineer | MERN Stack | DevOps | Deployment&lt;/p&gt;

</description>
      <category>cicd</category>
      <category>devops</category>
      <category>docker</category>
      <category>terraform</category>
    </item>
  </channel>
</rss>
