Tutorials Search / Shipping & infrastructure / Run a Node API on AWS Lightsail
πŸ“ Written ● Intermediate Updated 2026-05-13

Run a Node API on AWS Lightsail

Lightsail is AWS's simple corner. A fixed monthly price, a single button to create a Linux box, ssh in, run your code. None of the EC2 add-on charges, none of the IAM ceremony. The honest case for being on AWS without paying the AWS-complexity tax.

Most people who want a small Linux server to run a Node API don't actually need AWS. DigitalOcean droplets, Hetzner Cloud, Fly machines β€” all simpler, all cheaper, all faster to set up. The reason to pick Lightsail anyway is one of two things: you already have AWS infrastructure (S3 buckets, RDS databases, SES email) that this server needs to talk to and you want the integration; or your company has an "AWS only" policy. Outside those, Lightsail is fine but not winning on merits.

The thing Lightsail gets right β€” the reason it exists β€” is that EC2 is genuinely too complicated for "I want a $5 Linux box." EC2's pricing has half a dozen line items per instance; Lightsail charges one. EC2 hides the public IP behind an Elastic IP that you can attach for free until you detach it, at which point you pay for it; Lightsail's static IP is included. EC2 has security groups, network ACLs, NACL associations, VPCs, subnets, and route tables; Lightsail has a firewall toggle. The trade-off is that Lightsail has fewer knobs β€” if your workload needs them, you grow out of Lightsail and move to EC2.

This tutorial walks creating a Lightsail instance with the Node.js blueprint, deploying your app, running it with a process manager, opening the firewall, attaching a domain, and getting a free TLS cert. End state: https://api.mybrand.com resolving to your Node API. We'll use the AWS console for the create-instance flow (the CLI works but the console is genuinely shorter here) and the shell for everything after.

What you'll learn

Prerequisites: An AWS account, your local SSH key (or willingness to use the browser-based ssh), a working Node API in a git repo, and a domain whose DNS you control (Route 53 or any other DNS provider). After Step 2 (first SSH), run through Prepare a fresh Linux server for production before deploying anything β€” the Bitnami blueprint hardens the Bitnami services but not the OS layer (system updates, ufw, fail2ban, swap, unattended-upgrades).

Step 1: Create the instance

1

Pick a blueprint, a size, a region

In the AWS console, open Lightsail (note: it has its own console at lightsail.aws.amazon.com, separate from the main AWS console β€” works the same, different URL). Click Create instance:

  • Instance location: pick the region closest to your users. us-east-1 is fine if you're unsure.
  • Platform: Linux/Unix.
  • Blueprint: two reasonable options. "Node.js" ships Node, npm, nginx, and PM2 pre-installed. "OS Only β†’ Ubuntu 22.04" is a plain box; you install Node yourself. Pick the Node.js blueprint for speed; pick Ubuntu if you want a known-clean starting point.
  • Instance plan: $5/mo (512 MB RAM, 1 vCPU, 20 GB SSD, 1 TB transfer) handles a small Node API comfortably. $10/mo doubles everything if you're nervous.
  • Name: something like mybrand-api-prod.

Click Create. The instance boots in 60–90 seconds. Lightsail assigns it a public IP and an internal name. The first month is free under the AWS Free Tier for new accounts.

Step 2: SSH in

2

Browser-based or your own key

Two ways:

  • Browser SSH: instance page β†’ Connect using SSH. A terminal opens in a new tab. Zero setup, works through corporate firewalls, but won't preserve scrollback and copy/paste is awkward.
  • Local SSH: download the default key (Account β†’ SSH keys β†’ Default β†’ Download). Save it to ~/.ssh/lightsail.pem, chmod 600 ~/.ssh/lightsail.pem, then:
    ssh -i ~/.ssh/lightsail.pem bitnami@<PUBLIC_IP>
    # Username is bitnami for the Node.js blueprint, ubuntu for the Ubuntu blueprint.

You're in. The Node.js blueprint puts you in a home directory with /opt/bitnami/ holding nginx and the pre-baked Node sample app.

Step 3: Deploy your code

3

Git clone or rsync; both fine

# Option A: git clone (public repo or deploy key)
cd ~
git clone https://github.com/you/your-api.git
cd your-api
npm ci --production
# Set env vars in /etc/environment or a .env file your app reads.

# Option B: rsync from your laptop (no git access on the server)
# From your laptop:
rsync -avz --exclude node_modules \
  -e "ssh -i ~/.ssh/lightsail.pem" \
  ./ bitnami@<PUBLIC_IP>:/home/bitnami/your-api/
# Then on the server:
cd ~/your-api
npm ci --production

Test it manually first: node server.js (or your entry). Make sure it boots and listens on a port β€” typically 3000 or 8080. Stop it (Ctrl+C); we'll run it persistently in the next step.

Step 4: Run it persistently with PM2

4

Restart on crash, restart on reboot

PM2 is pre-installed on the Node.js blueprint. On a plain Ubuntu blueprint: sudo npm i -g pm2.

cd ~/your-api
pm2 start server.js --name api
pm2 save
pm2 startup
# pm2 startup prints a command β€” run it as root to register PM2
# as a systemd service so it survives reboots.

Now your API is running on http://<PUBLIC_IP>:3000 (or whatever port your app listens on). Test:

curl http://<PUBLIC_IP>:3000/health
# Currently this will time out β€” the firewall blocks it. That's Step 5.

Useful PM2 commands: pm2 logs api (live logs), pm2 restart api, pm2 monit (interactive dashboard).

Step 5: Open the firewall

5

Two ports: 80 for HTTP, 443 for HTTPS

Lightsail's firewall blocks everything by default except SSH (22). Open the web ports:

  1. Lightsail console β†’ your instance β†’ Networking tab.
  2. Under IPv4 Firewall, click Add rule.
  3. Add: Application = HTTP, Port = 80. Add: Application = HTTPS, Port = 443.
  4. Save.

Don't open port 3000 directly to the public β€” nginx will sit in front of your Node app on 80/443 (the blueprint already has nginx running) and proxy requests internally to your Node process. Run curl http://<PUBLIC_IP> from your laptop; you should hit the default nginx page or the blueprint's sample app.

Step 6: Configure nginx to proxy your API

6

Edit one file; reload nginx

On the Node.js blueprint, nginx config lives at /opt/bitnami/nginx/conf/server_blocks/. Create a file there:

sudo nano /opt/bitnami/nginx/conf/server_blocks/api.conf

Paste:

server {
    listen 80;
    server_name api.mybrand.com;

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

Reload: sudo /opt/bitnami/ctlscript.sh restart nginx. nginx is now proxying api.mybrand.com:80 to your Node process on 127.0.0.1:3000.

Step 7: Attach a static IP and the domain

7

Without static IP, your IP changes on stop/start

Lightsail's default IP is "dynamic" β€” survives reboots but not power-cycles. For a real domain you want a static IP that doesn't change:

  1. Lightsail β†’ Networking (top-level tab, not the instance one) β†’ Create static IP.
  2. Pick the region matching your instance. Attach to the instance.
  3. Free while attached; $0.005/hour (~$3.65/month) if you ever detach without using it. AWS pricing detail; the only Lightsail line that catches people.

Now point your domain at the static IP. In Route 53 (or your DNS provider): create an A record with name api and value = your static IP. DNS tutorial covers the records in general; this is a straight A-record case.

Step 8: Free TLS via Let's Encrypt

8

Bitnami ships a script for this

On the Node.js blueprint, certbot is pre-installed. SSH in and run:

sudo /opt/bitnami/bncert-tool

The tool asks for your domain name, your email, and whether you want HTTP-to-HTTPS redirect. Say yes to redirect. It modifies the nginx config, issues the cert, sets up auto-renewal. Two minutes, no manual nginx editing.

On a plain Ubuntu blueprint without Bitnami: sudo apt install certbot python3-certbot-nginx, then sudo certbot --nginx -d api.mybrand.com --redirect. Same result, slightly more steps.

Test: curl -I https://api.mybrand.com/health. You should see HTTP/2 200 (or whatever your health endpoint returns). HTTP→HTTPS redirect is in place; cert auto-renews every 90 days via a cron job.

The deploy loop after setup

For pushes-deploy code updates, the steady-state workflow is:

# Local: push to your repo
git push origin main

# Server: pull + restart
ssh -i ~/.ssh/lightsail.pem bitnami@<STATIC_IP>
cd ~/your-api
git pull
npm ci --production  # if dependencies changed
pm2 restart api

For something snappier, write a shell script on your laptop that runs the same commands over ssh:

#!/usr/bin/env bash
ssh -i ~/.ssh/lightsail.pem bitnami@<STATIC_IP> \
  'cd ~/your-api && git pull && npm ci --production && pm2 restart api'

For real CI/CD, a GitHub Actions workflow that ssh's in and runs the same is ~15 lines. For zero-downtime deploys (a meaningful step up), look at PM2's reload command or pair PM2 with a small reverse-proxy switch.

When you've outgrown Lightsail

You need autoscaling. Lightsail is single-instance. If traffic outgrows one box, you need EC2 + ALB + Auto Scaling Group, or move to a container orchestrator like ECS Fargate.

You need VPC peering or private subnets. Lightsail instances live in a managed VPC; you can't peer to other VPCs. If the server needs to talk to RDS / ElastiCache / private resources on the AWS side, EC2 is the path.

You need more than the $80/month tier (32 GB RAM, 8 vCPU). Lightsail's largest size is fixed; beyond that, EC2 is the only option.

What's next