Installation
dmart is one program, dmart: the server, the admin UIs it serves (cxb at /cxb/, catalog at /cat/) and the CLI. There are four ways to install it. The csdmart repository on GitHub is not public for now, so release files and the source are not open to everyone; the package repositories and the container are.
| Way | What you get | Upgrades |
|---|---|---|
| Package repositories (dnf, apt, apk) | a systemd (or OpenRC) service on SQLite, ready to start | through the package manager |
| The container | one container on port 8000, on SQLite | pull a newer image |
| Release files | the binary in a tarball, or a package file to install by hand | replace the file |
| From source | a build of your own | rebuild |
Every way can run on SQLite, with nothing else to install. PostgreSQL is optional, for several nodes or a larger instance: see Database & Storage. After installing, see Upgrading for later releases.
Package repositories
The package repositories at packages.imx.sh are signed and carry the five most recent releases. Prefer them to a downloaded file: upgrades arrive through the package manager, and the index is signed, so a tampered mirror fails instead of installing.
Fedora and RHEL 9 (dnf):
sudo rpm --import https://packages.imx.sh/dmart.asc
sudo tee /etc/yum.repos.d/dmart.repo >/dev/null <<'EOF'
[dmart]
name=dmart
baseurl=https://packages.imx.sh/rpm/fc44/x86_64
gpgcheck=1
gpgkey=https://packages.imx.sh/dmart.asc
EOF
sudo dnf install dmart
On RHEL 9, Alma or Rocky, use baseurl=https://packages.imx.sh/rpm/el9/x86_64. The two builds are not interchangeable: they link against different glibc versions.
Debian and Ubuntu (apt):
sudo install -d /etc/apt/keyrings
curl -fsSL https://packages.imx.sh/dmart.asc | sudo tee /etc/apt/keyrings/dmart.asc >/dev/null
echo "deb [signed-by=/etc/apt/keyrings/dmart.asc] https://packages.imx.sh/deb stable main" \
| sudo tee /etc/apt/sources.list.d/dmart.list >/dev/null
sudo apt update && sudo apt install dmart
Alpine (apk):
sudo curl -fsSL -o /etc/apk/keys/packages@imx.sh-6ab6757d.rsa.pub \
https://packages.imx.sh/alpine/packages@imx.sh-6ab6757d.rsa.pub
echo "https://packages.imx.sh/alpine/v3.24/main" | sudo tee -a /etc/apk/repositories
sudo apk update && sudo apk add dmart
The RPM and DEB packages are for x86-64; the APK for x86-64 and aarch64.
First start
The package writes /etc/dmart/config.env on the first install only, so an upgrade keeps your edits. It runs on SQLite at /var/lib/dmart/dmart.db, and the file explains how to switch to PostgreSQL. dmart will not start until JWT_SECRET holds a secret of at least 32 bytes that does not contain change-me. The first start creates the database, the management space with its users, roles, groups, permissions and schema folders, and the built-in dmart admin, with no password; every start creates any of these that is missing.
sudo vi /etc/dmart/config.env # set JWT_SECRET, e.g. from: openssl rand -base64 48
sudo systemctl enable --now dmart # Alpine: rc-update add dmart && rc-service dmart start
sudo dmart passwd dmart # once it has started: set the admin's password
In that order, and as root: /etc/dmart/config.env is readable by root and the dmart group only. Run before the first start, dmart passwd finds no account, changes nothing and exits with status 1; see passwd. The package's install message gives the same steps.
Then open http://<host>:8282/cxb/ and sign in as dmart. Set the password before the server is reachable from anywhere else.
The packaged service
-
User: runs as the
dmartsystem user, withWorkingDirectory=/var/lib/dmartandBACKEND_ENV=/etc/dmart/config.env. -
Logs: go to journald (
journalctl -u dmart -f). On Alpine, OpenRC runs/etc/init.d/dmartand logs to/var/log/dmart/dmart.log. -
Restarts:
Restart=on-failure, after 5 seconds. -
Changes: an upgrade replaces the unit file, so change it with a drop-in (
sudo systemctl edit dmart). For example, to serve a CXB config:[Service] ExecStart= ExecStart=/usr/bin/dmart serve --cxb-config /etc/dmart/config.json -
Completions: bash and fish completions for
dmartare installed with it. -
Removing it: removing the package stops and disables the service, and leaves
/etc/dmart,/var/lib/dmartand thedmartuser in place.
The container
podman run --name dmart -p 8000:8000 -v dmart-data:/root/.dmart -d ghcr.io/edraj/csdmart:latest
podman exec -it dmart dmart passwd dmart # once it is up: its first start creates the admin
# then open http://localhost:8000/cxb/ or http://localhost:8000/cat/
- Port: 8000, not 8282.
- Storage:
config.env, thedmart.dbdatabase, the UIs'config.jsonand the first-run marker all live in/root/.dmart. Mount a volume there, or a new container starts empty. - First run: writes a random
JWT_SECRET,DATABASE_DRIVER=sqliteandSQLITE_PATH=/root/.dmart/dmart.db. It also setsIS_SMPP_ENABLED=trueandMOCK_SMPP_API=true: SMS codes are not sent, and each appears only inpodman logs <container>. For real delivery, setSEND_SMS_OTP_APIandSMPP_AUTH_KEYand turn the mock off (MOCK_SMPP_API=false). - Admin password: the
dmartadmin has none until you rundmart passwd dmartin the container, as above. Do it before the container is reachable. - PostgreSQL:
config.envpins the driver, so to move to PostgreSQL change theDATABASE_DRIVERline topostgresqlas well as addingDATABASE_HOST,DATABASE_NAME,DATABASE_USERNAMEandDATABASE_PASSWORD. - Tags:
latestand<version>cover amd64 and arm64;<version>-amd64and<version>-arm64name one architecture.
Release files
Each release also carries the files below, on the releases page of csdmart's GitHub repository. That repository is not public for now; until it is, install from the package repositories, whose packages are the same builds, or use the container.
| Files | Runs on |
|---|---|
dmart-<v>-linux-x64.tar.gz, dmart-<v>-linux-arm64.tar.gz |
glibc 2.34 or newer (RHEL 9 and later), with libe_sqlite3.so and libargon2.so.1 beside the binary |
dmart-<v>-linux-musl-x64.tar.gz, dmart-<v>-linux-musl-arm64.tar.gz |
any Linux of that architecture: fully static |
RPM (el9, fc44) and DEB |
x86-64 only |
| APK | x86-64 and aarch64 |
dmart-<v>-win-x64.zip, dmart-<v>-osx-arm64.zip |
Windows x64 and macOS arm64; only in releases built while the repository is public |
| container image | amd64 and arm64 |
cxb-<v>.tar.gz, catalog-<v>.tar.gz |
the two admin UIs as static files; the binary already serves them |
Dmart.*.nupkg |
the .NET libraries; see Drivers & SDKs |
- libargon2: the Linux builds hash passwords with libargon2, so a missing one is a server that starts and signs nobody in. The packages depend on it (
libargon2,libargon2-1,argon2-libs); the RHEL 9 RPM bundles its own copy in/usr/lib64/dmart/, because RHEL carries libargon2 only in EPEL. The Windows and macOS builds use a managed Argon2 with the same output and need no library. - The static musl build links OpenSSL, SQLite and libargon2 into the binary, so distro security updates do not reach them: a fix in any of them needs a new dmart release. On the glibc builds, a distro OpenSSL update fixes the binary in place.
A package file installs as one from the repositories does (sudo dnf install ./dmart-*.rpm), then starts as in First start. A tarball holds the dmart binary with config.env.sample beside it. Unpack it and, from the directory that holds the binary:
./dmart init # writes ~/.dmart/config.env, the UIs' config.json and cli.ini
vi ~/.dmart/config.env # choose the database (see below)
./dmart serve # the first start creates the database and the admin
./dmart passwd dmart # in another terminal, once it is up
dmart init copies the sample, which selects PostgreSQL, and gives it a fresh random JWT_SECRET. For SQLite, set DATABASE_DRIVER="sqlite" and SQLITE_PATH instead of the DATABASE_* connection settings; see Database & Storage. The server reads ~/.dmart/config.env when BACKEND_ENV names no other file; a config.env in the current directory is never read. The server listens on port 8282 unless LISTENING_PORT says otherwise.
From source
The source is in csdmart's GitHub repository, which is not public for now. Building needs the .NET 10 SDK, and the server needs your distro's argon2 runtime package (libargon2, libargon2-1 or argon2-libs).
git clone https://github.com/edraj/csdmart
cd csdmart
cp config.env.sample config.env
vi config.env # set the database
BACKEND_ENV=./config.env dotnet run -- serve # ./config.env is never read implicitly
# in another terminal, once it is up (its first start creates the admin):
BACKEND_ENV=./config.env dotnet run --no-build -- passwd dmart
./build.sh makes a quick JIT build at bin/dmart; ./build.sh --aot makes the self-contained native binary that the releases ship.
Verifying a release
scripts/verify-release.sh, taken from the tag you deploy, checks every asset's checksum, its cosign keyless signature (made by one of csdmart's release workflows at that tag, and logged in Rekor), its SLSA build provenance and its CycloneDX SBOM attestation. It exits 0 only when every check passes, and needs cosign and gh 2.49 or later. The script and the release files are in csdmart's GitHub repository, which is not public for now. Until it is, the package managers' own checks are what verifies a package: dnf checks each package against the repository's key, and apt and apk check the repository's signed index.
TAG=vX.Y.Z # the release you deploy
git clone --depth 1 --branch "$TAG" https://github.com/edraj/csdmart
csdmart/scripts/verify-release.sh --tag "$TAG"
| Flag | Effect |
|---|---|
--require-hosted |
fail any artifact built on a self-hosted runner, as most of the distro packages are |
--commit <sha> |
also require the provenance and every signing certificate to name this commit |
--offline |
read the attestations from the release's .attestation.jsonl files instead of GitHub's API; the signature checks still contact Rekor |
--no-attestations |
for a release built while the repository was private: checksums and signatures only |
What it does not cover:
- The container image is neither signed nor attested.
- RPMs from the package repository are re-signed with the repository's key, so they no longer match the release checksums or verify against them;
rpmchecks the repository's signature instead. DEBs and APKs from the repositories are the release files byte for byte, and verify.
Checking it works
- Readiness:
curl -s http://localhost:8282/health/readyanswers200once the database answers a query, and503with the reason (database unreachable, say) until then./health/liveanswers200whenever the process is up. - A smoke test:
sudo dmart selfcheckchecks readiness, signs in as thedmartadmin, prints the server's version, lists spaces, and creates, queries, updates and deletes a test entry. On the server's own host it needs no password; see selfcheck. - The startup log names the dmart version and the database driver, and says whether the driver was set or inferred.
Next steps
- Configure it: every
config.envkey is in Settings. - Add people: users, roles and permissions are in Access Control.
- Run several nodes on one PostgreSQL database: Running several nodes.
- A small board: Small devices and diagnostics.
- Later releases: Upgrading.