In this tutorial, I will walk you through a fairly complex AWS deployment setup from scratch. I will assume you could already run your React app on your localhost. Also, I will assume your backend part is implemented based on Express and you can access your database from the EC2 instance.
Prerequisites
AWS EC2
The very first step is to have an EC2 instance in your AWS account. When the instance is successfully set up, the next step is to edit the inbound rules so that you can access your website once it is eventually deployed. For example, if your final web app could be accessed by HTTPS, then you need to open port 443 of TCP protocol. The corresponding source should be set to Anywhere so that anyone can visit your website.
The following steps include modifying the code. You could do it on your PC then upload to the EC2 instance or do it directly on the instance. It’s totally up to you.
CORS
When the whole application runs successfully on the localhost, three parts — the frontend, the backend, and the browser all run on the localhost. Now if the application is deployed on an EC2 instance, at least the browser will not be running on the localhost anymore, supposing both frontend and backend are deployed on the same instance and you are not opening a browser on the EC2 instance. One important thing you should know is that the frontend code is running on the browser. Therefore, you now need to replace all the fetch requests to localhost
with something else. The replacement would be the IP Address or the Domain Name that your backend runs on. For instance, if your backend runs on the same EC2 instance with the IP 111.111.111.111
. Now all fetch requests in your frontend code should look like
fetch("http:111.111.111.111:{port}/***/***")
Now we encounter the first big issue. We send requests from the domain where the browser runs on to the domain where the backend code runs on, which is restricted by default in Express. Fortunately, we have a package named cors
(Cross-Origin Resource Sharing), which aims to solve this tricky problem. Now we should modify the backend code like this
HTTPS (optional)
Why HTTPS
HTTPS has numerous advantages over HTTP. However, if it’s not so crucial for your web application to have a high-security level for any reason, you can skip this section. The main reason why our app needs HTTPS is that we incorporate Auth0. Auth0 must run a secure origin. In most browsers, secure origins are origins that match at least one of the following (scheme, host, port) patterns:
(https, *, *)
(wss, *, *)
(*, localhost, *)
(*, 127/8, *)
(*, ::1/128, *)
(file, *, —)
Configure SSL/TLS on EC2
AWS docs have a detailed tutorial about how to configure SSL/TLS on EC2 so I won’t talk too much here. The tutorial can be found here.
Certificate
There are multiple ways to get a Domain Name and a CA-signed Certificate. If you are a student, Github Student Developer Pack partners with several domain-name vendors that provide these services free for one year.
Normally, we put the certificate files in the folder /etc/pki/tls/certs/
and put the key files in the folder /etc/pki/tls/private/
. Afterward, we need to edit /etc/httpd/conf.d/ssl.conf
to reflect your new certificate and key files, as the AWS tutorial suggests:
Provide the path and file name of the CA-signed host certificate in Apache’s SSLCertificateFile directive:
SSLCertificateFile /etc/pki/tls/certs/custom.crt
If you received an intermediate certificate file (intermediate.crt in this example), provide its path and file name using Apache’s SSLCACertificateFile directive:
SSLCACertificateFile /etc/pki/tls/certs/intermediate.crt
Provide the path and file name of the private key (custom.key in this example) in Apache’s SSLCertificateKeyFile directive:
SSLCertificateKeyFile /etc/pki/tls/private/custom.key
Config in Development Environment
Now we are going to test if the certificate works. We could create a file named .env
in the client folder. In that file, we add these lines:
SSL_CRT_FILE=path/to/certificate/custom.crt
SSL_KEY_FILE=path/to/key/custom.key
Besides, we need to modify the scripts.start
code inpackage.json
like this to enable HTTPS.
"start": "HTTPS=true react-scripts start"
Mix Contents
As you start your application, you might notice something like this in the browser console.
That’s because the frontend now runs through HTTPS. But there are some other contents, maybe the backend runs through HTTP. Therefore, we need to modify our server code again so that it could accept HTTPS requests.
Also, we need to replace all the HTTP requests in the frontend code with HTTPS requests.
Production
The next step we need to do is create a production build. It has a minified(compressed) version of our javascript code, which makes the rendering of files on end-users’ browsers very quick and performance-enhancing.
In your client folder, simply run npm run build
. This creates a build
the folder that contains all the files we need. There are multiple ways to run the production build. The simplest way might be using the serve
package. You could install the package by running npm install -g serve
. In the client folder, we then run the serve -s build -l 4000
. -s
option indicates our application is a single-page application. build
is the folder contains all the static files. -l
specifies the port our application listens on.
However, we could not provide our certificate and key files using the serve
package. Therefore, we need to use a more advanced Web Server. The most widely used ones are Nginx and Apache. Here we use the Apache Web Server.
Apache Web Server
By default, the root folder of the webserver is /var/www/html
. We need to copy our production build files to this folder by running
sudo cp -r path/to/client/build/* /var/www/html/
Then we start the Apache server:
sudo systemctl start httpd
If your react app is not a single-page application, we are done here. But if it is, you may find that the page would become the 404 pages if you refresh your browser. The answer can be found here. We need to add these lines in the <Directory /var/www/html>
directive of the httpd.conf
file:
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]
# Rewrite everything else to index.html to allow html5 state links
RewriteRule ^ index.html [L]
The position of the httpd.conf
file might be different in different systems. In Amazon Linux 2, the file lies in /etc/httpd/conf
.
PM2
The last step is to set up the backend server, if applicable. We could use the pm2
package. Install the package and enter the server folder. Then run the following scripts:
pm2 start npm --name "app name" -- start
Now the backend should be running. We could check it by running:
pm2 list
That’s all. Hope this helps!