Add self-contained Docker deployment for EasyPanel / docker-compose: - Dockerfile: python:3.11-slim + nginx. Serves the PREBUILT Vue SPA (frontend/dist, committed) via nginx and reverse-proxies /api to the Flask backend on 127.0.0.1:5000. No node/npm in the image (avoids Vite/npm flakiness in Docker builds). VOLUME /app/backend/data for persistence (factor vintages, dividend ledger, forward runs, prices). HEALTHCHECK hits /api/v1/dashboard/summary. Exposes :80. - deploy/nginx.conf: SPA fallback + /api proxy to 127.0.0.1:5000 + gzip. - deploy/entrypoint.sh: starts Flask (HOST=0.0.0.0:5000) + nginx foreground, forwards signals. - docker-compose.yml: single service 'set50', port 8080:80, mounts ./backend/data for persistence, healthcheck. - .dockerignore excludes .git/.venv/backend/data/node_modules/docs. - .gitignore now tracks frontend/dist/ (prebuilt bundle required by the image); backend/data stays untracked. - Backend runtime verified: test_client GET /api/v1/dashboard/summary=200 (the HEALTHCHECK path). entrypoint sh -n, compose YAML parse, and all Dockerfile-referenced files exist. NOTE: no local docker here, so the image itself was not built — that happens on EasyPanel.
27 lines
1.0 KiB
YAML
27 lines
1.0 KiB
YAML
# Local/self-hosted single-container run for the SET50 alternative-data platform.
|
|
# Production (EasyPanel) builds from the Dockerfile directly; this compose file
|
|
# adds a persistent volume so factor vintages, the dividend ledger, forward runs
|
|
# and prices survive container recreate.
|
|
services:
|
|
set50:
|
|
build: .
|
|
image: set50-alternative-data:latest
|
|
ports:
|
|
- "8080:80"
|
|
environment:
|
|
# bind backend on all interfaces inside the container (nginx proxies /api)
|
|
HOST: "0.0.0.0"
|
|
PORT: "5000"
|
|
PAPER_BIND_HOST: "0.0.0.0"
|
|
# optional: make the dividend refresh faster for demos ()
|
|
# DIVIDEND_REFRESH_COOLDOWN_SECONDS: "300"
|
|
volumes:
|
|
- ./backend/data:/app/backend/data
|
|
restart: unless-stopped
|
|
healthcheck:
|
|
test: ["CMD", "python", "-c", "import urllib.request,sys; sys.exit(0 if urllib.request.urlopen('http://127.0.0.1/api/v1/dashboard/summary', timeout=4).status==200 else 1)"]
|
|
interval: 30s
|
|
timeout: 5s
|
|
retries: 3
|
|
start_period: 10s
|