Skip to content

Docker Deployment

The generated project uses a single Docker image that contains both Nginx and the backend, exposing just one port.

Browser ──▶ :5173 (Nginx)
├─ / Frontend static files (/usr/share/nginx/html)
├─ /api/ Reverse proxy to 127.0.0.1:8088 (backend in the same container)
└─ /docs Proxy to the backend API docs (Python)
  • The frontend is built into static files by the Node stage, served by Nginx, with the SPA fallback try_files ... /index.html.
  • The backend listens on 127.0.0.1:8088 inside the container and is exposed externally only through Nginx.
  • The image has EXPOSE 5173, and docker-compose.yml maps 5173:5173.
  • Nginx allows 1 GB uploads, disables proxy request/response buffering, and raises read/write timeouts to one hour for full-data import/export.
  1. node:22-alpine: build the frontend.
  2. python:3.12-slim: install Nginx and the backend dependencies (uv pip install --system -e .), and copy the frontend build output and nginx.conf.
终端窗口
# Build the image
docker build -t my-project .
# Run (a strong random JWT_SECRET_KEY is required)
docker run -d -p 5173:5173 \
-e JWT_SECRET_KEY="$(openssl rand -base64 48)" \
my-project
# Or use docker compose
JWT_SECRET_KEY="$(openssl rand -base64 48)" docker compose up -d

Visit http://localhost:5173.

  • The database file lives at /app/data in the container, mounted from the named volume app-data.
  • Temporary import/export files live under /app/data/tmp, also on the persistent data volume.
  • docker compose down preserves the data; running up -d again does not lose it.
  • To clear the data, run:
终端窗口
docker compose down -v # deletes the data volume; data is unrecoverable

Data management may keep a database snapshot, upload, and export archive at the same time. Reserve at least roughly three times the database size in the data volume.

The full export archive contains password hashes, AI API keys, SMTP passwords, and other sensitive data. Move it to controlled storage immediately and do not distribute it through chat tools.

The image has a built-in health check (interval 30s, timeout 5s, startup grace 15s, 3 retries) that accesses http://127.0.0.1:5173/api/public/config. The Python image uses the built-in urllib, and the Java image uses wget.

Variable Description
JWT_SECRET_KEY Required (Python backend), strong random
TZ Time zone, defaults to Asia/Shanghai
DATABASE_URL Already set to sqlite+aiosqlite:////app/data/app.db inside the Python image
PYTHONUNBUFFERED Already set to 1 inside the Python image