---
title: "Image CLI"
description: "The image is an appliance: the notarium entrypoint, the start, backup, restore, admin and version commands, and the exit-code contract."
---

# Image CLI

The image already knows how to start itself: there's no command to append to `docker run` — by default it brings up the server. An argument replaces only the command, so a one-off operation reads naturally — `docker run … IMAGE restore`.

Operator commands go into a running container through `docker exec`, under short names:

```bash
docker exec notarium backup
docker exec -it notarium admin list
```

## Commands

| Command | What it does | How it's usually invoked |
|---|---|---|
| `start` | Runs the HTTP/MCP server as PID 1 | The image's default command |
| `backup` | Streams out a verified online ZIP | `docker exec notarium backup` plus the safe publish sequence from the [runbook](/docs/self-hosting/backup/) |
| `backup verify` | Checks an archive, changing nothing | `docker exec -i notarium backup verify < file` |
| `restore` | Installs an archive into an empty data root | A one-off container on a fresh volume |
| `admin` | Recovers access outside the interface | `docker exec -it notarium admin …` |
| `healthcheck` | Polls the local `/api/health` | Docker's `HEALTHCHECK` |
| `version` | Version, commit, build time, and a link to the sources (`--json` for scripts) | Support and compatibility checks |
| `help` / `--help` | Describes the CLI or a single command | Any container |

`start` stays in the foreground, so container signals reach the server directly — `docker stop` shuts it down cleanly. There's deliberately no stop or restart command: that's the orchestrator's job. Schema migrations are applied at startup; you never run them as a separate command.

## Streams and exit codes

- In streaming mode (without `--output`), `backup` puts **only** ZIP bytes on stdout; diagnostics and the closing summary go to stderr. With `--output FILE` the archive is written to that file and a single JSON summary goes to stdout — don't redirect it into a `.zip`, what lands there isn't an archive.
- `backup verify`, `restore`, and the non-interactive `admin` commands print their result to stdout.
- Errors go to stderr and return a non-zero code. Unknown commands, unknown options, repeated options, and options with no value **fail** rather than being silently ignored.
- The canonical transport under Docker is **stdin and stdout**. The paired `--output FILE` on `backup` and `--input FILE` on `verify`/`restore` exist for setups where the container can already see the directory. `--output` has a welcome side effect: the command writes to a temporary file itself, verifies the archive, and publishes it atomically without overwriting anything, so there's no shell wrapper to write.
- Every command has `--help`; `notarium --version` is equivalent to `notarium version`.

## Build identity

`version` prints exactly what you're running — the starting point for any conversation about compatibility and for any upgrade:

```bash
docker run --rm docouno/notarium:latest version
docker compose exec notarium version --json
```

`version --json` returns the same thing as a single object — `version`, `commit`, `builtAt`, and `source` (a link to the exact source revision) — so a "what's deployed" check can go straight into your deploy pipeline. Whatever the build honestly doesn't have comes back as `null`: values are never invented, so you can rely on them. The same information is in the interface — **Settings → About**.

> [!important] Version tags are immutable
> A published version tag always means one specific image: `:0.1.0` will never move to a different build. In production, pin to a version rather than to `:latest`. The published image is built for `linux/amd64`; on other architectures, build from source.

## Health checks

`healthcheck` returns a zero exit code only when the local `/api/health` endpoint reports healthy. It's built for Docker's `HEALTHCHECK` directive and for orchestrator probes — no external dependencies and no `curl` on the host required.

## Recovering access

`admin` is the host's operator boundary. The ordinary ways to change a password all live in the app (your own password in the interface, someone else's through a one-time link from an administrator). The CLI is there for something else: **forcing** a password without presenting the current one, and issuing an administrator out of band. For those two operations there is deliberately no HTTP path — there's nothing to present — so they belong to whoever has access to the host.

```bash
docker compose exec notarium admin list
docker compose exec notarium admin create-admin <user> --random
```

The full list of commands and what each one means — [Authentication](/docs/self-hosting/authentication/#recovering-access).

## Next

- [Backup and restore](/docs/self-hosting/backup/) — the runbook behind `backup`, `backup verify`, and `restore`.
- [Authentication](/docs/self-hosting/authentication/) — what `admin` can do and when you need it.
- [Installation](/docs/self-hosting/install/) — running the image and the data volume.
