chore(deploy): prod deploy config
This commit is contained in:
5
deploy/.env.example
Normal file
5
deploy/.env.example
Normal 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
77
deploy/docker-compose.yml
Normal 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
50
deploy/nginx.conf
Normal 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
114
deploy/readme.md
Normal 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.
|
||||
Reference in New Issue
Block a user