added docker support
This commit is contained in:
46
DOKPLOY.md
Normal file
46
DOKPLOY.md
Normal 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
10
backend/.dockerignore
Normal file
@@ -0,0 +1,10 @@
|
||||
.venv
|
||||
__pycache__
|
||||
*.pyc
|
||||
*.pyo
|
||||
.pytest_cache
|
||||
.coverage
|
||||
htmlcov
|
||||
.env
|
||||
.env.*
|
||||
*.md
|
||||
27
backend/Dockerfile
Normal file
27
backend/Dockerfile
Normal 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"]
|
||||
@@ -1,3 +1,4 @@
|
||||
import os
|
||||
from fastapi import FastAPI
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
|
||||
@@ -7,9 +8,10 @@ app = FastAPI(
|
||||
version="0.1.0",
|
||||
)
|
||||
|
||||
_cors_origins = os.getenv("CORS_ORIGINS", "http://localhost:5173").split(",")
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=["http://localhost:5173"],
|
||||
allow_origins=[o.strip() for o in _cors_origins if o.strip()],
|
||||
allow_credentials=True,
|
||||
allow_methods=["*"],
|
||||
allow_headers=["*"],
|
||||
|
||||
30
docker-compose.yml
Normal file
30
docker-compose.yml
Normal 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
7
frontend/.dockerignore
Normal file
@@ -0,0 +1,7 @@
|
||||
node_modules
|
||||
dist
|
||||
.git
|
||||
.env
|
||||
.env.*
|
||||
*.md
|
||||
.DS_Store
|
||||
20
frontend/Dockerfile
Normal file
20
frontend/Dockerfile
Normal 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
23
frontend/nginx.conf
Normal 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;
|
||||
}
|
||||
Reference in New Issue
Block a user