From 3d344b86aca5b952e31f85758d1d6ae01fa035f1 Mon Sep 17 00:00:00 2001 From: Jamitz Date: Tue, 6 Jan 2026 16:41:39 +0000 Subject: [PATCH] update --- backend/.dockerignore | 32 ++++++++++++++++++++++++++++ backend/Dockerfile | 30 ++++++++++++++++++++------ backend/app/main.py | 2 +- compose.yaml | 42 +++++++++++++++++++++++++++++++----- frontend/.dockerignore | 27 ++++++++++++++++++++++++ frontend/Dockerfile | 15 ++++++++++++- frontend/nginx.conf | 48 ++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 183 insertions(+), 13 deletions(-) create mode 100644 backend/.dockerignore create mode 100644 frontend/.dockerignore create mode 100644 frontend/nginx.conf diff --git a/backend/.dockerignore b/backend/.dockerignore new file mode 100644 index 0000000..877081d --- /dev/null +++ b/backend/.dockerignore @@ -0,0 +1,32 @@ +__pycache__/ +*.py[cod] +*$py.class +*.so +.Python +.venv/ +venv/ +ENV/ +env/ +*.db +*.sqlite +*.sqlite3 +.pytest_cache/ +.coverage +htmlcov/ +.tox/ +.mypy_cache/ +.dmypy.json +dmypy.json +.vscode/ +.idea/ +*.log +.DS_Store +.env +.env.local +*.md +!README.md +.git/ +.gitignore +Dockerfile +docker-compose*.yml +compose*.yaml diff --git a/backend/Dockerfile b/backend/Dockerfile index 44bcbd8..5db4fd5 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -1,17 +1,35 @@ -FROM python:3.11-slim - +# ---- Builder stage ---- +FROM python:3.12-slim AS builder WORKDIR /app - +# Install dependencies COPY requirements.txt . +RUN pip install --upgrade pip && \ + pip install --no-cache-dir -r requirements.txt +# ---- Runtime stage ---- +FROM python:3.12-slim +WORKDIR /app +# Copy installed packages from builder +COPY --from=builder /usr/local/lib/python3.12/site-packages /usr/local/lib/python3.12/site-packages +COPY --from=builder /usr/local/bin /usr/local/bin -RUN pip install --no-cache-dir -r requirements.txt +# Copy application code +COPY app ./app +# Create data directory for SQLite and other persistent data +RUN mkdir -p /app/data +# Set environment variables +ENV PYTHONUNBUFFERED=1 \ + PYTHONDONTWRITEBYTECODE=1 -COPY ./app ./app +# Add healthcheck +HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \ + CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:8000/health').read()" || exit 1 +EXPOSE 8000 -CMD ["uvicorn", "app.main:app", "--port", "8000"] +# Run with production settings +CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000", "--proxy-headers", "--forwarded-allow-ips", "*"] diff --git a/backend/app/main.py b/backend/app/main.py index ef8b515..0382638 100644 --- a/backend/app/main.py +++ b/backend/app/main.py @@ -10,7 +10,7 @@ app = FastAPI(title="Notes API") app.add_middleware( CORSMiddleware, allow_origins=[ - "http://localhost:5173", + "http://localhost:80", "https://notes.fitzythe.dev", ], # Vite dev server allow_credentials=True, diff --git a/compose.yaml b/compose.yaml index 73bf1d2..970dd0b 100644 --- a/compose.yaml +++ b/compose.yaml @@ -3,9 +3,41 @@ services: build: context: ./backend container_name: fastnotes-api + environment: + - DATABASE_URL=${DATABASE_URL:-sqlite:///./data/notes.db} + - SECRET_KEY=${SECRET_KEY:-change-this-in-production} + - CORS_ORIGINS=${CORS_ORIGINS:-*} + # Internal only - accessed via nginx proxy + expose: + - "8000" + volumes: + - api_data:/app/data + restart: unless-stopped + healthcheck: + test: + [ + "CMD", + "python", + "-c", + "import urllib.request; urllib.request.urlopen('http://localhost:8000/health').read()", + ] + interval: 30s + timeout: 10s + retries: 3 - # ui: - # build: - # context: ./frontend - # args: - # VITE_API_URL: /api + ui: + build: + context: ./frontend + args: + # Frontend will use /api path (proxied by nginx) + VITE_API_URL: ${VITE_API_URL:-/api} + container_name: fastnotes-ui + ports: + - "80:80" + depends_on: + api: + condition: service_healthy + restart: unless-stopped + +volumes: + api_data: diff --git a/frontend/.dockerignore b/frontend/.dockerignore new file mode 100644 index 0000000..ff12f1f --- /dev/null +++ b/frontend/.dockerignore @@ -0,0 +1,27 @@ +node_modules/ +dist/ +build/ +.git/ +.gitignore +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.DS_Store +.env +.env.local +.env.development.local +.env.test.local +.env.production.local +.vscode/ +.idea/ +coverage/ +.nyc_output/ +*.md +!README.md +Dockerfile +docker-compose*.yml +compose*.yaml +.eslintcache +.cache +*.tsbuildinfo diff --git a/frontend/Dockerfile b/frontend/Dockerfile index 8c030b7..51e5e9c 100644 --- a/frontend/Dockerfile +++ b/frontend/Dockerfile @@ -6,13 +6,26 @@ WORKDIR /app ARG VITE_API_URL ENV VITE_API_URL=$VITE_API_URL +# Copy package files and install dependencies COPY package*.json ./ -RUN npm ci +RUN npm ci --prefer-offline --no-audit + +# Copy source and build COPY . . RUN npm run build # ---------- Runtime ---------- FROM nginx:stable-alpine AS runtime + +# Copy custom nginx config +COPY nginx.conf /etc/nginx/conf.d/default.conf + +# Copy built assets COPY --from=builder /app/dist /usr/share/nginx/html + +# Add healthcheck +HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ + CMD wget --no-verbose --tries=1 --spider http://localhost/health || exit 1 + EXPOSE 80 CMD ["nginx", "-g", "daemon off;"] diff --git a/frontend/nginx.conf b/frontend/nginx.conf new file mode 100644 index 0000000..8cb586d --- /dev/null +++ b/frontend/nginx.conf @@ -0,0 +1,48 @@ +server { + listen 80; + server_name _; + root /usr/share/nginx/html; + index index.html; + + # Gzip compression + gzip on; + gzip_vary on; + gzip_min_length 1024; + gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml+rss application/json application/javascript; + + # Security headers + add_header X-Frame-Options "SAMEORIGIN" always; + add_header X-Content-Type-Options "nosniff" always; + add_header X-XSS-Protection "1; mode=block" always; + + # Static files with caching + location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ { + expires 1y; + add_header Cache-Control "public, immutable"; + } + + # API proxy - routes /api requests to backend service + location /api { + proxy_pass http://api:8000; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection 'upgrade'; + proxy_set_header Host $host; + proxy_cache_bypass $http_upgrade; + 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; + } + + # SPA routing - serve index.html for all routes + location / { + try_files $uri $uri/ /index.html; + } + + # Health check endpoint + location /health { + access_log off; + return 200 "healthy\n"; + add_header Content-Type text/plain; + } +}