Step-by-step guide for deploying cppa-weblate-plugin to a staging or production server using the CD Docker Compose stack (docker/docker-compose.cd.yml).
| Requirement | Details |
|---|---|
| Docker Engine | 24 + with Compose v2 (docker compose) |
| Host PostgreSQL | 16 recommended; a dedicated user and database (see Database setup) |
| Redis | 7+; shared via the boost-data-collector_default external Docker network |
| Reverse proxy | nginx (or equivalent) terminating TLS and proxying to 127.0.0.1:8080 |
| Git checkout | Repository cloned to /opt/cppa-weblate-plugin on the deploy server |
Run once on the host PostgreSQL instance as a superuser:
CREATE USER weblate_app WITH PASSWORD '<strong-password>';
CREATE DATABASE weblate_db OWNER weblate_app;Ensure pg_hba.conf allows connections from the Docker bridge network (172.17.0.0/16 or your custom subnet) for that user.
Copy .env.example to the repo root as .env and fill in every value marked replace-*:
cp .env.example .env| Variable | Purpose |
|---|---|
POSTGRES_PASSWORD |
Host Postgres password for weblate_app |
WEBLATE_ADMIN_PASSWORD |
Initial admin account password |
Compose refuses to start if either is unset (enforced by ${VAR:?set in .env} syntax in docker-compose.cd.yml).
The plugin itself has no dedicated env vars. All wiring happens inside the Docker image at build time:
settings_override.pyis copied to/app/data/settings-override.pyby the Dockerfile. Weblate's Docker entrypointexec()s this file during settings load.WEBLATE_FORMATS— the override reads upstreamFormatsConf.FORMATSvia regex, appendsboost_weblate.formats.quickbook.QuickBookFormat, and writes the result back toWEBLATE_FORMATS. No env var needed.INSTALLED_APPS— the override appendsboost_weblate.endpoint.apps.BoostEndpointConfig. The app'sready()hook then registers/boost-endpoint/routes onweblate.urls.real_patterns.
Key variables set in the Compose file or .env (full reference in .env.example):
| Variable | Default | Notes |
|---|---|---|
WEBLATE_PORT |
8080 |
Host port bound to 127.0.0.1; nginx proxies to this |
WEBLATE_SITE_DOMAIN |
weblate.example.com |
Public hostname (no scheme) |
WEBLATE_URL_PREFIX |
/weblate |
Subpath when behind nginx at https://<host>/weblate/ |
WEBLATE_DEBUG |
0 |
Set 1 only for troubleshooting |
WEBLATE_ENABLE_HTTPS |
1 |
Required when TLS terminates at nginx |
WEBLATE_IP_PROXY_HEADER |
HTTP_X_FORWARDED_FOR |
Proxy header for real client IP |
POSTGRES_HOST |
host.docker.internal |
Reaches host Postgres via Docker gateway |
POSTGRES_USER |
weblate_app |
Must match the SQL CREATE USER above |
POSTGRES_DATABASE |
weblate_db |
Must match CREATE DATABASE above |
REDIS_HOST |
redis |
Resolved via the external bdc_redis network |
REDIS_DB |
1 |
Logical DB to avoid clashing with other apps on shared Redis |
CELERY_SINGLE_PROCESS |
1 |
Single Celery worker process; increase for heavier workloads |
From the repo root on the deploy server:
docker compose -f docker/docker-compose.cd.yml --env-file .env build
docker compose -f docker/docker-compose.cd.yml --env-file .env up -dThe Dockerfile builds an overlay image on weblate/weblate:latest:
- Copies
settings_override.py→/app/data/settings-override.py - Installs the plugin into
/app/venvviauv pip install
Defined in docker-compose.cd.yml:
healthcheck:
test: [CMD, curl, -sf, "http://localhost:8080${WEBLATE_URL_PREFIX:-}/healthz/"]
interval: 10s
timeout: 5s
retries: 12
start_period: 60sThe start_period gives Weblate 60 s to run migrations and boot before Docker begins counting failures. Total grace before marked unhealthy: 60 s + 12 × 10 s = 180 s.
Check container health:
docker compose -f docker/docker-compose.cd.yml --env-file .env psThe cd.yml GitHub Actions workflow polls after deploy (reads WEBLATE_PORT and WEBLATE_URL_PREFIX from .env):
set -a && [ -f .env ] && . ./.env && set +a
WEBLATE_PORT="${WEBLATE_PORT:-8080}"
WEBLATE_URL_PREFIX="${WEBLATE_URL_PREFIX:-}"
for i in $(seq 1 36); do
curl -sf "http://127.0.0.1:${WEBLATE_PORT}${WEBLATE_URL_PREFIX}/healthz/" && exit 0
sleep 5
doneThis gives 180 s (36 × 5 s) before failing the deploy.
The plugin exposes an unauthenticated ping endpoint:
set -a && [ -f .env ] && . ./.env && set +a
WEBLATE_PORT="${WEBLATE_PORT:-8080}"
WEBLATE_URL_PREFIX="${WEBLATE_URL_PREFIX:-}"
curl -sf "http://127.0.0.1:${WEBLATE_PORT}${WEBLATE_URL_PREFIX}/boost-endpoint/plugin-ping/"
# Expected: 200 ok (text/plain)A 200 ok response confirms:
- The Weblate container is running
BoostEndpointConfigloaded inINSTALLED_APPS- Plugin URL routes registered on
weblate.urls.real_patterns
Run these checks after every deploy (automated in CD; manual for first-time setup). Load deploy vars from .env first:
set -a && [ -f .env ] && . ./.env && set +a
WEBLATE_PORT="${WEBLATE_PORT:-8080}"
WEBLATE_URL_PREFIX="${WEBLATE_URL_PREFIX:-}"curl -sf "http://127.0.0.1:${WEBLATE_PORT}${WEBLATE_URL_PREFIX}/healthz/"curl -sf "http://127.0.0.1:${WEBLATE_PORT}${WEBLATE_URL_PREFIX}/boost-endpoint/plugin-ping/"curl -sf -H "Authorization: Token <API_TOKEN>" \
"http://127.0.0.1:${WEBLATE_PORT}${WEBLATE_URL_PREFIX}/boost-endpoint/info/"Expected JSON:
{
"module": "cppa-weblate-plugin",
"version": "0.1.0",
"capabilities": ["info", "add-or-update"]
}Verify inside the container:
docker compose -f docker/docker-compose.cd.yml --env-file .env \
exec -T weblate /app/venv/bin/python -c \
"from django.conf import settings; assert 'boost_weblate.formats.quickbook.QuickBookFormat' in settings.WEBLATE_FORMATS, 'QuickBook not in WEBLATE_FORMATS'"docker compose -f docker/docker-compose.cd.yml --env-file .env \
exec -T weblate /app/venv/bin/celery -A weblate.utils.celery inspect pingThe full pipeline (cd.yml) triggers on a successful CI run against develop:
- SSH to the deploy server
git pull origin developdocker compose … build && up -d- Poll
${WEBLATE_URL_PREFIX}/healthz/onWEBLATE_PORTfor up to 180 s - On failure: dump the last 40 lines of container logs and exit non-zero
Concurrency is locked per branch (cancel-in-progress: false) so deploys never overlap.
docker compose -f docker/docker-compose.cd.yml --env-file .env logs weblate | tail -80Common causes:
| Symptom | Likely cause | Fix |
|---|---|---|
AppRegistryNotReady |
Upstream Weblate reformatted FormatsConf.FORMATS |
Update the _FORMATS_BLOCK regex in settings_override.py |
connection refused on Postgres |
pg_hba.conf or firewall blocking Docker bridge |
Allow 172.17.0.0/16 in pg_hba.conf; reload Postgres |
WEBLATE_ADMIN_PASSWORD … set in .env |
.env missing or variable unset |
Ensure .env exists at repo root with both required secrets |
${WEBLATE_URL_PREFIX}/healthz/ 404 |
WEBLATE_URL_PREFIX mismatch |
Ensure .env has WEBLATE_URL_PREFIX matching nginx config |
| Redis connection error | External network missing | Run docker network create boost-data-collector_default or start the BDC stack first |
If Celery tasks fail with "No ED25519 host key is known for github.com":
docker compose -f docker/docker-compose.cd.yml --env-file .env \
exec -T weblate sh -c \
'ssh-keyscan -t ed25519,rsa github.com >> /app/data/ssh/known_hosts 2>/dev/null'docker compose -f docker/docker-compose.cd.yml --env-file .env restart weblatedocker compose -f docker/docker-compose.cd.yml --env-file .env down -v --remove-orphans