Deploy Frontend & Backend using S3, EC2, CloudFront and add domain from Spaceship.com

Hello readers, Deployment is a process which isn’t straight forward thing for many of us, and it wasn’t for me either. But that doesn’t mean that it’s impossible to do. With basic understanding of different steps, one can not only deploy their entire application but also become proficient in doing so. There are many ways to deploy your application, and in this article, we shall see one of the ways.

In this article we would be discussing how to deploy our React Application on S3 and our Backend Nodejs + JS on an ec2 instance and connect them with each other and also link our frontend to a domain from any domain provider (Spaceship.com) in our case). We would also be setting up redirects for our websites URL. Let’s break down the entire process in small steps.

Basic Requirements

To follow the steps below, you need to have the below things checked out:

  1. AWS account

  2. Domain

  3. Frontend

  4. Backend Code on GitHub

Frontend Setup

Let us start with setting up our frontend on s3, follow the steps below

  1. Login to your AWS account and search for S3

  2. From the left tab select General Purpose Buckets

  3. In the main section click on Create Bucket

  4. select General Purpose as bucket type

  5. Give some name to the bucket (exampledeploy.com)

  6. Select ACL’s enabled and Bucket Owner preferred under Object Ownership

  7. Uncheck Bock all public access and check the warning that appears below

  8. Disable Bucket versioning and ignore the tags section

  9. SSE S3 for encryption type and you can disable or leave enabled Bucket Key

  10. Click create bucket

  11. click the bucket name (exampledeploy.com) →Properties tab → scroll to Static website hosting and click edit

  12. Select all the options as stated in the image below, you can have separate error document, but in this case we shall go with index.html only:

  13. Click Save Changes

  14. Now go to the Permissions tab and click edit Bucket Polic

    y

  15. In policy enter:

  16. {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Sid": "PublicReadForWebsiteContent",
          "Effect": "Allow",
          "Principal": "*",
          "Action": "s3:GetObject",
          "Resource": "arn:aws:s3:::your-unique-bucket-name/*"
        }
      ]
    }
    

    Replace your-unique-bucket-name with your bucket name

  17. save changes

  18. Now in your React+Vite application, run npm run build this will create a dist folder in your app root level

  19. Go back inside your bucket and click on Upload button

  20. Click on add files and add folder and upload the contents of the dist folder that was generated ( do not upload the dist folder itself) and click upload in right corner end of screen.

  21. Goto Properties bucket and scroll to the very end, there you shall find a link where the frontend is now present.

  22. Your frontend deployment is complete.

Request for ACM certificates on AWS

The ACM certificates acts as proof that you actually own the domain that you claim to own, we have our domain from spaceship.com, follow the below steps:

  1. Goto AWS Certificate Manager and click on Request

  2. Remember your region now should be US East - N. Virginia in top right corner before going to the next step

  3. Select request a public certificate and click next

  4. Add www.<yourdomain> in the fully qualified domain textfield and add another textfield name <yourdomain>

  5. Select DNS validation in Validation method and click request button on bottom right corner.

  6. You shall be on domain page now, where you would see 2 domains and the corresponding CNAMES and CVALUES similar to the image below, you see the status is in pending validation step

  7. Now go to spaceship.com or the domain provider of your domain, here I shall discuss for spaceship.com but the flow would be the same for other domain providers as well.

  8. Login to your spaceship acc and click on library and select advance DNS in spaceship.com, you would see your domain there

  9. Click your domain and now select on Add records, choose the type as CNAME.

  10. On the left hand side you would see a text field and .<yourdomain> attached, in that text field copy the CNAME name from the 5th step, (NOTE: trim the .<yourdomain> from the CNAME before copy pasting because spaceship and other domain providers, attach it by default) and in the right hand side copy paste the CNAME value and leave the TTL as unchanged and click Add. Repeat the same for the second CNAME value as well.

  11. Once verified, it shall take some 5-10 min and you shall see the same image on point 5 in your certificate page but this time with status as Succes

Setting Up Cloudfront

Cloud Front is responsible for serving your website with HTTPS, follow the steps to set it up:

  1. Open AWS Cloudfront and click on Create Distribution

  2. Under Origin settings:

  3. Viewer protocol policy: Redirect HTTP to HTTPS

  4. Allowed HTTP method: GET, HEAD

  5. Leave other options as it is for now and find the section “Alternate domain name”, there you need to add one of domain name you had earlier created (e.g. www.exampledeploy.com), if you are wondering what about exampledeploy.com, then we shall use this domain to redirect to www.exampledeploy in future steps, so skip adding exampledeploy.com in this step but if you don’t want redirection then you can add this domain as well but for the sake of this blog, we won’t be and would suggest you don’t as well.

  6. The next section would be custom SSL certificate, add the ACM certificate that you had earlier created in US- east region, (it shall show you in a dropdown)

  7. Now simply click on create Distributions and wait for 10 mins while it is created

  8. You shall get a custom domain from cloudfront now, copy the value and go back to spaceship .com or your domain provider, and select advance domain and click create CNAME record

  9. Now for the CNAME record name, left hand add @ and then on the right hand side in value section paste the cloudfront domain that you received and click add, (i.e. now exampledeploy.com has started pointing to the s3 bucket you have) NOTE : This step needs to be done only if you have added your root domain (e.g.: exampledeploy.com) as alternate domain on step 5, if you are following this blog strictly, you should skip this step as of now.

  10. Now for www create a CNAME record and in the value paste the cloudfront domain that was generated. (i.e. www.exampledeploy.com starts pointing to the s3 bucket of your frontend as well)

Redirecting Websites

This step is optional at beginners’ stage, but it’s highly suggested to escape SEO penalties and getting correct details for analytics. This step also helps in bringing consistency to how your website is accessed. So basically, why we are doing this step is that when someone tries to visit exampledeploy.com they are redirected to www.exampledeploy.com and if someone visits www.exampledeploy.com then they don’t need any redirection and are served the content.

(NOTE: This step could be performed only if you skipped add your root domain in point 5 of “Setting Up CloudFront”. In case you have added your root domain as well and also performed step 9, you should not follow this section entirely and jump to setting up your backend.

So, if this section interests you, follow along:

  1. The first step is to create a new general purpose bucket (e.g. redirectexample.com).

  2. Disable ACL and untick Block public access

  3. Click on Create Bucket at the end of screen

  4. now open your bucket, go to properties and scroll to the very end and then clicl on edit Static Website Hosting

  5. Click Enable for Static website hosting

  6. Click Redirect requests for an object

  7. In the host name give your domain name starting with www (e.g. www.exampledeploy.com)

  8. choose https for Protocol

  9. Click Save Changes

  10. Now go back to your bucket you created now and go to properties and scroll to the end

  11. You shall see a Bucket website endpoint, clicking it would open your www domain, (e.g. www.exampledeploy.com)

  12. Now open your CloudFront in AWS again and click Create Distributions

  13. Under Origin settings:

    • Origin domain: select your redirect S3 bucket’s static website endpoint ( bucket name : redirectexample.com, you need to add the endpoint of this bucket now)

    • Origin protocol policy: HTTP only

  14. Viewer protocol policy: Redirect HTTP to HTTPS

  15. Allowed HTTP method: GET, HEAD

  16. In the alternate domain you now need to add your root domain (e.g. exampledeploy.com , in earlier cloudfront setup, you had added www.exampledeploy.com .

  17. The next section would be custom SSL certificate, add the ACM certificate that you had earlier created in US- east region, (it shall show you in a dropdown)

  18. Now simply click on create Distributions and wait for 10 mins while it is created

  19. You shall get a custom domain from cloudfront now, copy the value and go back to spaceship .com or your domain provider, and select advance domain and click create CNAME record

  20. This time for the root domain, just type @ and then in values add the cloudfront link that you received.

  21. You are done; you have successfully completed setting up your frontend linked with your domain, now typing www.exampledeploy.com or simply typing exampledeploy.com will open www.exampledeploy.com.

If you don’t have a backend for your application, then the below steps are not for your use case, see you in the Conclusion part of this blog, and if you have a backend, bear a little more with me.

Spinning Up your EC2 Instance

Now that your frontend part is complete, the next step is to spin an ec2 server for your backend and connect it with your frontend as well. Before continuing further, remember you need to whitelist your domain in backend so that we don’t face any CORS error. And after the backend is set up, you would be required to save the backend URL point in your frontend, create a build for it and push it into the s3 folder which was responsible for displaying your content.

Let’s get started, this is actually the last stage of setting up your backend so gear up:

  1. Open EC2 in AWS and click on Launch Instance

  2. Give a name to your server

  3. For machines select Ubuntu

  4. You can select any instance type, we will be selecting t2.micro in this blog

  5. click on create new key pair if you don’t have already and a popup shall appear, click on RSA and then select .pem and click Create key pair

  6. Security Group:

    • Allow ports 22, 80, 443 from anywhere (0.0.0.0/0)
  7. Now log in to your server, this isn’t a difficult step, and you can refer to any online video to complete this exact step. It would take around 5-10 mins to understand

  8. Now that you have logged into your server run the below commands to update the server and download nodejs and git and pm2. Pm2 is a software for production apps that would help run our apps even when the terminal is closed.

  9.  sudo apt update
     sudo apt install nodejs npm git -y
     sudo npm install -g pm2
    
  10. Don’t be surprised or overwhelmed when you see a lot of files getting downloaded, you are in the right path.

  11. Now it’s time to clone your backend gilt repo here, I assume it’s a public repo as for now. Run the below commands:

  12. git clone https://github.com/your-username/your-backend-repo.git
    cd your-backend-repo
    npm install
    

    replace the link after clone with your repo URL and backend-repo with your repo name.

  13. Now I am assuming index.js is responsible for running your backend app, and it is present in src directory, you can replace your file responsible for running your app and your path as well.

  14. #assuming that you are not into your project directory yet
    cd <yourDirectoryName>
    
    #my index.js is inside the src
    pm2 start src/index.js
    
    pm2 save
    pm2 startup
    
    #if you want to see real time logs follow the below command and press C to exit it
    pm2 logs
    

    Make sure your backend is bug free and listens to a port

  15. set up your env files if you have any by following this command

  16. #suppose you want your env in root directory
    #you are in the root directory as of now
    
    nano .env
    
    #This shall open an editor, now type of paste your env variables
    #After you are done press cntrl+ o then enter button and then cntrl+ x
    
    #you shall be moved out of the editor now
    
  17. Now we shall be setting up Nginx which is an open-source web server which we shall be using as reverse proxy server between our frontend and backend. But even before that we need to make sure our backend server requests on particular route starting with api (you can make your own choice as well), so when you make a request to an endpoint in the blog application it is.https://api.exampledeploy.com/yor_route/

  18. For the next steps, please READ THE COMMENTS that I provide and don’t copy paste blindly

  19. sudo apt install nginx -y
    
    #instead of api.exampledeploy you could have anything (eg. backend.exampledeploy)
    sudo nano /etc/nginx/sites-available/api.exampledeploy.com
    
    #remember to replace api with whatever you choose
    server {
        listen 80;
        server_name api.exampledeploy.com;
    #you can change your server name to anything but remember it should have your root domain in end e.g. exampledeploy.com
    #your server name is api.exampledeploy.com now, remember it as it will be used
    #NOTE: In the next lines you see <PORT>, you should replace it with your application port no.
    #e.g. my app runs on port 3000, so i say http://localhost:3000/
        location / {
            proxy_pass http://localhost:<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;
        }
    }
    
    #This is it, now Save and exit: Ctrl+O, Enter, then Ctrl+X
    
  20. Now lets enable our backend site, READ THE COMMENTS carefully

  21. #in the previous step you had decided your server name replace <your_server_name> with it
    
    sudo ln -s /etc/nginx/sites-available/<your_server_name> /etc/nginx/sites-enabled/
    sudo nginx -t
    sudo systemctl restart nginx
    

Point Domain to Server (DNS Setup)

Now it is time to create a A record in your dns provider (spaceship.com in my case), what this step does is that it tells the internet that if anyone on internet is visiting api.exampledeploy.com then send them to my EC2 server. Follow the below steps now:

  1. Go to your domain provider and create a DNS record ( for spaceship users, you need to look into advance dns section and click add record)

  2. select record type to be A

  3. In the name section fill it as the subdomain you decided in step 19 (e.g. api)

  4. Click Add and its done

Secure HTTPS using Certbot & Let’s Encrypt

Now to server HTTPS requests securely on the server we need to have a valid certificate, this certificate is provided by Let’s Encryptfor free and certbot is a Lets’ Encrypt took which works great with Nginx, If you skip this section, browsers will refuse to connect over HTTPS. Before running the below commands make sure your pm2 is up by checking pm2 status

  1. Install Certbot

     sudo apt install certbot python3-certbot-nginx -y
    
  2. Secure your domain with HTTPS, replace the A record domain name that you had set (e.g. api.exampledeploy.com)

     sudo certbot --nginx -d api.exampledeploy.com
    
  3. The above step shall prompt you for your email and agreement

    Choose redirect HTTP to HTTPS.

    Your output should look like

     Congratulations! Your certificate and chain have been saved...
    
  4. Test your API endpoint (e.g.: api.exampledeploy.com) with curl or browser:

     curl https://api.exampledeploy.com/api/v1/auth/get
    

    You should get a proper API response (or 401 if unauthorized, but no network errors).

  5. Let’s Encrypt certificates expire after 90 days so to automatically renew them:

     sudo certbot renew --dry-run
    
  6. Now to check your certificate you can:

     sudo certbot certificates
    

Frontend Environment Setup

In your .env file make sure that for prod, you use the endpoint that you set in the backend (e.g.: api.exampledeploy.com). Once done

  1. Run npm run build

  2. Upload the contents of the /dist folder in the s3 bucket you created to serve content (NOTE: not the bucket you created for redirect)

Final Sanity Checks:

You have come a long way make sure you check all the box:

TaskStatus
Set up S3 bucket to serve content
Create a S3 bucket to redirect request (optional)
Create certificates for your domain in AWS certificate manager
Set up the records for your domain
Create CloudFront Distribution
EC2 created + Elastic IP
SSH working
Backend + PM2 running
Nginx reverse proxy configured
Domain DNS pointing to EC2
HTTPS via Certbot
Frontend updated to hit correct API

Conclusion

There are many more ways to deploy your application, there could be easier ways like using services of render or Netlify. But this is one of the ways where you can customize a lot of things, learn a lot more about your domain, the different records. Once your application is set up it’s suggested that you search for different topics that were mentioned in the blog, I would be writing about them as well. But that’s it for today. It would be great if your leave your websites URL in the comments that you deployed following the above steps.

2
Subscribe to my newsletter

Read articles from Saurav Pratap Singh directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Saurav Pratap Singh
Saurav Pratap Singh