Installation
Zhang is a single program, zhang. Its serve command loads a ledger and serves the web UI and the HTTP API on one port. Run it with Docker, download a release binary, or build it from source.
Docker
Section titled “Docker”The image is kilerd/zhang on Docker Hub, for linux/amd64 and linux/arm64:
kilerd/zhang:latest: the latest release.kilerd/zhang:<version>, such askilerd/zhang:0.2.0: a specific release.
The image runs zhang serve /data --port 8000. Mount the folder that holds your ledger at /data and publish port 8000:
docker run --name zhang -v "/path/to/ledger:/data" -p "8000:8000" kilerd/zhang:latestOpen http://localhost:8000. Zhang reads main.zhang in the mounted folder. If the file does not exist yet, Zhang starts with an empty ledger and creates files when you record something in the web UI.
Arguments after the image name are added to the zhang serve command, and environment variables are passed with -e. For example, to read a beancount main file and enable the password login:
docker run --name zhang -v "/path/to/ledger:/data" -p "8000:8000" \ -e "ZHANG_AUTH=admin:change-me" \ kilerd/zhang:latest --endpoint main.beanWith Docker Compose:
services: zhang: image: kilerd/zhang:latest ports: - "8000:8000" volumes: - ./ledger:/data environment: ZHANG_AUTH: "admin:change-me" restart: unless-stoppedThe image sets RUST_LOG=info, so docker logs zhang shows what Zhang does, including the reason when the ledger cannot be loaded. It runs Zhang as root: files it creates in /data belong to root on the host (see file permissions).
Release binaries
Section titled “Release binaries”Each release has binaries named zhang-<version>-<target>, with the web UI built in:
| Platform | Target |
|---|---|
| Linux, x86-64 | x86_64-unknown-linux-gnu |
| Linux, ARM64 | aarch64-unknown-linux-gnu |
| macOS, Intel | x86_64-apple-darwin |
| macOS, Apple silicon | aarch64-apple-darwin |
There is no Windows binary; use Docker there. Download the file for your platform, rename it to zhang, make it executable and put it in a folder on your PATH:
mv zhang-*-x86_64-unknown-linux-gnu zhangchmod +x zhangsudo mv zhang /usr/local/bin/zhang serve /path/to/ledgerIf macOS refuses to open a binary downloaded with a browser, remove the quarantine flag with xattr -d com.apple.quarantine zhang.
Building from source
Section titled “Building from source”You need a stable Rust toolchain, Node.js with pnpm 9 for the web UI, and a C compiler, make and perl (OpenSSL is compiled from source).
git clone https://github.com/zhang-accounting/zhang.gitcd zhang/frontendpnpm installpnpm buildcd ..cargo build --release --bin zhang --features frontendThe binary is target/release/zhang. The frontend feature embeds the web UI built in frontend/dist. Without it, the server answers with a short notice instead of the web UI, and only the HTTP API works.
zhang serve
Section titled “zhang serve”zhang serve [OPTIONS] <PATH>| Option | Environment variable | Default | Description |
|---|---|---|---|
<PATH> |
required | The folder of the ledger. The S3, WebDAV and GitHub data sources ignore it and use their own settings. | |
-e, --endpoint <FILE> |
main.zhang |
The main file, relative to <PATH>. Its extension selects the format: .zhang, or .bean, .beancount and .bc for beancount. Zhang stops with an error on any other extension. |
|
--addr <ADDRESS> |
0.0.0.0 |
The address to listen on. Use 127.0.0.1 to accept connections from this computer only. |
|
-p, --port <PORT> |
8000 |
The port to listen on. | |
--auth <USER:PASSWORD> |
ZHANG_AUTH |
none | Enables the password login. See Authentication. |
--passkey <SECRET> |
ZHANG_PASSKEY |
none | Enables the passkey login. The value is the secret needed to register a passkey. See Authentication. |
--source <SOURCE> |
ZHANG_DATA_SOURCE |
fs |
Where the ledger is stored: fs (local file system), s3 (S3), web-dav (WebDAV) or github (GitHub). |
--no-report |
off | Stops the anonymous usage report: once an hour, Zhang sends its version and build date to https://zhang-cloud.kilerd.me/client_report. |
A command-line option takes precedence over its environment variable. An --auth or ZHANG_AUTH value without a colon is ignored, and an unknown ZHANG_DATA_SOURCE value falls back to fs.
Other environment variables:
| Variable | Description |
|---|---|
ZHANG_SESSION_SECRET, ZHANG_PASSKEY_ORIGIN, ZHANG_PASSKEY_RP_ID |
Sessions and passkeys, see Authentication. |
ZHANG_S3_*, ZHANG_WEBDAV_*, ZHANG_GITHUB_* |
The settings of the S3, WebDAV and GitHub data sources. |
ZHANG_QUERY_MAX_RESULT_VALUES |
How many values a query result may hold before the query is stopped. Default 1000000. Lower it on a machine with little memory. |
ZHANG_LOG |
The log filter, such as info, debug or zhang_core=trace (env_logger syntax). When it is not set, RUST_LOG is used; without either, the level is info. The Docker image sets RUST_LOG=info. |
When the ledger cannot be loaded at startup, for example because of a syntax error, or the port is already in use, zhang serve prints the reason on stderr and exits with code 1, so systemd, Docker and hosting platforms see a failed start. Problems in the books themselves, such as an unbalanced transaction, do not stop the server: they are listed in the web UI.
Other commands
Section titled “Other commands”zhang updatereplaces the binary with the latest release for your platform, see Upgrading.zhang parseandzhang exportare placeholders: they do not read the ledger yet. To check a ledger, startzhang serveand look at the error list in the web UI.
Next steps
Section titled “Next steps”- Your First Ledger writes a small ledger and tours the web UI.
- Coming from Beancount explains how to serve an existing beancount ledger.
- Authentication protects an instance that others can reach.
