In we started a server, responding to HTTP requests on port 3000. In this tutorial we will look at 4 more concepts part 1 Serving HTTP traffic on the standard port, 80 Keeping the Node.js process running Deploying code into the server Serving some HTML Serving HTTP traffic on the standard port, 80 Paste this URL into a URL bar in a new tab. http://imgur.com:80/ You will notice the gets dropped in the URL bar. That’s because port is the default port for HTTP traffic. 80 80 HTTPS traffic uses port . Try Hacker News. 443 https://news.ycombinator.com :443/ Because these ports are often public, you need special privileges to run processes using them. Also, it is not great to run Node.js on port or directly because you may want to open up a few different applications on these ports. With a router you will be able to send traffic from port or to any program you wish, depending on the headers of the incoming HTTP request. 80 443 80 443 There are few great choices for a router, but I find that is generally the best tool for most things. It’s great for building your first ever app, or when you need to scale up to millions of visitors. nginx Before beginning, start your server if it is stopped and SSH into it ( ). Once logged in, we can install . as shown in the last tutorial nginx Ubuntu comes with it’s own package manager, . Using , we can install in one command. apt-get apt-get nginx sudo apt-get install nginx Most Linux distributions come with a package manager, so Google your version if doesn’t work. runs nginx automatically after install so you should now have it running on port , check by entering your public DNS URL into a browser. apt-get apt-get 80 Default nginx page If this doesn’t work, you might need to start it manually. sudo /etc/init.d/nginx start If you are still can’t reach the server then check out Stack Overflow or post a comment here. We need to configure to route port traffic to port . has config placed in the folder where there is already a default config which serves the welcome page we saw earlier. nginx 80 3000 nginx /etc/nginx/sites-available nginx You can take a look at this config using cat. cat /etc/nginx/sites- /default available How are configs set up? Configs are stored in plain text files in with any name. Linking them into the folder will cause them to be read and used when starts. All of the configs are combined together by . nginx sites-available sites-enabled nginx nginx Let’s first remove the default config from , we will leave it in for reference. sites-enabled sites-available sudo rm /etc/nginx/sites- /default enabled Create a config file in and name it whatever you like. sites-available sudo nano /etc/nginx/sites- /tutorial available The following is the config we are going to use. server {listen 80;server_name tutorial;location / {proxy_set_header X-Real-IP $remote_addr;proxy_set_header Host $http_host;proxy_pass }} http://127.0.0.1:3000; This will forward all HTTP traffic from port to port . 80 3000 Link the config file in (this will make it seem like the file is actually copied in ). sites enabled sites-enabled sudo ln -s /etc/nginx/sites-available/tutorial /etc/nginx/sites-enabled/tutorial Read more about symbolic links here if they are unfamiliar. Restart for the new config to take effect. nginx sudo service nginx restart If you did not stop/start the server since the last tutorial then you may still have your node application running. # list background jobsjobs If your application shows up then no need to run it again. If it is not running then you need to start it. node tutorial/index.js Once the server is running, press , then resume it as a background task. ctrl+z bg %1 Now visit your server’s public DNS URL, using port . 80 The server is running on port ! 80 Keeping the Node.js process running It’s quite tedious using to pause a process, and then running it in the background. Also, doing it this way will not allow the Node.js process to restart when you restart your server after an update or crash. ctrl+z Before moving forward, stop your running node process # Nukes all Node processeskillall -9 node To keep these processes running we are going to use a great NPM package called . While in an SSH session, install PM2 globally. PM2 npm i -g pm2 To start your server, simply use to execute . pm2 index.js pm2 start tutorial/index.js To make sure that your PM2 restarts when your server restarts pm2 startup This will print out a line of code you need to run depending on the server you are using. Run the code it outputs. Finally, save the current running processes so they are run when PM2 restarts. pm2 save That’s it! You can log out/in to SSH, even restart your server and it will continue to run on port 80. To list all processes use pm2 ls Your process will have a pretty generic name, something like , which would be hard to differentiate if you had a few other microservices running on the server too. Let’s stop the process, remove it and start it back up with a nicer name. index # Use the number listed in pm2 ls# to stop the daemonpm2 stop index # Remove it from the listpm2 delete index # Start it again, but give it a# catchy namepm2 start tutorial/index.js --name “Tutorial” Great! Check out the to see what else you can do with process management. PM2 docs Deploying code into the server Instead of writing code in an SSH session, let’s push the code to a git repo in Github, SSH into the server and pull in the new code. Go to or your favourite source control website, login and create a new repository named what you like. If you aren’t able to make it private, make it public (it’s okay, no one’s going to look anyway). Github Make a new directory wherever you like to put your code projects (btw, to exit an SSH session just type ). I named mine with gusto and imagination, “tutorial-pt-2". locally exit cd ~/Codemkdir tutorial-pt-2cd tutorial-pt-2 Now set up your origin, make an empty commit and push it up, setting your upstream branch as master. git initgit commit --allow-empty -m "Well this is my first commit, *yay*" # Use your repo's origin URL heregit remote add origin :roberttod/tutorial-pt-2.gitgit push -u origin master git@github.com :). It’s nice to start with an empty commit Like we did on the server run and then create an file using the same code from the last tutorial. npm init index.js P.S. I am missing out the **_;_** s on purpose, check out Standard Style . const express = require('express')const app = express()app.get('/', (req, res) => {res.send('HEY!')}) app.listen(3000, () => console.log('Server running on port 3000')) NPM install express npm install express --save Also, let’s add a file so that we don’t check in the directory. files always get added to directories by OSX, they contain folder meta data. We want to ignore these too. .gitignore node_modules .DS_Store node_modules.DS_Store In general, it is best to only check in code that you actually need checked in, if you ever find yourself with chunks of copied or library code in your git repo then there is probably a better way to do it. Now add all your code and push it up git add .git commit -m "Ze server."git push Now we need to pull the code into the server. This is where it can be kind of tricky. We need to SSH into the server, generate a SSH private/public key pair and then add it as a deployment key in source control (i.e. Github). Only when the server is allowed access to the remote repo will it be able to clone the code and pull down changes. SSH into your server and generate the key pair. # When prompted, use the default name.# No need for a pass phrase.ssh-keygen -t rsa Show the contents of the file cat ~/.ssh/id_rsa.pub Select the key’s contents and copy it into Github. Deploy keys are added in a section called in the settings for your repo. Deploy keys Paste your key and call it something meaningful. Whenever you are logged in over SSH, you want the keys to be added so that they are used to authenticate with Github. To do this, add these lines to the top of your file. ~/.bashrc # Start the SSH agent eval `ssh-agent -s` # Add the SSH key ssh-add This will make sure you use the keys whenever you log on to the server. To run the code without logging out, execute the file .bashrc source ~/.bashrc Now we can clone the repo! Remove any previous code on the server and in the user directory, clone the repo # You should use your own git URL.git clone git@github.com:roberttod/tutorial-pt-2.git If it works, it will allow you to type “yes” to add github as a known host, then the repo will be downloaded. In a nice world we like to completely avoid ever using SSH. For deployment, we are going to use PM2 in order for us to do the git cloning on the server for us, with some bonus features. Before using PM2, remove the code you just pulled in from git into your server. rm -rf ~/tutorial-pt-2 While you are still in the SSH session, ensure that there are no processes still running on PM2, if there are then remove them. pm2 ls # Only do this if a task is still runningpm2 delete tutorial In your version of the project, install PM2 globally local npm i -g pm2 Now we need to add a config file PM2 can read so that it knows how to deploy. PM2 configs are fully explained in the . The config file can be auto generated but I prefer to just create my own from scratch, avoiding any config I don’t need. PM2 docs The config file should be named and should look like this ecosystem.config.js module.exports = {apps: [{name: 'tutorial-2',script: './index.js'}],deploy: {production: {user: 'ubuntu',host: 'ec2-52-209-166-225.eu-west-1.compute.amazonaws.com',key: '~/.ssh/tutorial-2.pem',ref: 'origin/master',repo: ' :roberttod/tutorial-pt-2.git',path: '/home/ubuntu/tutorial-2','post-deploy': 'npm install && pm2 startOrRestart ecosystem.config.js'}}} git@github.com You will need to add your own host in the config file. How does PM2 use this config file? When you run , PM2 SSHs into your server, clones your repo into the directory specified in , then it runs the on the server (so it starts your server using the PM2 installed globally on the server). After the deploy, you will be able to run on the server to see all the apps running, their names will be the same as specified in the config file. pm2 deploy ... path post-deploy pm2 ls Once the file is saved, setup the directories on the remote pm2 deploy ecosystem.config.js production setup If you run into any auth issues, look back at setting up the SSH agent to make sure you didn’t miss anything. Once setup, commit and push your changes to Github so that when it clones it gets your file, which is going to be used to start your app using PM2 on the server. ecosystem.config.js git add .git commit -m "Setup PM2"git push Now you can run the deploy command pm2 deploy ecosystem.config.js production This should come up with an error, which will be that was not found. npm The reason for this is because of some code in the file of the server. This code stops the file from running if the shell is not . Unlike using , PM2 logs into the server in a shell. NVM is set up in the file so PM2 isn’t running NVM, which adds the executable (thus the error from PM2). .bashrc interactive ssh non-interactive .bashrc npm Read more about interactive/non interactive shells. SSH into your server and open up the file. The code that excludes sessions is near the top. ~/.bashrc non-interactive # If not running interactively, don't do anything case $- in*i*) ;;*) return;;esac This code is some magic bash shit. All we need to do is move the NVM code above this code, so it always executes. Find the following lines and move them above the case statement export NVM_DIR="/home/ubuntu/.nvm"[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" # This loads nvm Save and exit. Back on your local terminal, try running the PM2 deploy again pm2 deploy ecosystem.config.js production It should work this time! And your server should still be running when you check in a browser. Using a global PM2 on the server and a global PM2 on the client is a bit messy. It would be better if our code used the local version of the PM2 package. To do this, add a and script to your deploy restart package.json ..."main": "index.js","scripts": {"restart": "pm2 startOrRestart ecosystem.config.js","deploy": "pm2 deploy ecosystem.config.js production","test": "echo \"Error: no test specified\" && exit 1"},"repository": {... Install PM2 locally and save, using --save-dev npm i pm2 --save-dev For those not that familiar with NPM, adding or adds the package, along with a version number to . Any packages in the file will be installed when running , which happens in the PM2 . --save --save-dev package.json package.json npm install post-deploy Before deploying, commit all your changes and push to git. When you run , it will now use the local version of PM2. Neat! npm deploy npm run-script deploy In case you find that your app isn’t running, check the PM2 logs on your server, located in . ~/.pm2/logs/ To make sure the app restarts when the server restarts, SSH back into your server and run pm2 save The only PM2 process running should be your deployed server, so PM2 will ensure that is always kept running. Serving HTML Before concluding the tutorial, let’s use our deployment setup to change the server so that it serves HTML, rather than just responding with “Hey”. Remove the route handler for and set up a static directory that express will use to serve static files. / const express = require('express')const app = express() app.use(express.static('public'))app.listen(3000, () => console.log('Server running on port 3000')) By calling with “public”, static files will be served from the directory. If we add an in , then this will be automatically served at by express (if we left a custom handler, then that would override this functionality). express.static public index.html /public / / Save a simple HTML file in public/index.html <!DOCTYPE html><html><head><title>Erm hey.</title></head><body><img src=" "></body></html> https://media.giphy.com/media/3o6Zt7aSSZLX6U5WtW/source.gif Commit these changes (perhaps you could check the server still works by running locally and visiting ). node index.js http://localhost:3000 Deploy the changes npm run-script deploy Your server will now respond with your static HTML page. Conclusion You should now have a simple express app that is fairly easy to deploy on EC2, running on port . I left my source code public in case you would like to take a look . 80 https://github.com/roberttod/tutorial-pt-2 If you like this tutorial, I am doing a few more explaining . how to setup Node with MySQL