Sunday, May 3, 2026

Fixing “Unhandled Promise Rejection: Connection Refused” When Deploying a NestJS API to a Shared Hosting VPS – A Developer’s Urgent Guide to mDNS, Port Conflicts and Corrupt Runtime Environments

Fixing “Unhandled Promise Rejection: Connection Refused” When Deploying a NestJS API to a Shared Hosting VPS – A Developer’s Urgent Guide to mDNS, Port Conflicts and Corrupt Runtime Environments

You’ve just pushed your sleek NestJS API to a cheap VPS, hit “deploy” and—in a flash—your console explodes with “Unhandled Promise Rejection: Connection Refused”. The error feels like a brick wall, and every retry just adds more noise. If you’re tired of hunting down phantom ports, fighting hidden mDNS services, or wondering why the runtime “just died” on a shared host, keep reading. This guide walks you through the exact fixes, step‑by‑step, so you can get your API back online in minutes and stop losing billable development hours.

Why This Matters

Every minute your API is down is a lost opportunity—whether that’s a paying customer hitting an endpoint, a webhook that never fires, or a cron job that stalls. On shared VPS plans, hidden services (like avahi‑daemon) can hijack the default 3000 port, while mis‑configured .env files silently point to the wrong database. The result? A dreaded ECONNREFUSED that looks like a code bug but is actually an environment problem.

Fixing it not only restores uptime, it teaches you how to future‑proof your deployments, avoid costly support tickets, and keep your dev pipeline humming.

Step‑by‑Step Tutorial

  1. Confirm the Runtime Environment

    Log into your VPS and verify Node.js and npm versions. Incompatible versions are a silent killer.

    node -v
    npm -v
    # Expected: Node 18.x or higher for Nest 9+
    Tip: If the version is outdated, install the latest LTS with nvm install --lts and set it as default.
  2. Check for Port Conflicts (mDNS & Shared Services)

    Many shared hosts run avahi-daemon or systemd-resolved that bind to 0.0.0.0:3000 for mDNS discovery. Use netstat or ss to see who’s listening.

    sudo ss -tulpn | grep :3000
    # Example output:
    # LISTEN 0 128 0.0.0.0:3000 0.0.0.0:* users:(("avahi-daemon",pid=785,fd=5))
    Warning: Never force‑kill a system service; you’ll break DNS on the whole server. Instead, change your NestJS port (see step 5) or stop the service safely if you control the VPS.
  3. Validate Your .env File

    Missing or malformed variables are the most common cause of ECONNREFUSED when connecting to a database or Redis.

    # .env (example)
    DB_HOST=127.0.0.1
    DB_PORT=5432
    DB_USER=nest_user
    DB_PASS=super_secret
    DB_NAME=nest_prod
    # Ensure no stray spaces or Windows line endings!
    Tip: Run cat -A .env to reveal hidden ^M characters that break parsing.
  4. Test Database Connectivity From the VPS

    Before Nest starts, confirm you can talk to the DB with a simple psql (Postgres) or mysql client.

    # Postgres example
    PGPASSWORD=$DB_PASS psql -h $DB_HOST -U $DB_USER -d $DB_NAME -p $DB_PORT -c "\l"
    Tip: If the client fails, the problem is outside Nest – fix firewall rules, bind addresses, or DB user permissions.
  5. Change the NestJS Listening Port

    Pick a high, unused port (e.g., 5000) to dodge hidden services.

    // main.ts
    async function bootstrap() {
      const app = await NestFactory.create(AppModule);
      const port = process.env.PORT || 5000; // ← changed
      await app.listen(port, () => console.log(`🚀 API listening on ${port}`));
    }
    bootstrap();
  6. Restart the Application with Proper Logging

    Use pm2 or a systemd service that captures stderr. This ensures unhandled rejections surface in the logs.

    # pm2 ecosystem file (ecosystem.config.js)
    module.exports = {
      apps: [{
        name: "nest-api",
        script: "dist/main.js",
        interpreter: "node",
        env: {
          NODE_ENV: "production",
          PORT: 5000
        },
        watch: false,
        error_file: "/var/log/nest-api/error.log",
        out_file: "/var/log/nest-api/out.log"
      }]
    };
    Tip: Add process.on('unhandledRejection', err => { console.error(err); process.exit(1); }); to force a crash and restart on fatal errors.
  7. Verify the Fix

    From your local machine, hit the new endpoint.

    curl -i http://your-vps-ip:5000/health
    # Expected: 200 OK with JSON { "status":"ok" }

Real‑World Use Case: E‑Commerce Checkout API

A small Shopify‑integrated startup deployed a NestJS checkout microservice on a $5/month VPS. After the first sale, the webhook from Shopify failed with “Connection Refused”. The root cause was the VPS’s default avahi-daemon occupying port 3000. By moving the API to 5000, updating the webhook URL, and locking the Node version with nvm, the checkout flow recovered in under 30 minutes, saving the team an estimated $250 in lost sales.

Results / Outcome

  • Zero “Unhandled Promise Rejection” errors in production logs.
  • Stable database connections verified with command‑line tools.
  • Fast, repeatable deployment script that works on any shared VPS.
  • Immediate revenue protection for time‑critical APIs.

Bonus Tips

  • Automate Environment Checks: Add a pre‑start script in package.json that runs node scripts/check-env.js to abort if any required variable is missing.
  • Use Docker Even on VPS: A lightweight node:18-alpine container isolates your app from host‑level services, eliminating most port‑conflict surprises.
  • Health‑Check Endpoint: Expose /health that returns DB connectivity status. Pair it with a monitoring service (UptimeRobot, Healthchecks.io).
  • Log Rotation: Set up logrotate for /var/log/nest-api/*.log to keep disk usage low on cheap plans.

Monetize Your Knowledge (Optional)

If you found this guide helpful, consider turning your troubleshooting expertise into a side hustle:

  1. Write a paid “NestJS on Shared Hosting” ebook and sell it on Gumroad.
  2. Offer a one‑hour consulting call for $75 to debug production APIs.
  3. Create a short video course on Udemy focusing on “Deploying Node.js Apps to Low‑Cost VPS”.

These extra revenue streams can quickly offset your hosting costs and give you more freedom to experiment.

No comments:

Post a Comment