Initial project upload

This commit is contained in:
Mohamed Mathar Irfan
2026-07-28 17:57:02 +05:30
commit ed6610d5d8
23919 changed files with 3003316 additions and 0 deletions

257
deploy/EC2_GITHUB_DEPLOY.md Normal file
View File

@@ -0,0 +1,257 @@
# VerifyPack — EC2 Deploy (GitHub + 16 GB EBS + Nginx + systemd + Actions)
Deploys to one Ubuntu EC2 instance. A **16 GB EBS volume mounted at `/mnt/data`**
holds the app code, MongoDB data, and uploads, so the root disk stays small.
Auto-deploy on `git push` via GitHub Actions.
```
/mnt/data/ ← 16 GB EBS volume
├── verifypack/ ← git repo (frontend + backend)
├── mongodb/ ← MongoDB dbPath
└── uploads/ ← file uploads (when MOCK_STORAGE=1)
Internet ─443─> Nginx ─┬─ / → Next.js (127.0.0.1:3000)
└─ api.… → FastAPI (127.0.0.1:8000) → Mongo (127.0.0.1:27017)
```
---
## 1. Launch the instance + volume
- **EC2:** Ubuntu 22.04 LTS, t3.small+ (t3.medium recommended), 12 GB root gp3.
- **Security group inbound:** 22 (your IP), 80, 443. **Nothing else** (27017/8000/3000 stay local).
- **Create a 16 GB gp3 EBS volume** in the **same Availability Zone** as the instance, then **Attach** it to the instance (it'll appear as `/dev/xvdf` or `/dev/nvme1n1`).
- Allocate an **Elastic IP**, associate it, point DNS:
- `app.yourdomain.com` → EIP
- `api.yourdomain.com` → EIP
SSH in: `ssh -i key.pem ubuntu@<eip>`
---
## 2. Format & mount the 16 GB EBS volume at /mnt/data
```bash
# find the device name (the ~16G disk with no mountpoint)
lsblk
# say it's /dev/nvme1n1 (or /dev/xvdf). Format ONCE (skip if it has data):
sudo mkfs -t ext4 /dev/nvme1n1
sudo mkdir -p /mnt/data
sudo mount /dev/nvme1n1 /mnt/data
# persist across reboots via UUID
UUID=$(sudo blkid -s UUID -o value /dev/nvme1n1)
echo "UUID=$UUID /mnt/data ext4 defaults,nofail 0 2" | sudo tee -a /etc/fstab
sudo mount -a # verify no errors
df -h /mnt/data # confirm 16G mounted
# app owns it
sudo mkdir -p /mnt/data/verifypack /mnt/data/mongodb /mnt/data/uploads
sudo chown -R ubuntu:ubuntu /mnt/data
```
---
## 3. Base packages
```bash
sudo apt update && sudo apt upgrade -y
sudo apt install -y git nginx python3-venv python3-pip build-essential curl ufw
sudo ufw allow OpenSSH && sudo ufw allow 'Nginx Full' && sudo ufw enable
# Node 20
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt install -y nodejs
```
---
## 4. MongoDB 7.0 with dbPath on the EBS volume
```bash
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
# point Mongo at the EBS volume
sudo systemctl stop mongod 2>/dev/null || true
sudo chown -R mongodb:mongodb /mnt/data/mongodb
sudo sed -i 's|dbPath:.*|dbPath: /mnt/data/mongodb|' /etc/mongod.conf
sudo systemctl enable --now mongod
sudo systemctl status mongod # active (running)
```
Enable auth (recommended):
```bash
mongosh
```
```javascript
use admin
db.createUser({ user:"vpadmin", pwd:"<STRONG_PASSWORD>", roles:[{role:"root",db:"admin"}] })
exit
```
```bash
sudo sed -i 's/#security:/security:\n authorization: enabled/' /etc/mongod.conf
sudo systemctl restart mongod
```
Connection string: `mongodb://vpadmin:<STRONG_PASSWORD>@127.0.0.1:27017/?authSource=admin`
---
## 5. GitHub deploy key (private repo)
```bash
ssh-keygen -t ed25519 -C "verifypack-ec2" -f ~/.ssh/verifypack_deploy -N ""
cat ~/.ssh/verifypack_deploy.pub
```
Copy that public key → **GitHub repo → Settings → Deploy keys → Add deploy key**
(read-only is fine). Then tell SSH to use it:
```bash
cat >> ~/.ssh/config <<'EOF'
Host github.com
IdentityFile ~/.ssh/verifypack_deploy
IdentitiesOnly yes
EOF
chmod 600 ~/.ssh/config
```
Clone onto the EBS volume:
```bash
cd /mnt/data
git clone git@github.com:<you>/verifypack.git verifypack
```
> Adjust paths below if your repo root differs from `/mnt/data/verifypack`
> containing `backend/` and `frontend/`.
---
## 6. Backend
```bash
cd /mnt/data/verifypack/backend
python3 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt gunicorn
cp .env.example .env && nano .env
```
Set in `.env` (uploads on EBS, real Mongo):
```env
ENVIRONMENT=production
SECRET_KEY=<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=1 # set 0 once AWS SES is configured
MOCK_STORAGE=1 # local uploads (kept on EBS via symlink below); set 0 for S3
GST_RATE=0.18
# ...Razorpay / SES / S3 / Google keys when ready (see DEPLOYMENT.md)
```
Keep local uploads on the EBS volume (only matters when `MOCK_STORAGE=1`):
```bash
mkdir -p /mnt/data/uploads
rm -rf /mnt/data/verifypack/backend/app/_uploads
ln -s /mnt/data/uploads /mnt/data/verifypack/backend/app/_uploads
```
Seed once, then install the service:
```bash
python -m app.db.seed
sudo cp /mnt/data/verifypack/deploy/verifypack-backend.service /etc/systemd/system/
sudo systemctl daemon-reload && sudo systemctl enable --now verifypack-backend
curl localhost:8000/health # {"status":"ok",...,"mock_db":false}
```
---
## 7. Frontend
```bash
cd /mnt/data/verifypack/frontend
npm ci
cp .env.local.example .env.local && nano .env.local
```
```env
NEXT_PUBLIC_API_URL=https://api.yourdomain.com
NEXT_PUBLIC_APP_URL=https://app.yourdomain.com
```
```bash
npm run build
sudo cp /mnt/data/verifypack/deploy/verifypack-frontend.service /etc/systemd/system/
sudo systemctl daemon-reload && sudo systemctl enable --now verifypack-frontend
curl localhost:3000 # HTML
```
---
## 8. Nginx + HTTPS
```bash
sudo cp /mnt/data/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
sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d app.yourdomain.com -d api.yourdomain.com
```
---
## 9. GitHub Actions auto-deploy
The workflow `.github/workflows/deploy.yml` (in the repo) SSHes into the box on every
push to `main` and runs `deploy/deploy.sh`.
Add these **GitHub repo → Settings → Secrets and variables → Actions** secrets:
| Secret | Value |
|---|---|
| `EC2_HOST` | your Elastic IP or `app.yourdomain.com` |
| `EC2_USER` | `ubuntu` |
| `EC2_SSH_KEY` | a **private** SSH key whose public half is in `~/.ssh/authorized_keys` on the box |
Create that CI key (locally or on the box), add the public part to the instance:
```bash
# on the instance, allow the CI key to SSH in:
echo "<CI_PUBLIC_KEY>" >> ~/.ssh/authorized_keys
```
Put the matching **private** key into the `EC2_SSH_KEY` secret.
`deploy.sh` restarts services with `sudo`. So CI (non-interactive) can do this
without a password, allow those two commands passwordless for the `ubuntu` user:
```bash
echo 'ubuntu ALL=(ALL) NOPASSWD: /bin/systemctl restart verifypack-backend, /bin/systemctl restart verifypack-frontend' | \
sudo tee /etc/sudoers.d/verifypack-deploy
sudo chmod 440 /etc/sudoers.d/verifypack-deploy
chmod +x /mnt/data/verifypack/deploy/deploy.sh
```
Now every `git push origin main` → Actions → SSH → `deploy.sh` (git pull, install,
rebuild, restart services). Manual deploy anytime: `bash /mnt/data/verifypack/deploy/deploy.sh`.
> **Commit hygiene:** ensure `.gitignore` excludes `backend/.env`, `frontend/.env.local`,
> `backend/.venv/`, `frontend/node_modules/`, `frontend/.next/`, and `backend/app/_uploads/`.
> Never commit secrets — set them in `.env` on the box only.
---
## 10. Ops
```bash
sudo journalctl -u verifypack-backend -f
sudo journalctl -u verifypack-frontend -f
df -h /mnt/data # watch EBS usage
# nightly Mongo backup (cron) onto the same volume:
mongodump --uri="mongodb://vpadmin:<pwd>@127.0.0.1:27017/verifypack?authSource=admin" \
--out /mnt/data/backups/$(date +\%F)
```
**Grow the volume later:** resize the EBS volume in AWS console, then on the box:
`sudo growpart /dev/nvme1n1 1 || true; sudo resize2fs /dev/nvme1n1`.
### Security recap
- 27017 / 8000 / 3000 are localhost-only (never in the SG).
- Mongo auth on; strong `SECRET_KEY`; seeded admin password changed.
- TLS via certbot; HTTP → HTTPS; `ufw` only allows SSH + Nginx.
- Deploy key is read-only; CI key only used for SSH deploy.

252
deploy/EC2_SETUP.md Normal file
View File

@@ -0,0 +1,252 @@
# 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:
```bash
ssh -i your-key.pem ubuntu@<elastic-ip>
```
---
## 1. Base packages
```bash
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)
```bash
sudo ufw allow OpenSSH
sudo ufw allow 'Nginx Full'
sudo ufw enable
```
---
## 2. Install MongoDB 7.0
```bash
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.
### (Recommended) enable auth on MongoDB
```bash
mongosh
```
```javascript
use admin
db.createUser({
user: "vpadmin",
pwd: "<STRONG_PASSWORD>",
roles: [ { role: "root", db: "admin" } ]
})
exit
```
Turn on auth:
```bash
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)
```bash
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
```bash
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)
```bash
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`:
```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:
```bash
python -m app.db.seed
```
Install the systemd service (file provided in `deploy/verifypack-backend.service`):
```bash
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)
```bash
cd /opt/verifypack/frontend
npm ci
cp .env.local.example .env.local
nano .env.local
```
Set:
```env
NEXT_PUBLIC_API_URL=https://api.yourdomain.com
NEXT_PUBLIC_APP_URL=https://app.yourdomain.com
```
Build & install service:
```bash
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
```bash
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
```bash
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
```bash
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
```bash
sudo journalctl -u verifypack-backend -f # backend logs
sudo journalctl -u verifypack-frontend -f # frontend logs
sudo systemctl status mongod
```
Mongo backup (cron nightly):
```bash
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`.

31
deploy/deploy.sh Normal file
View File

@@ -0,0 +1,31 @@
#!/usr/bin/env bash
# VerifyPack deploy — pull latest, install deps, rebuild frontend, restart services.
# Run on the EC2 box (or invoked by GitHub Actions over SSH).
set -euo pipefail
APP_DIR="/mnt/data/verifypack"
cd "$APP_DIR"
echo "==> git pull"
git fetch --all
git reset --hard origin/main
echo "==> backend deps"
cd "$APP_DIR/backend"
source .venv/bin/activate
pip install -r requirements.txt >/dev/null
deactivate
echo "==> frontend build"
cd "$APP_DIR/frontend"
npm ci
npm run build
echo "==> restart services"
sudo systemctl restart verifypack-backend
sudo systemctl restart verifypack-frontend
echo "==> health check"
sleep 3
curl -fsS http://127.0.0.1:8000/health && echo
echo "Deploy complete."

View File

@@ -0,0 +1,44 @@
# VerifyPack Nginx config — single EC2 instance.
# Two server names: app. (Next.js) and api. (FastAPI).
# certbot will rewrite these to add the 443 / TLS blocks automatically.
# ---------- Frontend: app.yourdomain.com ----------
server {
listen 80;
server_name app.yourdomain.com;
# Next.js
location / {
proxy_pass http://127.0.0.1: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;
}
}
# ---------- Backend API: api.yourdomain.com ----------
server {
listen 80;
server_name api.yourdomain.com;
client_max_body_size 10M; # allow logo / document / QR image uploads
location / {
proxy_pass http://127.0.0.1:8000;
proxy_http_version 1.1;
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;
# X-Forwarded-For carries the real client IP into scan logs
}
# Locally-stored uploads (only used when MOCK_STORAGE=1; S3 serves them otherwise)
location /uploads/ {
proxy_pass http://127.0.0.1:8000;
}
}

View File

@@ -0,0 +1,20 @@
[Unit]
Description=VerifyPack FastAPI backend
After=network.target mongod.service
Wants=mongod.service
[Service]
Type=simple
User=ubuntu
WorkingDirectory=/mnt/data/verifypack/backend
EnvironmentFile=/mnt/data/verifypack/backend/.env
ExecStart=/mnt/data/verifypack/backend/.venv/bin/gunicorn app.main:app \
-k uvicorn.workers.UvicornWorker \
-w 4 \
-b 127.0.0.1:8000 \
--timeout 120
Restart=always
RestartSec=3
[Install]
WantedBy=multi-user.target

View File

@@ -0,0 +1,16 @@
[Unit]
Description=VerifyPack Next.js frontend
After=network.target
[Service]
Type=simple
User=ubuntu
WorkingDirectory=/mnt/data/verifypack/frontend
Environment=NODE_ENV=production
Environment=PORT=3000
ExecStart=/usr/bin/npm start
Restart=always
RestartSec=3
[Install]
WantedBy=multi-user.target