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

8.4 KiB

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

# 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

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

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):

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

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:

cat >> ~/.ssh/config <<'EOF'
Host github.com
  IdentityFile ~/.ssh/verifypack_deploy
  IdentitiesOnly yes
EOF
chmod 600 ~/.ssh/config

Clone onto the EBS volume:

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

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):

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):

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:

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

cd /mnt/data/verifypack/frontend
npm ci
cp .env.local.example .env.local && nano .env.local
NEXT_PUBLIC_API_URL=https://api.yourdomain.com
NEXT_PUBLIC_APP_URL=https://app.yourdomain.com
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

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:

# 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:

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

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.