In this chapter, we discussed the fundamentals of JavaScript and explored its applications in both the frontend and backend, as well as how to created a full stack web application using JavaScript. As we reach the end of this chapter, it is time for us to discuss how to deploy the app to the cloud so that it is accessible on the internet.
There are several options available, each suited for different needs and flexibility. For example, you can deploy your app to a VPS (virtual private server), a could service such as AWS, or a PaaS (platform-as-a-service) such as Vercel.
Among these options, the VPS offers the most control and flexibility, as it is essentially a remote computer of which you have total control. But it also requires higher level of expertise on server management and it does not scale automatically. You have to buy more servers as your app attracts more users.
If you opt to use cloud services like AWS or Google Cloud Service, you are technically borrowing the computing power from Amazon or Google. Of course you are not going to have control of these servers, but it also saves you the trouble of managing them yourself, and the app will scale automatically without you doing anything.
As for PaaS such as Vercel and Netlify, they are platforms built on top of cloud services such as AWS by abstracting more backend services and infrastructures, making it easier for developers to deploy applications. Similarly, the app will scale automatically, and you will also be charged on the amount of resources consumed, but usually at a higher price for the convince they bring.
In this lesson, we will focus on deploying a Node.js application manually on a VPS, because our goal is to deepen your understanding of the inner workings of web applications.
Choose a VPS provider
A VPS (virtual private server) is a remote computer that you can use to host your web application. When your web app is visited, that computer will transfer the necessary resources to the client. As for the name "virtual", it means this computer utilizes the virtualization technology to split one physical server into multiple virtual servers so that they would be more affordable.
There are many companies that provide VPS services, such as Digital Ocean, Vultr, and Linode. They may offer different functionalities, but all three of them are big names in the industry, and offer decent and reliable services.
In this lesson, we're going to use Vultr as an example. You can use this link to claim $300 to get you started. Just in case you decide to use a different provider, we won't be using any of its special functionalities. Let's stick to the basics and set up everything manually.
First, go to Products -> Compute, and then click on Deploy Server:
Next, choose what kind of server you want. We recommend always starting with the cheapest option if you don't know what to choose. You can always upgrade to better servers, but VPS providers don't usually offers downgrade services.
Next, choose your CPU, server location, and operating system. Always choose a distribution you are familiar with. Here, we'll use Ubuntu for demonstration purposes:
Choose your server size, again, you should start with the cheapest option. For the Additional Features, you can leave them unchecked if you don't know what they are. You can always add them later if you need them. Finally, give your server a hostname and click Deploy Now:
It will take a few minutes for the server to install. Once the status becomes Running, the server will be assigned an IP address, and a root
user will be created:
You can use the IP address to access the server. On your own computer, open the terminal and type in:
1ssh root@<ip_address>
You will be prompted to type in the root
user's password. The password will not be displayed as you type, that is just a security measure, not a bug.
If you see the same output, that means your new server is ready.
Prepare your server
Before deploying your project, there are still some preparations you need to do, or the server will be vulnerable to cyber attacks.
Create a new user
First of all, you shouldn't be using the root
user. The root
user has the power to do anything to your server, and no one should have that much power. You can create a new user (let's call him jack
) account using the following command:
1adduser jack
Create a new password for user jack
, and type in his information:
Give this new user root privileges by adding him to the sudo
group:
1usermod -aG sudo jack
DO NOT close the terminal in case something goes wrong. Open up a new terminal window and sign in as the new user:
1ssh jack@<ip_address>
Make sure you can run commands as the administrator:
1sudo <command>
You will be prompted to type in jack
's password. If this works for you, then it is safe to close the root
user's windows. From now on, we'll be working as the new user, jack
.
Next, you need to make sure no one can sign in as the root
user. The root sign-in can be disabled in the sshd_config
file. Open up the file using the following command:
1sudo nano /etc/ssh/sshd_config
Scroll down and find PermitRootLogin
:
1. . .
2# Example of overriding settings on a per-user basis
3#Match User anoncvs
4# X11Forwarding no
5# AllowTcpForwarding no
6# PermitTTY no
7# ForceCommand cvs server
8PasswordAuthentication yes
9PermitRootLogin yes
Change yes
to no
:
1PermitRootLogin no
Press CTRL+X
to exit the nano
editor, and type Y
to save the buffer:
1Save modified buffer?
2 Y Yes
3 N No ^C Cancel
Press ENTER
to exit:
1File Name to Write: /etc/ssh/sshd_config
2^G Help M-D DOS Format M-A Append M-B Backup File
3^C Cancel M-M Mac Format M-P Prepend ^T Browse
For this change to take effect, you need to restart the sshd
daemon:
1sudo systemctl restart sshd
Now you can try to sign in as the root
user, and you will get a Permission denied
message:
Sign in via SSH keys
And then there is the password. Passwords, no matter how complex, are still too easy to crack. You need to make sure the only way to sign in to your server is via Secure Shell Protocol (SSH) keys.
First, you need to create a key pair. There should be a public key, which is placed on your server, and a private key, which is held by you. If the key pair match, then you will be signed in.
Using your own computer, create the key pair with the following command:
1ssh-keygen
This command will work on both Linux and macOS. We recommend setting up WSL if you are using Windows. By default, this command will create a 3072-bit RSA key pair. If you wish to make it more secure, you can add an optional -b
flag and specify the desired bits like this:
1ssh-keygen -b 4096
You should see the following output:
1Generating public/private rsa key pair.
2Enter file in which to save the key (/Users/<your_home>/.ssh/id_rsa):
By default, the private key will be generated under your home directory, in the .ssh
folder. You can change its destination if you want to. We'll keep the default path and press ENTER
:
1Enter passphrase (empty for no passphrase):
You can create an optional passphrase for the key pair. This is an extra layer of security for your server, and it is highly recommended if the data on your server is very important.
After you are done, you should get the following output:
1Your identification has been saved in /Users/<your_home>/.ssh/id_rsa
2Your public key has been saved in /Users/<your_home>/.ssh/id_rsa.pub
3The key fingerprint is:
4SHA256:EiQgE7ZQB/2v40ccfrXxnQrFs383qS/DgQ1xK8pjQ4Q erichu@Erics-MacBook-Pro.local
5The key's randomart image is:
6+---[RSA 3072]----+
7| =+++o . . |
8| o------------. |
9| . .. . + . |
10| .... oo= |
11| .+S...*+o.. |
12| .=*.o.+... |
13| o..o o + . |
14| o . = +o |
15| ..o .=.+ |
16+----[SHA256]-----+
Open the .ssh
directory, and you should see the generated key pair.
Next, you need to send the public key (id_rsa.pub
) to your server. On your own computer, run the following command:
1ssh-copy-id jack@<ip_address>
You should see the following output:
1/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/Users/erichu/.ssh/id_rsa.pub"
2/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
3/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
After you've typed in jack
's password:
1Number of key(s) added: 1
2
3Now try logging into the machine, with: "ssh 'jack@45.63.0.91'"
4and check to make sure that only the key(s) you wanted were added.
Unfortunately, this command utility is not available on Windows systems, so you can either set up WSL, or you can follow this tutorial from Digital Ocean, which offers an all-in-one command that copies the public key to your server:
1cat ~/.ssh/id_rsa.pub | ssh username@remote_host "mkdir -p ~/.ssh && touch ~/.ssh/authorized_keys && chmod -R go=$$ ~/.ssh && cat >~/.ssh/authorized_keys"
But as you can see, this command requires you to have a decent understanding of Linux systems.
Next, you can open up another terminal and try to sign in as jack
. This time you will be prompted to type in the passphrase for your private key instead of jack's password. If you didn't set up a passphrase, you would be signed in directly.
Lastly, you need to disable the password sign-in so that every user must use an SSH key. Go to the same sshd_config
file we discussed before:
1sudo nano /etc/ssh/sshd_config
Locate PasswordAuthentication yes
, and change it to no
:
1# Example of overriding settings on a per-user basis
2#Match User anoncvs
3# X11Forwarding no
4# AllowTcpForwarding no
5# PermitTTY no
6# ForceCommand cvs server
7PasswordAuthentication no
8PermitRootLogin no
Remember to restart the sshd
daemon:
1sudo systemctl restart sshd
And now, the only way to log into your server is through the SSH keys.
Deploy your project
Next, it is time to transfer your web app to the server. Of course, it is possible for you to upload the entire project manually, but it is difficult to keep track of things when you make changes in the future. Instead, it is better to use a version control tool such as Git, paired with a cloud code storage platform such as GitHub.
Your operating system should come with Git preinstalled, if not, following the instruction from the linked website to install Git.
To begin with, you need to create a new local Git repository. Go to your own machine, change into your project directory and run the following command:
1git init
Create a .gitignore
file under the project root directory. This file tells Git what files should be ignored. When deploy an application, you should always leave out the installed third-party packages, the database, uploaded media files and other sensitive data that should not be put to production. Here is a .gitignore
file for Node.js applications:
1# Node modules
2node_modules/
3
4# Databases
5*.sqlite
6
7# Logs
8logs
9*.log
10npm-debug.log*
11yarn-debug.log*
12yarn-error.log*
13pnpm-debug.log*
14
15# Dependency directories
16jspm_packages/
17
18# dotenv environment variables file
19.env
20
21# Build and compiled files
22dist/
23build/
24.out/
25.next/
26coverage/
27.vscode/
28.DS_Store
29
30# Optional npm cache directory
31.npm/
32
33# TypeScript cache
34*.tsbuildinfo
35
36# MacOS files
37*.DS_Store
And then, run the following commands to commit all the other files to the local repository.
1git add .
1git commit -m "Initial commit"
Next, we'll need to keep a copy of this repository on the cloud. Create a new GitHub account if you don't have one already, and then create a new remote repository.
We need to connect the local repository to the remote repository.
1git remote add origin https://github.com/username/repo-name.git
And then push the local changes to the remote. Set the current branch to main
first, if not already set.
1git branch -M main
1git push -u origin main
And then go back to the server we set up earlier. Change into the web app directory, and clone the repo from GitHub.
1git clone https://github.com/username/repo-name.git
Change into the repo and install necessary packages:
1npm install
And finally, start the server with the following command:
1node index.js
Go to your browser and type in the IP address of your server, and you should be able to access your web app.
It is recommended to set up reverse proxy for better performance and traffic handling.
Choose a domain
Now let's talk about what happens after you've deployed your project. Right now, your project should be accessible by visiting the server's IP address directly, but this is not ideal. For the website to be accessible to the public, you need to give it a domain.
There are many domain registers for you to choose from, and in this lesson, let's use GoDaddy as an example. Register an account on their website and search for a domain name:
After you've purchased a domain, you should see it under My Products.
Scroll down to the All Products and Services section, find your domain name and click the DNS button:
A DNS server is like a phone book of the internet, it maps domain names to IP addresses. When you visit a domain in your browser, you are actually visiting a DNS server first, that DNS server will find the corresponding IP address and route you there.
So what you need to do here is to register your domain with a DNS server by creating DNS records. There are many different types of DNS records, but for now, we only care about A
record and CNAME
records. The A
record is the primary record, and it should point to your server's IP address. The CNAME
records, on the other hand, are alias records. They create aliases (www.example.com
, me.example.com
, blog.example.com
...) that could point to an existing A
record, or a different server. For example:
Type | Host | Points to | TTL |
A | @ | <server_ip_address> | 1 hour |
CNAME | www | @ | 1 hour |
CNAME | gallery | <different_ip_address> | 1 hour |
For your first A
record, its host should be @
, which refers to your first-level domain (example.com
), and it should point to your server. TTL determines how long the DNS server would cache this record. The record will be refreshed automatically after it expires.
The first CNAME
creates an alias (www.example.com
), which points to the A
record we just defined. The second CNAME
creates another alias (gallery.example.com
), which points to a different server where you can host your gallery app.
Save the changes and wait for the DNS server to update. This process could take up to 48 hours to complete, so please be patient. After that, you should be able to access your app by visiting your domain.