Skip to main content

Hands-On: Deploy a Node App on Lightsail

What You Will Build

A Lightsail instance running the Node.js blueprint, with a static IP that survives restarts, your own Express app deployed and served on port 80.

Step 1 — Create the Instance

  1. Open the Lightsail console (it has its own console, separate from the main AWS one).
  2. Click Create instance.
  3. Region: pick the one closest to your users.
  4. Platform: Linux/Unix. Blueprint: Node.js (under Apps + OS — it's a Bitnami image with Node, npm, and Apache preinstalled).
  5. Instance plan: the $5 (1 GB RAM) plan is comfortable for a small API. The $3.50 plan works but swaps under npm installs.
  6. Name: node-app-1, then Create instance.

It's running in under a minute.

Step 2 — Attach a Static IP

The default public IP changes every time the instance stops. Fix that first, before you configure DNS or share the address anywhere:

  1. Go to Networking → Create static IP.
  2. Select the same region, attach it to node-app-1, name it node-app-1-ip.

Static IPs are free while attached to a running instance. An unattached one bills hourly, so release it if you delete the instance.

Step 3 — Connect via SSH

The browser terminal (the orange icon on the instance card) works for quick checks, but for real work download the default key from Account → SSH keys, then:

chmod 400 ~/Downloads/LightsailDefaultKey-us-east-1.pem
ssh -i ~/Downloads/LightsailDefaultKey-us-east-1.pem bitnami@YOUR_STATIC_IP

Note the user is bitnami, not ubuntu — this is a Bitnami blueprint.

Step 4 — Look Around the Blueprint

The Node.js blueprint ships with a Bitnami stack under /opt/bitnami:

node -v # preinstalled Node LTS
sudo /opt/bitnami/ctlscript.sh status # apache already running on 80/443

Apache is serving the default Bitnami landing page. The plan: run our Express app on port 3000 and have Apache proxy port 80 to it.

Step 5 — Deploy the Express App

mkdir ~/app && cd ~/app
npm init -y
npm install express

Create ~/app/server.js:

const express = require('express');
const app = express();
const PORT = 3000;

app.get('/', (req, res) => {
res.json({ app: 'lightsail-node', status: 'running' });
});

app.listen(PORT, () => console.log(`Listening on ${PORT}`));

For a real project, clone from Git instead of writing files on the server:

cd ~ && git clone https://github.com/your-user/your-app.git app
cd app && npm ci

Step 6 — Keep the App Running

The blueprint doesn't include a process manager, so install PM2:

sudo npm install -g pm2
cd ~/app
pm2 start server.js --name node-app
pm2 startup systemd # run the sudo command it prints
pm2 save

Step 7 — Proxy Port 80 Through Apache

Create a vhost config so Apache forwards traffic to the Express app. Create the file /opt/bitnami/apache/conf/vhosts/node-app-vhost.conf:

<VirtualHost 127.0.0.1:80 _default_:80>
ServerAlias *
ProxyPass / http://localhost:3000/
ProxyPassReverse / http://localhost:3000/
</VirtualHost>

Then restart Apache:

sudo /opt/bitnami/ctlscript.sh restart apache

Visit http://YOUR_STATIC_IP — you should see the JSON from Express instead of the Bitnami page.

Step 8 — Open Ports in the Lightsail Firewall

Lightsail has its own firewall per instance, separate from anything on the OS. Manage it under instance → Networking tab → IPv4 Firewall.

Defaults are SSH (22) and HTTP (80) open. Adjust to:

ApplicationPortSourceNote
SSH22Restrict to your IPClick the rule, enable source IP restriction
HTTP80AnyPublic traffic
HTTPS443AnyAdd this now for the TLS step later

Don't open 3000 — Apache proxies to it locally, so it never needs public exposure. That's the point of the proxy setup.

Step 9 — Snapshot Before You Experiment

Now that the instance works, take a snapshot so you can roll back:

  1. Instance → Snapshots tab → Create snapshot, name it node-app-1-working.

Snapshots bill at $0.05/GB/month — cheap insurance. I take one before every risky change on Lightsail boxes since there's no other undo.

Common Problems

SymptomLikely Cause
Port 80 still shows the Bitnami pageApache didn't pick up the vhost — check the file path and restart output
Site unreachable after instance restartYou're using the old ephemeral IP — use the static IP
EACCES on npm install -gPrefix with sudo on Bitnami images
App down after rebootpm2 save was skipped after pm2 startup