Custom settings

You can use any of the settings understood by Django and django-ca provides some of its own settings.

How to configure

If you use django-ca as a Django app, use settings.py file, as you normally would.

If you use the full django-ca project (e.g. if you install from source, or use Docker or Docker Compose), use YAML files that django-ca loads (in alphabetical order) from a preconfigured directory. Please see the respective installation instructions for how to configure settings.

In the django-ca project, you can also use environment variables. The variable name is the same as the setting but prefixed with DJANGO_CA_. For example to set the CA_ENABLE_ACME setting, pass a DJANGO_CA_CA_ENABLE_ACME environment variable. Environment variables take precedence over the YAML configuration files above.

The django-ca project also recognizes some environment variables to better integrate with other systems. See Global environment variables for more information.

Required Django settings

If you use django-ca as a Django app the only required settings are the settings any Django project requires anyway, most importantly DATABASES, SECRET_KEY, ALLOWED_HOSTS and STATIC_ROOT.

If you install from source, you only have to set the DATABASES and SECRET_KEY settings. The CA_DEFAULT_HOSTNAME also configures the ALLOWED_HOSTS setting if not set otherwise. Please see the section on configuration for more information.

If you use Docker or docker-compose, there isn’t really any standard Django setting you have to configure, as safe defaults are used. SECRETS_KEY is generated automatically, ALLOWED_HOSTS is set via CA_DEFAULT_HOSTNAME and the DATABASES setting is automatically populated with environment variables also used by the PostgreSQL/MySQL containers.

django-ca settings

All settings used by django-ca start with the CA_ prefix.

CA_CRL_PROFILES

Type: dict, default:

CA_CRL_PROFILES = {
    'user': {'only_contains_user_certs': True},
    'ca': {'only_contains_ca_certs': True}
}
CA_CRL_PROFILES:
  ca:
    only_contains_ca_certs: true
  user:
    only_contains_user_certs: true
DJANGO_CA_CA_CRL_PROFILES='{"user": {"only_contains_user_certs": true}, "ca": {"only_contains_ca_certs": true}}'

A set of CRLs to create using automated tasks. The default value is usually fine.

Each entry supports the following fields:

field

type

default

comment

only_contains_ca_certs

bool

False

True if CRL should contain only certificate authorities.

only_contains_user_certs

bool

False

True if CRL should contain only end-entity certificates.

only_contains_attribute_certs

bool

False

No effect (attribute certs are not supported).

only_some_reasons

list

None

Optional set of ReasonFlags.

expires

timedelta

1 day

How long the CRL remains valid.

renewal

timedelta

12 hours

How soon the CRL is renewed.

OVERRIDES

dict

{}

See below.

Only one of only_contains_ca_certs, only_contains_user_certs and only_contains_attribute_certs is may be set to True. If none are, all certificates (CAs and end-entity) are included.

The expires key determines how long a newly generated CRL is valid. The renewal key specifies for how soon the CRL must expire to be automatically renewed by the periodic task to generate CRLs.

You may also specify an "OVERRIDES" key for a particular profile to specify custom behavior for select certificate authorities named by serial. It can set the same values as a general profile, plus the "skip" that disables the certificate authority for a particular profile. For example, to disable a profile for one certificate authority and use a non-standard expiry time for the other:

{
    "user": {
         # other values
         OVERRIDES: {
             "00:11:22": {"skip": True},
             "33:44:55": {"expires": 3600},
         }
    }
}

Changed in version 2.1.0:

  • The only_some_reasons parameter was added.

  • The encodings parameter was removed. Both supported encodings are now always available.

Changed in version 2.3.0:

  • The scope parameter to CA_CRL_PROFILES was removed in favor of the only_contains_ca_certs, only_contains_user_certs and only_some_reasons parameters.

CA_DEFAULT_CA

Type: str, default: Not set.

The serial of the CA to use when no CA is explicitly given.

For example, if you sign a certificate using the manage.py sign_cert command and do not pass the --ca parameter, the CA given here will be used. You can get a list of serials from the admin interface or via the manage.py list_cas command.

Warning

Some parts of django-ca will start throwing errors when attempting to use a default CA that is expired or disabled. So please make sure you keep this setting up to date.

If this setting is not set, django-ca will select the CA that is currently usable (enabled, currently valid, not revoked) and and has an expiry furthest in the future.

CA_DEFAULT_DSA_SIGNATURE_HASH_ALGORITHM

Type: str, default:

CA_DEFAULT_DSA_SIGNATURE_HASH_ALGORITHM = 'SHA-256'
CA_DEFAULT_DSA_SIGNATURE_HASH_ALGORITHM: SHA-256
DJANGO_CA_CA_DEFAULT_DSA_SIGNATURE_HASH_ALGORITHM='SHA-256'

The default signature hash algorithm for new DSA based CAs.

Please see SignatureHashAlgorithmName for valid values for this setting. The default hash algorithm for RSA and EC certificates can be configured with CA_DEFAULT_SIGNATURE_HASH_ALGORITHM.

Added in version 1.23.0.

CA_DEFAULT_ELLIPTIC_CURVE

Type: str, default:

CA_DEFAULT_ELLIPTIC_CURVE = 'secp256r1'
CA_DEFAULT_ELLIPTIC_CURVE: secp256r1
DJANGO_CA_CA_DEFAULT_ELLIPTIC_CURVE='secp256r1'

The default elliptic curve for EC based CAs.

Please see ELLIPTIC_CURVE_TYPES for a list of valid values.

Changed in version 1.26.0: This setting used to be called CA_DEFAULT_ECC_CURVE.

CA_DEFAULT_EXPIRES

Type: timedelta, default:

CA_DEFAULT_EXPIRES = datetime.timedelta(days=100)
CA_DEFAULT_EXPIRES: P100D
DJANGO_CA_CA_DEFAULT_EXPIRES='P100D'

The default validity time for a new certificate.

Certificates issued via ACMEv2 are not affected by this setting, as CA_ACME_DEFAULT_CERT_VALIDITY is used there.

An integer value will be parsed as a number of days.

Changed in version 2.6.0: The default value was changed to 100 days (from 365 days).

CA_DEFAULT_HOSTNAME

Type: str, default: Not set.

If set, the default hostname will be used to automatically generate URLs for CRLs and OCSP services. This setting must not include the protocol, as OCSP always uses HTTP (not HTTPS) and this setting might be used for other values in the future. For example:

CA_DEFAULT_HOSTNAME = 'ca.example.com'
CA_DEFAULT_HOSTNAME: ca.example.com
DJANGO_CA_CA_DEFAULT_HOSTNAME='ca.example.com'

Warning

If you change this setting, OCSP and CRL URLs encoded in existing certificates and intermediate CAs become invalid, so certificate validation using these URLs will fail. Also, ACMEv2 URLs will change, so every ACMEv2 client has to be updated.

If you do change this setting after creating any certificates, you have to either start with a completely fresh set of certificates or make sure that the old URLs continue to work (e.g. by providing your own NGINX configuration).

CA_DEFAULT_KEY_SIZE

Type: int, default:

CA_DEFAULT_KEY_SIZE = 4096
CA_DEFAULT_KEY_SIZE: 4096
DJANGO_CA_CA_DEFAULT_KEY_SIZE='4096'

The default key size for new RSA and DSA based CAs. Value must be at least 1024 and a power of two (e.g. 2048 or 4096).

The value must be a power of two (e.g. 2048, 4096, …) and no lower then 1024.

CA_DEFAULT_NAME_ORDER

Default:

(
   "dnQualifier", "countryName", "postalCode", "jurisdictionStateOrProvinceName",
   "localityName", "domainComponent", "organizationName", "organizationalUnitName",
   "title", "commonName", "uid", "emailAddress", "serialNumber"
)

Added in version 1.24.0.

Default order to use for x509 Names (such as the certificates subject). The value is used when signing certificates to normalize the order of x509 name fields in the certificates subject.

This setting is used when signing certificates via ACMEv2 to determine the position of the CommonName field if the selected profile defines a subject fragment (see Configure the subject for more information).

The setting is also used when signing certificates via the command-line to determine the position of the CommonName field if only subject alternative names are defined via the command-line and/or if the selected profile defines a subject fragment.

On most applications, the order does not matter, but is relevant in LDAP applications.

The value must be a tuple, with the values being either a NameOID or a str. String values must be one or the values listed in NAME_OID_TYPES or the dotted string value of the OID:

from cryptography.x509.oid import NameOID

CA_DEFAULT_NAME_ORDER = (
    "countryName",
    NameOID.ORGANIZATION_NAME,
    "2.5.4.3",  # OID for commonName
)
CA_DEFAULT_NAME_ORDER:
  - countryName
  - organizationName
  - 2.5.4.3  # OID for commonName

The default is based on experience with existing certificates, as there is no known standard for an order.

The value is used when signing certificates to normalize the order of x509 name fields such as the certificates subject and issuer field. On most applications, the order does not matter, but is relevant in LDAP applications.

CA_DEFAULT_PRIVATE_KEY_TYPE

Type: str, default:

CA_DEFAULT_PRIVATE_KEY_TYPE = 'RSA'
CA_DEFAULT_PRIVATE_KEY_TYPE: RSA
DJANGO_CA_CA_DEFAULT_PRIVATE_KEY_TYPE='RSA'

The default key type for new CAs.

Note that this setting is not used when generating OCSP responder certificates, where the default private key type is the same as the certificate authority.

CA_DEFAULT_PROFILE

Type: str, default:

CA_DEFAULT_PROFILE = 'webserver'
CA_DEFAULT_PROFILE: webserver
DJANGO_CA_CA_DEFAULT_PROFILE='webserver'

The default profile to use.

CA_DEFAULT_SIGNATURE_HASH_ALGORITHM

Type: str, default:

CA_DEFAULT_SIGNATURE_HASH_ALGORITHM = 'SHA-512'
CA_DEFAULT_SIGNATURE_HASH_ALGORITHM: SHA-512
DJANGO_CA_CA_DEFAULT_SIGNATURE_HASH_ALGORITHM='SHA-512'

The default signature hash algorithm for new RSA and EC based CAs.

Please see SignatureHashAlgorithmName for valid values for this setting.

Since certificate authorities that use a DSA key pair don’t work well with a SHA-512 hash, the default can be configured separately using CA_DEFAULT_DSA_SIGNATURE_HASH_ALGORITHM.

CA_DEFAULT_STORAGE_ALIAS

Type: str, default:

CA_DEFAULT_STORAGE_ALIAS = 'django-ca'
CA_DEFAULT_STORAGE_ALIAS: django-ca
DJANGO_CA_CA_DEFAULT_STORAGE_ALIAS='django-ca'

The storage alias used by the Storages key backend and the Storages OCSP key backend (the default key backends) to store private keys.

CA_DEFAULT_SUBJECT

Type: dict, default: Not set.

Changed in version 2.2.0: Before 2.2.0, this value (and subjects in profiles) were a tuple tuple consisting of two-tuples naming the attribute type and value. The old format was deprecated since 1.29.0.

The default subject for Profiles that don’t define their own subject. You can use this setting to define a default subject for all profiles without having to define the subject in every profile.

Please see Configure the subject for how this value is used when signing certificates.

Note that when signing via the command-line or ACMEv2, the subject attributes of a certificate will be sorted according to CA_DEFAULT_NAME_ORDER, regardless of the order given here.

The value is a list or tuple of key/value mappings defining a name attribute:

CA_DEFAULT_SUBJECT = [
    {'oid': 'countryName', 'value': 'AT'},
    {'oid': 'localityName', 'value': 'Vienna'},
    {'oid': 'organizationName', 'value': 'django-ca'}
]
CA_DEFAULT_SUBJECT:
- oid: countryName
  value: AT
- oid: localityName
  value: Vienna
- oid: organizationName
  value: django-ca
DJANGO_CA_CA_DEFAULT_SUBJECT='[{"oid": "countryName", "value": "AT"}, {"oid": "localityName", "value": "Vienna"}, {"oid": "organizationName", "value": "django-ca"}]'

OID values can be any key from NAME_OID_TYPES or a dotted string as documented in NameOID. The following example is equivalent to the above:

CA_DEFAULT_SUBJECT = [
    {'oid': 'C', 'value': 'AT'},
    {'oid': 'localityName', 'value': 'Vienna'},
    {'oid': '2.5.4.10', 'value': 'django-ca'}
]
CA_DEFAULT_SUBJECT:
- oid: C
  value: AT
- oid: localityName
  value: Vienna
- oid: 2.5.4.10
  value: django-ca
DJANGO_CA_CA_DEFAULT_SUBJECT='[{"oid": "C", "value": "AT"}, {"oid": "localityName", "value": "Vienna"}, {"oid": "2.5.4.10", "value": "django-ca"}]'

If you use Python as a configuration format, the value can also be a x509.Name instance. For convenience, you can also give x509.NameAttribute instances in the tuple defined above, or use an x509.ObjectIdentifier as "oid" key:

from cryptography import x509
from cryptography.x509.oid import NameOID

CA_DEFAULT_SUBJECT = (
    {"oid": "countryName", "value": "AT"},
    {"oid": "2.5.4.8", "value": "Vienna"},  # dottet string for "stateOrProvinceName"
    {"oid": NameOID.ORGANIZATION_NAME, "value": "orgName"},
    x509.NameAttribute(oid=NameOID.ORGANIZATIONAL_UNIT_NAME, value="orgUnitName"),
)

# Or you just define the full name:
# CA_DEFAULT_SUBJECT = x509.Name(...)
CA_ENABLE_REST_API

Type: bool, default:

CA_ENABLE_REST_API = False
CA_ENABLE_REST_API: false
DJANGO_CA_CA_ENABLE_REST_API='false'

Set to True to enable the experimental REST API.

CA_KEY_BACKENDS

Type: dict, default:

CA_KEY_BACKENDS = {
    'default': {
        'BACKEND': 'django_ca.key_backends.storages.StoragesBackend',
        'OPTIONS': {'storage_alias': 'django-ca'}
    }
}
CA_KEY_BACKENDS:
  default:
    BACKEND: django_ca.key_backends.storages.StoragesBackend
    OPTIONS:
      storage_alias: django-ca
DJANGO_CA_CA_KEY_BACKENDS='{"default": {"BACKEND": "django_ca.key_backends.storages.StoragesBackend", "OPTIONS": {"storage_alias": "django-ca"}}}'

The backends available to store private keys.

See Key backends for a list of available backends and their options.

The StoragesBackend configured by default uses a storage alias called "django-ca" by default, so it implies that the STORAGES setting has a “django-ca” alias defined. See project documentation on storages for more information.

CA_MIN_KEY_SIZE

Type: int, default:

CA_MIN_KEY_SIZE = 2048
CA_MIN_KEY_SIZE: 2048
DJANGO_CA_CA_MIN_KEY_SIZE='2048'

The minimum key size for new CAs (not used for CAs based on EC, Ed448 or Ed25519).

The value must be a power of two (e.g. 2048, 4096, …) and no lower then 1024.

CA_NOTIFICATION_DAYS

Type: list, default:

CA_NOTIFICATION_DAYS = (14, 7, 3, 1)
CA_NOTIFICATION_DAYS:
- 14
- 7
- 3
- 1
DJANGO_CA_CA_NOTIFICATION_DAYS='[14, 7, 3, 1]'

Days before expiry that certificate watchers will receive notifications.

CA_OCSP_URLS

Type: dict, default:

CA_OCSP_URLS = {}
CA_OCSP_URLS: {}
DJANGO_CA_CA_OCSP_URLS='{}'

Configuration for OCSP responders. See Run a OCSP responder for more information.

A full example might look like this:

CA_OCSP_URLS = {
    'path-name': {
        'ca': 'ca-name-or-serial',
        'responder_key': '-----BEGIN PRIVATE KEY-----\n...',
        'responder_cert': '-----BEGIN CERTIFICATE-----\n...',
        'expires': 'P1D',
        'ca_ocsp': False
    }
}
CA_OCSP_URLS:
  path-name:
    ca: ca-name-or-serial
    ca_ocsp: false
    expires: P1D
    responder_cert: '-----BEGIN CERTIFICATE-----

      ...'
    responder_key: '-----BEGIN PRIVATE KEY-----

      ...'
DJANGO_CA_CA_OCSP_URLS='{"path-name": {"ca": "ca-name-or-serial", "responder_key": "-----BEGIN PRIVATE KEY-----\n...", "responder_cert": "-----BEGIN CERTIFICATE-----\n...", "expires": "P1D", "ca_ocsp": false}}'
CA_OCSP_KEY_BACKENDS

Type: dict, default:

CA_OCSP_KEY_BACKENDS = {
    'default': {
        'BACKEND': 'django_ca.key_backends.storages.StoragesOCSPBackend',
        'OPTIONS': {'storage_alias': 'django-ca'}
    },
    'db': {
        'BACKEND': 'django_ca.key_backends.db.ocsp_backend.DBOCSPBackend',
        'OPTIONS': {}
    }
}
CA_OCSP_KEY_BACKENDS:
  db:
    BACKEND: django_ca.key_backends.db.ocsp_backend.DBOCSPBackend
    OPTIONS: {}
  default:
    BACKEND: django_ca.key_backends.storages.StoragesOCSPBackend
    OPTIONS:
      storage_alias: django-ca
DJANGO_CA_CA_OCSP_KEY_BACKENDS='{"default": {"BACKEND": "django_ca.key_backends.storages.StoragesOCSPBackend", "OPTIONS": {"storage_alias": "django-ca"}}, "db": {"BACKEND": "django_ca.key_backends.db.ocsp_backend.DBOCSPBackend", "OPTIONS": {}}}'

Configuration for storing OCSP keys. See OCSP Key backends for more information.

CA_OCSP_RESPONDER_CERTIFICATE_RENEWAL

Type: timedelta, default:

CA_OCSP_RESPONDER_CERTIFICATE_RENEWAL = datetime.timedelta(days=1)
CA_OCSP_RESPONDER_CERTIFICATE_RENEWAL: P1D
DJANGO_CA_CA_OCSP_RESPONDER_CERTIFICATE_RENEWAL='P1D'

Renew OCSP certificates if they expire within the given interval.

This setting is used by the periodic task to generate OCSP responder certificates to determine if an OCSP responder certificate should be renewed or not.

Warning

The value must be lower then the frequency of the regular task and lower then the OCSP responder certificate validity that you configure with the --ocsp-responder-key-validity option to manage .py init_ca/manage .py edit_ca.

CA_PASSWORDS

Type: dict, default:

CA_PASSWORDS = {}
CA_PASSWORDS: {}
DJANGO_CA_CA_PASSWORDS='{}'

Passwords for encrypted private keys of certificate authorities.

This setting is used by the Storages backend when using a CA private key that was encrypted (using manage init_ca --password ...). The setting is required for automatically generating CRLs and OCSP keys for certificate authorities with encrypted private keys.

Note

If you use Celery, the setting is only required for the Celery workers (which can run on a different host), the web application server (e.g. Gunicorn) does not need to use private keys in this case.

Example:

CA_PASSWORDS = {'example-serial': 'example-secret-password'}
CA_PASSWORDS:
  example-serial: example-secret-password
DJANGO_CA_CA_PASSWORDS='{"example-serial": "example-secret-password"}'
CA_PROFILES

Type: dict, default: See Profiles.

Add new profiles or change existing ones. Please see Profiles for more information on profiles.

CA_USE_CELERY

Type: bool, default: True if Celery is installed, False if not.

If Celery is used for asynchronous tasks or not.

Using Celery is highly recommended for performance and security reasons. You may set this to False to disable the use of Celery despite it being installed. If disabled, long-running tasks (e.g. signing a certificate or accessing a HSM) will happen directly in the web application server (e.g. Gunicorn).

ACMEv2 settings

CA_ENABLE_ACME

Type: bool, default:

CA_ENABLE_ACME = True
CA_ENABLE_ACME: true
DJANGO_CA_CA_ENABLE_ACME='true'

Set to False to disable all ACME functionality.

Note that even when enabled, you need to explicitly enable ACMEv2 support for a certificate authority either via the admin interface or via the command-line interface.

CA_ACME_DEFAULT_CERT_VALIDITY

Type: timedelta, default:

CA_ACME_DEFAULT_CERT_VALIDITY = datetime.timedelta(days=45)
CA_ACME_DEFAULT_CERT_VALIDITY: P45D
DJANGO_CA_CA_ACME_DEFAULT_CERT_VALIDITY='P45D'

The default validity time any certificate issued via ACME is valid.

An integer value will be parsed as a number of days.

Changed in version 2.6.0: The default value was changed to 45 days (from 90 days).

CA_ACME_MAX_CERT_VALIDITY

Type: timedelta, default:

CA_ACME_MAX_CERT_VALIDITY = datetime.timedelta(days=90)
CA_ACME_MAX_CERT_VALIDITY: P90D
DJANGO_CA_CA_ACME_MAX_CERT_VALIDITY='P90D'

The maximum validity time any certificate issued via ACME is valid.

The ACMEv2 protocol allows for clients to request a non-default validity time, but certbot currently does not expose this feature.

An integer value will be parsed as a number of days.

CA_ACME_ORDER_VALIDITY

Type: timedelta, default:

CA_ACME_ORDER_VALIDITY = datetime.timedelta(seconds=3600)
CA_ACME_ORDER_VALIDITY: PT1H
DJANGO_CA_CA_ACME_ORDER_VALIDITY='PT1H'

The time a request for a new certificate (“order”) remains valid.

An integer value will be parsed as a number of days. The maximum value is one day.

Project settings

Project settings are available if you use the full django-ca project (including if you use the Docker container or via docker-compose). Many settings are _not_ prefixed with CA_, because they configure how Django itself works.

As any other setting, they can be set by using environment variables prefixed with DJANGO_CA_ (Example: To set LOG_LEVEL, set the DJANGO_CA_LOG_LEVEL environment variable).

CA_DIR

Type: str, default:

CA_DIR = 'files/'
CA_DIR: files/
DJANGO_CA_CA_DIR='files/'

Directory root for storing private keys if you use the Storages backend (the default configuration).

This setting has no effect if you define a "django-ca" alias in STORAGES (see also: CA_KEY_BACKENDS).

CA_ENABLE_CLICKJACKING_PROTECTION

Type: bool, default:

CA_ENABLE_CLICKJACKING_PROTECTION = True
CA_ENABLE_CLICKJACKING_PROTECTION: true
DJANGO_CA_CA_ENABLE_CLICKJACKING_PROTECTION='true'

Set to False to disable Clickjacking Protection.

The setting influences if the XFrameOptionsMiddleware is added to the list of middlewares. This setting is useful if the header is already set by the web server.

CA_URL_PATH

Type: str, default:

CA_URL_PATH = 'django_ca/'
CA_URL_PATH: django_ca/
DJANGO_CA_CA_URL_PATH='django_ca/'

To URL path to use for ACMEv2, OCSP, CRL and the REST API, but not the admin interface.

Warning

If you change this setting, OCSP and CRL URLs encoded in existing certificates and intermediate CAs become invalid, so certificate validation using these URLs will fail. Also, ACMEv2 URLs will change, so every ACMEv2 client has to be updated.

If you do change this setting after creating any certificates, you have to either start with a completely fresh set of certificates or make sure that the old URLs continue to work (e.g. by providing your own NGINX configuration).

If you use django-ca as app, the effect of this setting is achieved by the URL path given in your root URL conf.

ENABLE_ADMIN

Type: bool, default:

ENABLE_ADMIN = True
ENABLE_ADMIN: true
DJANGO_CA_ENABLE_ADMIN='true'

Set to False to disable the default Django admin interface.

EXTEND_CELERY_BEAT_SCHEDULE

Type: dict, default:

EXTEND_CELERY_BEAT_SCHEDULE = {}
EXTEND_CELERY_BEAT_SCHEDULE: {}
DJANGO_CA_EXTEND_CELERY_BEAT_SCHEDULE='{}'

Add periodic Celery tasks to the default schedule. Any existing task (see CELERY_BEAT_SCHEDULE) will be overwritten by this setting, which can be used to change the schedule of existing tasks.

The following example will overwrite the generate-crls task to run every hour and add a custom task to run every five minutes:

EXTEND_CELERY_BEAT_SCHEDULE = {
    'generate-crls': {
        'task': 'django_ca.tasks.generate_crls',
        'schedule': 3600
    },
    'custom-task': {'task': 'myapp.tasks.custom_task', 'schedule': 300}
}
EXTEND_CELERY_BEAT_SCHEDULE:
  custom-task:
    schedule: 300
    task: myapp.tasks.custom_task
  generate-crls:
    schedule: 3600
    task: django_ca.tasks.generate_crls
DJANGO_CA_EXTEND_CELERY_BEAT_SCHEDULE='{"generate-crls": {"task": "django_ca.tasks.generate_crls", "schedule": 3600}, "custom-task": {"task": "myapp.tasks.custom_task", "schedule": 300}}'

Note that for schedule, only int is supported.

EXTEND_INSTALLED_APPS

Type: list, default:

EXTEND_INSTALLED_APPS = []
EXTEND_INSTALLED_APPS: []
DJANGO_CA_EXTEND_INSTALLED_APPS='[]'

Append Django applications to INSTALLED_APPS.

This setting is extended if given in multiple configuration sources, see EXTEND_* settings for more information.

If this setting is an environment variable, it must be a JSON-encoded list:

EXTEND_INSTALLED_APPS = ['myapp', 'otherapp.apps.OtherAppConfig']
EXTEND_INSTALLED_APPS:
- myapp
- otherapp.apps.OtherAppConfig
DJANGO_CA_EXTEND_INSTALLED_APPS='["myapp", "otherapp.apps.OtherAppConfig"]'
EXTEND_URL_PATTERNS

Type: list, default:

EXTEND_URL_PATTERNS = []
EXTEND_URL_PATTERNS: []
DJANGO_CA_EXTEND_URL_PATTERNS='[]'

Append URL patterns to the default URL configuration. This allows you to add custom endpoints to your project.

This setting is extended if given in multiple configuration sources, see EXTEND_* settings for more information.

The syntax is very similar to normal URL configuration. For example:

EXTEND_URL_PATTERNS = [
    # Add a simple view, equivalent to:
    #   path("/path", yourapp.views.YourView.as_view())
    {
        "route": "/path",
        "view": {
            # Can be a function or class-based view:
            "view": "yourapp.views.YourView",
            # Optional: Additional arguments for django.urls.path()
            # "name": "simple-view"
            # "kwargs": {
            #     "foo": "bar",
            # }
        },
    },
    # Add an URL with re_path(),equivalent to:
    #   re_path("^path/(?P<username>\\w+)/$", yourapp.views.YourView.as_view())
    {
        "func": "re_path",
        "route": r"^path/(?P<username>\w+)/$",
        "view": {
            # Can be a function or class-based view:
            "view": "yourapp.views.YourView",
            # Optional: Additional arguments passed to as_view():
            # "initkwargs": {
            #   "foo": "bar",
            # }
        },
        # Optional: Additional arguments for django.urls.re_path()
        # "name": "re-simple-view",
        # "kwargs": {
        #     "foo": "bar",
        # }
    },
    # Add a path via django.urls.include(), equivalent to:
    #   path("/included-path/", include("yourapp.urls"))
    {
        "route": "/included-path/",
        "view": {
            "module": "yourapp.urls",
            # Optional: override the namespace
            # "namespace": "yourapp",
        },
    },
]
EXTEND_URL_PATTERNS:
  # Add a simple view, equivalent to:
  #   path("/path", yourapp.views.YourView.as_view())
  - route: /path
    view:
      # Can be a function or class-based view:
      view: yourapp.views.YourView
    # Optional: Additional arguments for django.urls.path()
    #name: simple-view
    #kwargs:
    #  foo: bar

  # Add an URL with re_path(),equivalent to:
  #   re_path("^path/(?P<username>\\w+)/$", yourapp.views.YourView.as_view())
  - type: re_path
    route: "^path/(?P<username>\\w+)/$"
    view:
      # Can be a function or class-based view:
      view: yourapp.views.YourView
      # Optional: Additional arguments passed to as_view():
      #initkwargs:
      #  foo: bar

    # Optional: Additional arguments for django.urls.re_path()
    #name: re-simple-view
    #kwargs:
    #  foo: bar

  # Add a path via django.urls.include(), equivalent to:
  #   include("/included-path/", "yourapp.urls")
  - route: /included-path/
    view:
      module: yourapp.urls
      # Optional: override the namespace
      #namespace: yourapp

If this setting is an environment variable, it must be a JSON-encoded list.

LIBRARY_LOG_LEVEL

Type: str, default:

LIBRARY_LOG_LEVEL = 'WARNING'
LIBRARY_LOG_LEVEL: WARNING
DJANGO_CA_LIBRARY_LOG_LEVEL='WARNING'

The log level for all messages except from django-ca. This setting has no effect if you define the LOGGING setting.

The value must be a valid Python logging level, e.g. "WARNING" or "DEBUG".

LOG_FORMAT

Type: str, default:

LOG_FORMAT = '[%(levelname)-8s %(asctime).19s] %(message)s'
LOG_FORMAT: '[%(levelname)-8s %(asctime).19s] %(message)s'
DJANGO_CA_LOG_FORMAT='[%(levelname)-8s %(asctime).19s] %(message)s'

The default log format of log messages. This setting has no effect if you define the LOGGING setting.

LOG_LEVEL

Type: str, default:

LOG_LEVEL = 'WARNING'
LOG_LEVEL: WARNING
DJANGO_CA_LOG_LEVEL='WARNING'

The log level for all messages from django-ca. This setting has no effect if you define the LOGGING setting.

The value must be a valid Python logging level, e.g. "WARNING" or "DEBUG".

SECRET_KEY_FILE

Type: str, default: Not set.

A path to a file that stores Django’s SECRET_KEY. The setting is only used if no SECRET_KEY is defined.

If you use Docker/Docker Compose, the file is automatically generated with a random value on first startup. You only have to use this setting if you want to specify a custom value for some reason. If you use Docker Compose, you should make sure that the``frontend``, backend and beat container have access to the same file.

The default value for Docker/Docker Compose is:

SECRET_KEY_FILE = '/var/lib/django-ca/certs/ca/shared/secret_key'
SECRET_KEY_FILE: /var/lib/django-ca/certs/ca/shared/secret_key
DJANGO_CA_SECRET_KEY_FILE='/var/lib/django-ca/certs/ca/shared/secret_key'

3rd-party settings (Django, Celery, etc)

All standard Django setting or Celery settings (as well as for any third-party apps you add via EXTEND_INSTALLED_APPS can be configured if you use Python or YAML-based configuration.

If you use environment variables, variables have to be prefixed with DJANGO_CA_, so e.g. the SECRET_KEY setting has to use the DJANGO_CA_SECRET_KEY environment variable. Any standard string setting (such as EMAIL_BACKEND or EMAIL_HOST) will just work, but for other settings, only some standard settings are parsed correctly.

The USE_TZ setting is parsed as an int, while ALLOWED_HOSTS is parsed as list. CACHES, DATABASES and STORAGES are parsed as dict. The CELERY_BEAT_SCHEDULE setting is also supported.

ALLOWED_HOSTS

Type: list, default:

ALLOWED_HOSTS = []
ALLOWED_HOSTS: []
DJANGO_CA_ALLOWED_HOSTS='[]'

If you do not define this setting but define CA_DEFAULT_HOSTNAME, this setting defaults to the default CA hostname.

An example value could be:

ALLOWED_HOSTS = ['ca.example.com']
ALLOWED_HOSTS:
- ca.example.com
DJANGO_CA_ALLOWED_HOSTS='["ca.example.com"]'
CELERY_BEAT_SCHEDULE

Type: dict, default:

CELERY_BEAT_SCHEDULE = {
    'generate-crls': {
        'task': 'django_ca.tasks.generate_crls',
        'schedule': 3600
    },
    'generate-ocsp-keys': {
        'task': 'django_ca.tasks.generate_ocsp_keys',
        'schedule': 3600
    },
    'acme-cleanup': {'task': 'django_ca.tasks.acme_cleanup', 'schedule': 300}
}
CELERY_BEAT_SCHEDULE:
  acme-cleanup:
    schedule: 300
    task: django_ca.tasks.acme_cleanup
  generate-crls:
    schedule: 3600
    task: django_ca.tasks.generate_crls
  generate-ocsp-keys:
    schedule: 3600
    task: django_ca.tasks.generate_ocsp_keys
DJANGO_CA_CELERY_BEAT_SCHEDULE='{"generate-crls": {"task": "django_ca.tasks.generate_crls", "schedule": 3600}, "generate-ocsp-keys": {"task": "django_ca.tasks.generate_ocsp_keys", "schedule": 3600}, "acme-cleanup": {"task": "django_ca.tasks.acme_cleanup", "schedule": 300}}'

Default periodic tasks for Celery.

Do not change this setting, instead use EXTEND_CELERY_BEAT_SCHEDULE to add new tasks or update existing tasks.

DATABASES

django-ca does not directly set a default for this value, but see Databases for how environment variables can be used to configure database access details in a unified way for Docker-based setups.

An example for PostgreSQL (not using POSTGRES_* environment variables):

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'HOST': 'localhost',
        'NAME': 'django_ca',
        'USER': 'django_ca',
        'PASSWORD': 'change_me'
    }
}
DATABASES:
  default:
    ENGINE: django.db.backends.postgresql
    HOST: localhost
    NAME: django_ca
    PASSWORD: change_me
    USER: django_ca
DJANGO_CA_DATABASES='{"default": {"ENGINE": "django.db.backends.postgresql", "HOST": "localhost", "NAME": "django_ca", "USER": "django_ca", "PASSWORD": "change_me"}}'

And an example for MariaDB (not using MARIADB_* environment variables):

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'HOST': 'localhost',
        'NAME': 'django_ca',
        'USER': 'django_ca',
        'PASSWORD': 'change_me'
    }
}
DATABASES:
  default:
    ENGINE: django.db.backends.mysql
    HOST: localhost
    NAME: django_ca
    PASSWORD: change_me
    USER: django_ca
DJANGO_CA_DATABASES='{"default": {"ENGINE": "django.db.backends.mysql", "HOST": "localhost", "NAME": "django_ca", "USER": "django_ca", "PASSWORD": "change_me"}}'
STORAGES

Type: dict, default:

STORAGES = {
    'default': {'BACKEND': 'django.core.files.storage.FileSystemStorage'},
    'staticfiles': {
        'BACKEND': 'django.contrib.staticfiles.storage.StaticFilesStorage'
    },
    'django-ca': {
        'BACKEND': 'django.core.files.storage.FileSystemStorage',
        'OPTIONS': {
            'location': '.../files/',
            'file_permissions_mode': 384,
            'directory_permissions_mode': 448
        }
    }
}
STORAGES:
  default:
    BACKEND: django.core.files.storage.FileSystemStorage
  django-ca:
    BACKEND: django.core.files.storage.FileSystemStorage
    OPTIONS:
      directory_permissions_mode: 448
      file_permissions_mode: 384
      location: '.../files/'
  staticfiles:
    BACKEND: django.contrib.staticfiles.storage.StaticFilesStorage
DJANGO_CA_STORAGES='{"default": {"BACKEND": "django.core.files.storage.FileSystemStorage"}, "staticfiles": {"BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage"}, "django-ca": {"BACKEND": "django.core.files.storage.FileSystemStorage", "OPTIONS": {"location": ".../files/", "file_permissions_mode": 384, "directory_permissions_mode": 448}}}'

If this value is not defined, the default will include the backends defined above. The configuration for storing private keys with the Storages backend is added based on CA_DEFAULT_STORAGE_ALIAS and CA_DIR.

Note that the configuration for storing private keys is not used if you do not use the Storages backend.

Global environment variables

If you use the full django-ca project (e.g. if you install from source or use Docker or docker-compose), you can also make use of some environment variables set by other systems.

Configuration directory

The django-ca project reads custom settings from YAML files in a directory.

All installation options already include a good default for this environment variable and examples in the quickstart guides assume it is not modified. It is documented here for completeness.

DJANGO_CA_SETTINGS

The directory where to load YAML settings files. All files in the directory that have a .yaml suffix will be read in alphabetical order.

Multiple directories can be separated by a colon (":"). In this case, django-ca will first read all directories from the first directory, then from the second one, and so on.

The setting can also point to a single file, assumed to be a YAML file.

If not set, the value of the CONFIGURATION_DIRECTORY environment variable (see SystemD) is used as a fallback.

Startup (Docker only)

The startup scripts in the Docker container read environment variables that influence the startup behavior.

By default, all manage.py commands are run on startup, but the Compose setup disables them on some containers to optimize startup times and ensure that they are only run once.

DJANGO_CA_STARTUP_CHECK

Set to 0 if you don’t want to run manage.py check (see Djangos System check framework) on startup. This will save a second or two in container startup time.

DJANGO_CA_STARTUP_COLLECTSTATIC

Set to 0 if you don’t want to run manage.py collectstatic on startup.

DJANGO_CA_STARTUP_MIGRATE

Set to 0 if you don’t want to run manage.py migrate on startup.

DJANGO_CA_STARTUP_GENERATE_CRLS

Set to 0 if you don’t want to run manage.py generate_crls on startup.

Changed in version 3.0.0: The variable was renamed from DJANGO_CA_STARTUP_CACHE_CRLS.

DJANGO_CA_STARTUP_GENERATE_OCSP_KEYS

Set to 0 if you don’t want to run manage.py generate_ocsp_keys on startup.

Changed in version 3.0.0: The variable was renamed from DJANGO_CA_STARTUP_REGENERATE_OCSP_KEYS.

DJANGO_CA_STARTUP_WAIT_FOR_CONNECTIONS

A space-separated string in the form of hostname:port, for example db.example.com:5432. If set, the startup script will make a TCP connection attempt until the connection succeeds. This can be useful to ensure that the main application does not start unless other systems are running.

This is useful if the startup script is configured to run other manage.py commands that require access to the database. Note that the Compose setup already asserts that via healthcheck commands.

DJANGO_CA_STARTUP_WAIT_FOR_SECRET_KEY_FILE

Set to 1 to wait for the secret key file to be created elsewhere. This is used in the Compose setup to ensure that one container generates and writes a secret key to a file and the other containers then read that file.

Databases

Both the PostgreSQL and MySQL Docker containers get their database name and access credentials from environment variables and django-ca also recognizes these variables.

This is especially powerful when using docker-compose, where it is sufficient to set the POSTGRES_PASSWORD environment variable to configure the database, all other options use default values that just work.

But any other setup can also make use of this feature. For example, with plain Docker, you could just configure PostgreSQL:

DATABASES = {'default': {'ENGINE': 'django.db.backends.postgresql'}}
DATABASES:
  default:
    ENGINE: django.db.backends.postgresql
DJANGO_CA_DATABASES='{"default": {"ENGINE": "django.db.backends.postgresql"}}'

… and then start your docker containers with (not a full example here):

$ docker run -e POSTGRES_PASSWORD=... postgres
$ docker run -e POSTGRES_PASSWORD=... mathiasertl/django-ca
POSTGRES_DB, POSTGRES_DB_FILE, POSTGRES_USER, POSTGRES_USER_FILE, POSTGRES_PASSWORD, POSTGRES_PASSWORD_FILE

Access details to a PostgreSQL database. See the Docker image documentation for more information.

MYSQL_DATABASE, MYSQL_DATABASE_FILE, MYSQL_USER, MYSQL_USER_FILE, MYSQL_PASSWORD, MYSQL_PASSWORD_FILE

Access details to a MySQL database. See the Docker image documentation for more information.

MARIADB_DATABASE, MARIADB_DATABASE_FILE, MARIADB_USER, MARIADB_USER_FILE, MARIADB_PASSWORD, MARIADB_PASSWORD_FILE

Access details to a MariaDB database. See the Docker image documentation for more information.

NGINX

The compose.yaml file provided by the project uses environment variables to parameterize the NGINX configuration. Except for NGINX_TEMPLATE, these environment variables are not used by django-ca itself, but only by the NGINX container itself. As usual, you have to set these variables in your .env file, for example:

.env
# NGINX TLS configuration
NGINX_TEMPLATE=tls
NGINX_PRIVATE_KEY=/etc/certs/live/ca.example.com/privkey.pem
NGINX_PUBLIC_KEY=/etc/certs/live/ca.example.com/fullchain.pem
NGINX_HOST

Default: value of DJANGO_CA_CA_DEFAULT_HOSTNAME

The hostname used by the web server. Internally, this is used in the server_name directive. The default is to use the value of DJANGO_CA_CA_DEFAULT_HOSTNAME, so you usually do not have to configure this variable.

NGINX_HTTPS_PORT

Default: 443

The HTTPS port to use for HTTPS connections. This is only used if you use NGINX_TEMPLATE=tls.

NGINX_PORT

Default: 80

The HTTP port to use for HTTP connections.

NGINX_PRIVATE_KEY

Path to the TLS private key. This is only used if you use NGINX_TEMPLATE=tls.

NGINX_PUBLIC_KEY

Path to the TLS public key. This is only used if you use NGINX_TEMPLATE=tls.

NGINX_TEMPLATE

Default: default

The configuration template to use. There are currently only two templates provided by django-ca:

  • default: The “simple” default configuration, providing all access via plain HTTP.

  • tls: A configuration that includes TLS configuration. It requires that you also set NGINX_PRIVATE_KEY and NGINX_PUBLIC_KEY.

SystemD

The django-ca project also recognizes some environment variables set by SystemD.

The SystemD services included in our quickstart guide already set this variable and further examples assume that you did not modify it. It is documented here for completeness.

CONFIGURATION_DIRECTORY

If set, django-ca will load YAML configuration files from this directory. The variable is set by the ConfigurationDirectory= directive.

EXTEND_* settings

Settings that are prefixed with EXTEND_ are used to extend a different setting. If you use the full django-ca project (e.g. if you install from source, or use Docker or docker-compose) and have multiple configuration sources, the setting will be extended by all instances in this setting.

For example, if you have:

conf/10-enable-first-app.yaml
EXTEND_INSTALLED_APPS:
   - first_app

and:

conf/20-enable-second-app.yaml
EXTEND_INSTALLED_APPS:
   - second_app

… then both first_app and second_app will be added to INSTALLED_APPS.

Setting types

All django-ca settings have a specific type. While they directly map to Python types (if you’re familiar with them), there are a few subtleties in YAML and even more so if you use environment variables.

Note that if you use django-ca as app and use normal settings in settings.py, you can also always use the YAML/environment-variable equivalents as well. For example, you can also use "P45D" to configure an interval.

Strings

Strings are straight forward in all configuration formats. For example:

CA_DEFAULT_HOSTNAME = 'ca.example.com'
CA_DEFAULT_HOSTNAME: ca.example.com
DJANGO_CA_CA_DEFAULT_HOSTNAME='ca.example.com'

Warning: unquoted strings in YAML

A file will fail to load if an unquoted string starts with a character that is also used in the YAML syntax, for example with a * or a [:

# THIS WILL NOT WORK:
#SECRET_KEY: [random-string-that-happens-to-start-with-a-bracket
# But this will (note the added quotes):
SECRET_KEY: "[random-string-that-happens-to-start-with-a-bracket"

The same applies to strings that happen to be an integer:

# THIS WILL NOT WORK: A CA serial that happens to have only digits in its hex representation:
#CA_DEFAULT_CA = 1234
# But this will (note the added quotes):
CA_DEFAULT_CA = "1234"

Integers

Integers are straight forward in all configuration formats. For example:

CA_DEFAULT_KEY_SIZE = 8192
CA_DEFAULT_KEY_SIZE: 8192
DJANGO_CA_CA_DEFAULT_KEY_SIZE='8192'

Booleans

Boolean settings are straight forward in Python and YAML syntax. For environment variables, Pydantic model validation is used:

CA_ENABLE_ACME = True
CA_ENABLE_ACME: true
DJANGO_CA_CA_ENABLE_ACME='true'

String values like "true" and "yes" are parsed as true, while "false" and "no" are parsed as false. The official Conversion Table has a list of allowed values for str inputs for bool values.

Intervals (Timedeltas)

Intervals (time deltas) are represented as timedelta objects in Python. In YAML and for environment variables, you have to use the ISO 8601 string representation. For example, to set CA_DEFAULT_EXPIRES to 45 days:

CA_DEFAULT_EXPIRES = datetime.timedelta(days=45)
CA_DEFAULT_EXPIRES: P45D
DJANGO_CA_CA_DEFAULT_EXPIRES='P45D'

Integer values also work, but the meaning depends on the setting. An integer value might be considered as days or seconds, please refer to the respective setting documentation for the exact meaning. This is equivalent to the above:

CA_DEFAULT_EXPIRES = 45
CA_DEFAULT_EXPIRES: 45
DJANGO_CA_CA_DEFAULT_EXPIRES='45'

Lists and dictionaries

For lists and dictionaries, you can use the standard Python and YAML mechanisms for representation. If you, use an environment variable, it has to be a JSON-encoded string. For a list:

CA_NOTIFICATION_DAYS = (14, 7, 3, 1)
CA_NOTIFICATION_DAYS:
- 14
- 7
- 3
- 1
DJANGO_CA_CA_NOTIFICATION_DAYS='[14, 7, 3, 1]'

And for a dictionary:

CA_PASSWORDS = {'example-serial': 'example-secret-password'}
CA_PASSWORDS:
  example-serial: example-secret-password
DJANGO_CA_CA_PASSWORDS='{"example-serial": "example-secret-password"}'