2.9 KiB
Production deployment
Unified build for the SAR Link portal monorepo. One compose.yml builds all
services from the repo root, wiring together the two submodules:
backend/— Django API (gunicorn on:5000, static via WhiteNoise)frontend/— Next.js portal (standalone server on:3000)
A single nginx container is the only published entrypoint. The browser only
ever talks to Next.js; Next.js reaches Django server-side over the compose
network (SARLINK_API_BASE_URL=http://backend:5000). nginx only exposes
Django's browser-facing surface — the admin, its static assets, and media.
host.com/ -> frontend (Next.js) # incl. its own /api/* route handlers
host.com/admin/ -> backend (Django admin)
host.com/static/ -> backend (WhiteNoise)
host.com/media/ -> nginx (shared `media` volume)
/api/is not proxied to Django — it belongs to Next.js (NextAuth etc.). Django's own/api/...is reached only internally viaSARLINK_API_BASE_URL.
Files
| File | Purpose |
|---|---|
compose.yml |
postgres + backend + frontend + nginx |
api.Dockerfile |
Django image (collectstatic at build) |
frontend.Dockerfile |
Next.js standalone image |
nginx.Dockerfile |
nginx + nginx.conf |
entrypoint.sh |
backend: wait for postgres, migrate, then gunicorn |
nginx.conf |
front reverse proxy |
Configure
Fill each submodule's .env (copy from its .env.example); compose reads
backend/.env and frontend/.env. For the compose network set:
backend/.env
POSTGRES_HOST=database
POSTGRES_PORT=5432
POSTGRES_DATABASE=sarlink
POSTGRES_USER=sarlink
POSTGRES_PASSWORD=changeme
ALLOWED_HOSTS=localhost,127.0.0.1,backend # + your public host
CSRF_TRUSTED_ORIGINS=https://portal.example.com
frontend/.env
SARLINK_API_BASE_URL=http://backend:5000
NEXTAUTH_URL=https://portal.example.com
NEXTAUTH_SECRET=...
The POSTGRES_* values also feed the database service (via compose defaults),
so keep them in sync — or export them in the shell before up.
Build & run
docker compose -f .build/prod/compose.yml up -d --build
The published site is on http://localhost:8080 (remap the nginx port in
compose.yml behind your TLS terminator). The backend runs migrations on
startup; create an admin user once with:
docker compose -f .build/prod/compose.yml exec backend python manage.py createsuperuser
Running from published images
The build pushes to git.shihaam.dev/sarlink/sarlinkportal/{backend,frontend,nginx}.
To deploy without building, replace each service's build: block with its
image: and keep the database, volumes, env_file, and nginx port mapping.