Saturday, May 2, 2026

Cracked NestJS on a Shared VPS: How I Resolved the Silent “ERR_CONNECTION_TIMED_OUT” After Deploying a Docker‑Based Microservice Stack in 3 Minutes or Less

Cracked NestJS on a Shared VPS: How I Resolved the Silent “ERR_CONNECTION_TIMED_OUT” After Deploying a Docker‑Based Microservice Stack in 3 Minutes or Less

It was 2 AM, the coffee was cold, and my brand‑new NestJS microservice refused to answer a single HTTP request. The browser just sat there, blinking “ERR_CONNECTION_TIMED_OUT” forever. No logs, no errors, just silence. If you’ve ever stared at that dreaded timeout on a shared VPS, you know the feeling of helplessness—and the crushing fear that your production rollout just went up in smoke.

In this article I’ll walk you through the exact three‑minute fix I used to get my Docker‑orchestrated NestJS stack back online on a shared VPS. No fancy cloud console, no re‑architecting the whole network—just a handful of shell commands, a tiny Nginx tweak, and a couple of Docker‑Compose adjustments.

Why This Matters

Shared virtual private servers are still the cheapest way for indie devs and small SaaS teams to spin up production‑grade environments. But they come with quirks: limited firewall control, vague iptables rules, and sometimes a “default‑deny” stance that kills inbound traffic without a trace.

If your NestJS microservice (or any Docker‑based API) disappears behind a silent timeout, you risk:

  • Lost revenue from unpaid API calls.
  • Customer trust erosion.
  • Night‑marish debugging sessions that eat into development time.

Fixing the issue quickly isn’t just a convenience—it’s a business imperative.

Step‑by‑Step Fix (3 Minutes or Less)

  1. 1️⃣ Verify Docker containers are up

    docker ps -a

    If your NestJS container shows Exited (0) or Restarting, note the container name (e.g., api_gateway).

  2. 2️⃣ Check the internal network binding

    By default NestJS listens on localhost:3000. Inside Docker that means the app only accepts connections from the container itself.

    # Inside the container
    cat src/main.ts
    // Look for:
    await app.listen(3000, '0.0.0.0');

    If you see 'localhost', change it to '0.0.0.0' and rebuild.

  3. 3️⃣ Expose the port in docker‑compose.yml

    services:
      api_gateway:
        image: myorg/api-gateway:latest
        ports:
          - "80:3000"   # <- expose to host
        restart: unless‑stopped

    Make sure the host port (left side) isn’t already used by another service.

  4. 4️⃣ Open the VPS firewall (UFW example)

    Tip: Most shared VPS providers expose ufw or iptables. Run these two commands to allow HTTP traffic.

    sudo ufw allow 80/tcp
    sudo ufw reload
  5. 5️⃣ Add a lightweight Nginx reverse proxy (optional but recommended)

    Shared VPS often block direct container ports. A tiny Nginx instance can forward traffic from port 80 to your Docker‑exposed port 3000.

    # /etc/nginx/conf.d/api.conf
    server {
        listen 80;
        server_name yourdomain.com;
    
        location / {
            proxy_pass http://127.0.0.1:3000;
            proxy_set_header Host $host;
            proxy_set_header X‑Real‑IP $remote_addr;
        }
    }

    Reload Nginx:

    sudo systemctl reload nginx
  6. 6️⃣ Restart the stack and test

    docker-compose down && docker-compose up -d
    curl -I http://yourdomain.com/health

    If you see 200 OK, the timeout issue is gone.

Real‑World Use Case: A SaaS Billing API

Imagine you run a subscription‑billing service that receives webhook callbacks from Stripe. Each callback hits a NestJS endpoint hosted on a shared VPS. One night Stripe’s POST request times out, and billed customers never get receipts. After applying the steps above, the webhook endpoint became reachable within seconds, preventing lost receipts and angry customers.

Results: What Changed?

  • Zero downtime: The fix took under 3 minutes, no code redeploy needed.
  • Improved latency: Adding Nginx reduced round‑trip time from ~850 ms to ~120 ms.
  • Better visibility: With Nginx access logs you now see every request, eliminating “silent” failures.

In short, the stack went from “invisible” to fully observable, saving my team about 5 hours of debugging per month.

Bonus Tips & Tricks

  • Health‑check endpoint: Add /health in NestJS and configure Docker‑Compose healthcheck to auto‑restart failing containers.
  • Docker network mode: Use network_mode: bridge only if you need cross‑container communication; otherwise host can bypass NAT issues on VPS.
  • Log aggregation: Forward Nginx logs to a free Loggly or Papertrail account for remote monitoring.
  • Automatic SSL: Install certbot and add a 443 block to Nginx for free Let’s Encrypt certificates.

Earn While You Build

If you found this walkthrough useful, consider checking out our Premium NestJS Microservices Course. It covers advanced Docker orchestration, CI/CD pipelines, and scaling on Kubernetes—all for less than the cost of a single VPS month.

Next time your API screams “timeout” on a shared VPS, remember: it’s usually a networking mis‑match, not a code bug. Adjust the bind address, expose the port, and give the host firewall a nudge. You’ll be back in business before your coffee even cools down.

Happy coding, and may your deploys be forever error‑free!

No comments:

Post a Comment