> ## Documentation Index
> Fetch the complete documentation index at: https://help.draftable.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Draftable API Self Hosted v3 Docker Compose Guide

> This is a guide for the Docker Compose file used in the API Self Hosted v3 image.

<CardGroup>
  <Card title="Web Server" icon="server" href="#web-server" iconType="solid" horizontal />

  <Card title="Application" icon="gear" href="#application" iconType="solid" horizontal />

  <Card title="Licensing" icon="id-card" href="#licensing" iconType="solid" horizontal />

  <Card title="Compare API" icon="code" href="#compare-api" iconType="solid" horizontal />

  <Card title="Application Security" icon="shield-halved" href="#application-security" iconType="solid" horizontal />

  <Card title="Database (PostgreSQL)" icon="database" href="#database-postgresql" iconType="solid" horizontal />

  <Card title="Redis" icon="bolt" href="#redis" iconType="solid" horizontal />

  <Card title="AMQP (RabbitMQ)" icon="arrows-spin" href="#amqp-rabbitmq" iconType="solid" horizontal />

  <Card title="File Storage" icon="folder" href="#file-storage" iconType="solid" horizontal />

  <Card title="HTTP Headers" icon="network-wired" href="#http-headers" iconType="solid" horizontal />

  <Card title="X-Frame-Options (iframe embedding)" icon="triangle-exclamation" href="#x-frame-options-iframe-embedding" iconType="solid" horizontal />

  <Card title="Logging" icon="clipboard-list" href="#logging" iconType="solid" horizontal />

  <Card title="Infrastructure Services" icon="cubes" href="#infrastructure-services" iconType="solid" horizontal />
</CardGroup>

## Web server

### `SERVER_DNS`

* **Type**: String
* **Default**: (empty)
* **Example**: `draftable.yourcompany.com`

Primary domain name for the server. Used for configuring the load balancer to serve requests, SSL certificate validation, and virtual host configuration.

### `TLS_CERT`

* **Type**: String (PEM content)
* **Default**: (empty)

Full PEM-encoded SSL/TLS certificate content. Paste the entire certificate including the `-----BEGIN CERTIFICATE-----` and `-----END CERTIFICATE-----` lines directly into the `.env` file.

<Note>The load balancer container reads certificate content from environment variables and writes it to its internal Nginx SSL paths. You must provide the actual PEM content — file paths are not supported.</Note>

### `TLS_KEY`

* **Type**: String (PEM content)
* **Default**: (empty)

Full PEM-encoded SSL/TLS private key content. Paste the entire key including the `-----BEGIN PRIVATE KEY-----` and `-----END PRIVATE KEY-----` lines directly into the `.env` file.

### `TLS_CA_CHAIN`

* **Type**: String (PEM content)
* **Default**: (empty)

Full PEM-encoded SSL/TLS certificate authority chain. If your certificate chain includes intermediate and root CA certificates, concatenate them together in a single value.

To populate your `.env` file from existing certificate files, you can use:

```bash theme={null}
echo "TLS_CERT=\"$(cat /path/to/tls-cert.pem)\"" >> .env
echo "TLS_KEY=\"$(cat /path/to/privkey.pem)\"" >> .env
echo "TLS_CA_CHAIN=\"$(cat /path/to/tls-ca-chain.pem)\"" >> .env
```

## Application

### `APP_BASE_URL`

* **Type**: String
* **Default**: `https://localhost`
* **Example**: `https://draftable.yourcompany.com`

Base URL where the application is accessible. Must include the protocol (`https://`) and port if non-standard. Used for generating links in API responses and the web interface.

### `ENV`

* **Type**: String
* **Default**: `prod`
* **Valid Values**: `dev`, `prod`

Environment mode for the application containers. Use `prod` for all production and customer deployments.

### `CSRF_TRUSTED_ORIGINS`

* **Type**: List
* **Default**: Value of `APP_BASE_URL`
* **Example**: `https://draftable.yourcompany.com`

List of trusted origins for CSRF validation. In most deployments, the default (derived from `APP_BASE_URL`) is sufficient. Set explicitly if serving from multiple origins.

### `APP_MODE`

* **Type**: String
* **Valid Values**: `web`, `web_init`, `celery_worker`, `celery_beat`

Defines the role of each application container. This is set automatically in Docker Compose and should be set per-container in Kubernetes deployments. `web_init` runs database migrations and should complete before other containers start.

### `DEFAULT_FROM_EMAIL`

* **Type**: String
* **Default**: `draftable@localhost`
* **Example**: `noreply@yourcompany.com`

Default sender email address for system notifications.

## Licensing

### `DRAFTABLE_PRODUCT_KEY`

* **Type**: String
* **Default**: (empty)

Product key for automatic activation of Draftable API Self-hosted. If left empty, the product key can be entered in the web administration interface.

<Tip>
  **Upgrading from v2?** Your existing v2 product key is fully compatible with v3. No new key is required.
</Tip>

## Compare API

### `COMPARE_API_ACCOUNT_SIGNUP_ENABLED`

* **Type**: Boolean
* **Default**: `true`

Allow users to create accounts through self-registration.

### `COMPARE_API_SOURCE_URL_ALLOW_HTTP`

* **Type**: Boolean
* **Default**: `false`

Allow HTTP URLs in the `source_url` parameter of comparison requests.

### `COMPARE_API_SOURCE_URL_ALLOW_PRIVATE_IP`

* **Type**: Boolean
* **Default**: `false`

Allow private IP addresses in the `source_url` parameter of comparison requests.

## Application security

### `DJANGO_SECRET_KEY`

* **Mandatory setting**
* **Type**: String
* **Default**: (empty)

Secret key used for cryptographic signing by web containers. A random alphanumeric value of at least 64 characters is recommended. The secret key can be changed at any time, however, doing so will invalidate all existing login sessions forcing all users to login again.

### `ALLOWED_HOSTS`

* **Type**: List
* **Default**: Value of `SERVER_DNS`
* **Example**: `draftable.yourcompany.com, www.draftable.yourcompany.com`

List of hosts and domains which the application is permitted to serve. By default, the value of `SERVER_DNS` is automatically used.

### `REQUIRE_HTTPS`

* **Type**: Boolean
* **Default**: `true`

Require all web requests and responses be served over HTTPS. When enabled, any HTTP requests will be redirected to the equivalent HTTPS URL. See also the configuration of the [`X-Forwarded-Proto` HTTP header](#x-forwarded-proto).

### `SESSION_COOKIE_AGE`

* **Type**: Integer
* **Default**: `86400`
* **Valid Values**: >= 0

Duration for which a session cookie (login session) is valid. The value is provided in seconds with the default of `86400` equal to one day.

### `SESSION_COOKIE_SAMESITE`

* **Type**: String
* **Default**: `Lax`
* **Valid Values**: `Strict`, `Lax`, `None`, (empty)

Value for the `SameSite` attribute of session cookies. Consult general online documentation for the behaviours set by the `Strict`, `Lax`, and `None` values. Setting an empty string will result in omitting the `SameSite` attribute from session cookies, which on modern web browsers is typically equivalent to the `Lax` setting.

## Database (PostgreSQL)

PostgreSQL database connection settings. When using the default Docker Compose configuration, the built-in PostgreSQL container is used and these defaults are sufficient. For Kubernetes deployments or when connecting to an external database (e.g. Amazon RDS), you must configure these variables explicitly.

### `DB_HOST`

* **Type**: String
* **Default**: `pgsql`

Hostname or IP address of the PostgreSQL server.

<Note>The default value `pgsql` corresponds to the Docker Compose service name. For Kubernetes or external database deployments, set this to your database hostname (e.g. `postgres.internal` or `your-rds-endpoint.region.rds.amazonaws.com`).</Note>

### `DB_PORT`

* **Type**: Integer
* **Default**: `5432`
* **Valid Range**: 1–65535

Port number for the PostgreSQL server.

### `DB_NAME`

* **Type**: String
* **Default**: `draftable`

Name of the PostgreSQL database.

### `DB_USER`

* **Type**: String
* **Default**: `postgres`

Username for PostgreSQL authentication.

### `DB_PASS`

* **Type**: String
* **Default**: `password`

Password for PostgreSQL authentication. **Change from default in production.**

### `DB_TLS_MODE`

* **Type**: String
* **Default**: `prefer`
* **Valid Values**: `disable`, `allow`, `prefer`, `require`, `verify-ca`, `verify-full`

TLS connection mode for PostgreSQL. Use `require` or higher for production, especially when connecting to a remote or managed database.

### `DB_CONN_MAX_AGE`

* **Type**: Integer
* **Default**: `-1`
* **Valid Values**: `-1` (unlimited), `0` (no persistent connections), `>0` (seconds)

Lifetime of database connections in seconds. The default of `-1` enables unlimited persistent connections, which is appropriate for most deployments.

***

## Redis

Redis is used for caching, session storage, license data, and custom font storage. When using the default Docker Compose configuration, the built-in Redis container is used and these defaults are sufficient. For Kubernetes deployments or when connecting to an external Redis instance (e.g. Amazon ElastiCache), you must configure these variables explicitly.

<Warning>
  **Redis persistence is critical.** Redis stores the activated license and any custom fonts. If Redis data is lost, all users will be locked out until the license is reactivated. Always ensure Redis is configured with persistent storage (the default Docker Compose configuration includes AOF and RDB persistence). If using a managed Redis service, ensure persistence is enabled.

  If Redis data is lost, re-run the `web_init` container to reactivate the license from the `DRAFTABLE_PRODUCT_KEY` environment variable. In Docker Compose: `docker compose run --rm web_init`. You do not need to restart the entire deployment.
</Warning>

### `REDIS_HOST`

* **Type**: String
* **Default**: `redis`

Hostname or IP address of the Redis server.

<Note>The default value `redis` corresponds to the Docker Compose service name. For Kubernetes or external Redis deployments, set this to your Redis hostname (e.g. `redis.internal` or `your-elasticache-endpoint.region.cache.amazonaws.com`).</Note>

<Warning>
  **Kubernetes naming conflict**: Kubernetes automatically creates an environment variable `REDIS_PORT=tcp://ip:port` when a service is named `redis`. This conflicts with the integer port value expected by the application. To avoid this, name your Redis Kubernetes service something other than `redis` (e.g. `redis-svc`).
</Warning>

### `REDIS_PORT`

* **Type**: Integer
* **Default**: `6379`
* **Valid Range**: 1–65535

Port number for the Redis server. Use `6380` for TLS connections if required by your provider.

### `REDIS_PASSWORD`

* **Type**: String
* **Default**: (empty)

Password for Redis authentication. Leave empty if Redis has no authentication configured.

### `REDIS_USER`

* **Type**: String
* **Default**: (empty)

Username for Redis authentication (Redis 6.0+ with ACLs). Leave empty for password-only authentication.

### `REDIS_TLS`

* **Type**: Boolean
* **Default**: `false`

Enable TLS encryption for Redis connections. Set to `true` when connecting to managed Redis services that require TLS (e.g. ElastiCache in-transit encryption).

### `REDIS_DB`

* **Type**: Integer
* **Default**: `0`
* **Valid Range**: 0–2147483646

Redis database number to use.

***

## AMQP (RabbitMQ)

RabbitMQ is the message broker used for communication between the web application and the comparison engine. When using the default Docker Compose configuration, the built-in RabbitMQ container is used and these defaults are sufficient. For Kubernetes deployments or when connecting to an external RabbitMQ instance (e.g. Amazon MQ), you must configure these variables explicitly.

<Warning>
  **Draftable requires RabbitMQ (AMQP 0-9-1). AWS SQS and Amazon MQ for ActiveMQ are not supported.** The comparison engine communicates exclusively over the AMQP 0-9-1 protocol and uses RabbitMQ-specific features, which neither SQS nor ActiveMQ provide. ActiveMQ implements AMQP 1.0, which is a different, non-interoperable protocol despite the shared "AMQP" name.

  * If you use **Amazon MQ**, select the **RabbitMQ** engine (not ActiveMQ), and connect on port `5671` for TLS.
  * **Self-managed RabbitMQ** (in-cluster or on a dedicated host) is also supported.
  * You do not need to pre-create exchanges, queues, or bindings — Draftable declares its own on startup. Provide a running broker on the default virtual host (`/`) with a user that has configure, write, and read permissions.
</Warning>

### `AMQP_HOST`

* **Type**: String
* **Default**: `rabbitmq`

Hostname or IP address of the RabbitMQ server.

<Note>The default value `rabbitmq` corresponds to the Docker Compose service name. For Kubernetes or external RabbitMQ deployments, set this to your broker hostname (e.g. `rabbitmq.internal` or `your-amazonmq-endpoint.mq.region.amazonaws.com`).</Note>

### `AMQP_PORT`

* **Type**: Integer
* **Default**: `5672`
* **Valid Range**: 1–65535

Port number for the RabbitMQ server. Use `5671` for TLS connections (e.g. Amazon MQ).

### `AMQP_USER`

* **Type**: String
* **Default**: `draftable`

Username for RabbitMQ authentication.

### `AMQP_PASSWORD`

* **Type**: String
* **Default**: `draftable`

Password for RabbitMQ authentication. **Change from default in production.**

### `AMQP_TLS`

* **Type**: Boolean
* **Default**: `false`

Enable TLS encryption for RabbitMQ connections. Set to `true` when connecting to managed RabbitMQ services that require TLS (e.g. Amazon MQ).

***

## File storage

### `FILE_STORAGE_TYPE`

* **Type**: String
* **Default**: `local`
* **Valid Values**: `local`, `s3`

Storage provider to use for storing uploaded documents and resulting comparison data.

* `local`\
  Data is made directly accessible to Draftable containers through the container filesystem. When using the default Docker Compose configuration a Docker volume will be created and mounted into all Draftable containers. Using a Docker volume is not generally compatible with deployments where Draftable containers span multiple servers as the underlying volume will typically not be accessible across discrete hosts.
* `s3`\
  Data is stored in AWS S3 buckets. This storage option is highly scalable and permits usage of Draftable containers across multiple servers due to the separation of the storage backed from compute. The AWS S3 buckets must be configured in advance. Please reach out to Draftable support for details.

<Warning>
  **Azure Blob Storage is not supported.** The only supported values for `FILE_STORAGE_TYPE` are `local` and `s3` (AWS S3). There is no native support for Azure Blob Storage, Azure Files, or any other Azure storage identifier. Customers deploying on Microsoft Azure infrastructure should use `local` storage or contact [support@draftable.com](mailto:support@draftable.com) to discuss their requirements.
</Warning>

<Warning>
  **NFS shared volumes (e.g. Azure NetApp Files) are not officially supported.** While it is technically possible to use an NFS shared volume with `FILE_STORAGE_TYPE=local` to share the `/srv/draftable` mount across multiple pods (for example, in an Azure AKS deployment), Draftable does not test or optimise against NFS storage internally. Our limited testing has identified performance issues inherent to NFS that can impact comparison workloads.

  Customers who choose to use NFS do so at their own risk. Draftable support is unable to assist with troubleshooting issues related to NFS storage performance, reliability, or configuration. Your infrastructure team is welcome to build and optimise an NFS-based solution that works within your environment, but this falls outside the scope of Draftable's supported deployment configurations.

  If you are deploying on Azure and require a supported multi-node storage solution, please contact [support@draftable.com](mailto:support@draftable.com) to discuss your requirements.
</Warning>

### `DRAFTABLE_API_FILE_STORAGE_ROOT`

* **Type**: String
* **Default**: `/srv/draftable/data`

Path at which the comparison data will be mounted in Draftable containers when using the `local` storage type. Changing the default is not recommended unless directed by Draftable support for specific advanced scenarios.

**To enable S3 storage, the 2 environment variables must be set below:**

### `S3_STORAGE_BUCKET`

\- **Type**: String\
\- **Default**: (empty).

Name of the bucket to use. The bucket must be configured with Cross-origin resource sharing (CORS). Below is a minimal JSON example:

```json theme={null}
[
   {
       "AllowedHeaders": [
           "*"
       ],
       "AllowedMethods": [
           "GET"
       ],
       "AllowedOrigins": [
           "*"
       ],
       "ExposeHeaders": []
   }
]
```

### `AWS_REGION`

\- **Type**: String\
\- **Default**: (empty)

AWS region name. Must match the region of the bucket.

### `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`

AWS credentials. The user/role used to access the bucket requires the following permissions:

`s3:ListBucket`, `s3:GetObject`, `s3:PutObject`, `s3:DeleteObject`

Example IAM policy:

```json theme={null}
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "ListBucket",
            "Effect": "Allow",
            "Action": [
                "s3:ListBucket"
            ],
            "Resource": "arn:aws:s3:::bucket-name"
        },
        {
            "Sid": "ReadWriteObjects",
            "Effect": "Allow",
            "Action": [
                "s3:PutObject",
                "s3:GetObject",
                "s3:DeleteObject"
            ],
            "Resource": "arn:aws:s3:::bucket-name/*"
        }
    ]
}
```

## HTTP headers

### X-Frame-Options (iframe embedding)

<Warning>
  **Known issue (v3.0.5 and earlier):** The load balancer container includes a hardcoded `X-Frame-Options: DENY` header on all HTTPS responses. This prevents the comparison viewer from being embedded in an iframe — a regression from v2 where iframe embedding worked without issue.

  Adding `X_FRAME_OPTIONS` to your `.env` file will **not** resolve this, as the header is set at the nginx level inside the load balancer container, not by the application.

  A fix will be included in a future release. In the meantime, use the workaround below.
</Warning>

**Workaround: override the nginx configuration template**

<Note>
  The load balancer container uses a template file at `/nginx.conf.template` which its entrypoint script processes on startup — substituting your `SERVER_DNS` value and DNS resolver — before writing the final configuration to `/etc/nginx/nginx.conf`. The workaround below replaces this template so that the entrypoint can still run normally.
</Note>

<Steps>
  <Step title="Extract the nginx configuration template">
    Extract the template file (not the processed config) from the running container:

    ```bash theme={null}
    docker compose exec server cat /nginx.conf.template > custom-nginx.conf
    ```
  </Step>

  <Step title="Edit the template">
    Open `custom-nginx.conf` and find this line in the HTTPS server block:

    ```nginx theme={null}
    add_header X-Frame-Options DENY always;
    ```

    Change it to one of the following depending on your requirements:

    * **Same-origin embedding** (viewer iframe is hosted on the exact same origin as the APISH server):
      ```nginx theme={null}
      add_header X-Frame-Options SAMEORIGIN always;
      ```
    * **Cross-origin embedding** (viewer iframe is on a different domain or subdomain to the APISH server):
      Remove the `add_header X-Frame-Options` line entirely.

    <Tip>
      `SAMEORIGIN` requires an **exact origin match** (scheme + host + port). Different subdomains — for example, embedding from `app.yourcompany.com` when APISH is hosted at `draftable.yourcompany.com` — are considered cross-origin and will still be blocked by `SAMEORIGIN`. In this case, remove the line entirely.

      For more granular control, you can replace the `X-Frame-Options` line with a `Content-Security-Policy` header that specifies which origins are permitted to embed the viewer:

      ```nginx theme={null}
      add_header Content-Security-Policy "frame-ancestors https://app.yourcompany.com https://draftable.yourcompany.com" always;
      ```

      You can also use wildcards (e.g. `https://*.yourcompany.com`). See the [MDN Content-Security-Policy frame-ancestors documentation](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/frame-ancestors) for full syntax.
    </Tip>

    <Warning>
      Do not change the `SERVER_NAME_PLACEHOLDER` or `RESOLVER_PLACEHOLDER` tokens in the file. These are replaced automatically by the container's entrypoint script on startup.
    </Warning>
  </Step>

  <Step title="Mount the custom template">
    Add a volume mount to the `server` service in your `docker-compose.yml`, mapping your custom file to `/nginx.conf.template`:

    ```yaml theme={null}
    server:
      image: draftable/apish-load-balancer:latest
      volumes:
        - ./custom-nginx.conf:/nginx.conf.template:ro
      # ... keep your existing configuration below
    ```
  </Step>

  <Step title="Restart the stack">
    ```bash theme={null}
    docker compose down
    docker compose up -d
    ```
  </Step>

  <Step title="Verify the fix">
    Open your browser's developer tools, load the comparison viewer URL, and confirm the `X-Frame-Options` response header now shows `SAMEORIGIN` (or is absent if you removed the line).
  </Step>
</Steps>

### Cross-Origin Resource Sharing (CORS)

#### `CORS_ENABLED`

* **Type**: Boolean
* **Default**: `false`

Enable including CORS headers in API Self-hosted responses to HTTP(S) requests.

#### `CORS_ALLOWED_ORIGINS`

* **Type**: List
* **Default**: (empty)
* **Example**: `https://app.yourcompany.com, https://api.yourcompany.com`

List of origins permitted to make cross-origin requests.

#### `CORS_ALLOWED_ORIGIN_REGEXES`

* **Type**: List
* **Default**: (empty)
* **Example**: `https://.*\.yourcompany\.com`

List of regular expression patterns for which matches are permitted to make cross-origin requests.

#### `CORS_ALLOW_ALL_ORIGINS`

* **Type**: Boolean
* **Default**: `false`

Permit requests from any origin. Enabling this behaviour can be a security risk and should be carefully evaluated.

### Cross-Site Request Forgery (CSRF) protection

#### `CSRF_COOKIE_SAMESITE`

* **Type**: String
* **Default**: `Strict`
* **Valid Values**: `Strict`, `Lax`, `None`, (empty)

Value for the `SameSite` attribute of CSRF cookies. Consult general online documentation for the behaviours set by the `Strict`, `Lax`, and `None` values. Setting an empty string will result in omitting the `SameSite` attribute from CSRF cookies, which on modern web browsers is typically equivalent to the `Lax` setting.

### HTTP Strict Transport Security (HSTS)

#### `SECURE_HSTS_SECONDS`

* **Type**: Integer
* **Default**: `0`
* **Valid Values**: >= 0

Number of seconds for which the HSTS policy will be enforced when received by a web browser. The configured value is set in the `max-age` attribute of the HSTS header. The default of zero disables the HSTS header, while for production deployments a value of two years (`63072000`) is recommended.

#### `SECURE_HSTS_INCLUDE_SUBDOMAINS`

* **Type**: Boolean
* **Default**: `false`

Enables applying the HSTS policy to all subdomains of the API Self-hosted domain. When enabled, sets the `includeSubDomains` attribute in the HSTS header.

#### `SECURE_HSTS_PRELOAD`

* **Type**: Boolean
* **Default**: `false`
* **Required**: Optional

Enables inclusion of the HSTS policy in the [preload list](https://hstspreload.org/) maintained by Google. When enabled, sets the `preload` attribute in the HSTS header, indicating that the API Self-hosted domain may be included in the preload list, which is used by all major web browsers. To take effect the `SECURE_HSTS_SECONDS` value must be at least one year (`31536000`) and `SECURE_HSTS_INCLUDE_SUBDOMAINS` must be enabled.

There are additional requirements for inclusion in the preload list; see the [submission requirements](https://hstspreload.org/#submission-requirements) for full details.

### `X-Forwarded-Proto`

#### `SECURE_PROXY_SSL_HEADER_ENABLED`

* **Type**: Boolean
* **Default**: `true`

Enables setting the `X-Forwarded-Proto` header on requests sent from the load balancer to web containers and configures the API Self-hosted application to respect the header.

If HTTPS support is enabled via the `REQUIRE_HTTPS` setting (the default) then the `X-Forwarded-Proto` header will be implicitly enabled irrespective of the value of this setting.

#### `SECURE_PROXY_SSL_HEADER_NAME`

* **Type**: String
* **Default**: `HTTP_X_FORWARDED_PROTO`

The name of the header used to communicate the protocol used by the client which originated the request.

#### `SECURE_PROXY_SSL_HEADER_VALUE`

* **Type**: String
* **Default**: `https`

The value of the header which indicates that the originating client request is secure.

## Logging

Configuration of logging functionality and minimum logging severity levels of components. Changing logging severity levels from the defaults is not recommended unless directed by Draftable support.

### `CONSOLE_LOG_LEVEL`

* **Type**: String
* **Default**: `WARNING`
* **Valid Values**: `CRITICAL`, `ERROR`, `WARNING`, `INFO`, `DEBUG`

Minimum severity level for outputting logs to the console.

### `AWS_LOG_LEVEL`

* **Type**: String
* **Default**: `INFO`
* **Valid Values**: `CRITICAL`, `ERROR`, `WARNING`, `INFO`, `DEBUG`

Minimum severity level for logs from Amazon Web Services (AWS) libraries.

### `CELERY_LOG_LEVEL`

* **Type**: String
* **Default**: `INFO`
* **Valid Values**: `CRITICAL`, `ERROR`, `WARNING`, `INFO`, `DEBUG`

Minimum severity level for logs from the Celery distributed task queue.

### `DJANGO_LOG_LEVEL`

* **Type**: String
* **Default**: `INFO`
* **Valid Values**: `CRITICAL`, `ERROR`, `WARNING`, `INFO`, `DEBUG`

Minimum severity level for logs from the Django web application framework.

### `DRAFTABLE_LOG_LEVEL`

* **Type**: String
* **Default**: `INFO`
* **Valid Values**: `CRITICAL`, `ERROR`, `WARNING`, `INFO`, `DEBUG`

Minimum severity level for logs from Draftable components.

### `GUNICORN_LOG_LEVEL`

* **Type**: String
* **Default**: `INFO`
* **Valid Values**: `CRITICAL`, `ERROR`, `WARNING`, `INFO`, `DEBUG`

Minimum severity level for logs from the Gunicorn WSGI HTTP server.

### `MISC_LOG_LEVEL`

* **Type**: String
* **Default**: `INFO`
* **Valid Values**: `CRITICAL`, `ERROR`, `WARNING`, `INFO`, `DEBUG`

Minimum severity level for logs from components not covered by a specific `LOG_LEVEL` setting.

### `CONSOLE_LOG_TIMESTAMP_ENABLED`

* **Type**: Boolean
* **Default**: `true`

Prepend a timestamp for logs output to the console. When collecting console logs via a log aggregation system that adds its own timestamps to the processed events you may wish to disable this behaviour to avoid duplication of timestamps.

## Infrastructure services

These environment variables configure supporting infrastructure services and the document processing pipeline.

### `JODCONVERTER_URL`

* **Type**: String
* **Default**: `http://converter:8080/lool/convert-to/pdf`

URL for the JODConverter service used for document format conversion (e.g. Office to PDF). The default value uses the Docker Compose service name. For Kubernetes deployments, update this to match your converter service name and namespace (e.g. `http://converter-svc.draftable.svc.cluster.local:8080/lool/convert-to/pdf`).

### `COMPARE_WORKERS_COUNT`

* **Type**: Integer
* **Default**: `1`
* **Valid Range**: 1–10

Number of comparison worker processes within the compare container. Increase for higher throughput on multi-core systems. In Kubernetes, you can also scale horizontally by increasing the number of compare pod replicas.

### `HTTP_PORT`

* **Type**: Integer
* **Default**: `80`

HTTP port exposed by the load balancer container. Only applicable to Docker Compose deployments.

### `HTTPS_PORT`

* **Type**: Integer
* **Default**: `443`

HTTPS port exposed by the load balancer container. Only applicable to Docker Compose deployments.
