Skip to content

devSahinur/EC2-Nginx-deployment-guide

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 

Repository files navigation

AWS EC2 + Nginx Deployment Guide

A comprehensive guide to deploying applications on AWS EC2 with Nginx as a reverse proxy.


Table of Contents

  1. Prerequisites
  2. Launch EC2 Instance
  3. Connect to EC2 Instance
  4. Initial Server Setup
  5. Install Nginx
  6. Configure Firewall
  7. Deploy Your Application
  8. Configure Nginx as Reverse Proxy
  9. SSL/TLS Configuration with Let's Encrypt
  10. Domain Configuration
  11. Performance Optimization
  12. Monitoring and Logs
  13. Troubleshooting

Prerequisites

Before starting, ensure you have:

  • AWS Account with appropriate permissions
  • SSH client installed on your local machine
  • Domain name (optional, for SSL setup)
  • Basic knowledge of Linux commands

Launch EC2 Instance

Step 1: Navigate to EC2 Dashboard

  1. Log in to AWS Console
  2. Search for "EC2" in the services search bar
  3. Click on "EC2" to open the dashboard

Step 2: Launch Instance

  1. Click "Launch Instance" button
  2. Configure the following:

Name and Tags

Name: my-web-server

Application and OS Images (AMI)

  • Select Ubuntu Server 22.04 LTS (recommended)
  • Architecture: 64-bit (x86)

Instance Type

Use Case Instance Type vCPU Memory
Testing/Dev t2.micro 1 1 GB
Small Apps t2.small 1 2 GB
Medium Apps t2.medium 2 4 GB
Production t3.medium+ 2+ 4+ GB

Key Pair (Login)

  1. Click "Create new key pair"
  2. Name: my-ec2-key
  3. Key pair type: RSA
  4. Private key format: .pem (for Linux/Mac) or .ppk (for Windows/PuTTY)
  5. Click "Create key pair" and save the file securely

Network Settings

  1. Click "Edit"
  2. Configure Security Group:
Security Group Name: web-server-sg

Inbound Rules:
- SSH (22)        : Source = My IP
- HTTP (80)       : Source = Anywhere (0.0.0.0/0)
- HTTPS (443)     : Source = Anywhere (0.0.0.0/0)
- Custom TCP      : Port 3000-9000 (for app servers, optional)

Configure Storage

  • Root volume: 20-30 GB gp3 (General Purpose SSD)

Step 3: Launch

Click "Launch Instance" and wait for the instance to start.


Connect to EC2 Instance

Option 1: SSH from Terminal (Linux/Mac/Windows)

# Set correct permissions for key file
chmod 400 my-ec2-key.pem

# Connect to instance
ssh -i "my-ec2-key.pem" ubuntu@<your-ec2-public-ip>

Option 2: EC2 Instance Connect (Browser)

  1. Select your instance in EC2 Dashboard
  2. Click "Connect" button
  3. Choose "EC2 Instance Connect" tab
  4. Click "Connect"

Option 3: PuTTY (Windows)

  1. Convert .pem to .ppk using PuTTYgen
  2. Open PuTTY
  3. Host: ubuntu@<your-ec2-public-ip>
  4. Connection > SSH > Auth > Browse for .ppk file
  5. Click "Open"

Initial Server Setup

Update System Packages

# Update package lists
sudo apt update

# Upgrade installed packages
sudo apt upgrade -y

# Install essential tools
sudo apt install -y curl wget git vim htop unzip

Set Timezone

# Check current timezone
timedatectl

# Set timezone (example: Asia/Dhaka)
sudo timedatectl set-timezone Asia/Dhaka

Create Swap Space (Recommended for small instances)

# Create 2GB swap file
sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile

# Make swap permanent
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab

# Verify swap
free -h

Install Nginx

Install Nginx

# Install Nginx
sudo apt install nginx -y

# Start and enable Nginx
sudo systemctl start nginx
sudo systemctl enable nginx

# Check status
sudo systemctl status nginx

Verify Installation

Open your browser and navigate to:

http://<your-ec2-public-ip>

You should see the "Welcome to nginx!" page.

Nginx Directory Structure

/etc/nginx/
├── nginx.conf              # Main configuration file
├── sites-available/        # Available site configurations
├── sites-enabled/          # Enabled site configurations (symlinks)
├── conf.d/                 # Additional configurations
└── snippets/               # Reusable configuration snippets

/var/www/                   # Web root directory
/var/log/nginx/             # Log files (access.log, error.log)

Configure Firewall

Using UFW (Uncomplicated Firewall)

# Enable UFW
sudo ufw enable

# Allow SSH (IMPORTANT: Do this first!)
sudo ufw allow ssh
# OR
sudo ufw allow 22

# Allow Nginx HTTP
sudo ufw allow 'Nginx HTTP'

# Allow Nginx HTTPS
sudo ufw allow 'Nginx HTTPS'

# Allow both HTTP and HTTPS
sudo ufw allow 'Nginx Full'

# Check status
sudo ufw status

Expected Output

Status: active

To                         Action      From
--                         ------      ----
22/tcp                     ALLOW       Anywhere
Nginx Full                 ALLOW       Anywhere
22/tcp (v6)                ALLOW       Anywhere (v6)
Nginx Full (v6)            ALLOW       Anywhere (v6)

Deploy Your Application

Option 1: Node.js Application

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

# Verify installation
node --version
npm --version

# Create application directory
sudo mkdir -p /var/www/myapp
sudo chown -R $USER:$USER /var/www/myapp

# Clone your repository
cd /var/www/myapp
git clone https://github.com/yourusername/your-repo.git .

# Install dependencies
npm install

# Install PM2 for process management
sudo npm install -g pm2

# Start application with PM2
pm2 start app.js --name "myapp"

# Save PM2 configuration
pm2 save

# Setup PM2 to start on boot
pm2 startup systemd
# Run the command it outputs

Option 2: Python Application

# Install Python and pip
sudo apt install -y python3 python3-pip python3-venv

# Create application directory
sudo mkdir -p /var/www/myapp
sudo chown -R $USER:$USER /var/www/myapp

# Clone your repository
cd /var/www/myapp
git clone https://github.com/yourusername/your-repo.git .

# Create virtual environment
python3 -m venv venv
source venv/bin/activate

# Install dependencies
pip install -r requirements.txt

# Install Gunicorn
pip install gunicorn

# Run with Gunicorn
gunicorn --bind 0.0.0.0:8000 app:app

Option 3: Static Website

# Create web directory
sudo mkdir -p /var/www/mysite
sudo chown -R $USER:$USER /var/www/mysite

# Copy your static files
cd /var/www/mysite
# Place your HTML, CSS, JS files here

Configure Nginx as Reverse Proxy

Basic Reverse Proxy Configuration

Create a new server block:

sudo nano /etc/nginx/sites-available/myapp

Add the following configuration:

server {
    listen 80;
    server_name your-domain.com www.your-domain.com;
    # Or use: server_name _;  for IP-based access

    # Logs
    access_log /var/log/nginx/myapp_access.log;
    error_log /var/log/nginx/myapp_error.log;

    # Proxy settings
    location / {
        proxy_pass http://localhost:3000;  # Your app port
        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;
    }
}

Static Files Configuration

server {
    listen 80;
    server_name your-domain.com www.your-domain.com;

    root /var/www/mysite;
    index index.html index.htm;

    location / {
        try_files $uri $uri/ =404;
    }

    # Cache static assets
    location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
        expires 30d;
        add_header Cache-Control "public, immutable";
    }
}

Enable the Site

# 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

# Reload Nginx
sudo systemctl reload nginx

SSL/TLS Configuration with Let's Encrypt

Install Certbot

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

Obtain SSL Certificate

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

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

Verify Auto-Renewal

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

# Check renewal timer
sudo systemctl status certbot.timer

Manual SSL Configuration (After Certbot)

Your Nginx config will be automatically updated, but here's what it looks like:

server {
    listen 80;
    server_name your-domain.com www.your-domain.com;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name your-domain.com www.your-domain.com;

    # SSL certificates (managed by Certbot)
    ssl_certificate /etc/letsencrypt/live/your-domain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/your-domain.com/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

    # Your application
    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;
    }
}

Domain Configuration

Step 1: Get Your EC2 Public IP

# From EC2 Dashboard or run:
curl http://checkip.amazonaws.com

Step 2: Configure DNS Records

Go to your domain registrar (GoDaddy, Namecheap, Route53, etc.) and add:

Type Name Value TTL
A @ <EC2-Public-IP> 300
A www <EC2-Public-IP> 300

Step 3: Using AWS Route 53 (Optional)

  1. Create a Hosted Zone for your domain
  2. Add A record pointing to EC2 IP
  3. Update nameservers at your registrar

Step 4: Elastic IP (Recommended for Production)

# Allocate Elastic IP from EC2 Dashboard:
# 1. Go to EC2 > Elastic IPs
# 2. Click "Allocate Elastic IP address"
# 3. Click "Allocate"
# 4. Select the IP > Actions > Associate Elastic IP address
# 5. Select your instance
# 6. Click "Associate"

Performance Optimization

Nginx Performance Tuning

Edit main Nginx config:

sudo nano /etc/nginx/nginx.conf
user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;

events {
    worker_connections 1024;
    multi_accept on;
    use epoll;
}

http {
    # Basic Settings
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;
    types_hash_max_size 2048;
    server_tokens off;

    # Buffer Settings
    client_body_buffer_size 10K;
    client_header_buffer_size 1k;
    client_max_body_size 50M;
    large_client_header_buffers 2 1k;

    # Gzip Compression
    gzip on;
    gzip_vary on;
    gzip_proxied any;
    gzip_comp_level 6;
    gzip_types text/plain text/css text/xml application/json application/javascript application/rss+xml application/atom+xml image/svg+xml;

    # Rate Limiting
    limit_req_zone $binary_remote_addr zone=one:10m rate=10r/s;

    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    # Logging
    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;

    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;
}

Enable Caching

Add to your server block:

# Browser caching for static files
location ~* \.(jpg|jpeg|png|gif|ico|css|js|pdf|woff|woff2)$ {
    expires 30d;
    add_header Cache-Control "public, no-transform";
}

# Proxy caching
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=my_cache:10m max_size=1g inactive=60m use_temp_path=off;

location / {
    proxy_cache my_cache;
    proxy_cache_valid 200 60m;
    proxy_cache_use_stale error timeout http_500 http_502 http_503 http_504;
    # ... other proxy settings
}

Monitoring and Logs

View Nginx Logs

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

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

# Application-specific logs
sudo tail -f /var/log/nginx/myapp_access.log
sudo tail -f /var/log/nginx/myapp_error.log

Monitor System Resources

# Real-time system monitor
htop

# Disk usage
df -h

# Memory usage
free -m

# Nginx process status
ps aux | grep nginx

Check Nginx Status

# Service status
sudo systemctl status nginx

# Active connections
curl http://localhost/nginx_status

Enable Nginx Status Module

Add to your server block:

location /nginx_status {
    stub_status on;
    allow 127.0.0.1;
    deny all;
}

Troubleshooting

Common Issues and Solutions

1. Nginx Won't Start

# Check for syntax errors
sudo nginx -t

# Check error logs
sudo journalctl -u nginx
sudo tail -50 /var/log/nginx/error.log

# Check if port 80 is in use
sudo lsof -i :80

2. 502 Bad Gateway

# Check if your application is running
sudo systemctl status your-app
pm2 status

# Check if app is listening on correct port
sudo netstat -tlnp | grep :3000

# Check Nginx proxy settings
# Ensure proxy_pass port matches your app port

3. 403 Forbidden

# Check file permissions
ls -la /var/www/myapp/

# Fix permissions
sudo chown -R www-data:www-data /var/www/myapp/
sudo chmod -R 755 /var/www/myapp/

4. Connection Refused

# Check security group rules in AWS Console
# Ensure ports 80/443 are open

# Check UFW
sudo ufw status

# Check if Nginx is listening
sudo netstat -tlnp | grep nginx

5. SSL Certificate Issues

# Renew certificate manually
sudo certbot renew

# Check certificate expiry
sudo certbot certificates

# Test SSL configuration
curl -I https://your-domain.com

Useful Commands Reference

# Nginx commands
sudo systemctl start nginx
sudo systemctl stop nginx
sudo systemctl restart nginx
sudo systemctl reload nginx
sudo nginx -t                    # Test configuration
sudo nginx -s reload             # Reload without downtime

# PM2 commands (Node.js)
pm2 list                         # List all processes
pm2 logs                         # View logs
pm2 restart all                  # Restart all processes
pm2 monit                        # Monitor processes

# System commands
sudo reboot                      # Restart server
sudo shutdown -h now             # Shutdown server

Security Best Practices

1. Keep System Updated

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

2. Configure Fail2Ban

# Install Fail2Ban
sudo apt install fail2ban -y

# Create local config
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local

# Enable and start
sudo systemctl enable fail2ban
sudo systemctl start fail2ban

3. Disable Root Login

sudo nano /etc/ssh/sshd_config

# Set these values:
PermitRootLogin no
PasswordAuthentication no

# Restart SSH
sudo systemctl restart sshd

4. Security Headers

Add to your Nginx server block:

# Security headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "no-referrer-when-downgrade" always;
add_header Content-Security-Policy "default-src 'self' http: https: data: blob: 'unsafe-inline'" always;

Quick Reference Card

Task Command
SSH to server ssh -i key.pem ubuntu@IP
Restart Nginx sudo systemctl restart nginx
Test Nginx config sudo nginx -t
View access logs sudo tail -f /var/log/nginx/access.log
View error logs sudo tail -f /var/log/nginx/error.log
Renew SSL sudo certbot renew
Check disk space df -h
Check memory free -m
List PM2 apps pm2 list
Restart PM2 app pm2 restart app-name

Resources


Author: Sahinur Last Updated: January 2026 License: MIT

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published