diff --git a/docs/DEPLOYMENT.md b/docs/DEPLOYMENT.md new file mode 100644 index 0000000..86f446d --- /dev/null +++ b/docs/DEPLOYMENT.md @@ -0,0 +1,219 @@ +# Deployment Guide for Grateful Journal + +## Overview + +This guide covers deploying the Grateful Journal Docker stack to a production server. The app requires HTTPS — the Web Crypto API used for end-to-end encryption is blocked by browsers on plain HTTP. + +--- + +## Deployment Options + +### Option 1: VPS (Recommended) — DigitalOcean, Hetzner, Linode, Vultr + +Full control. Run Docker Compose directly on the server behind a reverse proxy. + +**Minimum specs:** 1 vCPU, 1 GB RAM, 20 GB disk + +**Steps:** +1. Provision a server running Ubuntu 22.04+ +2. Install Docker and Docker Compose +3. Point your domain DNS A record to the server IP +4. Set up a reverse proxy with SSL (see Reverse Proxy section below) +5. Clone the repo and configure environment files +6. Run `docker compose up --build -d` + +--- + +### Option 2: Railway / Render / Fly.io + +Platform-as-a-service. Easier setup but less control. These platforms handle SSL automatically. + +- **Railway** — supports Docker Compose directly, good free tier +- **Render** — supports Docker, free tier available but spins down on inactivity +- **Fly.io** — supports Docker, generous free tier, good global distribution + +Note: MongoDB on these platforms should be replaced with MongoDB Atlas (managed) since persistent volumes can be unreliable on free tiers. + +--- + +### Option 3: Cloud VM (AWS EC2, GCP Compute, Azure VM) + +Same as VPS but on a major cloud provider. More expensive for small apps but useful if you're already in that ecosystem. + +--- + +## Reverse Proxy Setup (Required for HTTPS) + +The frontend container must not be exposed directly. A reverse proxy handles SSL termination and forwards traffic to the frontend container. + +### Using Nginx + Certbot (Let's Encrypt) + +Install on the host (not inside Docker): + +```bash +sudo apt install nginx certbot python3-certbot-nginx +``` + +Change `docker-compose.yml` to bind frontend to localhost only: + +```yaml +ports: + - "127.0.0.1:8000:80" +``` + +Create `/etc/nginx/sites-available/grateful-journal`: + +```nginx +server { + listen 80; + server_name yourdomain.com; + + 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; + } +} +``` + +Enable and get SSL certificate: + +```bash +sudo ln -s /etc/nginx/sites-available/grateful-journal /etc/nginx/sites-enabled/ +sudo certbot --nginx -d yourdomain.com +sudo systemctl reload nginx +``` + +Certbot auto-renews the certificate. Done — the app is now on HTTPS. + +### Using Traefik (Docker-native alternative) + +Traefik runs as a Docker container and handles SSL automatically via Let's Encrypt. Better if you want everything inside Docker. Requires adding a `traefik` service to `docker-compose.yml` with labels on the frontend service. + +--- + +## Environment Changes for Production + +### `backend/.env` + +```env +MONGODB_URI=mongodb://mongo:27017 +MONGODB_DB_NAME=grateful_journal +API_PORT=8001 +ENVIRONMENT=production +FRONTEND_URL=https://yourdomain.com +``` + +- Change `FRONTEND_URL` to your actual domain with `https://` +- This is used for CORS — must match exactly what the browser sends as the Origin header + +### Root `.env` (frontend build args) + +```env +VITE_FIREBASE_API_KEY=... +VITE_FIREBASE_AUTH_DOMAIN=... +VITE_FIREBASE_PROJECT_ID=... +VITE_FIREBASE_STORAGE_BUCKET=... +VITE_FIREBASE_MESSAGING_SENDER_ID=... +VITE_FIREBASE_APP_ID=... +VITE_API_URL=/api +``` + +- `VITE_API_URL=/api` stays as-is — nginx proxy handles routing +- Firebase keys stay the same unless you create a separate Firebase project for production + +--- + +## Firebase Configuration + +Firebase requires your production domain to be added as an **authorized domain** for Google Sign-In. + +1. Go to [Firebase Console](https://console.firebase.google.com) +2. Select your project → Authentication → Settings → Authorized domains +3. Add `yourdomain.com` + +Without this, Google sign-in will fail on the production domain. + +--- + +## MongoDB Security + +The current setup has no MongoDB authentication — fine for local dev, not for production. + +Add a MongoDB username and password: + +### `docker-compose.yml` — add environment to mongo service: + +```yaml +mongo: + image: mongo:6 + environment: + MONGO_INITDB_ROOT_USERNAME: admin + MONGO_INITDB_ROOT_PASSWORD: your_strong_password + ... +``` + +### `backend/.env` — update the connection string: + +```env +MONGODB_URI=mongodb://admin:your_strong_password@mongo:27017 +``` + +Use a strong random password. Store it securely (not in git). + +--- + +## Keeping Secrets Out of Git + +Never commit `.env` files with real credentials. Before deploying: + +- Add `.env` and `backend/.env` to `.gitignore` (already done) +- On the server, create the `.env` files manually or via a secrets manager +- Use environment variables injected by the platform if using Railway/Render/Fly.io + +--- + +## Data Backups + +MongoDB data lives in the `mongo_data` Docker volume. Back it up regularly: + +```bash +# Dump +docker exec grateful-journal-mongo-1 mongodump --out /data/backup +docker cp grateful-journal-mongo-1:/data/backup ./mongo-backup + +# Restore +docker cp ./mongo-backup grateful-journal-mongo-1:/data/backup +docker exec grateful-journal-mongo-1 mongorestore /data/backup +``` + +For automated backups, set up a cron job or use MongoDB Atlas which has built-in backups. + +--- + +## Deploying Updates + +After pushing code changes to the server: + +```bash +git pull +docker compose up --build -d +``` + +This rebuilds only changed images and replaces containers with zero manual steps. + +--- + +## Pre-Deployment Checklist + +- [ ] Domain DNS pointing to server IP +- [ ] HTTPS set up via reverse proxy +- [ ] `FRONTEND_URL` updated to production domain in `backend/.env` +- [ ] Production domain added to Firebase authorized domains +- [ ] MongoDB authentication enabled +- [ ] `.env` files not committed to git +- [ ] `docker-compose.yml` frontend port bound to `127.0.0.1:8000:80` +- [ ] MongoDB backup strategy in place