added docker support

This commit is contained in:
WillowMT
2026-02-20 14:03:24 +07:00
parent f17c0ba90e
commit 984b1a68a6
8 changed files with 166 additions and 1 deletions

46
DOKPLOY.md Normal file
View File

@@ -0,0 +1,46 @@
# Dokploy Deployment
## Assumptions
- **Frontend**: React Vite SPA built with Bun, served by nginx. Single public entry point.
- **Backend**: FastAPI, internal only. No Traefik labels, no public ports.
- **Routing**: nginx proxies `/api` to backend. Traefik routes all traffic to frontend (port 80).
- **Domain**: Replace `your-domain.com` in Traefik labels with your actual domain.
## Build & Run Locally
```bash
# Create network (Dokploy provides this)
docker network create dokploy-network 2>/dev/null || true
# Build and run
docker compose up --build
```
Frontend will be on port 80 (or the mapped port). Backend is internal.
## Dokploy Setup
1. Create `dokploy-network` if not exists:
```bash
docker network create dokploy-network
```
2. Deploy via Dokploy UI: add project, use this `docker-compose.yml`.
3. Set environment variables in Dokploy:
- `CORS_ORIGINS`: Comma-separated allowed origins (e.g. `https://your-domain.com`)
4. Update Traefik labels in `docker-compose.yml`:
- Replace `your-domain.com` with your domain
- Ensure `certResolver=letsencrypt` matches your Traefik config
## Port Rules
- **Frontend**: Exposes port 80 internally. Traefik routes to it.
- **Backend**: No ports exposed. Communicates via `dokploy-network`.
## Service Communication
- Frontend (nginx) proxies `/api` to `http://backend:8000`
- Backend is reachable only from within the Docker network

10
backend/.dockerignore Normal file
View File

@@ -0,0 +1,10 @@
.venv
__pycache__
*.pyc
*.pyo
.pytest_cache
.coverage
htmlcov
.env
.env.*
*.md

27
backend/Dockerfile Normal file
View File

@@ -0,0 +1,27 @@
# syntax=docker/dockerfile:1
FROM python:3.12-alpine AS builder
WORKDIR /app
RUN pip install --no-cache-dir --upgrade pip
COPY requirements.txt .
RUN pip wheel --no-cache-dir --wheel-dir /wheels -r requirements.txt
# ---
FROM python:3.12-alpine AS runtime
RUN addgroup -g 1001 -S appgroup && adduser -S appuser -u 1001 -G appgroup
WORKDIR /app
COPY --from=builder /wheels /wheels
RUN pip install --no-cache-dir /wheels/* && rm -rf /wheels
COPY --chown=appuser:appgroup main.py .
USER appuser
EXPOSE 8000
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

View File

@@ -1,3 +1,4 @@
import os
from fastapi import FastAPI from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware from fastapi.middleware.cors import CORSMiddleware
@@ -7,9 +8,10 @@ app = FastAPI(
version="0.1.0", version="0.1.0",
) )
_cors_origins = os.getenv("CORS_ORIGINS", "http://localhost:5173").split(",")
app.add_middleware( app.add_middleware(
CORSMiddleware, CORSMiddleware,
allow_origins=["http://localhost:5173"], allow_origins=[o.strip() for o in _cors_origins if o.strip()],
allow_credentials=True, allow_credentials=True,
allow_methods=["*"], allow_methods=["*"],
allow_headers=["*"], allow_headers=["*"],

30
docker-compose.yml Normal file
View File

@@ -0,0 +1,30 @@
services:
backend:
build:
context: ./backend
dockerfile: Dockerfile
restart: always
networks:
- dokploy-network
frontend:
build:
context: ./frontend
dockerfile: Dockerfile
restart: always
ports:
- 80
networks:
- dokploy-network
depends_on:
- backend
labels:
- "traefik.enable=true"
- "traefik.http.routers.frontend.rule=Host(`your-domain.com`)"
- "traefik.http.routers.frontend.entrypoints=websecure"
- "traefik.http.routers.frontend.tls.certResolver=letsencrypt"
- "traefik.http.services.frontend.loadbalancer.server.port=80"
networks:
dokploy-network:
external: true

7
frontend/.dockerignore Normal file
View File

@@ -0,0 +1,7 @@
node_modules
dist
.git
.env
.env.*
*.md
.DS_Store

20
frontend/Dockerfile Normal file
View File

@@ -0,0 +1,20 @@
# syntax=docker/dockerfile:1
FROM oven/bun:1-alpine AS builder
WORKDIR /app
COPY package.json bun.lock* package-lock.json* pnpm-lock.yaml* yarn.lock* ./
RUN bun install --frozen-lockfile || bun install
COPY . .
RUN bun run build
# ---
FROM nginx:alpine AS runtime
COPY --from=builder /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

23
frontend/nginx.conf Normal file
View File

@@ -0,0 +1,23 @@
server {
listen 80;
server_name _;
root /usr/share/nginx/html;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
location /api {
rewrite ^/api/?(.*) /$1 break;
proxy_pass http://backend:8000;
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;
}
gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml;
}