Files
verify/deploy/EC2_SETUP.md
Mohamed Mathar Irfan ed6610d5d8 Initial project upload
2026-07-28 17:57:02 +05:30

6.4 KiB

VerifyPack — Single EC2 (Ubuntu) Deployment

Everything on one Ubuntu EC2 instance: MongoDB + FastAPI backend + Next.js frontend, with Nginx as the public reverse proxy.

Because MongoDB runs on the same box, it binds to 127.0.0.1 and is never exposed to the internet — no DB port in the security group.

Internet ──443──> Nginx ──┬── /            → Next.js (localhost:3000)
                          └── /api/* , etc → FastAPI (localhost:8000)
                                              FastAPI ──> MongoDB (localhost:27017)

0. Provision the instance

  • AMI: Ubuntu Server 22.04 LTS
  • Type: t3.small minimum (t3.medium recommended — Mongo + Node build need RAM)
  • Storage: 30 GB gp3
  • Security Group inbound:
    • 22 (SSH) — your IP only
    • 80 (HTTP) — anywhere
    • 443 (HTTPS) — anywhere
    • Do NOT open 27017, 8000, or 3000. They stay local.
  • Allocate an Elastic IP and point your domain's A records at it:
    • app.yourdomain.com → EIP
    • api.yourdomain.com → EIP (or serve API under app.../api — see Nginx below)

SSH in:

ssh -i your-key.pem ubuntu@<elastic-ip>

1. Base packages

sudo apt update && sudo apt upgrade -y
sudo apt install -y git nginx python3-venv python3-pip build-essential curl ufw

Firewall (defense in depth)

sudo ufw allow OpenSSH
sudo ufw allow 'Nginx Full'
sudo ufw enable

2. Install MongoDB 7.0

curl -fsSL https://www.mongodb.org/static/pgp/server-7.0.asc | \
  sudo gpg -o /usr/share/keyrings/mongodb-server-7.0.gpg --dearmor

echo "deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-7.0.gpg ] https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/7.0 multiverse" | \
  sudo tee /etc/apt/sources.list.d/mongodb-org-7.0.list

sudo apt update
sudo apt install -y mongodb-org
sudo systemctl enable --now mongod
sudo systemctl status mongod      # should be active (running)

Mongo listens on 127.0.0.1:27017 by default — leave it that way.

mongosh
use admin
db.createUser({
  user: "vpadmin",
  pwd: "<STRONG_PASSWORD>",
  roles: [ { role: "root", db: "admin" } ]
})
exit

Turn on auth:

sudo sed -i 's/#security:/security:\n  authorization: enabled/' /etc/mongod.conf
sudo systemctl restart mongod

Your connection string becomes: mongodb://vpadmin:<STRONG_PASSWORD>@127.0.0.1:27017/?authSource=admin


3. Install Node 20 (for the frontend)

curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt install -y nodejs
node --version    # v20.x

4. Get the code onto the box

sudo mkdir -p /opt/verifypack && sudo chown ubuntu:ubuntu /opt/verifypack
cd /opt/verifypack
# either git clone your repo, or scp the "verify pack" folder up:
#   scp -i key.pem -r "verify pack" ubuntu@<eip>:/opt/verifypack/

Assume the result is /opt/verifypack/backend and /opt/verifypack/frontend.


5. Backend (FastAPI)

cd /opt/verifypack/backend
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt gunicorn
cp .env.example .env
nano .env

Set in backend/.env:

ENVIRONMENT=production
SECRET_KEY=<32+ random chars — run: openssl rand -hex 32>
FRONTEND_URL=https://app.yourdomain.com

MONGODB_URL=mongodb://vpadmin:<STRONG_PASSWORD>@127.0.0.1:27017/?authSource=admin
MONGODB_DB=verifypack
MOCK_DB=0

MOCK_EMAIL=0
MOCK_STORAGE=0

AWS_REGION=ap-south-1
AWS_ACCESS_KEY_ID=...
AWS_SECRET_ACCESS_KEY=...
SES_FROM_EMAIL=no-reply@yourdomain.com
S3_BUCKET=verifypack-uploads

GOOGLE_CLIENT_ID=...
GOOGLE_CLIENT_SECRET=...
GOOGLE_REDIRECT_URI=https://api.yourdomain.com/auth/google/callback

RAZORPAY_KEY_ID=...
RAZORPAY_KEY_SECRET=...
RAZORPAY_WEBHOOK_SECRET=...
GST_RATE=0.18

To run fully offline first (DB only, no AWS/Razorpay), set MOCK_EMAIL=1 MOCK_STORAGE=1 and leave the cloud keys blank — the app still boots.

Seed once:

python -m app.db.seed

Install the systemd service (file provided in deploy/verifypack-backend.service):

sudo cp /opt/verifypack/deploy/verifypack-backend.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now verifypack-backend
sudo systemctl status verifypack-backend
curl localhost:8000/health      # {"status":"ok",...,"mock_db":false}

6. Frontend (Next.js)

cd /opt/verifypack/frontend
npm ci
cp .env.local.example .env.local
nano .env.local

Set:

NEXT_PUBLIC_API_URL=https://api.yourdomain.com
NEXT_PUBLIC_APP_URL=https://app.yourdomain.com

Build & install service:

npm run build
sudo cp /opt/verifypack/deploy/verifypack-frontend.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now verifypack-frontend
sudo systemctl status verifypack-frontend
curl localhost:3000             # HTML returned

7. Nginx reverse proxy

sudo cp /opt/verifypack/deploy/nginx-verifypack.conf /etc/nginx/sites-available/verifypack
sudo ln -s /etc/nginx/sites-available/verifypack /etc/nginx/sites-enabled/
sudo rm -f /etc/nginx/sites-enabled/default
sudo nginx -t && sudo systemctl reload nginx

HTTPS with Let's Encrypt

sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d app.yourdomain.com -d api.yourdomain.com
# auto-renew is installed as a systemd timer

8. Updating after a code change

cd /opt/verifypack && git pull          # or re-scp
# backend
cd backend && source .venv/bin/activate && pip install -r requirements.txt
sudo systemctl restart verifypack-backend
# frontend
cd ../frontend && npm ci && npm run build
sudo systemctl restart verifypack-frontend

9. Logs & ops

sudo journalctl -u verifypack-backend -f      # backend logs
sudo journalctl -u verifypack-frontend -f     # frontend logs
sudo systemctl status mongod

Mongo backup (cron nightly):

mongodump --uri="mongodb://vpadmin:<pwd>@127.0.0.1:27017/verifypack?authSource=admin" \
  --out /opt/backups/$(date +\%F)

10. Single-instance security recap

  • 27017 / 8000 / 3000 are localhost only — never in the security group.
  • MongoDB auth enabled; strong SECRET_KEY; seeded admin password changed.
  • TLS via certbot; HTTP redirects to HTTPS.
  • ufw allows only SSH + Nginx.
  • Consider snapshots/EBS backups + the nightly mongodump.