Background Overlay
AWS Lightsail Deployment

How to Deploy a Frontend Application on AWS Lightsail (Step-by-Step Guide)

AWS Lightsail Deployment

Deploying a frontend application (such as a Next.js or React app) on AWS Lightsail can feel challenging if you are doing it for the first time. In this guide, I’ll walk you through the complete deployment process — from preparing your local build to configuring Lightsail with Nginx, PM2, SSL, and swap memory. By the end, you’ll have a production-ready frontend running on Lightsail.

Why AWS Lightsail?

AWS Lightsail is an affordable and beginner-friendly cloud service from Amazon Web Services. It provides preconfigured instances with predictable pricing. If you want to host small to medium-scale frontend or backend apps, Lightsail is a perfect choice compared to EC2. To get started, you'll need an AWS account. You can create a Lightsail instance directly from the AWS Console

Step 1: Prepare Your Local Build

Before you can deploy any application to a server, you must first prepare its production build on your local machine. This typically involves running a build command that optimizes your application and gathers all the necessary files into a deployable format. Next, you will bundle all of these files—including the optimized build, static assets, and any configuration files—into a single compressed archive using a command like zip or tar. Finally, you will securely transfer this archive to your server using a secure file transfer protocol like scp (Secure Copy Protocol) or sftp (SSH File Transfer Protocol). This process requires you to have a private key and to set the correct permissions on that key to ensure a secure and authorized connection to the server.

zip -r nextjs-build.zip .next public package.json package-lock.json next.config.js .env
chmod 400 ~/lightsail-keys/LightsailDefaultKey.pem
scp -i ~/lightsail-keys/LightsailDefaultKey.pem nextjs-build.zip bitnami@<YOUR_LIGHTSAIL_IP>:/home/bitnami/your-app

Step 2: Prepare the Server Environment

After preparing your application build and transferring it to the server, the next step is to prepare the server environment itself. You'll first connect to your Lightsail instance using SSH, a secure way to access the server's command line. Once connected, you must update the server's package list and install the unzip utility, which is essential for extracting the files from the zipped archive you uploaded. After unzipping the build file, you will install all of your application's production dependencies, completing the server setup and making it ready to run your app.

ssh -i ~/lightsail-keys/LightsailDefaultKey.pem bitnami@<YOUR_LIGHTSAIL_IP>
sudo apt update
sudo apt install unzip -y
unzip nextjs-build.zip
npm install --omit=dev

Step 3: Run the Application with PM2

After preparing the server, the final step is to run your application using PM2, a production process manager for Node.js. You'll first install PM2 globally on your server, which allows it to be used as a command-line tool. You then use PM2 to start your application, giving it a descriptive name for easy management. By using PM2, your application will run in the background and automatically restart if it crashes, ensuring it remains online. You will then configure PM2 to automatically start your application whenever the server reboots and save the current list of running processes.

sudo npm install -g pm2
pm2 start npm --name "frontend-app" -- start
pm2 startup
pm2 save
pm2 list

Step 4: Configure Nginx as a Reverse Proxy

Nginx is a powerful web server that can be configured as a reverse proxy for your application. This is a crucial step because it directs incoming web traffic from port 80 (the standard HTTP port) to the internal port where your application is running (e.g., port 3000). This configuration allows users to access your application using your domain name or IP address without needing to specify a port number. It also provides a layer of security by hiding the application's internal port. The configuration involves installing Nginx, then creating a new configuration file for your application that listens on port 80 and forwards requests to your application's internal address.

sudo apt install nginx -y
sudo nano /etc/nginx/sites-available/frontend-app
server {
  listen 80;
  server_name yourdomain.com;

  location / {
    proxy_pass http://127.0.0.1:3000;
    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;
  }
}

Then disable Apache and enable your new Nginx config.

sudo /opt/bitnami/ctlscript.sh stop apach
sudo fuser -k 80/tcp

Step 5: Enable SSL with Certbot

Certbot is an open-source tool that automates the process of obtaining and renewing SSL/TLS certificates from Let's Encrypt. These certificates enable HTTPS for your website, ensuring all data transmitted between your server and a user's browser is encrypted and secure. Without it, your site would be vulnerable to security threats and would be flagged as "Not Secure" by web browsers. Before you can use Certbot, you must install it on your instance. The recommended way to install Certbot on most Linux instances is by using snapd. First, install snapd if it's not already on your system using sudo apt install snapd, then you can install Certbot itself with sudo snap install --classic certbot. Finally, create a symbolic link so the certbot command is easily accessible: sudo ln -s /snap/bin/certbot /usr/bin/certbot.

sudo certbot --nginx -d yourdomain.com
sudo certbot renew --dry-run

Step 6: Configure Swap Memory

This series of commands is used to configure and permanently activate a swap file on a Linux system, which is crucial for an AWS Lightsail Node.js instance with limited RAM. The process involves using fallocate to create a /swapfile (e.g., 2GB in size), securing it with chmod 600, preparing it for swap with mkswap, and then activating it using swapon. The final command appends a line to /etc/fstab, ensuring the swap space persists across reboots. This swap space acts as a vital virtual memory overflow, preventing the Node.js application from crashing due to out-of-memory errors when the physical RAM is fully consumed.

sudo fallocate -l 1G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
swapon --show
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab

Step 7: Updating Your Application

This manual process outlines how to deploy an update to a Node.js application (likely a Next.js project) hosted on an AWS Lightsail instance managed by PM2 and running under the Bitnami stack. It is essentially a stop-copy-rebuild-restart workflow. You first halt the running application process using PM2 to ensure a clean update. Next, you securely transfer the new build files (compressed as a zip) from your local machine to the server using SCP. Once the old application files, dependencies, and build artifacts are deleted from the server, you unzip the new code and run npm install --omit=dev to install the necessary production dependencies. Finally, you instruct PM2 to restart the application, which loads the new code and applies the updates. This ensures minimal downtime while deploying a fresh version of the app.

pm2 stop frontend-app
scp -i ~/lightsail-keys/LightsailDefaultKey.pem nextjs-build.zip bitnami@<YOUR_LIGHTSAIL_IP>:/home/bitnami/your-app
sudo rm package-lock.json package.json next.config.js
sudo rm -rf node_modules public .next
unzip nextjs-build.zip
npm install --omit=dev
pm2 restart frontend-app

Step 8: Create a New User (Optional)

This sequence of steps describes the optional but highly recommended security practice of creating a new, dedicated user on your instance instead of relying solely on the default bitnami user. The primary advantage is enhanced security and separation of privilege. By creating a user named myuser and adding them to the sudo group, you gain the ability to perform administrative tasks without being permanently logged in as a superuser. Crucially, the process copies the existing SSH key to the new user's profile, allowing you to log in securely directly as myuser using the same key pair. This practice adheres to the principle of least privilege: you only use the administrative powers (sudo) when explicitly needed, minimizing the security risk compared to continuously operating under a shared default account like bitnami for all deployments and general server maintenance.

sudo adduser myuser
sudo usermod -aG sudo myuser
sudo mkdir -p /home/myuser/.ssh
sudo cp /home/bitnami/.ssh/authorized_keys /home/myuser/.ssh/
sudo chown -R myuser:myuser /home/myuser/.ssh
sudo chmod 700 /home/myuser/.ssh
sudo chmod 600 /home/myuser/.ssh/authorized_keys
sudo su - myuser

Final Thoughts

You now have a production-ready frontend application running on AWS Lightsail with Nginx, PM2, and SSL. This setup is secure, scalable, and cost-effective. By following these steps, you can easily deploy any frontend framework like Next.js, React, or Vue.js.

Happy coding!


If you enjoyed this post, consider sharing it on social media. For more articles on JavaScript and modern web development, follow my Medium , StackoverFlow or check out my GitHub repositories.