Your First Deployment
Your First Deployment
Step-by-step guide to deploying your first real application on Lambda.
What We'll Build
In this tutorial, you'll deploy a complete web application stack:
- Frontend: React app
- Backend: Node.js API
- Database: PostgreSQL
- Reverse Proxy: Nginx
Architecture:
Internet → Lambda Instance (Nginx) → Node.js API → PostgreSQL
↓
React Static FilesPrerequisites
- Lambda account (Sign up)
- Lambda CLI installed
- Basic knowledge of Node.js and React
- SSH key configured
Step 1: Create Your Instance
Choose Instance Size
For this tutorial, we'll use compute-4x (4 vCPU, 8GB RAM).
Option 1: Using the Dashboard
- Go to dashboard.lambda.io/instances/create
- Configure:
- Name:
fullstack-app - Type:
compute-4x - Region:
us-west-1 - Image:
ubuntu-22.04 - SSH Key: Select or add your public key
- Name:
- Click "Launch Instance"
- Note your instance IP once it's running
Option 2: Using the CLI
lambda create instance \
--name fullstack-app \
--type compute-4x \
--region us-west-1 \
--image ubuntu-22.04 \
--ssh-key ~/.ssh/id_rsa.pub \
--waitExpected Output:
Creating instance...
✓ Instance created: inst_abc123xyz
Status: running
PublicIP: 203.0.113.42
SSH: lambda@203.0.113.42Save the instance ID and IP:
export INSTANCE_ID="inst_abc123xyz"
export INSTANCE_IP="203.0.113.42"Step 2: Configure Firewall
Open necessary ports for your application.
Option 1: Using the Dashboard
- Go to dashboard.lambda.io/instances
- Click on your instance:
fullstack-app - Go to "Firewall" tab
- Add rules:
- SSH (port 22): Your IP only
- HTTP (port 80): All sources (0.0.0.0/0)
- HTTPS (port 443): All sources (0.0.0.0/0)
- Click "Save Rules"
Option 2: Using the CLI
# SSH (for you only)
lambda firewall allow $INSTANCE_ID \
--port 22 \
--source "$(curl -s ifconfig.me)/32" \
--description "SSH from my IP"
# HTTP/HTTPS (public)
lambda firewall allow $INSTANCE_ID \
--port 80 \
--source "0.0.0.0/0" \
--description "HTTP traffic"
lambda firewall allow $INSTANCE_ID \
--port 443 \
--source "0.0.0.0/0" \
--description "HTTPS traffic"
# Verify rules
lambda firewall list $INSTANCE_IDStep 3: Initial Server Setup
Connect to Instance
lambda ssh $INSTANCE_IDUpdate System
sudo apt update && sudo apt upgrade -yCreate Application User
sudo useradd -m -s /bin/bash appuser
sudo usermod -aG sudo appuserInstall Base Packages
sudo apt install -y \
curl \
wget \
git \
build-essential \
ufw \
fail2banStep 4: Install Node.js
Install Node.js 20.x
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 # Should show 10.x.xInstall PM2 (Process Manager)
sudo npm install -g pm2Step 5: Install PostgreSQL
Install PostgreSQL 15
sudo apt install -y postgresql postgresql-contrib
# Start PostgreSQL
sudo systemctl start postgresql
sudo systemctl enable postgresqlCreate Database and User
sudo -u postgres psqlIn PostgreSQL shell:
-- Create database
CREATE DATABASE myapp_db;
-- Create user
CREATE USER myapp_user WITH ENCRYPTED PASSWORD 'secure_password_here';
-- Grant privileges
GRANT ALL PRIVILEGES ON DATABASE myapp_db TO myapp_user;
-- Exit
\qConfigure PostgreSQL for Local Access
sudo nano /etc/postgresql/15/main/pg_hba.confAdd this line:
local myapp_db myapp_user md5Restart PostgreSQL:
sudo systemctl restart postgresqlStep 6: Deploy Backend
Create Project Directory
sudo mkdir -p /var/www
sudo chown appuser:appuser /var/www
cd /var/wwwClone or Create Your Backend
# Option 1: Clone existing project
git clone https://github.com/yourusername/your-api.git api
cd api
# Option 2: Create new Express app
mkdir api && cd api
npm init -y
npm install express pg dotenv cors helmetSample Express App
Create index.js:
const express = require("express");
const { Pool } = require("pg");
const cors = require("cors");
const helmet = require("helmet");
const app = express();
const port = process.env.PORT || 3000;
// Database connection
const pool = new Pool({
user: process.env.DB_USER || "myapp_user",
host: process.env.DB_HOST || "localhost",
database: process.env.DB_NAME || "myapp_db",
password: process.env.DB_PASSWORD || "secure_password_here",
port: 5432,
});
// Middleware
app.use(helmet());
app.use(cors());
app.use(express.json());
// Health check
app.get("/health", (req, res) => {
res.json({ status: "healthy", timestamp: new Date() });
});
// Sample API endpoint
app.get("/api/users", async (req, res) => {
try {
const { rows } = await pool.query("SELECT * FROM users");
res.json(rows);
} catch (error) {
res.status(500).json({ error: error.message });
}
});
app.listen(port, () => {
console.log(`API running on port ${port}`);
});Create Environment File
cat > .env << EOF
PORT=3000
DB_USER=myapp_user
DB_HOST=localhost
DB_NAME=myapp_db
DB_PASSWORD=secure_password_here
NODE_ENV=production
EOF
# Secure the env file
chmod 600 .envStart with PM2
pm2 start index.js --name api
pm2 save
pm2 startupTest the API:
curl http://localhost:3000/healthStep 7: Deploy Frontend
Build React App (on your local machine)
# In your React project directory
npm install
npm run build
# This creates a 'build' directory with static filesUpload to Instance
# From your local machine
scp -r build/* lambda@$INSTANCE_IP:/tmp/frontend/Move Files on Instance
# SSH into instance
lambda ssh $INSTANCE_ID
# Create directory and move files
sudo mkdir -p /var/www/frontend
sudo mv /tmp/frontend/* /var/www/frontend/
sudo chown -R www-data:www-data /var/www/frontendStep 8: Install and Configure Nginx
Install Nginx
sudo apt install -y nginxConfigure Nginx
sudo nano /etc/nginx/sites-available/myappAdd configuration:
server {
listen 80;
server_name your-domain.com; # Replace with your domain or IP
# Frontend
location / {
root /var/www/frontend;
try_files $uri $uri/ /index.html;
}
# Backend API
location /api {
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_connect_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
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;
}
# Health check
location /health {
proxy_pass http://localhost:3000/health;
access_log off;
}
}Enable Site
sudo ln -s /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled/
sudo rm /etc/nginx/sites-enabled/default
sudo nginx -t
sudo systemctl restart nginxStep 9: Setup SSL with Let's Encrypt
Install Certbot
sudo apt install -y certbot python3-certbot-nginxObtain Certificate
sudo certbot --nginx -d your-domain.com -d www.your-domain.comFollow the prompts. Certbot will automatically configure Nginx for HTTPS.
Auto-Renewal
sudo certbot renew --dry-runStep 10: Application Monitoring
Setup PM2 Monitoring
pm2 install pm2-logrotate
pm2 set pm2-logrotate:max_size 10M
pm2 set pm2-logrotate:retain 7
# View logs
pm2 logs api
# Monitor processes
pm2 monitSetup Lambda Monitoring
# From your local machine
lambda monitoring enable $INSTANCE_ID \
--alerts cpu,memory,disk \
--threshold-cpu 80 \
--threshold-memory 90 \
--notify email:you@example.comStep 11: Database Migrations
Install Migration Tool
cd /var/www/api
npm install pg-migrateCreate Migration
Create migrations/001_initial.sql:
CREATE TABLE users (
id SERIAL PRIMARY KEY,
email VARCHAR(255) UNIQUE NOT NULL,
name VARCHAR(255) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_users_email ON users(email);Run Migration
npx pg-migrate upStep 12: Testing Your Deployment
Test API
# From your local machine
curl http://$INSTANCE_IP/api/health
curl http://$INSTANCE_IP/api/usersTest Frontend
Open browser to: http://$INSTANCE_IP
Load Testing (Optional)
# Install Apache Bench
sudo apt install apache2-utils
# Test API endpoint
ab -n 1000 -c 10 http://$INSTANCE_IP/api/healthStep 13: Backup Strategy
Automated Snapshots
# Schedule daily snapshots
lambda snapshot schedule $INSTANCE_ID \
--frequency daily \
--time "02:00" \
--retain 7Database Backups
Create backup script /home/appuser/backup_db.sh:
#!/bin/bash
BACKUP_DIR="/home/appuser/backups"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
mkdir -p $BACKUP_DIR
# Backup database
PGPASSWORD=secure_password_here pg_dump \
-h localhost \
-U myapp_user \
-d myapp_db \
-F c \
-f "$BACKUP_DIR/db_backup_$TIMESTAMP.dump"
# Keep only last 7 days
find $BACKUP_DIR -name "db_backup_*" -mtime +7 -deleteMake executable and schedule:
chmod +x /home/appuser/backup_db.sh
# Add to crontab
crontab -eAdd line:
0 3 * * * /home/appuser/backup_db.shStep 14: Security Hardening
Configure UFW Firewall
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enableSetup Fail2Ban
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
sudo nano /etc/fail2ban/jail.localAdd SSH protection:
[sshd]
enabled = true
port = 22
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 3600sudo systemctl restart fail2banDisable Root Login
sudo nano /etc/ssh/sshd_configSet:
PermitRootLogin no
PasswordAuthentication nosudo systemctl restart sshdStep 15: Monitoring & Alerts
Setup Application Health Checks
Create /home/appuser/health_check.sh:
#!/bin/bash
HEALTH_URL="http://localhost:3000/health"
RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" $HEALTH_URL)
if [ $RESPONSE -ne 200 ]; then
echo "Health check failed! Response: $RESPONSE"
pm2 restart api
# Send alert
curl -X POST "https://api.your-alerts.com/alert" \
-d "message=API health check failed"
fiAdd to crontab:
*/5 * * * * /home/appuser/health_check.shStep 16: CI/CD Integration (Optional)
GitHub Actions
Create .github/workflows/deploy.yml:
name: Deploy to Lambda
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Deploy API
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.LAMBDA_IP }}
username: lambda
key: ${{ secrets.SSH_PRIVATE_KEY }}
script: |
cd /var/www/api
git pull
npm install
pm2 restart api
- name: Build and Deploy Frontend
run: |
npm install
npm run build
- name: Upload Frontend
uses: appleboy/scp-action@master
with:
host: ${{ secrets.LAMBDA_IP }}
username: lambda
key: ${{ secrets.SSH_PRIVATE_KEY }}
source: "build/*"
target: "/var/www/frontend"Troubleshooting
API Not Responding
# Check PM2 status
pm2 status
# View logs
pm2 logs api
# Restart if needed
pm2 restart apiDatabase Connection Errors
# Check PostgreSQL status
sudo systemctl status postgresql
# Check connections
sudo -u postgres psql -c "SELECT * FROM pg_stat_activity;"Nginx Errors
# Check configuration
sudo nginx -t
# View error logs
sudo tail -f /var/log/nginx/error.log
# Restart
sudo systemctl restart nginxNext Steps
Performance Optimization
-
Enable caching
- Configure Redis for session storage
- Add CDN for static assets
-
Database optimization
- Add indexes
- Connection pooling
- Query optimization
-
Scale horizontally
- Add load balancer
- Deploy multiple instances
- Database replication
Advanced Features
- Monitoring: ELK Stack, Prometheus + Grafana
- CI/CD: GitHub Actions, GitLab CI
- Container: Dockerize application
- Orchestration: Kubernetes deployment
Congratulations! 🎉
You've successfully deployed a full-stack application on Lambda!
What you've learned:
- ✓ Instance creation and configuration
- ✓ Firewall setup
- ✓ Backend deployment with Node.js and PostgreSQL
- ✓ Frontend deployment with React
- ✓ Nginx configuration and SSL
- ✓ Monitoring and backups
Next Step
Now that your application is deployed, let's understand the underlying architecture.
- ✓ Security hardening
Think Lambda, Think Privacy
