From 333de65fbd0da3708c048b3d094b96262219fd89 Mon Sep 17 00:00:00 2001 From: "mamonov.ep" Date: Mon, 12 Jan 2026 11:02:33 +0300 Subject: [PATCH] Add nginx reverse proxy and environment configuration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add nginx.conf for proxying API requests to backend - Update frontend Dockerfile for production build with nginx - Move hardcoded values to .env variables in docker-compose.yml - Add .env.example template for configuration 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .env.example | 58 +++++++++++++++++++++++++++++ docker-compose.yml | 29 +++++++++------ frontend/Dockerfile | 20 +++++----- nginx/nginx.conf | 90 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 175 insertions(+), 22 deletions(-) create mode 100644 .env.example create mode 100644 nginx/nginx.conf diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..e3392bc --- /dev/null +++ b/.env.example @@ -0,0 +1,58 @@ +# =========================================== +# Anime Quiz - Environment Configuration +# =========================================== +# Copy this file to .env and fill in your values + +# PostgreSQL Database +POSTGRES_USER=animequiz +POSTGRES_PASSWORD=your_secure_password_here +POSTGRES_DB=animequiz + +# Database connection (for backend) +# Format: postgresql+asyncpg://USER:PASSWORD@HOST:PORT/DB +DATABASE_URL=postgresql+asyncpg://animequiz:your_secure_password_here@db:5432/animequiz + +# =========================================== +# S3 Storage Configuration +# =========================================== +S3_ENDPOINT=https://s3.firstvds.ru +S3_ACCESS_KEY=your_access_key_here +S3_SECRET_KEY=your_secret_key_here +S3_REGION=default +S3_BUCKET=anime-quiz + +# =========================================== +# Paths Configuration +# =========================================== +OUTPUT_PATH=/app/output/videos +TEMP_PATH=/tmp/anime_quiz +CACHE_PATH=/tmp/anime_quiz/cache + +# =========================================== +# Video Settings +# =========================================== +SHORTS_WIDTH=1080 +SHORTS_HEIGHT=1920 +FULL_WIDTH=1920 +FULL_HEIGHT=1080 + +# Timing (seconds) +ANSWER_DURATION=5.0 +FINAL_SCREEN_DURATION=3.0 +AUDIO_BUFFER=1.0 +AUDIO_FADE_DURATION=0.7 + +# =========================================== +# Openings Downloader Settings +# =========================================== +DOWNLOADER_SHIKIMORI_USER_AGENT=AnimeQuiz/1.0 +DOWNLOADER_SHIKIMORI_TOKEN=your_shikimori_oauth_token_here +DOWNLOADER_S3_STORAGE_LIMIT_BYTES=107374182400 +DOWNLOADER_DOWNLOAD_TIMEOUT_SECONDS=300 +DOWNLOADER_DEFAULT_ESTIMATED_SIZE_BYTES=6291456 + +# =========================================== +# Ports Configuration +# =========================================== +APP_PORT=5001 +DB_PORT=5003 diff --git a/docker-compose.yml b/docker-compose.yml index 6042cc6..d1fc3b0 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,16 +3,16 @@ services: image: postgres:16-alpine container_name: anime-quiz-db environment: - POSTGRES_USER: animequiz - POSTGRES_PASSWORD: animequiz123 - POSTGRES_DB: animequiz + POSTGRES_USER: ${POSTGRES_USER} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} + POSTGRES_DB: ${POSTGRES_DB} volumes: - postgres_data:/var/lib/postgresql/data ports: - - "5432:5432" + - "${DB_PORT}:5432" restart: unless-stopped healthcheck: - test: ["CMD-SHELL", "pg_isready -U animequiz"] + test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER}"] interval: 10s timeout: 5s retries: 5 @@ -22,15 +22,20 @@ services: context: ./backend dockerfile: Dockerfile container_name: anime-quiz-backend - ports: - - "8000:8000" volumes: - ./output:/app/output env_file: - .env environment: - - QUIZ_OUTPUT_PATH=/app/output/videos - - DATABASE_URL=postgresql+asyncpg://animequiz:animequiz123@db:5432/animequiz + - DATABASE_URL=${DATABASE_URL} + - S3_ENDPOINT=${S3_ENDPOINT} + - S3_ACCESS_KEY=${S3_ACCESS_KEY} + - S3_SECRET_KEY=${S3_SECRET_KEY} + - S3_REGION=${S3_REGION} + - S3_BUCKET=${S3_BUCKET} + - OUTPUT_PATH=${OUTPUT_PATH} + - TEMP_PATH=${TEMP_PATH} + - CACHE_PATH=${CACHE_PATH} depends_on: db: condition: service_healthy @@ -48,11 +53,11 @@ services: dockerfile: Dockerfile container_name: anime-quiz-frontend ports: - - "5173:5173" + - "${APP_PORT}:80" + volumes: + - ./nginx/nginx.conf:/etc/nginx/conf.d/default.conf:ro depends_on: - backend - environment: - - VITE_API_URL=http://backend:8000 restart: unless-stopped volumes: diff --git a/frontend/Dockerfile b/frontend/Dockerfile index 6b0c268..2566c0e 100644 --- a/frontend/Dockerfile +++ b/frontend/Dockerfile @@ -1,18 +1,18 @@ -FROM node:20-slim +# Build stage +FROM node:20-slim AS build WORKDIR /app -# Copy package files -COPY package.json . - -# Install dependencies +COPY package.json package-lock.json* ./ RUN npm install -# Copy source files COPY . . +RUN npm run build -# Expose port -EXPOSE 5173 +# Production stage - just serve static files +FROM nginx:alpine -# Run dev server -CMD ["npm", "run", "dev"] +# Copy built frontend +COPY --from=build /app/dist /usr/share/nginx/html + +EXPOSE 80 diff --git a/nginx/nginx.conf b/nginx/nginx.conf new file mode 100644 index 0000000..cbe51f2 --- /dev/null +++ b/nginx/nginx.conf @@ -0,0 +1,90 @@ +upstream backend { + server backend:8000; +} + +server { + listen 80; + server_name localhost; + + # Frontend static files + location / { + root /usr/share/nginx/html; + index index.html; + try_files $uri $uri/ /index.html; + } + + # Downloader API + location /api/downloader { + proxy_pass http://backend; + 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; + } + + # Openings API + location /api/openings { + proxy_pass http://backend; + 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; + } + + # Backgrounds API + location /api/backgrounds { + proxy_pass http://backend; + 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; + } + + # Core API - strip /api prefix + location /api/ { + proxy_pass http://backend/; + 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; + } + + # Videos endpoint + location /videos { + proxy_pass http://backend; + 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; + } + + # Download endpoint + location /download { + proxy_pass http://backend; + 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; + } + + # Health check + location /health { + proxy_pass http://backend; + proxy_http_version 1.1; + proxy_set_header Host $host; + } + + # Increase max body size for video uploads + client_max_body_size 500M; + + # Timeouts for long video generation + proxy_connect_timeout 300s; + proxy_send_timeout 300s; + proxy_read_timeout 300s; +}