2.2 KiB
Deployment
Local environment
Copy .env.example to .env, replace the development placeholders, then run:
cp .env.example .env
docker compose up --build -d
docker compose ps
docker compose exec backend python manage.py seed_demo
The backend applies migrations and collects static files before starting Gunicorn. All services have health checks; wait for healthy status before opening the site.
Add 127.0.0.1 azionelab.org to the local hosts file, then use
http://azionelab.org:8080. NGINX binds to loopback port 8080 by default and routes
the domain to Astro or Wagtail. Their direct loopback ports 4321 and 8000 remain
available for diagnostics. PostgreSQL is available only on the Compose network.
postgres_data and media_data are persistent named volumes.
The stack uses explicit PostgreSQL 16.9, Python 3.12.12, Node.js 22.20, and NGINX 1.30.0
image versions. Containers are not privileged and use no-new-privileges.
Required runtime variables are DATABASE_URL, DJANGO_SECRET_KEY, DJANGO_DEBUG,
DJANGO_ALLOWED_HOSTS, WAGTAILADMIN_BASE_URL, PUBLIC_CMS_API_URL,
NGINX_BIND_ADDRESS, and NGINX_HTTP_PORT. PostgreSQL bootstrap variables are also
documented in .env.example. Do not use the example credentials outside local
development.
WAGTAILADMIN_BASE_URL must be browser-reachable because it is used for media URLs.
PUBLIC_CMS_API_URL must be reachable by Astro; within Compose it is
http://backend:8000.
The local virtual host is HTTP-only. Production must publish NGINX through the intended
network interface, configure DNS for azionelab.org, terminate TLS, and prevent direct
external access to application ports.
Production boundary
The Compose stack is a local development deployment. A public environment still needs TLS termination, production static/media serving, restricted admin access, managed secrets, off-host backups, monitoring, and an explicit domain/allowed-host policy.
Rollback
Revert the application commit and rebuild images. Keep the database and media volumes unless content deletion is intentional. Schema rollback must be evaluated per Django migration; take coordinated database and media backups first.