1079 lines
23 KiB
Markdown
1079 lines
23 KiB
Markdown
# Looking - Production Deployment Guide
|
|
|
|
> **Complete guide to deploying the Looking application to production**
|
|
|
|
This document covers building Docker images, configuring Traefik reverse proxy, setting up SSL certificates with Let's Encrypt, managing environment variables, and backup/restore procedures.
|
|
|
|
---
|
|
|
|
## 📋 Table of Contents
|
|
|
|
- [Overview](#overview)
|
|
- [Prerequisites](#prerequisites)
|
|
- [Architecture](#architecture)
|
|
- [Pre-Deployment Checklist](#pre-deployment-checklist)
|
|
- [Building Docker Images](#building-docker-images)
|
|
- [Environment Variables](#environment-variables)
|
|
- [Deployment](#deployment)
|
|
- [Traefik Configuration](#traefik-configuration)
|
|
- [SSL/TLS Certificates](#ssltls-certificates)
|
|
- [Domain Configuration](#domain-configuration)
|
|
- [Database Management](#database-management)
|
|
- [Backup and Restore](#backup-and-restore)
|
|
- [Monitoring and Logs](#monitoring-and-logs)
|
|
- [Rollback Procedures](#rollback-procedures)
|
|
- [Troubleshooting](#troubleshooting)
|
|
|
|
---
|
|
|
|
## 🎯 Overview
|
|
|
|
The production deployment uses **Docker Compose** with:
|
|
|
|
- **Traefik** - Reverse proxy and load balancer
|
|
- **Let's Encrypt** - Automatic SSL certificate management
|
|
- **Docker Volumes** - Persistent storage for database and images
|
|
- **Custom Networks** - Isolated backend and external traffic separation
|
|
|
|
**Production Domains**:
|
|
|
|
- **Frontend**: https://pfosi.mifi.dev
|
|
- **Backend API**: https://api.pfosi.mifi.dev
|
|
- **Database Admin**: https://mongo.pfosi.mifi.dev
|
|
|
|
---
|
|
|
|
## ✅ Prerequisites
|
|
|
|
### Server Requirements
|
|
|
|
- **OS**: Linux (Ubuntu 20.04+ or Debian 11+ recommended)
|
|
- **CPU**: 2+ cores
|
|
- **RAM**: 4GB+ (8GB recommended)
|
|
- **Disk**: 20GB+ free space
|
|
- **Docker**: 20.10+ with Docker Compose v2
|
|
- **Network**: Public IP address
|
|
- **Ports**: 80 (HTTP), 443 (HTTPS) open to internet
|
|
|
|
### Domain Setup
|
|
|
|
1. **Register domains**:
|
|
|
|
- `pfosi.mifi.dev` (frontend)
|
|
- `api.pfosi.mifi.dev` (backend)
|
|
- `mongo.pfosi.mifi.dev` (admin panel)
|
|
|
|
2. **DNS Configuration**:
|
|
|
|
- Point all domains to your server's public IP
|
|
- Use A records:
|
|
```
|
|
pfosi.mifi.dev A <server-ip>
|
|
api.pfosi.mifi.dev A <server-ip>
|
|
mongo.pfosi.mifi.dev A <server-ip>
|
|
```
|
|
|
|
3. **Wait for DNS propagation** (can take up to 24-48 hours, usually minutes)
|
|
```bash
|
|
dig pfosi.mifi.dev
|
|
dig api.pfosi.mifi.dev
|
|
```
|
|
|
|
### Software Requirements
|
|
|
|
```bash
|
|
# Install Docker and Docker Compose
|
|
curl -fsSL https://get.docker.com -o get-docker.sh
|
|
sudo sh get-docker.sh
|
|
sudo usermod -aG docker $USER
|
|
|
|
# Verify installation
|
|
docker --version
|
|
docker compose version
|
|
```
|
|
|
|
### Traefik Setup
|
|
|
|
This deployment assumes you have **Traefik already running** with:
|
|
|
|
- External network: `marina-net`
|
|
- Let's Encrypt configured
|
|
- Ports 80/443 exposed
|
|
|
|
If you don't have Traefik, see [Traefik Configuration](#traefik-configuration) section.
|
|
|
|
---
|
|
|
|
## 🏗️ Architecture
|
|
|
|
```
|
|
┌───────────────────────────────────────────────────────────────┐
|
|
│ Internet │
|
|
└────────────────────────────┬──────────────────────────────────┘
|
|
│
|
|
Port 80/443
|
|
│
|
|
┌────────────────────────────▼──────────────────────────────────┐
|
|
│ Traefik (Reverse Proxy) │
|
|
│ - SSL Termination (Let's Encrypt) │
|
|
│ - HTTP → HTTPS Redirect │
|
|
│ - Domain Routing │
|
|
│ - CORS Headers │
|
|
└──────┬─────────────────┬────────────────────┬─────────────────┘
|
|
│ │ │
|
|
│ marina-net │ marina-net │ marina-net
|
|
│ (external) │ (external) │ (external)
|
|
│ │ │
|
|
┌──────▼─────────┐ ┌────▼──────────┐ ┌─────▼──────────────┐
|
|
│ Frontend │ │ Backend │ │ Mongo Express │
|
|
│ (Nginx) │ │ (Express) │ │ (Web UI) │
|
|
│ │ │ │ │ │
|
|
│ Port: 80 │ │ Port: 3069 │ │ Port: 8081 │
|
|
│ (internal) │ │ (internal) │ │ (internal) │
|
|
│ │ │ │ │ │
|
|
│ Domain: │ │ Domain: │ │ Domain: │
|
|
│ pfosi. │ │ api.pfosi. │ │ mongo.pfosi. │
|
|
│ mifi.dev │ │ mifi.dev │ │ mifi.dev │
|
|
└────────────────┘ └────┬──────────┘ └─────┬──────────────┘
|
|
│ │
|
|
│ backend-net │ backend-net
|
|
│ (internal) │ (internal)
|
|
│ │
|
|
┌────▼────────────────────▼────┐
|
|
│ MongoDB 4.4 │
|
|
│ │
|
|
│ Port: 27017 (internal) │
|
|
│ Database: urge │
|
|
│ │
|
|
│ Volume: mongo_data │
|
|
│ (persistent storage) │
|
|
└─────────────────────────────┘
|
|
│
|
|
┌─────────▼──────────┐
|
|
│ api_images volume │
|
|
│ (profile/message │
|
|
│ image storage) │
|
|
└────────────────────┘
|
|
```
|
|
|
|
### Network Topology
|
|
|
|
| Network | Type | Purpose |
|
|
| --------------- | -------- | --------------------------------------------------------- |
|
|
| **marina-net** | External | Traefik-to-services communication, public internet access |
|
|
| **backend-net** | Internal | Services-to-MongoDB communication, isolated from internet |
|
|
|
|
---
|
|
|
|
## 📝 Pre-Deployment Checklist
|
|
|
|
### 1. Update Seed Data
|
|
|
|
⚠️ **CRITICAL**: Database is wiped and reseeded on each deployment.
|
|
|
|
**Edit profile data**:
|
|
|
|
```bash
|
|
nano backend/data/profiles.json
|
|
```
|
|
|
|
**Add images**:
|
|
|
|
```bash
|
|
cp new-profile.jpg backend/src/images/profile/
|
|
```
|
|
|
|
**Commit changes**:
|
|
|
|
```bash
|
|
git add backend/data/profiles.json backend/src/images/
|
|
git commit -m "Update profile data for deployment"
|
|
git push
|
|
```
|
|
|
|
---
|
|
|
|
### 2. Set Environment Variables
|
|
|
|
Create `.env` file in project root:
|
|
|
|
```bash
|
|
cp backend/.env.example .env
|
|
nano .env
|
|
```
|
|
|
|
**Required variables** (see [Environment Variables](#environment-variables) section):
|
|
|
|
- JWT_SECRET
|
|
- GOOGLE_MAPS_API_KEY
|
|
- MAIL_HOST, MAIL_PORT, MAIL_USER, MAIL_PASS
|
|
- MONGO_ROOT_USER, MONGO_ROOT_PASSWORD
|
|
- MONGO_EXPRESS_USER, MONGO_EXPRESS_PASSWORD
|
|
|
|
---
|
|
|
|
### 3. Update Docker Compose
|
|
|
|
**Edit [docker-compose.yml](docker-compose.yml)**:
|
|
|
|
Update image registry URLs:
|
|
|
|
```yaml
|
|
image: git.mifi.dev:12023/mifi/pfosi-looking-frontend:latest
|
|
# Change to your registry
|
|
```
|
|
|
|
Update domains in Traefik labels:
|
|
|
|
```yaml
|
|
- "traefik.http.routers.looking-frontend.rule=Host(`pfosi.mifi.dev`)"
|
|
# Change to your domain
|
|
```
|
|
|
|
---
|
|
|
|
### 4. Test Locally
|
|
|
|
```bash
|
|
# Build images
|
|
npm run docker:build
|
|
|
|
# Test services
|
|
docker-compose up -d
|
|
|
|
# Verify services
|
|
curl http://localhost:80 # Frontend
|
|
curl http://localhost:3069/profiles # Backend
|
|
```
|
|
|
|
---
|
|
|
|
## 🐳 Building Docker Images
|
|
|
|
### Frontend Dockerfile
|
|
|
|
**File**: `app/Dockerfile` (must be created)
|
|
|
|
```dockerfile
|
|
# Stage 1: Build
|
|
FROM node:14-bullseye AS builder
|
|
|
|
WORKDIR /app
|
|
COPY package*.json ./
|
|
RUN npm install --legacy-peer-deps
|
|
|
|
COPY . .
|
|
RUN npm run build
|
|
|
|
# Stage 2: Production
|
|
FROM nginx:alpine
|
|
|
|
COPY --from=builder /app/www /usr/share/nginx/html
|
|
COPY nginx.conf /etc/nginx/nginx.conf
|
|
|
|
EXPOSE 80
|
|
CMD ["nginx", "-g", "daemon off;"]
|
|
```
|
|
|
|
**Create `app/nginx.conf`**:
|
|
|
|
```nginx
|
|
server {
|
|
listen 80;
|
|
server_name _;
|
|
root /usr/share/nginx/html;
|
|
index index.html;
|
|
|
|
location / {
|
|
try_files $uri $uri/ /index.html;
|
|
}
|
|
|
|
location /assets {
|
|
expires 1y;
|
|
add_header Cache-Control "public, immutable";
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### Backend Dockerfile
|
|
|
|
**File**: `backend/Dockerfile`
|
|
|
|
```dockerfile
|
|
FROM node:14-bullseye
|
|
|
|
WORKDIR /app
|
|
|
|
COPY package*.json ./
|
|
RUN npm install --production
|
|
|
|
COPY . .
|
|
|
|
EXPOSE 3069
|
|
|
|
CMD ["node", "src/bin/www"]
|
|
```
|
|
|
|
---
|
|
|
|
### Build Commands
|
|
|
|
**Build both images**:
|
|
|
|
```bash
|
|
npm run docker:build
|
|
```
|
|
|
|
**Or build individually**:
|
|
|
|
```bash
|
|
# Frontend
|
|
docker build -t pfosi-looking-frontend:latest ./app
|
|
|
|
# Backend
|
|
docker build -t pfosi-looking-backend:latest ./backend
|
|
```
|
|
|
|
---
|
|
|
|
### Push to Registry
|
|
|
|
If using a private registry:
|
|
|
|
```bash
|
|
# Tag images
|
|
docker tag pfosi-looking-frontend:latest git.mifi.dev:12023/mifi/pfosi-looking-frontend:latest
|
|
docker tag pfosi-looking-backend:latest git.mifi.dev:12023/mifi/pfosi-looking-backend:latest
|
|
|
|
# Login to registry
|
|
docker login git.mifi.dev:12023
|
|
|
|
# Push images
|
|
docker push git.mifi.dev:12023/mifi/pfosi-looking-frontend:latest
|
|
docker push git.mifi.dev:12023/mifi/pfosi-looking-backend:latest
|
|
```
|
|
|
|
---
|
|
|
|
## 🔐 Environment Variables
|
|
|
|
### Production .env File
|
|
|
|
**Location**: Project root `.env` (NOT committed to Git)
|
|
|
|
```bash
|
|
# JWT Secret (generate with: openssl rand -base64 32)
|
|
JWT_SECRET=your-production-secret-min-32-chars-long
|
|
|
|
# Google Maps API
|
|
GOOGLE_MAPS_API_KEY=AIzaSyXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
|
|
|
# SMTP Configuration
|
|
MAIL_HOST=smtp.gmail.com
|
|
MAIL_PORT=587
|
|
MAIL_USER=support@example.com
|
|
MAIL_PASS=app-specific-password-here
|
|
|
|
# MongoDB Credentials
|
|
MONGO_ROOT_USER=admin
|
|
MONGO_ROOT_PASSWORD=strong-password-here
|
|
|
|
# Mongo Express Credentials
|
|
MONGO_EXPRESS_USER=admin
|
|
MONGO_EXPRESS_PASSWORD=different-strong-password
|
|
```
|
|
|
|
### Using Docker Secrets (Recommended)
|
|
|
|
For enhanced security, use Docker secrets:
|
|
|
|
```bash
|
|
# Create secrets
|
|
echo "strong-password" | docker secret create mongo_root_password -
|
|
echo "jwt-secret" | docker secret create jwt_secret -
|
|
|
|
# Update docker-compose.yml
|
|
secrets:
|
|
mongo_root_password:
|
|
external: true
|
|
jwt_secret:
|
|
external: true
|
|
|
|
services:
|
|
looking-backend:
|
|
secrets:
|
|
- jwt_secret
|
|
environment:
|
|
- JWT_SECRET_FILE=/run/secrets/jwt_secret
|
|
```
|
|
|
|
---
|
|
|
|
## 🚀 Deployment
|
|
|
|
### Deploy Services
|
|
|
|
```bash
|
|
# From project root
|
|
npm run deploy
|
|
|
|
# Or manually
|
|
docker-compose up -d
|
|
```
|
|
|
|
---
|
|
|
|
### Verify Deployment
|
|
|
|
```bash
|
|
# Check container status
|
|
docker-compose ps
|
|
|
|
# Should show:
|
|
# - looking-frontend (healthy)
|
|
# - looking-backend (healthy)
|
|
# - looking-mongo (healthy)
|
|
# - looking-mongo-express (healthy)
|
|
|
|
# View logs
|
|
docker-compose logs -f looking-backend
|
|
docker-compose logs -f looking-frontend
|
|
|
|
# Test endpoints
|
|
curl https://pfosi.mifi.dev
|
|
curl https://api.pfosi.mifi.dev/profiles
|
|
```
|
|
|
|
---
|
|
|
|
### Initial Database Seed
|
|
|
|
Database automatically seeds on first MongoDB startup:
|
|
|
|
```bash
|
|
# View MongoDB logs to confirm seeding
|
|
docker logs looking-mongo
|
|
|
|
# Or manually seed
|
|
docker exec -it looking-backend npm run seed
|
|
```
|
|
|
|
---
|
|
|
|
## 🔀 Traefik Configuration
|
|
|
|
If you don't have Traefik running, here's a basic setup.
|
|
|
|
### Create Traefik docker-compose.yml
|
|
|
|
**File**: `~/traefik/docker-compose.yml`
|
|
|
|
```yaml
|
|
version: "3.8"
|
|
|
|
services:
|
|
traefik:
|
|
image: traefik:v2.10
|
|
container_name: traefik
|
|
restart: unless-stopped
|
|
command:
|
|
- "--api.dashboard=true"
|
|
- "--providers.docker=true"
|
|
- "--providers.docker.exposedbydefault=false"
|
|
- "--entrypoints.web.address=:80"
|
|
- "--entrypoints.websecure.address=:443"
|
|
- "--certificatesresolvers.letsencrypt.acme.email=admin@yourdomain.com"
|
|
- "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json"
|
|
- "--certificatesresolvers.letsencrypt.acme.httpchallenge=true"
|
|
- "--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web"
|
|
ports:
|
|
- "80:80"
|
|
- "443:443"
|
|
volumes:
|
|
- /var/run/docker.sock:/var/run/docker.sock:ro
|
|
- traefik-letsencrypt:/letsencrypt
|
|
networks:
|
|
- marina-net
|
|
labels:
|
|
- "traefik.enable=true"
|
|
- "traefik.http.routers.traefik.rule=Host(`traefik.yourdomain.com`)"
|
|
- "traefik.http.routers.traefik.service=api@internal"
|
|
- "traefik.http.routers.traefik.tls.certresolver=letsencrypt"
|
|
- "traefik.http.middlewares.redirect-https.redirectscheme.scheme=https"
|
|
- "traefik.http.middlewares.redirect-https.redirectscheme.permanent=true"
|
|
- "traefik.http.routers.http-catchall.rule=hostregexp(`{host:.+}`)"
|
|
- "traefik.http.routers.http-catchall.entrypoints=web"
|
|
- "traefik.http.routers.http-catchall.middlewares=redirect-https"
|
|
|
|
volumes:
|
|
traefik-letsencrypt:
|
|
|
|
networks:
|
|
marina-net:
|
|
external: true
|
|
```
|
|
|
|
### Start Traefik
|
|
|
|
```bash
|
|
cd ~/traefik
|
|
docker network create marina-net
|
|
docker-compose up -d
|
|
```
|
|
|
|
---
|
|
|
|
## 🔒 SSL/TLS Certificates
|
|
|
|
### Let's Encrypt Configuration
|
|
|
|
**In docker-compose.yml Traefik labels**:
|
|
|
|
```yaml
|
|
labels:
|
|
- "traefik.http.routers.looking-frontend.tls=true"
|
|
- "traefik.http.routers.looking-frontend.tls.certresolver=letsencrypt"
|
|
```
|
|
|
|
**Certificate storage**: `/letsencrypt/acme.json` in Traefik container
|
|
|
|
**Renewal**: Automatic (Traefik handles renewals)
|
|
|
|
---
|
|
|
|
### Certificate Troubleshooting
|
|
|
|
**View certificate info**:
|
|
|
|
```bash
|
|
docker exec traefik cat /letsencrypt/acme.json | jq
|
|
```
|
|
|
|
**Force certificate renewal**:
|
|
|
|
```bash
|
|
# Delete acme.json and restart Traefik
|
|
docker exec traefik rm /letsencrypt/acme.json
|
|
docker restart traefik
|
|
```
|
|
|
|
**Let's Encrypt rate limits**:
|
|
|
|
- 50 certificates per domain per week
|
|
- Use staging server for testing:
|
|
```yaml
|
|
- "--certificatesresolvers.letsencrypt.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory"
|
|
```
|
|
|
|
---
|
|
|
|
## 🌐 Domain Configuration
|
|
|
|
### Traefik Labels
|
|
|
|
**Frontend**:
|
|
|
|
```yaml
|
|
labels:
|
|
- "traefik.http.routers.looking-frontend.rule=Host(`pfosi.mifi.dev`)"
|
|
- "traefik.http.services.looking-frontend.loadbalancer.server.port=80"
|
|
```
|
|
|
|
**Backend**:
|
|
|
|
```yaml
|
|
labels:
|
|
- "traefik.http.routers.looking-backend.rule=Host(`api.pfosi.mifi.dev`)"
|
|
- "traefik.http.services.looking-backend.loadbalancer.server.port=3069"
|
|
```
|
|
|
|
**Mongo Express**:
|
|
|
|
```yaml
|
|
labels:
|
|
- "traefik.http.routers.mongo-express.rule=Host(`mongo.pfosi.mifi.dev`)"
|
|
- "traefik.http.services.mongo-express.loadbalancer.server.port=8081"
|
|
```
|
|
|
|
---
|
|
|
|
### CORS Configuration
|
|
|
|
**Backend CORS middleware** (already in docker-compose.yml):
|
|
|
|
```yaml
|
|
labels:
|
|
- "traefik.http.routers.looking-backend.middlewares=api-cors"
|
|
- "traefik.http.middlewares.api-cors.headers.accesscontrolallowmethods=GET,OPTIONS,PUT,POST,DELETE,PATCH"
|
|
- "traefik.http.middlewares.api-cors.headers.accesscontrolalloworiginlist=https://pfosi.mifi.dev"
|
|
- "traefik.http.middlewares.api-cors.headers.accesscontrolallowcredentials=true"
|
|
- "traefik.http.middlewares.api-cors.headers.accesscontrolallowheaders=Origin,X-Requested-With,Content-Type,Accept,Authorization,Cache-Control"
|
|
```
|
|
|
|
**Key settings**:
|
|
|
|
- **Origin**: `https://pfosi.mifi.dev` (frontend domain only)
|
|
- **Credentials**: Enabled (for JWT cookies if used)
|
|
- **Methods**: Standard REST verbs + OPTIONS for preflight
|
|
|
|
---
|
|
|
|
## 💾 Database Management
|
|
|
|
### Current Workflow (Seed-Based)
|
|
|
|
⚠️ **Database is wiped and reseeded on each deployment**
|
|
|
|
**Steps**:
|
|
|
|
1. Edit `backend/data/profiles.json`
|
|
2. Commit changes to Git
|
|
3. Deploy (database drops and reloads)
|
|
|
|
**No user-generated content is preserved.**
|
|
|
|
---
|
|
|
|
### Future Interactive Workflow
|
|
|
|
**When the app becomes interactive** (user-generated content):
|
|
|
|
1. **Disable auto-seeding**:
|
|
|
|
- Remove seed data mount from docker-compose.yml
|
|
- Don't run `npm run seed` after initial deployment
|
|
|
|
2. **Implement backups** (see [Backup and Restore](#backup-and-restore))
|
|
|
|
3. **Add backup cron job**:
|
|
|
|
```bash
|
|
# /etc/cron.d/mongodb-backup
|
|
0 2 * * * /usr/local/bin/backup-mongodb.sh
|
|
```
|
|
|
|
4. **Test restore procedure** regularly
|
|
|
|
---
|
|
|
|
## 🔄 Backup and Restore
|
|
|
|
### Current State: Not Required
|
|
|
|
With seed-based workflow:
|
|
|
|
- All data is in `backend/data/profiles.json` (version controlled)
|
|
- No user-generated content
|
|
- Redeployment = fresh database
|
|
|
|
**No backups needed currently.**
|
|
|
|
---
|
|
|
|
### Future: When Interactive
|
|
|
|
**If app becomes interactive** with user-generated content, implement these procedures:
|
|
|
|
---
|
|
|
|
### Backup Procedure
|
|
|
|
**Create backup script**: `/usr/local/bin/backup-mongodb.sh`
|
|
|
|
```bash
|
|
#!/bin/bash
|
|
set -e
|
|
|
|
BACKUP_DIR="/backups/mongodb"
|
|
DATE=$(date +%Y%m%d_%H%M%S)
|
|
BACKUP_FILE="$BACKUP_DIR/urge_$DATE.gz"
|
|
|
|
# Create backup directory
|
|
mkdir -p "$BACKUP_DIR"
|
|
|
|
# Dump database
|
|
docker exec looking-mongo mongodump \
|
|
--db=urge \
|
|
--archive | gzip > "$BACKUP_FILE"
|
|
|
|
# Keep last 30 days of backups
|
|
find "$BACKUP_DIR" -name "urge_*.gz" -mtime +30 -delete
|
|
|
|
echo "Backup completed: $BACKUP_FILE"
|
|
```
|
|
|
|
**Make executable**:
|
|
|
|
```bash
|
|
chmod +x /usr/local/bin/backup-mongodb.sh
|
|
```
|
|
|
|
---
|
|
|
|
### Restore Procedure
|
|
|
|
**Restore from backup**:
|
|
|
|
```bash
|
|
# List backups
|
|
ls -lh /backups/mongodb/
|
|
|
|
# Restore specific backup
|
|
gunzip < /backups/mongodb/urge_20240115_020000.gz | \
|
|
docker exec -i looking-mongo mongorestore --archive --db=urge
|
|
```
|
|
|
|
---
|
|
|
|
### Volume Snapshots
|
|
|
|
**Backup Docker volume directly**:
|
|
|
|
```bash
|
|
# Stop services (optional, for consistency)
|
|
docker-compose stop looking-backend
|
|
|
|
# Create volume backup
|
|
docker run --rm \
|
|
-v pfosi-looking-monorepo_mongo_data:/data \
|
|
-v /backups:/backup \
|
|
alpine tar czf /backup/mongo_data_$(date +%Y%m%d).tar.gz /data
|
|
|
|
# Restart services
|
|
docker-compose start looking-backend
|
|
```
|
|
|
|
**Restore volume**:
|
|
|
|
```bash
|
|
# Stop all services
|
|
docker-compose down
|
|
|
|
# Restore volume
|
|
docker run --rm \
|
|
-v pfosi-looking-monorepo_mongo_data:/data \
|
|
-v /backups:/backup \
|
|
alpine sh -c "rm -rf /data/* && tar xzf /backup/mongo_data_20240115.tar.gz -C /"
|
|
|
|
# Start services
|
|
docker-compose up -d
|
|
```
|
|
|
|
---
|
|
|
|
### Backup Image Uploads
|
|
|
|
**Backup `api_images` volume**:
|
|
|
|
```bash
|
|
docker run --rm \
|
|
-v pfosi-looking-monorepo_api_images:/data \
|
|
-v /backups:/backup \
|
|
alpine tar czf /backup/api_images_$(date +%Y%m%d).tar.gz /data
|
|
```
|
|
|
|
**Restore**:
|
|
|
|
```bash
|
|
docker run --rm \
|
|
-v pfosi-looking-monorepo_api_images:/data \
|
|
-v /backups:/backup \
|
|
alpine sh -c "rm -rf /data/* && tar xzf /backup/api_images_20240115.tar.gz -C /"
|
|
```
|
|
|
|
---
|
|
|
|
## 📊 Monitoring and Logs
|
|
|
|
### View Logs
|
|
|
|
**All services**:
|
|
|
|
```bash
|
|
docker-compose logs -f
|
|
```
|
|
|
|
**Specific service**:
|
|
|
|
```bash
|
|
docker-compose logs -f looking-backend
|
|
docker-compose logs -f looking-frontend
|
|
docker-compose logs -f looking-mongo
|
|
```
|
|
|
|
**With timestamps**:
|
|
|
|
```bash
|
|
docker-compose logs -f --timestamps looking-backend
|
|
```
|
|
|
|
---
|
|
|
|
### Container Status
|
|
|
|
```bash
|
|
# Check running containers
|
|
docker-compose ps
|
|
|
|
# Resource usage
|
|
docker stats
|
|
```
|
|
|
|
---
|
|
|
|
### MongoDB Logs
|
|
|
|
```bash
|
|
# View MongoDB logs
|
|
docker logs looking-mongo
|
|
|
|
# Follow logs
|
|
docker logs -f looking-mongo
|
|
|
|
# Search logs
|
|
docker logs looking-mongo 2>&1 | grep ERROR
|
|
```
|
|
|
|
---
|
|
|
|
### Application Logs
|
|
|
|
**Backend** (Winston logger):
|
|
|
|
- Console output via `docker-compose logs`
|
|
- File logs: `backend/logs/` (if configured)
|
|
|
|
**Nginx** (Frontend):
|
|
|
|
```bash
|
|
docker exec looking-frontend cat /var/log/nginx/access.log
|
|
docker exec looking-frontend cat /var/log/nginx/error.log
|
|
```
|
|
|
|
---
|
|
|
|
### Health Checks
|
|
|
|
**MongoDB**:
|
|
|
|
```bash
|
|
docker exec looking-mongo mongo --eval "db.adminCommand('ping')"
|
|
```
|
|
|
|
**Backend API**:
|
|
|
|
```bash
|
|
curl https://api.pfosi.mifi.dev/profiles
|
|
```
|
|
|
|
**Frontend**:
|
|
|
|
```bash
|
|
curl https://pfosi.mifi.dev
|
|
```
|
|
|
|
---
|
|
|
|
## ⏪ Rollback Procedures
|
|
|
|
### Quick Rollback
|
|
|
|
**1. Identify previous image version**:
|
|
|
|
```bash
|
|
docker images | grep pfosi-looking
|
|
```
|
|
|
|
**2. Update docker-compose.yml**:
|
|
|
|
```yaml
|
|
image: git.mifi.dev:12023/mifi/pfosi-looking-backend:previous-tag
|
|
```
|
|
|
|
**3. Redeploy**:
|
|
|
|
```bash
|
|
docker-compose up -d looking-backend
|
|
```
|
|
|
|
---
|
|
|
|
### Full Rollback with Database
|
|
|
|
**1. Stop services**:
|
|
|
|
```bash
|
|
docker-compose down
|
|
```
|
|
|
|
**2. Restore database backup** (if needed):
|
|
|
|
```bash
|
|
gunzip < /backups/mongodb/urge_previous.gz | \
|
|
docker exec -i looking-mongo mongorestore --archive --db=urge
|
|
```
|
|
|
|
**3. Deploy previous version**:
|
|
|
|
```bash
|
|
git checkout <previous-commit>
|
|
npm run deploy
|
|
```
|
|
|
|
---
|
|
|
|
### Emergency Rollback
|
|
|
|
**Restore from Git**:
|
|
|
|
```bash
|
|
# Clone fresh copy
|
|
git clone <repository-url> PfosiLooking-monorepo-backup
|
|
cd PfosiLooking-monorepo-backup
|
|
git checkout <known-good-commit>
|
|
|
|
# Deploy
|
|
npm run docker:build
|
|
npm run deploy
|
|
```
|
|
|
|
---
|
|
|
|
## 🔧 Troubleshooting
|
|
|
|
### Services Won't Start
|
|
|
|
**Check logs**:
|
|
|
|
```bash
|
|
docker-compose logs
|
|
```
|
|
|
|
**Verify network exists**:
|
|
|
|
```bash
|
|
docker network ls | grep marina-net
|
|
|
|
# Create if missing
|
|
docker network create marina-net
|
|
```
|
|
|
|
**Check disk space**:
|
|
|
|
```bash
|
|
df -h
|
|
docker system df
|
|
```
|
|
|
|
---
|
|
|
|
### SSL Certificate Issues
|
|
|
|
**Domain not resolving**:
|
|
|
|
```bash
|
|
dig pfosi.mifi.dev
|
|
nslookup pfosi.mifi.dev
|
|
```
|
|
|
|
**Certificate not issued**:
|
|
|
|
```bash
|
|
# Check Traefik logs
|
|
docker logs traefik | grep -i acme
|
|
|
|
# Verify domain is reachable
|
|
curl -I http://pfosi.mifi.dev
|
|
```
|
|
|
|
**Rate limit errors**:
|
|
|
|
- Use Let's Encrypt staging server for testing
|
|
- Wait 1 week if hit production limit
|
|
|
|
---
|
|
|
|
### Database Connection Errors
|
|
|
|
**Backend can't reach MongoDB**:
|
|
|
|
```bash
|
|
# Verify MongoDB is on backend-net
|
|
docker network inspect pfosi-looking-monorepo_backend-net
|
|
|
|
# Test connection from backend
|
|
docker exec looking-backend nc -zv mongo 27017
|
|
```
|
|
|
|
**Wrong credentials**:
|
|
|
|
```bash
|
|
# Check environment variables
|
|
docker exec looking-backend env | grep MONGO
|
|
```
|
|
|
|
---
|
|
|
|
### CORS Errors
|
|
|
|
**Browser shows CORS error**:
|
|
|
|
1. **Verify Traefik middleware**:
|
|
|
|
```bash
|
|
docker exec traefik cat /etc/traefik/dynamic.conf
|
|
```
|
|
|
|
2. **Check allowed origin**:
|
|
|
|
```yaml
|
|
accesscontrolalloworiginlist=https://pfosi.mifi.dev
|
|
# Must match frontend domain exactly
|
|
```
|
|
|
|
3. **Test with curl**:
|
|
```bash
|
|
curl -H "Origin: https://pfosi.mifi.dev" \
|
|
-H "Access-Control-Request-Method: POST" \
|
|
-H "Access-Control-Request-Headers: Content-Type" \
|
|
-X OPTIONS https://api.pfosi.mifi.dev/profiles
|
|
```
|
|
|
|
---
|
|
|
|
### Image Upload Failures
|
|
|
|
**Volume permissions**:
|
|
|
|
```bash
|
|
# Check volume exists
|
|
docker volume ls | grep api_images
|
|
|
|
# Inspect volume
|
|
docker volume inspect pfosi-looking-monorepo_api_images
|
|
```
|
|
|
|
**Directory writable**:
|
|
|
|
```bash
|
|
docker exec looking-backend ls -la /app/src/images
|
|
docker exec looking-backend touch /app/src/images/test
|
|
```
|
|
|
|
---
|
|
|
|
## 📚 Related Documentation
|
|
|
|
- **[Root README](README.md)** - Project overview
|
|
- **[Backend README](backend/README.md)** - API server setup
|
|
- **[Frontend README](app/README.md)** - Ionic app setup
|
|
- **[DevContainer Guide](.devcontainer/README.md)** - Development environment
|
|
- **[API Reference](backend/API.md)** - REST API endpoints
|
|
- **[Database Schema](backend/SCHEMA.md)** - MongoDB collections
|
|
|
|
---
|
|
|
|
**Need Help?** Check individual component documentation or [open an issue](your-repository-issues-url) for deployment-specific problems.
|