diff --git a/.beans/nuzlocke-tracker-ahza--deployment-strategy.md b/.beans/nuzlocke-tracker-ahza--deployment-strategy.md index 4b60a7a..7220cd4 100644 --- a/.beans/nuzlocke-tracker-ahza--deployment-strategy.md +++ b/.beans/nuzlocke-tracker-ahza--deployment-strategy.md @@ -49,7 +49,7 @@ Define and implement a deployment strategy for running the nuzlocke-tracker in p - [ ] **Set up branching structure** — create `develop` branch from `main`, establish the `main`/`develop`/`feature/*` workflow - [ ] **Update CLAUDE.md with branching rules** — once the branching structure is in place, add instructions to CLAUDE.md that the branching strategy must be adhered to (always work on feature branches, never commit directly to `main`, merge flow is `feature/*` → `develop` → `main`) - [ ] **Configure Gitea container registry** — create an access token with `read:package` and `write:package` scopes, verify `docker login gitea.yourdomain.com` works, test pushing and pulling an image as a user-level package -- [ ] **Create production docker-compose file** (`docker-compose.prod.yml`) — uses images from the Gitea container registry, production env vars, no source volume mounts, proper restart policies +- [x] **Create production docker-compose file** (`docker-compose.prod.yml`) — uses images from the Gitea container registry, production env vars, no source volume mounts, proper restart policies - [ ] **Create production Dockerfiles (or multi-stage builds)** — ensure frontend is built and served statically (e.g., via the API or a lightweight nginx container), API runs without debug mode - [x] **Set up Portainer on Unraid** — install Portainer CE as a Docker container, configure the stack from the production compose file - [ ] **Configure Portainer webhook for automated redeployment** — add a webhook trigger in Portainer that pulls latest images and restarts the stack diff --git a/.beans/nuzlocke-tracker-xmyh--create-production-dockerfiles.md b/.beans/nuzlocke-tracker-xmyh--create-production-dockerfiles.md index 355c2e7..88721fb 100644 --- a/.beans/nuzlocke-tracker-xmyh--create-production-dockerfiles.md +++ b/.beans/nuzlocke-tracker-xmyh--create-production-dockerfiles.md @@ -1,10 +1,11 @@ --- # nuzlocke-tracker-xmyh title: Create production Dockerfiles -status: todo +status: in-progress type: task +priority: normal created_at: 2026-02-09T15:30:42Z -updated_at: 2026-02-09T15:30:42Z +updated_at: 2026-02-09T16:59:19Z parent: nuzlocke-tracker-ahza --- diff --git a/backend/Dockerfile.prod b/backend/Dockerfile.prod new file mode 100644 index 0000000..2023083 --- /dev/null +++ b/backend/Dockerfile.prod @@ -0,0 +1,19 @@ +# Production Dockerfile for the backend API +FROM python:3.14-slim + +WORKDIR /app + +# Install system dependencies +RUN apt-get update && apt-get install -y --no-install-recommends \ + curl \ + && rm -rf /var/lib/apt/lists/* + +# Install Python dependencies +COPY pyproject.toml README.md alembic.ini ./ +COPY src/ ./src/ + +RUN pip install --no-cache-dir . + +EXPOSE 8000 + +CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000", "--app-dir", "src"] diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml index c3bb6a1..dd1d0df 100644 --- a/docker-compose.prod.yml +++ b/docker-compose.prod.yml @@ -1,6 +1,9 @@ services: api: image: gitea.nerdboden.de/julian/nuzlocke-tracker-api:latest + build: + context: ./backend + dockerfile: Dockerfile.prod command: > sh -c "alembic upgrade head && uvicorn app.main:app --host 0.0.0.0 --port 8000 --app-dir src" environment: @@ -13,6 +16,9 @@ services: frontend: image: gitea.nerdboden.de/julian/nuzlocke-tracker-frontend:latest + build: + context: ./frontend + dockerfile: Dockerfile.prod ports: - "8080:80" depends_on: diff --git a/frontend/Dockerfile.prod b/frontend/Dockerfile.prod new file mode 100644 index 0000000..d95f253 --- /dev/null +++ b/frontend/Dockerfile.prod @@ -0,0 +1,21 @@ +# Production Dockerfile for the frontend +# Stage 1: Build +FROM node:24-slim AS build + +WORKDIR /app + +COPY package*.json ./ +RUN npm ci + +COPY . . +RUN npm run build + +# Stage 2: Serve +FROM nginx:alpine + +COPY --from=build /app/dist /usr/share/nginx/html +COPY nginx.conf /etc/nginx/conf.d/default.conf + +EXPOSE 80 + +CMD ["nginx", "-g", "daemon off;"] diff --git a/frontend/nginx.conf b/frontend/nginx.conf new file mode 100644 index 0000000..1224549 --- /dev/null +++ b/frontend/nginx.conf @@ -0,0 +1,20 @@ +server { + listen 80; + + root /usr/share/nginx/html; + index index.html; + + # Proxy API requests to the backend service + location /api/ { + proxy_pass http://api:8000; + 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; + } + + # Serve static files, fall back to index.html for SPA routing + location / { + try_files $uri $uri/ /index.html; + } +}