Skip to content

Instantly share code, notes, and snippets.

@bradtraversy
Last active October 10, 2024 11:48
Show Gist options
  • Save bradtraversy/cd90d1ed3c462fe3bddd11bf8953a896 to your computer and use it in GitHub Desktop.
Save bradtraversy/cd90d1ed3c462fe3bddd11bf8953a896 to your computer and use it in GitHub Desktop.
Node app deploy with nginx & SSL

Node.js Deployment

Steps to deploy a Node.js app to DigitalOcean using PM2, NGINX as a reverse proxy and an SSL from LetsEncrypt

1. Sign up for Digital Ocean

If you use the referal link below, you get $10 free (1 or 2 months) https://m.do.co/c/5424d440c63a

2. Create a droplet and log in via ssh

I will be using the root user, but would suggest creating a new user

3. Install Node/NPM

curl -sL https://deb.nodesource.com/setup_12.x | sudo -E bash -

sudo apt install nodejs

node --version

4. Clone your project from Github

There are a few ways to get your files on to the server, I would suggest using Git

git clone yourproject.git

5. Install dependencies and test app

cd yourproject
npm install
npm start (or whatever your start command)
# stop app
ctrl+C

6. Setup PM2 process manager to keep your app running

sudo npm i pm2 -g
pm2 start app (or whatever your file name)

# Other pm2 commands
pm2 show app
pm2 status
pm2 restart app
pm2 stop app
pm2 logs (Show log stream)
pm2 flush (Clear logs)

# To make sure app starts when reboot
pm2 startup ubuntu

You should now be able to access your app using your IP and port. Now we want to setup a firewall blocking that port and setup NGINX as a reverse proxy so we can access it directly using port 80 (http)

7. Setup ufw firewall

sudo ufw enable
sudo ufw status
sudo ufw allow ssh (Port 22)
sudo ufw allow http (Port 80)
sudo ufw allow https (Port 443)

8. Install NGINX and configure

sudo apt install nginx

sudo nano /etc/nginx/sites-available/default

Add the following to the location part of the server block

    server_name yourdomain.com www.yourdomain.com;

    location / {
        proxy_pass http://localhost:5000; #whatever port your app runs on
        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;
    }
# Check NGINX config
sudo nginx -t

# Restart NGINX
sudo service nginx restart

You should now be able to visit your IP with no port (port 80) and see your app. Now let's add a domain

9. Add domain in Digital Ocean

In Digital Ocean, go to networking and add a domain

Add an A record for @ and for www to your droplet

Register and/or setup domain from registrar

I prefer Namecheap for domains. Please use this affiliate link if you are going to use them https://namecheap.pxf.io/c/1299552/386170/5618

Choose "Custom nameservers" and add these 3

  • ns1.digitalocean.com
  • ns2.digitalocean.com
  • ns3.digitalocean.com

It may take a bit to propogate

  1. Add SSL with LetsEncrypt
sudo add-apt-repository ppa:certbot/certbot
sudo apt-get update
sudo apt-get install python-certbot-nginx
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com

# Only valid for 90 days, test the renewal process with
certbot renew --dry-run

Now visit https://yourdomain.com and you should see your Node app

@MuttakinHasib
Copy link

how can I redirect from v2.example.com to example.com?
@bradtraversy

@GoodnessEzeokafor
Copy link

awesome

@Mihaidev-cloud
Copy link

For people who don't want to bother their minds with this, I created an automatic installer! https://github.com/Mihaidev-cloud/Nodejs-Webserver-AutoInstaller-Nginx

@bishoplee
Copy link

This is a life-saver. Great work Brad. Thanks also to all the inline comments.

@serfoll
Copy link

serfoll commented Sep 2, 2022

This was great, works well with google cloud too

@vinsonw
Copy link

vinsonw commented Oct 17, 2022

Successfully deployed on vultr. Left out the security and ssl part due to time limit.
Great course, learned a lot, thanks!

@hall500
Copy link

hall500 commented Oct 30, 2022

www.example.com, www is a subdomain already. so you can only use sub.example.com.

@mellifluus
Copy link

Thanks! This was extremely helpful. For anyone having trouble with POST requests, the problem is NGINX redirects requests to https with status code 301, which sometimes changes the method of the request to GET. The solution is to redirect requests with status code 308, which doesn't change the method of the request

@aldrichsan
Copy link

is it possible to do the ssl without a domain and use the IP address instead?

@msrumon
Copy link

msrumon commented Dec 14, 2022

is it possible to do the ssl without a domain and use the IP address instead?

No. SSL is issued to domain names, not IP addresses.

@wackyapps
Copy link

Is this works with Let's Encrypt and auto renew of SSL from Let's Encrypt after 90 days?

@SV-sites
Copy link

SV-sites commented Mar 2, 2023

Update 2023 install Certbot
sudo pip3 install certbot-nginx

Thanks a lot!

"Do not use no-name name servers, because you will suck with NGINX!" => I learned this after 2.5 day struggling :)

@Answer32
Copy link

Answer32 commented Apr 3, 2023

What if I deploy the app on a local server and acces it through HTTP only on my local network? Will the browser complain about an insecure connection?

@msrumon
Copy link

msrumon commented Apr 3, 2023

What if I deploy the app on a local server and acces it through HTTP only on my local network? Will the browser complain about an insecure connection?

If the browser sees "localhost" in the address bar, it'll most probably not complain.

@Answer32
Copy link

Answer32 commented Apr 3, 2023

What if I deploy the app on a local server and acces it through HTTP only on my local network? Will the browser complain about an insecure connection?

If the browser sees "localhost" in the address bar, it'll most probably not complain.

What if I access it from another computer that is on the same network?

@msrumon
Copy link

msrumon commented Apr 3, 2023

What if I deploy the app on a local server and acces it through HTTP only on my local network? Will the browser complain about an insecure connection?

If the browser sees "localhost" in the address bar, it'll most probably not complain.

What if I access it from another computer that is on the same network?

Same. 'Cause the other device and the device the server is running on are technically under the same network.

@ahmedRSA
Copy link

ahmedRSA commented Apr 4, 2023

for ssl just move your name servers to cloudflare
ez

@mubashirzebi
Copy link

for SSL , i have use instruction from https://certbot.eff.org/instructions?ws=nginx&os=debianbuster , as given in th doc is depricated

@ENO-QC
Copy link

ENO-QC commented Jun 18, 2023

sudo apt-get install certbot python3-certbot-nginx worked for me

@ThakkarChandresh
Copy link

I've configured it as shown and it's working perfectly fine.

But only one problem I'm facing very badly.

I'm continuously getting one error in the console.
WebSocketClient.js:16 WebSocket connection to 'wss://compressorpartsfactory.com:3000/ws' failed:

@jairosnyirenda19
Copy link

sudo pip3 install certbot-nginx

Thank you for this!!!

@aviatorBeijing
Copy link

Are you sure "localhost" will work in Nginx config? I recall you have to use 127.0.0.1 instead, because nginx expects to see an IP, not "localhost".

@ilyshaxa
Copy link

Thanks bro! It worked!

@piincher
Copy link

www.example.com, www is a subdomain already. so you can only use sub.example.com.

Can You please help on how to setup subdomain for my api instead of main domain

@mitchgruen
Copy link

Looks like step 10 is deprecated. The link below helped me to get https working.

https://certbot.eff.org/instructions?ws=nginx&os=ubuntufocal

@safvan-husain
Copy link

Awesome

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