Files
azionelab/docs/deployment.md
2026-04-29 23:39:12 +02:00

8.1 KiB

Deployment

Production Readiness

Before a real deployment, treat .env.example as local-development only. Create a separate .env for production and replace all placeholder values.

Required production changes:

  • set DJANGO_DEBUG=false;
  • set a strong random DJANGO_SECRET_KEY;
  • set DJANGO_ALLOWED_HOSTS to the real public hostnames only;
  • set DJANGO_CSRF_TRUSTED_ORIGINS to the real public HTTPS origins;
  • set SITE_BASE_URL to the real public HTTPS base URL used for confirmation emails and QR/check-in links;
  • replace the console email backend with real SMTP settings and a valid sender address;
  • publish only nginx and terminate HTTPS at nginx or a trusted upstream reverse proxy;
  • keep collectstatic --noinput in the deployment flow before up -d;
  • persist the PostgreSQL named volume and configure tested backups before accepting bookings;
  • create the first admin account explicitly with python manage.py createsuperuser.

Reverse proxy and HTTPS notes:

  • the current nginx template listens on plain HTTP port 80 only and must be adapted for production TLS;
  • if TLS is terminated by another reverse proxy, forward the public host and scheme correctly so generated links remain accurate;
  • keep SITE_BASE_URL, DJANGO_ALLOWED_HOSTS, and DJANGO_CSRF_TRUSTED_ORIGINS aligned with the final public URL.

AzioneLab should deploy with a simple Docker Compose topology:

  • nginx: public reverse proxy and static frontend server;
  • frontend: Angular build source or build stage for static assets;
  • backend: Django 5.2 LTS application served by gunicorn;
  • postgres: PostgreSQL database.

Only nginx should expose public ports. The backend and database should stay on the internal Compose network.

The initial Compose setup is located at infra/docker/compose.yml.

Services

nginx

Responsibilities:

  • listen on public HTTP and HTTPS ports;
  • serve built Angular files;
  • proxy /api/ and /admin/ requests to the backend;
  • serve static and media files according to the selected storage layout;
  • apply request size and timeout limits appropriate for booking and admin usage.

Public ports:

  • 80 for HTTP;
  • 443 for HTTPS in production.

frontend

The frontend is an Angular application using Angular Material.

Deployment options:

  • build the Angular app in a Docker build stage and copy static files into the nginx image;
  • or run a one-shot build container that writes static files to a shared volume consumed by nginx.

The first option is preferred for a simple production deployment because nginx can serve immutable built assets without a long-running Node process.

At the infrastructure placeholder stage, the frontend service serves a static placeholder page with nginx. The Angular build will replace this placeholder later.

backend

The backend is a Django application served by gunicorn.

Responsibilities:

  • REST API;
  • Django admin;
  • booking, confirmation, QR generation, and check-in logic;
  • transactional capacity validation;
  • email sending.

The backend should run database migrations before or during deployment through an explicit operational command, not as hidden startup magic unless that choice is documented later.

The backend service runs gunicorn against the Django WSGI application. The current backend is an initial skeleton with Django admin, Django REST Framework, CORS configuration, the shows, bookings, and checkins apps, and a health endpoint.

postgres

PostgreSQL is the only database service.

Responsibilities:

  • persistent application data;
  • reservation and check-in state;
  • transactional capacity enforcement.

Use a named Docker volume for database data.

Networks

Recommended Compose networks:

  • public: nginx-facing network when needed;
  • internal: private network for nginx, backend, and db communication.

The database should not be published to the host in production.

Volumes

Recommended volumes:

  • postgres_data: PostgreSQL data directory;
  • media: uploaded media and generated QR assets if stored on disk;
  • static: collected Django static files if served by nginx from a shared volume.

Generated QR codes may also be generated on demand instead of stored as files. If stored, they must not reveal personal data and access must remain controlled.

Configuration

Copy .env.example to .env and replace all placeholder values before running or deploying the stack.

.env.example is intentionally local-dev oriented. Do not use it unchanged for production.

Required backend configuration:

  • DJANGO_SECRET_KEY;
  • DJANGO_ALLOWED_HOSTS;
  • DJANGO_CSRF_TRUSTED_ORIGINS;
  • DJANGO_DEBUG=false;
  • CORS_ALLOWED_ORIGINS;
  • SITE_BASE_URL;
  • TIME_ZONE;
  • DATABASE_URL or equivalent database settings;
  • email host, port, username, password, TLS settings, and sender address;
  • public site URL used to build confirmation and QR verification links.

Local Docker convention:

  • use nginx as the public entrypoint at http://localhost;
  • set SITE_BASE_URL=http://localhost;
  • keep DJANGO_CSRF_TRUSTED_ORIGINS and browser-facing CORS_ALLOWED_ORIGINS aligned with that public URL;
  • if you publish nginx on a different port, update SITE_BASE_URL and trusted origins to the same host and port.
  • local/debug reservation email sends also log the confirmation URL so browser testing can continue even if SMTP is missing or fails.

Required database configuration:

  • database name;
  • database user;
  • database password;
  • data volume path.

Required nginx configuration:

  • upstream backend service name and port;
  • static frontend root;
  • proxy rules for /api/ and /admin/;
  • TLS certificate paths for production.

Secrets must be provided through deployment-managed environment variables, Docker secrets, or another secret manager. Do not commit real secret values.

Example Request Routing

Visitor browser
  -> nginx
    -> Angular static files
    -> /api/ requests proxied to backend:gunicorn
    -> /admin/ requests proxied to backend:gunicorn
Backend
  -> PostgreSQL
  -> SMTP provider

Deployment Commands

The exact commands will be finalized when application code and Compose files are added.

Expected production-style flow:

docker compose --env-file .env -f infra/docker/compose.yml build
docker compose --env-file .env -f infra/docker/compose.yml run --rm backend python manage.py migrate
docker compose --env-file .env -f infra/docker/compose.yml run --rm backend python manage.py collectstatic --noinput
docker compose --env-file .env -f infra/docker/compose.yml run --rm backend python manage.py createsuperuser
docker compose --env-file .env -f infra/docker/compose.yml up -d

Expected validation commands:

docker compose --env-file .env.example -f infra/docker/compose.yml config
docker compose --env-file .env.example -f infra/docker/compose.yml run --rm --build backend python manage.py test
docker compose --env-file .env -f infra/docker/compose.yml run --rm backend python manage.py check --deploy
docker compose --env-file .env -f infra/docker/compose.yml run --rm backend python manage.py test

The canonical repository check for the current stage is:

docker compose --env-file .env.example -f infra/docker/compose.yml config
docker compose --env-file .env.example -f infra/docker/compose.yml run --rm --build backend python manage.py test

Rollback

Rollback should be designed around immutable images and database backups.

Basic rollback steps:

  1. identify the previous known-good image tags or Git commit;
  2. stop the current Compose stack;
  3. deploy the previous image tags or commit;
  4. restore the database from backup only if a migration or data change requires it;
  5. run smoke checks for public pages, booking creation, confirmation, and check-in.

Database rollback needs special care once migrations exist. Down migrations or backup restore procedures should be documented before production use.

Operational Notes

  • Configure database backups before accepting real bookings.
  • Monitor backend errors, email delivery failures, and check-in failures.
  • Keep container images explicitly versioned; do not use latest tags.
  • Keep the system small until operational needs justify additional services.