chore(deploy): prod deploy config

This commit is contained in:
2025-09-12 14:57:04 +01:00
parent 9ac071764e
commit d1208fa8b0
4 changed files with 246 additions and 0 deletions

5
deploy/.env.example Normal file
View File

@@ -0,0 +1,5 @@
# Database
POSTGRES_PASSWORD=your_secure_password_here
# Cloudflare Tunnel token from Zero Trust dashboard
CLOUDFLARE_TUNNEL_TOKEN=your_tunnel_token_here

77
deploy/docker-compose.yml Normal file
View File

@@ -0,0 +1,77 @@
services:
db:
image: postgres:16-alpine
container_name: codetutor-db
environment:
POSTGRES_USER: codetutor
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is required}
POSTGRES_DB: codetutor
volumes:
- ./data/postgres:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U codetutor"]
interval: 10s
timeout: 5s
retries: 5
restart: unless-stopped
networks:
- internal
backend:
build:
context: ../backend
dockerfile: Dockerfile
container_name: codetutor-backend
environment:
DATABASE_URL: postgresql+asyncpg://codetutor:${POSTGRES_PASSWORD}@db:5432/codetutor
CORS_ORIGINS: '["https://codetutor-demo.kschappell.com", "https://kschappell.com"]'
depends_on:
db:
condition: service_healthy
restart: unless-stopped
networks:
- internal
frontend:
build:
context: ../frontend
dockerfile: Dockerfile
container_name: codetutor-frontend
environment:
NEXT_PUBLIC_API_URL: https://codetutor-demo.kschappell.com
depends_on:
- backend
restart: unless-stopped
networks:
- internal
nginx:
image: nginx:alpine
container_name: codetutor-nginx
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
depends_on:
- frontend
- backend
restart: unless-stopped
networks:
- internal
- public-network
cloudflared:
image: cloudflare/cloudflared:latest
container_name: codetutor-cloudflared
command: tunnel run
environment:
TUNNEL_TOKEN: ${CLOUDFLARE_TUNNEL_TOKEN:?CLOUDFLARE_TUNNEL_TOKEN is required}
depends_on:
- nginx
restart: unless-stopped
networks:
- public-network
networks:
internal:
driver: bridge
public-network:
external: true

50
deploy/nginx.conf Normal file
View File

@@ -0,0 +1,50 @@
events {
worker_connections 1024;
}
http {
upstream frontend {
server frontend:3000;
}
upstream backend {
server backend:8000;
}
server {
listen 80;
server_name _;
# Allow iframe embedding from portfolio
add_header Content-Security-Policy "frame-ancestors 'self' https://kschappell.com https://*.kschappell.com" always;
# API routes to backend
location /api {
proxy_pass http://backend;
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;
}
# Everything else to frontend
location / {
proxy_pass http://frontend;
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;
# WebSocket support for Next.js HMR (dev) and any real-time features
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
# Health check endpoint
location /health {
return 200 'OK';
add_header Content-Type text/plain;
}
}
}

114
deploy/readme.md Normal file
View File

@@ -0,0 +1,114 @@
# CodeTutor Deployment
Production deployment configuration using Docker Compose and Cloudflare Tunnel.
## Architecture
```
Internet -> Cloudflare Tunnel -> nginx -> frontend (Next.js)
\-> backend (FastAPI)
\-> PostgreSQL
```
## Prerequisites
- Docker and Docker Compose
- Cloudflare account with Zero Trust access
- External Docker network: `public-network`
Create the external network if it doesn't exist:
```bash
docker network create public-network
```
## Setup
### 1. Configure Environment
```bash
cp .env.example .env
```
Edit `.env` with:
- `POSTGRES_PASSWORD`: Strong password for the database
- `CLOUDFLARE_TUNNEL_TOKEN`: Token from Cloudflare Zero Trust dashboard
### 2. Create Cloudflare Tunnel
1. Go to [Cloudflare Zero Trust Dashboard](https://one.dash.cloudflare.com/)
2. Navigate to Networks > Tunnels
3. Create a new tunnel named `codetutor-demo`
4. Add public hostname:
- Subdomain: `codetutor-demo`
- Domain: `kschappell.com`
- Service: `http://nginx:80`
5. Copy the tunnel token to your `.env` file
### 3. Deploy
```bash
docker compose up -d --build
```
### 4. Verify
- Check service health: `docker compose ps`
- View logs: `docker compose logs -f`
- Test endpoint: `curl https://codetutor-demo.kschappell.com/health`
## Database Management
### Initial Setup
The database is automatically created on first run. To seed with initial data:
```bash
docker compose exec backend python -m alembic upgrade head
docker compose exec backend python -m scripts.seed_db
```
### Backups
```bash
docker compose exec db pg_dump -U codetutor codetutor > backup.sql
```
### Restore
```bash
docker compose exec -T db psql -U codetutor codetutor < backup.sql
```
## Updating
```bash
git pull
docker compose up -d --build
```
## Troubleshooting
### Services not starting
Check logs for specific service:
```bash
docker compose logs backend
docker compose logs frontend
docker compose logs nginx
```
### Database connection issues
Ensure the database is healthy:
```bash
docker compose ps db
docker compose logs db
```
### Tunnel not connecting
Verify the tunnel token is correct and the tunnel is active in the Cloudflare dashboard.