Section 03

Server Deployment Notes

EC2, keys, security groups, SSH, Docker, Nginx, domain.

Private key (.pem)

Your key. Keep on laptop. Never share. Never commit to GitHub.

Public key

Installed on EC2 by AWS. Like a lock on the door. Matches your private key.

Analogy: Public key = lock · Private key = key in your pocket · SSH = opening the door

Security Group — Inbound vs Outbound

PortServiceOpen?
22SSHYES
80HTTP / NginxYES
443HTTPSOPTIONAL
8080Docker directNO
3306MySQLNO

Inbound = traffic INTO server (SSH, website). Outbound = traffic OUT (apt, git clone, docker pull). Workshop: outbound allow-all is fine.

SSH login + first checks

chmod 400 workshop-key.pem
ssh -i workshop-key.pem ubuntu@YOUR_PUBLIC_IP

whoami
hostname
pwd
uname -a
free -h
df -h
sudo apt update
sudo apt upgrade -y

Clone + Docker Compose on EC2

git clone https://github.com/USERNAME/REPO.git
cd REPO
docker --version
docker compose version
docker compose up -d --build
docker compose ps
curl http://127.0.0.1:8080

If curl works, Docker is fine. Fix Docker before configuring Nginx.

Nginx reverse proxy

Public entry on :80 → forwards to Docker on localhost:8080

sudo apt install nginx -y
sudo systemctl status nginx
server {
    listen 80;
    server_name your-domain.duckdns.org;
    location / {
        proxy_pass http://127.0.0.1:8080;
        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;
    }
}
sudo nginx -t
sudo systemctl reload nginx

# Better Docker port binding after Nginx works:
# ports: ["127.0.0.1:8080:80"]

Go-live checklist

  1. Create EC2 Ubuntu + key pair (.pem)
  2. Inbound: 22 + 80 (+443 optional)
  3. SSH login
  4. Install Git + Docker
  5. Clone repo → compose up → curl localhost:8080
  6. Install Nginx + reverse proxy
  7. Point domain / DuckDNS to public IP
  8. Open domain without :8080
  9. Restrict Docker to 127.0.0.1:8080
Download Server slides →