Files
grateful-journal/docs/DEPLOYMENT.md
2026-03-23 10:41:25 +05:30

5.9 KiB

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

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

sudo apt install nginx certbot python3-certbot-nginx

Change docker-compose.yml to bind frontend to localhost only:

ports:
  - "127.0.0.1:8000:80"

Create /etc/nginx/sites-available/grateful-journal:

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:

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

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)

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

mongo:
  image: mongo:6
  environment:
    MONGO_INITDB_ROOT_USERNAME: admin
    MONGO_INITDB_ROOT_PASSWORD: your_strong_password
  ...

backend/.env — update the connection string:

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:

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

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