258 lines
8.4 KiB
Markdown
258 lines
8.4 KiB
Markdown
# 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.
|