# Production deployment One `compose.yml` builds every service from the repo root: - **`backend/`** — Django API on gunicorn `:5000`, static via WhiteNoise - **`frontend/`** — Vite SPA, built to static files at image build time - **`web`** — the only published container: nginx serving the SPA and reverse proxying the API. No node or bun at runtime. ``` host.com/ -> nginx (SPA, history fallback to index.html) host.com/api/ -> backend (Django REST API) host.com/admin/ -> backend (Django admin) host.com/static/ -> backend (WhiteNoise: admin/DRF assets) host.com/media/ -> nginx (shared `media` volume) ``` Because nginx fronts both, the browser sees one origin and there is no CORS in production. ## Files | File | Purpose | | ----------------- | -------------------------------------------------------- | | `compose.yml` | database + backend + worker + web | | `api.Dockerfile` | Django image (collectstatic at build) | | `web.Dockerfile` | node builds `frontend/dist`, nginx serves it | | `nginx.conf` | SPA + API/admin/static/media routing, asset cache headers | | `entrypoint.sh` | backend: wait for postgres, `migrate`, then gunicorn | ## Configure Fill `backend/.env` (copy from `backend/.env.example`). For the compose network: ``` DJANGO_DEBUG=False SECRET_KEY= POSTGRES_HOST=database POSTGRES_PORT=5432 POSTGRES_DATABASE=sarlink POSTGRES_USER=sarlink POSTGRES_PASSWORD= ALLOWED_HOSTS=localhost,127.0.0.1,backend,portal.sarlink.net CSRF_TRUSTED_ORIGINS=https://portal.sarlink.net FRONTEND_URL=https://portal.sarlink.net SMS_API_URL=... SMS_API_KEY=... ``` The `POSTGRES_*` values also feed the `database` service through compose defaults, so keep them in sync or export them before `up`. The frontend needs no runtime configuration: it calls a relative `/api/...` which nginx routes to the backend. ## Build & run ```sh docker compose -f .build/prod/compose.yml up -d --build docker compose -f .build/prod/compose.yml exec backend python manage.py createsuperuser ``` The site is on `http://localhost:8080`; remap the `web` port behind your TLS terminator. Migrations run on backend startup. ## Running from published images The build pushes `git.shihaam.dev/sarlink/sarlinkportal/{backend,web}`. To deploy without building, replace each service's `build:` block with its `image:` and keep `database`, the volumes, `env_file` and the `web` port mapping.