AWS
intermediate
45-60 minutes

Lightsail: Traditional Deployment

Deploy your application to AWS Lightsail without Docker. Use rsync, PM2, and Nginx for a classic VPS deployment.

What you'll accomplish

Your application running on a Lightsail VPS with Nginx, SSL, and process management

Prerequisites

  • AWS account with CLI configured
  • SSH keys set up (previous lesson)
  • A Node.js/Python/etc. application ready to deploy

What is Lightsail?

AWS Lightsail is a simplified VPS (Virtual Private Server) service. Think of it as "EC2 made easy" - you get a full Linux server with:

  • Predictable pricing - Fixed monthly cost ($3.50-$160/month)
  • Included bandwidth - No surprise data transfer bills
  • Simple management - Less overwhelming than full EC2
  • Static IP - Free static IP address included
Note

Lightsail is perfect for small to medium applications, blogs, and learning. For high-traffic or complex architectures, consider EC2 or containerized solutions.

Step 1: Create a Lightsail Instance

1.1 Open Lightsail Console

Go to lightsail.aws.amazon.com and click Create instance.

1.2 Choose Location

Select a region close to your users:

  • Virginia (us-east-1) - US East Coast, cheapest
  • Oregon (us-west-2) - US West Coast
  • Frankfurt (eu-central-1) - Europe
  • Tokyo (ap-northeast-1) - Asia Pacific

1.3 Choose Platform and Blueprint

  1. Select Linux/Unix
  2. Under Select a blueprint, choose OS Only
  3. Select Ubuntu 22.04 LTS
Note

Ubuntu is the most common choice - documentation and community support are excellent.

1.4 Choose Your SSH Key

  1. Click Change SSH key pair
  2. Select the key you uploaded in the previous lesson
  3. Or upload a new one now

1.5 Choose Instance Plan

For a typical web application:

PlanRAMCPUStorageTransferPrice
$3.50/mo512 MB1 vCPU20 GB1 TBTesting only
$5/mo1 GB1 vCPU40 GB2 TBSmall apps
$10/mo2 GB1 vCPU60 GB3 TBMedium apps
$20/mo4 GB2 vCPUs80 GB4 TBLarger apps

Start with $5/month - you can upgrade later.

1.6 Name Your Instance

Enter a descriptive name like myapp-production and click Create instance.

1.7 Wait for Instance

The instance takes 1-2 minutes to start. Wait until the status shows Running.

Step 2: Configure Networking

2.1 Create a Static IP

Without a static IP, your server's IP address can change when rebooted.

  1. Go to Networking tab
  2. Click Create static IP
  3. Attach it to your instance
  4. Name it (e.g., myapp-ip)

Save this IP address - you'll use it to connect and configure DNS.

2.2 Open Firewall Ports

By default, Lightsail allows SSH (22) and HTTP (80). Add HTTPS:

  1. Click on your instance
  2. Go to Networking tab
  3. Under IPv4 Firewall, click Add rule
  4. Add: HTTPS (443)

Step 3: Connect and Set Up the Server

3.1 Connect via SSH

3.2 Update the System

bash
# Update package lists
sudo apt update

# Upgrade installed packages
sudo apt upgrade -y

# Install essential tools
sudo apt install -y curl wget git build-essential

3.3 Install Node.js (for Node/JavaScript apps)

bash
# Install Node.js 20 LTS via NodeSource
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt install -y nodejs

# Verify installation
node --version  # Should show v20.x.x
npm --version

3.4 Install PM2 (Process Manager)

PM2 keeps your app running and restarts it if it crashes:

bash
# Install PM2 globally
sudo npm install -g pm2

# Verify
pm2 --version

3.5 Install Nginx (Web Server/Reverse Proxy)

bash
# Install Nginx
sudo apt install -y nginx

# Start and enable on boot
sudo systemctl start nginx
sudo systemctl enable nginx

# Verify - visit http://YOUR_STATIC_IP in browser
# You should see "Welcome to nginx!"

Step 4: Deploy Your Application

4.1 Create Application Directory

bash
# Create directory for your app
sudo mkdir -p /var/www/myapp
sudo chown ubuntu:ubuntu /var/www/myapp

4.2 Deploy Using rsync (Recommended)

From your local machine (not the server):

4.3 Install Dependencies (on server)

SSH back into your server and install dependencies:

bash
# Connect to server
ssh ubuntu@YOUR_STATIC_IP

# Go to app directory
cd /var/www/myapp

# Install production dependencies
npm ci --production

# If you need to build on server
npm run build

4.4 Create Environment File

bash
# Create .env file on server
nano /var/www/myapp/.env

Add your environment variables:

env
NODE_ENV=production
PORT=3000
DATABASE_URL=postgresql://user:pass@localhost:5432/mydb
API_KEY=your-secret-key

Save with Ctrl+O, Enter, Ctrl+X.

Note

Never commit .env files to git! Create them manually on the server or use a secrets manager.

Step 5: Start Your Application with PM2

5.1 Start the App

bash
cd /var/www/myapp

# Start with PM2
pm2 start npm --name "myapp" -- start

# Or if you have a specific entry point
pm2 start dist/index.js --name "myapp"

# Check it's running
pm2 status

5.2 Configure PM2 to Restart on Reboot

bash
# Generate startup script
pm2 startup systemd

# This outputs a command - copy and run it!
# Something like:
# sudo env PATH=$PATH:/usr/bin pm2 startup systemd -u ubuntu --hp /home/ubuntu

# Save current process list
pm2 save

5.3 Useful PM2 Commands

bash
pm2 status              # Show all processes
pm2 logs myapp          # View logs
pm2 logs myapp --lines 100  # Last 100 log lines
pm2 restart myapp       # Restart the app
pm2 stop myapp          # Stop the app
pm2 delete myapp        # Remove from PM2
pm2 monit               # Real-time monitoring dashboard

Step 6: Configure Nginx as Reverse Proxy

Nginx will handle incoming web traffic and forward it to your Node.js app.

6.1 Create Nginx Configuration

bash
# Create site configuration
sudo nano /etc/nginx/sites-available/myapp

Add this configuration:

nginx
server {
    listen 80;
    server_name YOUR_DOMAIN_OR_IP;

    location / {
        proxy_pass http://localhost:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_cache_bypass $http_upgrade;
    }
}

Replace YOUR_DOMAIN_OR_IP with your domain or static IP.

6.2 Enable the Site

bash
# Create symbolic link
sudo ln -s /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled/

# Remove default site (optional)
sudo rm /etc/nginx/sites-enabled/default

# Test configuration
sudo nginx -t

# If test passes, reload Nginx
sudo systemctl reload nginx

6.3 Test Your Site

Visit http://YOUR_STATIC_IP in your browser - you should see your application!

Step 7: Add SSL with Let's Encrypt (Free HTTPS)

Note

SSL requires a domain name pointing to your server. If you're using just an IP address, skip this step for now.

7.1 Install Certbot

bash
# Install Certbot and Nginx plugin
sudo apt install -y certbot python3-certbot-nginx

7.2 Obtain SSL Certificate

bash
# Get certificate (replace with your domain)
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com

# Follow the prompts:
# - Enter your email
# - Agree to terms
# - Choose whether to redirect HTTP to HTTPS (recommended: yes)

7.3 Verify Auto-Renewal

bash
# Test renewal process
sudo certbot renew --dry-run

Certbot automatically renews certificates before they expire.

Step 8: Create a Deployment Script

Automate future deployments with a script.

Local Deployment Script

Create deploy.sh in your project:

bash
#!/bin/bash
set -e

SERVER="ubuntu@YOUR_STATIC_IP"
APP_PATH="/var/www/myapp"

echo "🔨 Building application..."
npm run build

echo "📤 Uploading files..."
rsync -avz --progress \
  --exclude 'node_modules' \
  --exclude '.git' \
  --exclude '.env*' \
  ./ $SERVER:$APP_PATH/

echo "📦 Installing dependencies on server..."
ssh $SERVER "cd $APP_PATH && npm ci --production"

echo "🔄 Restarting application..."
ssh $SERVER "pm2 restart myapp"

echo "✅ Deployment complete!"

Make it executable and run:

bash
chmod +x deploy.sh
./deploy.sh

Monitoring and Maintenance

View Logs

bash
# Application logs (via PM2)
pm2 logs myapp

# Nginx access logs
sudo tail -f /var/log/nginx/access.log

# Nginx error logs
sudo tail -f /var/log/nginx/error.log

Monitor Resources

bash
# System resources
htop

# Disk usage
df -h

# Memory usage
free -m

Automatic Updates (Security)

bash
# Enable automatic security updates
sudo apt install -y unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades

Troubleshooting

App Not Accessible

  1. Check PM2: pm2 status - is the app running?
  2. Check Nginx: sudo systemctl status nginx
  3. Check firewall: Lightsail console → Networking → Firewall rules
  4. Check logs: pm2 logs myapp

502 Bad Gateway

Nginx can't reach your app:

  • Verify app is running: pm2 status
  • Check the port matches: proxy_pass http://localhost:3000
  • Check app logs: pm2 logs myapp

Permission Denied

bash
# Fix ownership
sudo chown -R ubuntu:ubuntu /var/www/myapp

Out of Memory

Upgrade your Lightsail instance or add swap:

bash
# Add 2GB swap file
sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab

Cost Summary

ComponentCost
Lightsail Instance ($5 plan)$5/month
Static IPFree (with instance)
SSL CertificateFree (Let's Encrypt)
Bandwidth (2TB included)Free
Total$5/month

What's Next?

You've deployed a traditional application to AWS! For containerized deployments with more flexibility, check out the next lesson on Lightsail with Docker.

Note

Checkpoint: Your site should be accessible at http://YOUR_STATIC_IP or https://yourdomain.com if you configured SSL.