Consent Docs

Deploy with Docker Compose

Start the API, the console, the documentation, PostgreSQL and Redis with Docker Compose, put them behind TLS and connect sign-in.

How-to3 min readFor project administrators and deployment operators

Do this once to bring up your own deployment from a clone of the repository. The compose file starts five containers: the API, the console, this documentation, PostgreSQL 18 and Redis 7.

Before you start#

You need:

  • Docker with Compose v2.
  • A public HTTPS hostname, such as consent.example.in. Customer sites load the banner from it and send consent to it.
  • A reverse proxy that you run, to end TLS.
  • The PIEDAP IAM service. The console has no accounts of its own.
  • A safe place to keep secrets. Some of them can never change.
  • Outbound HTTPS from the API to webhook endpoints, scanned sites and vendor-list.consensu.org.

Start the stack#

  1. Create the secrets. Store each one in your secret manager.

    Shell
    openssl rand -hex 16     # DB_PASSWORD
    openssl rand -hex 16     # REDIS_PASSWORD
    openssl rand -hex 32     # ENCRYPTION_KEY
    openssl rand -hex 32     # SUBJECT_HASH_PEPPER
    openssl rand -hex 32     # the secret half of EVIDENCE_CHAIN_KEYS
    openssl rand -base64 32  # RECEIPT_SIGNING_PRIVATE_KEY
    openssl rand -hex 32     # RECEIPT_SIGNING_KEY
    openssl rand -hex 32     # PLATFORM_API_KEY
    openssl rand -hex 32     # METRICS_TOKEN
  2. Write them to a file named .env next to docker-compose.yml. Add your public address and the values from IAM. Keep the file out of version control.

    .envConfig
    DB_PASSWORD=...
    REDIS_PASSWORD=...
    ENCRYPTION_KEY=...
    SUBJECT_HASH_PEPPER=...
    EVIDENCE_CHAIN_KEYS=2026a:...
    EVIDENCE_CHAIN_ACTIVE_KEY=2026a
    RECEIPT_SIGNING_PRIVATE_KEY=...
    RECEIPT_SIGNING_KEY=...
    PLATFORM_API_KEY=...
    METRICS_TOKEN=...
    
    PUBLIC_API_URL=https://consent.example.in
    UI_URL=https://consent.example.in
    
    LOGIN_COOKIE=...
    LOGIN_SECRET=...
    VERIFY_LOGIN_COOKIE=...
    REFRESH_COOKIE=...
    COOKIE_DOMAIN=...
    BASE_IAM_URL=...
    IAM_LOGIN_URL=...
    SERVER_SIDE_API_KEY=...
  3. Build the images and start the stack.

    Shell
    docker compose up -d --build
  4. Check that the API is up and reaches the database.

    Shell
    curl -s http://127.0.0.1:8080/health

The answer is 200 with "status": "ok" and "database": "up". On first start the API builds the schema in an empty database.

Set every key before the first consent

An empty SUBJECT_HASH_PEPPER, EVIDENCE_CHAIN_KEYS or RECEIPT_SIGNING_PRIVATE_KEY is taken from another secret. A different value later breaks search and proof for older records. See values that must never change.

Without PUBLIC_API_URL, install snippets, links and receipts point at localhost.

Put it behind TLS#

End TLS in your own proxy and send every request to the console on port 8080. The console passes /api/, /sdk/ and /health on to the API, so browsers see one origin.

consent.example.in.confnginx
server {
  listen 443 ssl;
  server_name consent.example.in;

  ssl_certificate     /etc/ssl/consent.example.in/fullchain.pem;
  ssl_certificate_key /etc/ssl/consent.example.in/privkey.pem;

  client_max_body_size 200m;

  location / {
    proxy_pass http://127.0.0.1:8080;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
  }
}

Check three things:

  • Client addresses. If your proxy reaches the stack from a public address, set TRUST_PROXY.
  • API reference. The API serves /api/docs without sign-in. Block that path if you do not want it public.
  • Imports. A property import can be 200 MB. Add client_max_body_size 200m; to web/nginx.conf too, or large files fail with 413.
Less common proxy settings
  • Metrics. The console does not forward /metrics. Scrape port 3003 of the API.
  • Country. If your CDN sets a country header such as CF-IPCountry, the API uses it.
  • A CDN for the runtime. Published runtime files never change, so a CDN may serve them. Set RUNTIME_CDN_URL so install snippets point at it.
  • Framing. The console allows framing only by itself and PIEDAP domains. To embed it elsewhere, change the frame-ancestors header in web/nginx.conf and in the API.

Connect sign-in#

Users, organisations and projects all come from IAM. There is no admin account to create.

  • IAM writes each session to Redis and the API reads it there. Both must use the same Redis.
  • LOGIN_COOKIE and LOGIN_SECRET must match IAM. If they differ, every console request gets 403.
  • COOKIE_DOMAIN must match IAM and cover the console's hostname.

The compose file points the API at its own Redis and passes only the variables it lists. To change either, add an override file as shown under the compose file.

The Platform area needs five permissions in IAM, under the Consent application and its PlatformServices module. To list the ones IAM lacks, run the script below with an IAM admin token; add --apply to create them. Then give them to the platform roles in IAM.

Shell
IAM_URL=https://iam.example.in IAM_TOKEN=<admin token> \
CONSENT_APPLICATION_ID=<uuid> PLATFORM_MODULE_ID=<uuid> \
node scripts/register-platform-permissions.mjs

Check the result#

Open https://consent.example.in and sign in. The console opens in the project IAM gives you. New keys are test keys until you approve them.

↑↓ to move, Enter to open