Deployment
This guide covers running OLDP in production. For local development use Getting Started; for the containerised quickstart see Docker & Podman. All environment variables referenced here are documented in the Configuration reference.
Overview
A production OLDP deployment consists of:
the OLDP app (Django, served by an application server such as Gunicorn),
a relational database (MariaDB/MySQL recommended),
Elasticsearch 7.17.x for search,
optionally Redis as the cache backend and a CDN / reverse proxy (e.g. Nginx) in front of the app.
The shipped docker-compose.yaml defines the app, db (MariaDB) and search
(Elasticsearch) services and is a good starting point for a single-host
deployment.
Production configuration
Select the production settings class and provide the required secrets:
export DJANGO_CONFIGURATION=ProdConfiguration
export DJANGO_SECRET_KEY="<a long random secret>"
export DJANGO_ALLOWED_HOSTS="de.openlegaldata.io"
export DJANGO_SITE_URL="https://de.openlegaldata.io"
export DATABASE_URL="mysql://oldp:<password>@db/oldp"
export DJANGO_ELASTICSEARCH_URL="http://search:9200/"
When deploying the German site, point Django at the theme settings instead and
keep DJANGO_CONFIGURATION at the theme’s production class (see
The OLDP ecosystem):
export DJANGO_SETTINGS_MODULE=oldp_de.settings
export DJANGO_CONFIGURATION=ProdDEConfiguration
See the Configuration reference for caching (Redis), email, MCP rate limits, logging and CDN cache settings.
First-time setup
Prepare the database, assets and translations:
# Apply database migrations
./manage.py migrate
# Build front-end assets and collect static files
./manage.py compress
./manage.py collectstatic --no-input
# Compile translations (needed for production)
./manage.py compilemessages --l de --l en
# Build the search index
./manage.py rebuild_index
With Docker Compose the equivalent steps are available as Make targets
(make migrate, make rebuild-index, make compile-locale).
Create an administrator account:
./manage.py createsuperuser
Deploying updates
When rolling out new code:
Back up the database (and review test/CI status before deploying).
Pull the new code or container image.
Run
./manage.py migratefor any schema changes.Rebuild assets if they changed:
./manage.py compressand./manage.py collectstatic --no-input.Run
./manage.py update_index(incremental) or./manage.py rebuild_index(full) if search mappings changed.Restart the application server.
Production checklist
[ ]
DJANGO_CONFIGURATION=ProdConfiguration(or the theme’s prod class)[ ]
DJANGO_SECRET_KEYset to a strong, secret value[ ]
DJANGO_DEBUG=False(implied by the prod configuration)[ ]
DJANGO_ALLOWED_HOSTSandDJANGO_CSRF_TRUSTED_ORIGINSrestricted to your domains[ ]
DJANGO_SITE_URLset to the public HTTPS origin (also used for MCP OAuth discovery)[ ] Database backups configured
[ ] Elasticsearch reachable and index built
[ ] TLS terminated at the proxy/CDN; static files served efficiently
[ ] Cache backend chosen (
DJANGO_CACHE_BACKEND=redisfor multi-process deployments)
Operations
Elasticsearch — reindexing, realtime sync, index fields.
Sitemaps — XML sitemaps and search-engine pinging.
Data Dumps & Bulk Downloads — exporting snapshots with
dump_api_data.Data Repairs — auditing and fixing rows an ingestion bug left behind.
Going further
For tuning the application server, reverse proxy, database, Elasticsearch and Redis beyond Django defaults, see the internal Performance notes. These are engineering notes rather than a prescriptive configuration — benchmark against your own traffic.