Development setup (source)¶
This is the development path for step 4: build CHAP from a local clone so you can change chap-core or models. For the quicker alternative and its trade-offs, see Choose how to run CHAP.
Here you clone the chap-core repository and build it with Docker Compose, layering in the
chapkit models overlay. (You still run it in containers - you are building the image from
the cloned code, not running Python by hand.) CHAP then runs as its own Compose project (not
on DHIS2's network), so DHIS2 reaches it on the host - and DHIS2's chap-route-init already
points the route there, so the two connect with no extra configuration.
Do not run both CHAP setups at once
The bundled CHAP (compose.chapkit.yml) and this locally built CHAP both use port 8000.
Run only one. If the bundled stack is up, drop CHAP and keep DHIS2 with
docker compose up -d --remove-orphans (in docker-dhis2-core) before bringing up the
locally built CHAP here.
Before you start
DHIS2 is running on its own - docker compose up -d in docker-dhis2-core (the DHIS2-only
stack, not the chap overlay) - and you can log in with admin / district.
Step 1 - Get chap-core¶
In a new terminal, clone chap-core next to your DHIS2 folder:
The defaults in .env are fine for local use - you do not need to edit anything.
Step 2 - Start chap-core with the chapkit models¶
What each part means:
compose.yml- chap-core itself: the API, a background worker that runs models, a Redis broker, and a Postgres database.compose.chapkit.yml- an umbrella overlay that pulls in the chapkit-based model services. Today that is just EWARS; more chapkit models get added here over time. Each one registers itself with chap-core on startup.--buildbuilds chap-core from the source in this folder. The first build takes a while; later starts are fast.
Apple Silicon (M1/M2/M3) Macs
chap-core itself builds for your machine's architecture. The amd64-only piece is the
model image: the bundled EWARS model (INLA/R) is published for amd64, so on an
Apple-Silicon Mac it runs under emulation - you will see a harmless platform does not match
warning, and it just runs a little slower.
Handy commands while developing (from the chap-core folder). The
-f compose.yml -f compose.chapkit.yml pair selects the same stack each time:
# rebuild and restart after editing chap-core source (keeps data)
docker compose -f compose.yml -f compose.chapkit.yml up -d --build
# print the chap_core version running inside the container
docker compose -f compose.yml -f compose.chapkit.yml exec chap \
python -c 'import chap_core; print(chap_core.__version__)'
# full clean rebuild, WIPES the chap database
docker compose -f compose.yml -f compose.chapkit.yml down -v
docker compose -f compose.yml -f compose.chapkit.yml build --no-cache
docker compose -f compose.yml -f compose.chapkit.yml up -d
Step 3 - Verify chap-core is up¶
chap-core publishes its API on http://localhost:8000:
curl -s http://localhost:8000/health | jq
curl -s http://localhost:8000/v2/services | jq -r '.services[].info.display_name'
The health check should return healthy, and the services list should include
CHAP-EWARS Model (chapkit). The interactive API docs are at
http://localhost:8000/docs.
Step 4 - The DHIS2 route is already wired¶
Your locally built CHAP runs on your host, not on DHIS2's network, so DHIS2 reaches it at
http://host.docker.internal:8000 - the special hostname a container uses to reach a service
on the host. DHIS2 already pointed the chap route there for you - its chap-route-init
one-shot (which runs with the DHIS2-only stack) repoints the route the demo database ships at
host.docker.internal:8000, so there is nothing to configure here. Confirm it:
curl -s -u admin:district \
"http://localhost:8080/api/routes.json?filter=code:eq:chap&fields=code,url" | jq -c '.routes[0]'
Running CHAP on a different port?
The default target is port 8000. If your locally built CHAP uses another port, set it
before starting DHIS2:
CHAP_ROUTE_URL=http://host.docker.internal:8001/** docker compose up -d (in
docker-dhis2-core). Or repoint the existing route by hand with a PUT to
…/api/routes/<id> carrying {"name":"chap","code":"chap","url":"<your-url>/**"} (see the
DHIS2 Route API).
Step 5 - Test the connection end to end¶
A healthy response means the full path works: your browser -> DHIS2 -> route -> the
chap-core you built.
Assignment: your built chap-core connected
-
curl http://localhost:8000/healthreturnshealthy. -
/v2/serviceslistsCHAP-EWARS Model (chapkit). - The proxy check
…/api/routes/chap/run/healthreturnshealthy.
Troubleshooting¶
| Symptom | Likely cause / fix |
|---|---|
| Proxy returns a connection error | chap-core is not running, or is on a different port. Check docker compose -f compose.yml -f compose.chapkit.yml ps and curl http://localhost:8000/health. |
Proxy points at http://chap:8000 |
The route was left targeting the bundled service by a previous bundled run (compose.chapkit.yml). Re-run docker compose up -d (DHIS2 only, in docker-dhis2-core) to repoint it back at host.docker.internal:8000. |
Port 8000 already in use |
The bundled CHAP (compose.chapkit.yml) is still running. Stop it first - see the warning at the top. |
platform does not match warning |
Harmless emulation notice on Apple-Silicon Macs (see Step 2). |
Next step¶
Continue to step 5: install the DHIS2 apps.