Skip to content

Instantly share code, notes, and snippets.

@dPacc
Last active June 20, 2025 14:24
Show Gist options
  • Save dPacc/5e0ddaeba0a54e18133b6606dcf49682 to your computer and use it in GitHub Desktop.
Save dPacc/5e0ddaeba0a54e18133b6606dcf49682 to your computer and use it in GitHub Desktop.
EC2 - ExpressJS Server Setup with Custom Domain

(PRE) Create a free tier ec2 Ubuntu machine

  • SSH into the server instance

  • Run as super user: sudo su

  • Run: apt-get update

(1) NPM and Nodejs installation: https://docs.aws.amazon.com/sdk-for-javascript/v2/developer-guide/setting-up-node-on-ec2-instance.html

(2) Setting up the server

  • It is conventional to place the code in /var/www/APP_NAME, so mkdir -p /var/www/APP_NAME

  • Go into the dir cd /var/www/APP_NAME and clone the server repo git clone /var/www/APP_NAME

(3) Installing Nginx

  • Install nginx: apt-get install nginx

  • To verify if nginx is running, open the Public IPv4 address of your EC2 server

  • Go to /etc/nginx/sites-available

  • Run nano default and delete everything and paste the following

  • Let us first run it without SSL, paste the following

server {
  listen       80;
  server_name  _;

  location / {
    proxy_pass http://EC2_Private_IPv4:APP_PORT;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection 'upgrade';
    proxy_set_header Host $host;
    proxy_cache_bypass $http_upgrade;
  }
}
  • Run systemctl restart nginx

  • Go to your Domain DNS Settings and create a CNAME with sub-domain with the value to be EC2 Public IPv4 DNS (ec2-2-3...)

  • Go to your /var/www/YOUR_APP, and run your server npm i and npm start

(4) Set up SSL certificate

  • Install snapd package manager: apt-get install snapd

  • Install certbot: snap install --classic certbot

  • sudo ln -s /snap/bin/certbot /usr/bin/certbot

  • Run the following to generate the certs: certbot -d SUB_DOMAIN.DOMAIN.com and go through the questions

  • Reconfigure NGINX to setup the certificates

  • Go to /etc/nginx/sites-available

  • Run nano default and delete everything and paste the following

server {
        listen 80;
        server_name SUB_DOMAIN.YOUR_APP.com;
        return 301 https://$host$request_uri;
}

server {
        listen 443 ssl;

        server_name SUB_DOMAIN.YOUR_APP.com;
        ssl_certificate /etc/letsencrypt/live/SUB_DOMAIN.YOUR_APP.com/fullchain.pem; # managed by Certbot
        ssl_certificate_key /etc/letsencrypt/live/SUB_DOMAIN.YOUR_APP.com/privkey.pem; # managed by Certbot

        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
        ssl_prefer_server_ciphers on;
        ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH';

location / {
        proxy_pass http://EC2_Private_IPv4:APP_PORT;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }
}
  • Run systemctl restart nginx

  • Go to your /var/www/YOUR_APP, and run your server npm start

  • Open the domain you configured and it should be running the server

(5) Setting up PM2 (Ref: https://www.digitalocean.com/community/tutorials/how-to-set-up-a-node-js-application-for-production-on-ubuntu-20-04)

  • Install build essentials: apt install build-essential

  • Install pm2: npm install pm2@latest -g

  • Start the server: pm2 start server.js

@dPacc
Copy link
Author

dPacc commented Oct 24, 2023

The IP address ::ffff:172.31.80.91 appears to be a private IPv4-mapped IPv6 address. When you see this, it usually indicates that you're running your application in a networked environment, such as a cloud service, behind a load balancer or reverse proxy. The address you're seeing is likely the internal address of the proxy or load balancer forwarding the requests to your application.

Here are some ways to tackle this issue:

X-Forwarded-For Header

You can check if the X-Forwarded-For HTTP header is being set by your reverse proxy. This header contains the original IP address of the client making the request.

To read the first IP from this header in your keyGenerator, you can do:

keyGenerator: (req, res) => {
  const forwarded = req.headers['x-forwarded-for'];
  const ip = forwarded ? forwarded.split(/, /)[0] : req.ip;
  console.log("Client IP:", ip);
  return req.user ? req.user._id : ip;
}

Reverse Proxy Configuration

Ensure that your reverse proxy is configured to pass along the original client IP. Below are some example configurations for popular reverse proxies:

  • For Nginx, you can use:

    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  • For Apache, you can use:

    ProxyPreserveHost On
    ProxyPass / http://localhost:3000/
    ProxyPassReverse / http://localhost:3000/

If you're running in a cloud environment, also check if there's a specific way to capture the client IP for your specific service.

Trust Proxy Setting

You've already set app.set("trust proxy", 1); which is good. This tells Express to trust the first proxy it encounters, which should allow req.ip to correctly reflect the client’s IP address when behind a proxy.

Make sure this setting is before your rate limiter middleware.

Multiple Proxies

If there are multiple proxies involved, you can set 'trust proxy' to the number of proxies in the chain, or to true to trust all proxies. However, be cautious when setting it to true as it could potentially lead to security risks.

app.set("trust proxy", true);  // Be cautious using this

By properly setting one or more of these options, you should be able to capture the original client IP address.

@dPacc
Copy link
Author

dPacc commented Mar 17, 2024

In house use private IP of the server

@dPacc
Copy link
Author

dPacc commented Jun 9, 2025

Useful commands for the future:

pm2 save - Save current process list (do this after adding/removing apps)
pm2 startup
pm2 resurrect - Manually restore saved processes
pm2 logs - View application logs
pm2 monit - Real-time monitoring dashboard

Your autonoly-server and autonoly-lp-server are now properly configured for automatic recovery. The issue you experienced won't happen again! 🎉

@ashiwanikumar
Copy link

Useful commands for managing your applications

Restart specific application

pm2 restart digisvc-prod
pm2 restart digisvc-staging

View logs for specific app

pm2 logs digisvc-prod --lines 50

Monitor applications

pm2 monit

Check detailed info

pm2 describe digisvc-prod

Check if ports are working

netstat -tlnp | grep :8000
netstat -tlnp | grep :8001

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment