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 only80(HTTP) — anywhere443(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→ EIPapi.yourdomain.com→ EIP (or serve API underapp.../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.
(Recommended) enable auth on MongoDB
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=1and 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.
ufwallows only SSH + Nginx.- Consider snapshots/EBS backups + the nightly
mongodump.