An image that bundles:
| Component | Source |
|---|---|
| Kresus | npm release pinned in the Dockerfile (0.26.0, build-arg KRESUS_VERSION) |
| Woob | https://gitlab.com/woob/woob at the master commit the patches were made against (3bc0f159c, build-arg WOOB_REF: branch, tag or full SHA) |
| Patched modules | boursedirect, esalia, fortuneo: one patch per module in patches/, applied on top of master |
bp module |
the master one, with what its Selenium login needs: Firefox ESR, geckodriver, selenium |
| Sure bridge | sure-bridge/sure-bridge.py, run every day by the sure-bridge service |
| Crypto ledger | crypto-ledger/crypto-ledger.py: archive of the Binance and Kraken movements, cost per coin, export replayed in Sure by the bridge |
Kresus uses the modules of the embedded Woob checkout directly (KRESUS_WOOB_SOURCES_LIST points to
file:///opt/woob/modules): it does not download a module release.
cp config/sure-bridge.env.example config/sure-bridge.env # then edit: Sure API key, account names
docker compose up -d --buildKresus UI: http://localhost:9876 (add your bank accesses).
| Service | Role | Persistence |
|---|---|---|
kresus |
Kresus + Woob | volume kresus-data (/var/lib/kresus): SQLite database, config.ini with the encryption salt, sessions, module exports |
sure-bridge |
sure-bridge.py sync at SURE_SYNC_TIME (07:30 by default) |
volume sure-bridge-state (what has already been sent); configuration in config/sure-bridge.env (outside the image) |
crypto-ledger.py sync just before the bridge, in the same service |
volume crypto-ledger (archive of the exchange movements, see crypto-ledger/README.md) |
The volumes survive docker compose down and image rebuilds. docker compose down -v deletes them:
back them up first (see below).
Edit config/sure-bridge.env on the host, then docker compose restart sure-bridge. KRESUS_URL is
http://kresus:9876 (the service name). Optional variables in .env (template: .env.example):
TZ, KRESUS_PORT, SURE_SYNC_TIME (HH:MM), SURE_RUN_ON_START=1 (also send at startup).
docker compose run --rm sure-bridge sure-bridge.py accounts # check the account names
docker compose run --rm sure-bridge sure-bridge.py sync --dry-run # dry run
docker compose logs -f sure-bridge # output of the sendsThe Sure accounts must exist before the first send. See sure-bridge/README.md.
The Dockerfile pins the Kresus version, the Woob commit and the Selenium and geckodriver versions, so the patches
keep applying. The base image (node:24-bookworm-slim) is deliberately not pinned: a rebuild picks up its latest
security updates. To upgrade:
docker compose build --build-arg KRESUS_VERSION=latest --build-arg WOOB_REF=master # try the newest of boththen, if it works, put the new values in the Dockerfile and commit. The patches are applied with git apply:
if Woob changed the same lines, the build fails (it never produces a half-patched image). Regenerate the
patches from your local clone, which must be on the commit you want to build:
scripts/make-patches.sh /path/to/woob feat/boursedirect-esaliaIt writes one patch per module (0001-boursedirect.patch, 0002-esalia.patch, ...) and none for a module that no
longer differs from upstream, so a patch can be dropped on its own once upstream has integrated the fix.
Multi-stage build on node:24-bookworm-slim: compilers, -dev packages, git and npm caches stay in the builder
stage, and npm/yarn, the icon theme and the docs are removed from the final image. About 1.3 GB uncompressed (a
single-stage build on the full node image was 3.1 GB). Firefox ESR, which the bp module's Selenium login needs,
is about 0.5 GB of it with its libraries, so there is no browser-less variant.
The image is published to GitHub Container Registry as ghcr.io/gamso/kresus_docker by
.github/workflows/publish.yml whenever a version tag is pushed:
git tag v1.0.1 && git push origin v1.0.1 # publishes 1.0.1, 1.0 and latestPull requests only run a test build. docker-compose.yml uses ghcr.io/gamso/kresus_docker:${IMAGE_TAG:-1.0.0};
set IMAGE_TAG in .env to pick another version. Number a release whenever the pinned Kresus or Woob version in the
Dockerfile changes. The package is private until you make it public (your GitHub profile → Packages →
kresus_docker → Package settings → Change visibility); only the amd64 architecture is built.
docker run --rm -v kresus-docker_kresus-data:/d -v "$PWD":/b alpine tar czf /b/kresus-data.tgz -C /d .
docker run --rm -v kresus-docker_crypto-ledger:/d -v "$PWD":/b alpine tar czf /b/crypto-ledger.tgz -C /d .(Volumes are prefixed with the compose project name kresus-docker: see docker volume ls.) The salt in config.ini
encrypts the bank credentials: without it the backed-up database is unusable. The crypto ledger archive keeps
movements the exchanges may no longer return: without it, only what they still have can be fetched again.
- Selenium and Firefox: Woob still calls
find_element_by_xpath(removed in Selenium 4.3),capabilities=andservice_log_path=(removed in 4.10), so the image pinsselenium==4.2.0(SELENIUM_VERSION). With a newer version thebpSelenium login fails (AttributeError) and the module falls back to the "legacy" HTTP browser: strong authentication at every login, and a 403 from the bank with Woob's frozen Firefox 102 User-Agent. Firefox runs headless withshm_size: 1gb. - Hard-coded paths: the
boursedirectandesaliamodules write to/var/lib/kresus(Esalia tokens, JSON positions and history, device id; Bourse Direct positions and account history). That is the data volume; the bridge reads the positions read-only. - Bourse Direct history backfill: the account history page only goes back about two months. On the first sync
(no
boursedirect-avis-<account>.jsonyet) the module walks the trade confirmations ("avis d'opéré", one page per day, month by month) back to the first one, saves them in that file and adds the operations older than the history page toboursedirect-history-<account>.json. Later syncs only use the history page. To redo the backfill, delete both files and sync again. - Esalia: the module registers the terminal (
REMEMBER_DEVICE = True) with an identifier stored in/var/lib/kresus/esalia-device-id, i.e. in the volume. If the OTP code is asked again every day, look indocker compose logs kresusfor the line "new device identifier generated": it means the identifier was recreated (volume lost or not mounted). If the identifier is stable and the code is still asked, setESALIA_KEEP_COOKIES=1in.envand rundocker compose up -d: the module then keeps its cookies between full logins (they are cleared by default), in case Esalia recognizes the trusted terminal through a cookie. Enter the OTP code once, then check the 03:00 sync the next day. Experimental, off by default. - Bourse Direct: the module sets a 60 s HTTP timeout (Woob's default is 10 s) because the legacy
/priv/pages can be slow right after a fresh login. - Tested: build, startup, Kresus health, loading of the
bp,fortuneo,boursedirectandesaliamodules, Firefox + geckodriver + Selenium headless, bridge reaching Sure.
Kresus: AGPL-3.0. Woob and its modules: LGPL-3.0-or-later (the patches are modifications of them). The rest: personal use.