diff --git a/DOCKER.md b/DOCKER.md index 4d77bad..981b1dc 100644 --- a/DOCKER.md +++ b/DOCKER.md @@ -11,7 +11,7 @@ Deploy **dashboard-cpsp** with Docker Compose. Layout mirrors the legacy `dashbo │ ┌─────────────┐ /api/* ┌──────────────┐ │ │ │ frontend │────────────►│ api │ │ │ │ (Nginx) │ │ (Django) │ │ -│ │ port 5002 │ │ port 8000 │ │ +│ │ port 80 │ │ port 8000 │ │ │ └─────────────┘ └──────┬───────┘ │ │ │ │ │ ┌─────────────┐ ▼ │ @@ -26,7 +26,7 @@ Deploy **dashboard-cpsp** with Docker Compose. Layout mirrors the legacy `dashbo | Container | Image / build | Host port | Role | | ---------- | ------------------ | ---------------- | ----------------------------- | -| frontend | `docker/Dockerfile.web` | 5002 → 80 | React SPA + Nginx API proxy | +| frontend | `docker/Dockerfile.web` | 80 → 80 | React SPA + Nginx API proxy | | api | `docker/Dockerfile.api` | 18000 → 8000 | Gunicorn, migrations, static | | cron | same as api | — | Scheduled management commands | | database | postgres:16-alpine | 15432 → 5432 | PostgreSQL | @@ -35,7 +35,7 @@ Deploy **dashboard-cpsp** with Docker Compose. Layout mirrors the legacy `dashbo - Docker 20.10+ - Docker Compose v2+ -- Ports available: **5002** (UI), **18000** (direct API), **15432** (Postgres on localhost) +- Ports available: **80** (UI), **18000** (direct API), **15432** (Postgres on localhost) ```bash docker --version @@ -74,11 +74,11 @@ Logins after seed: `admin` / `admin123`, `staff` / `staff123`. Do **not** run `s docker compose ps docker compose logs -f -curl http://localhost:5002/health -curl http://localhost:5002/api/v1/health/ +curl http://localhost/health +curl http://localhost/api/v1/health/ ``` -Open **http://localhost:5002** in a browser. +Open **http://localhost** in a browser. ## Configuration files (`docker/`) @@ -112,7 +112,7 @@ Important production values: | `BOOTSTRAP_STAFF_PASSWORD` | Staff password (required when `BOOTSTRAP_STAFF_USER` is set) | | `BOOTSTRAP_API_KEY` | Optional fixed API key for scripts (hashed at rest) | -Wagtail admin is proxied at **http://localhost:5002/admin/** (through Nginx → Django). +Wagtail admin is proxied at **http://localhost/admin/** (through Nginx → Django). ## Management @@ -212,7 +212,7 @@ docker compose exec api python manage.py bootstrap_admin - Do not commit `.env` with real secrets. - Use strong `SECRET_KEY` and `DB_PASSWORD` in production. - Restrict database port `15432` to localhost (already bound to `127.0.0.1`). -- Put HTTPS in front of port 5002 (reverse proxy + Let's Encrypt) for public deployment. +- Put HTTPS in front of port 80 (reverse proxy + Let's Encrypt) for public deployment. --- diff --git a/README.md b/README.md index 1075f39..d775bb0 100644 --- a/README.md +++ b/README.md @@ -89,7 +89,7 @@ docker compose up -d --build docker compose exec api python manage.py bootstrap_admin ``` -- UI: [http://localhost:5002](http://localhost:5002) — login `admin` / password from `BOOTSTRAP_ADMIN_PASSWORD` in `.env` +- UI: [http://localhost](http://localhost) — login `admin` / password from `BOOTSTRAP_ADMIN_PASSWORD` in `.env` - API (direct): [http://localhost:18000/api/v1/health/](http://localhost:18000/api/v1/health/) - Postgres (host): `localhost:15432` diff --git a/backend/config/settings.py b/backend/config/settings.py index 4b67af7..e0985ab 100644 --- a/backend/config/settings.py +++ b/backend/config/settings.py @@ -39,7 +39,18 @@ def env_json_dict(key: str, default: str = "") -> dict[str, int]: SECRET_KEY = env("SECRET_KEY", "insecure-dev-key") DEBUG = env_bool("DEBUG", True) ALLOWED_HOSTS = env_list("ALLOWED_HOSTS", "localhost,127.0.0.1") -CSRF_TRUSTED_ORIGINS = env_list("CSRF_TRUSTED_ORIGINS", "http://localhost:8000") +CSRF_TRUSTED_ORIGINS = env_list( + "CSRF_TRUSTED_ORIGINS", + "http://localhost:3001,http://127.0.0.1:3001,http://localhost,http://127.0.0.1", +) +if DEBUG: + # Dev/LAN: allow Vite (:3001) and Docker UI (:80) from private networks. + CSRF_TRUSTED_ORIGIN_REGEXES = [ + r"^http://localhost:\d+$", + r"^http://127\.0\.0\.1:\d+$", + r"^http://192\.168\.\d{1,3}\.\d{1,3}:\d+$", + r"^http://10\.\d{1,3}\.\d{1,3}\.\d{1,3}:\d+$", + ] INSTALLED_APPS = [ "django.contrib.auth", @@ -127,7 +138,10 @@ MEDIA_ROOT = BASE_DIR / "media" DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" -CORS_ALLOWED_ORIGINS = env_list("CORS_ALLOWED_ORIGINS", "http://localhost:3000") +CORS_ALLOWED_ORIGINS = env_list( + "CORS_ALLOWED_ORIGINS", + "http://localhost:3001,http://127.0.0.1:3001,http://localhost,http://127.0.0.1", +) CORS_ALLOW_CREDENTIALS = env_bool("CORS_ALLOW_CREDENTIALS", True) SESSION_COOKIE_SECURE = env_bool("SESSION_COOKIE_SECURE", False) diff --git a/docker-compose.yml b/docker-compose.yml index 6aef4de..4773535 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -42,8 +42,8 @@ services: DEBUG: ${DEBUG:-false} SECRET_KEY: ${SECRET_KEY:-test-secret-key} ALLOWED_HOSTS: ${ALLOWED_HOSTS:-localhost,127.0.0.1,api,frontend,192.168.192.106} - CSRF_TRUSTED_ORIGINS: ${CSRF_TRUSTED_ORIGINS:-http://localhost:5002,http://127.0.0.1:5002,http://192.168.192.106:5002} - CORS_ALLOWED_ORIGINS: ${CORS_ALLOWED_ORIGINS:-http://localhost:5002,http://127.0.0.1:5002,http://192.168.192.106:5002} + CSRF_TRUSTED_ORIGINS: ${CSRF_TRUSTED_ORIGINS:-http://localhost,http://127.0.0.1,http://192.168.192.106} + CORS_ALLOWED_ORIGINS: ${CORS_ALLOWED_ORIGINS:-http://localhost,http://127.0.0.1,http://192.168.192.106} CORS_ALLOW_CREDENTIALS: "true" DB_ENGINE: django.db.backends.postgresql DB_NAME: ${DB_NAME:-dashboard} @@ -134,7 +134,7 @@ services: container_name: dashboard-cpsp-frontend restart: unless-stopped ports: - - "5002:80" + - "80:80" depends_on: api: condition: service_healthy diff --git a/docker/.env.example b/docker/.env.example index b681477..9dab40b 100644 --- a/docker/.env.example +++ b/docker/.env.example @@ -10,8 +10,8 @@ DB_NAME=newdashboard SECRET_KEY=change-me-in-production-use-a-long-random-string DEBUG=false ALLOWED_HOSTS=localhost,127.0.0.1,api,frontend -CSRF_TRUSTED_ORIGINS=http://localhost:5002,http://127.0.0.1:5002 -CORS_ALLOWED_ORIGINS=http://localhost:5002,http://127.0.0.1:5002 +CSRF_TRUSTED_ORIGINS=http://localhost,http://127.0.0.1 +CORS_ALLOWED_ORIGINS=http://localhost,http://127.0.0.1 # Production admin (bootstrap_admin — no demo data) BOOTSTRAP_ADMIN_USER=admin