Test / test (push) Successful in 7m5s
Release / gates (push) Successful in 7m28s
Release / build (amd64, freebsd) (push) Successful in 2m52s
Release / build (amd64, linux) (push) Successful in 2m46s
Release / build (arm64, freebsd) (push) Successful in 2m22s
Release / build (arm64, linux) (push) Successful in 2m38s
Release / build (loong64, linux) (push) Successful in 2m7s
Release / build (riscv64, linux) (push) Successful in 2m17s
Release / release (push) Successful in 1m0s
Assisted-by: GLM 5.3
274 lines
10 KiB
Markdown
274 lines
10 KiB
Markdown
# Command line
|
|
|
|
The reference below is taken from the program's own `--help`. If the two
|
|
disagree, the program is right and this file is a defect. The same reference
|
|
ships as a manual page, [man/volumen.1](../man/volumen.1), and the page moves
|
|
in the same commit as the flags it documents.
|
|
|
|
## Synopsis
|
|
|
|
```sh
|
|
volumen <command> [options]
|
|
```
|
|
|
|
## Commands
|
|
|
|
| Command | Purpose |
|
|
|---|---|
|
|
| `serve` | Start the publishing server |
|
|
| `status` | Show installation status |
|
|
| `doctor` | Check installation health |
|
|
| `check-update` | Compare with the latest Gitea release |
|
|
| `export` | Export posts, media, and users to a tar.gz |
|
|
| `import` | Import a backup archive |
|
|
| `publish-due` | Publish scheduled posts whose date arrived |
|
|
| `validate` | Validate the content directory |
|
|
| `version` | Show version |
|
|
|
|
## `volumen serve`
|
|
|
|
```text
|
|
volumen serve [--config <path>] [--content <dir>] [--host <addr>] [--port <n>]
|
|
```
|
|
|
|
| Flag | Default | Meaning |
|
|
|------|---------|---------|
|
|
| `--config` | `/etc/volumen/config.toml`, then `~/.config/volumen/config.toml` | Path to `config.toml` |
|
|
| `--content` | from config | Override the posts directory |
|
|
| `--host` | from config (`::`) | Override the bind address |
|
|
| `--port` | from config (`9091`) | Override the port |
|
|
|
|
A `--port` outside `1..65535` is rejected rather than ignored, and a positional
|
|
argument is an error.
|
|
|
|
Starts the HTTP server: the public API under `/api/volumen`, the admin under
|
|
`/admin`, uploaded media under `/media`, plus `/healthz`, `/robots.txt`,
|
|
`/sitemap.xml` and `/favicon.ico`. The configuration is validated at startup;
|
|
invalid values abort with exit code `1`, before the socket is bound.
|
|
|
|
With no `--config` the server reads `/etc/volumen/config.toml` if it exists,
|
|
then `~/.config/volumen/config.toml`, and when neither exists it runs on the
|
|
built-in defaults. Those defaults put the state under the user's home
|
|
(`~/.local/share/volumen`, honouring `XDG_DATA_HOME`), so a plain
|
|
`volumen serve` on a fresh machine works without root and without any
|
|
configuration file. On the first start the account file is empty and
|
|
`/admin` shows the first-run wizard: it creates the administrator account,
|
|
the interface language and the colour scheme, and signs the operator in. The
|
|
server keeps the session secret it generates in `secret.key` beside the
|
|
account file; `[admin].session_key` overrides it.
|
|
|
|
The server sets a 10 second read-header timeout, a 60 second read timeout, a
|
|
120 second write timeout and a 120 second idle timeout, and bounds a request
|
|
line and its headers at 1 MiB. `SIGINT` and `SIGTERM` drain in-flight requests
|
|
for up to 15 seconds and then exit `0`.
|
|
|
|
When `[scheduler].enabled = true`, an internal goroutine publishes the due
|
|
posts once at start-up and then every `[scheduler].interval` seconds. A
|
|
background release check fills the admin update banner without blocking
|
|
requests. Logging goes to stderr, either as text or as JSON lines when
|
|
`[server].log_format = "json"`; the server's own protocol errors go there too,
|
|
through `log/slog`, rather than to a bare stderr line. Every request carries a
|
|
16-character id: it is answered in `X-Request-Id`, it is attached to every line
|
|
the handlers write for that request, and the request's own access line records
|
|
the method, the path, the status and the duration under it.
|
|
|
|
## `volumen status`
|
|
|
|
```text
|
|
volumen status [--config <path>] [--data <dir>] [--users-file <path>] [--json]
|
|
```
|
|
|
|
Reports whether the config exists, parses and validates, the number of posts
|
|
(with the draft count), and the number of users; with no accounts yet the user
|
|
count carries the hint `open /admin to run the setup wizard`. `--json` prints
|
|
`{"ok": true, "checks": {…}}`, with a `config_validate` entry naming the first
|
|
invalid value, a `posts_unreadable` entry when a post file cannot be parsed, and
|
|
`users: "unreadable"` when the accounts file cannot be read. Exit code `1` when
|
|
the config is missing, unparseable or invalid, when content cannot be parsed, or
|
|
when the users file cannot be read.
|
|
|
|
Read-only: it inspects the content directory without creating or changing
|
|
anything, so a mistyped `content_dir` is reported rather than turned into an
|
|
empty tree.
|
|
|
|
## `volumen doctor`
|
|
|
|
```text
|
|
volumen doctor [--config <path>] [--json]
|
|
```
|
|
|
|
Runs the health checks: config presence and validation, whether every post file
|
|
can be parsed, whether every post renders, whether the users file can be read,
|
|
whether the installation has its first account, and whether any stored scrypt
|
|
parameters are below the policy floor. The
|
|
checks carry two levels: a missing or broken config, an unreadable content
|
|
directory and an unreadable users file are `fail` and exit code `1`; posts
|
|
that fail to render, an installation still waiting for the first-run wizard
|
|
and weak stored hashes are `warn`, reported without
|
|
changing the exit code. `--json` prints
|
|
`{"ok": bool, "checks": [{"name", "status", "detail"}]}`.
|
|
|
|
## `volumen check-update`
|
|
|
|
```text
|
|
volumen check-update [--json]
|
|
```
|
|
|
|
Compares the running version with the latest release published on the Gitea
|
|
instance (`https://sourcedock.dev/petrbalvin/volumen/releases`).
|
|
|
|
| Exit code | Meaning |
|
|
|-----------|---------|
|
|
| `0` | Up to date (or the local build is newer) |
|
|
| `1` | A newer release is available, or the release check failed (offline, timeout, malformed response) |
|
|
| `2` | The arguments were wrong |
|
|
|
|
`--json` prints `{"current": …, "latest": …, "available": bool}` and keeps the
|
|
same exit-code contract, so it works as a CI or monitoring probe.
|
|
|
|
## `volumen export`
|
|
|
|
```text
|
|
volumen export [--config <path>] [--out <archive>]
|
|
```
|
|
|
|
Writes a `.tar.gz` containing `posts/` (including `.revisions/` and `media/`),
|
|
`users.toml`, `templates.toml` and `tokens.toml`. Default output:
|
|
`volumen-backup.tar.gz`, written mode `0600`.
|
|
|
|
The config file is deliberately not included: it may hold the session signing
|
|
key override, and `volumen import` ignores it anyway. A file that exists but cannot be read
|
|
aborts the export rather than producing an archive that looks complete: the
|
|
archive is written to a temporary file and renamed into place, so a failure
|
|
leaves the previous backup untouched. Exit code `1` on I/O errors.
|
|
|
|
## `volumen import`
|
|
|
|
```text
|
|
volumen import [--config <path>] <archive>
|
|
```
|
|
|
|
Restores an archive produced by `volumen export` or the admin Backup panel
|
|
into the configured locations. An archive entry named `users.toml`,
|
|
`templates.toml` or `tokens.toml` is written to the path the deployment
|
|
configures for that file, which may be a different name; the post files under
|
|
`posts/` are written into the content directory.
|
|
|
|
Extraction is confined to the content directory, so an entry that tries to
|
|
escape it is refused, and only post files, revision archives and images with an
|
|
allowed extension are written: the media directory is served from a public
|
|
route, so an archive can never plant a document there. The decompressed total
|
|
is bounded. Exit code `1` on a malformed archive or one that holds no file the
|
|
layout recognises.
|
|
|
|
## `volumen publish-due`
|
|
|
|
```text
|
|
volumen publish-due [--config <path>] [--dry-run] [--json]
|
|
```
|
|
|
|
Publishes every post whose `publish_at` date is today or earlier: removes the
|
|
`publish_at` key and defaults `date` to it when the post has no date. This is
|
|
the cron and systemd-timer counterpart to the in-app `[scheduler]`.
|
|
|
|
- `--dry-run` lists the due slugs without touching files.
|
|
- `--json` prints `{"published": […], "failed": n}` (or
|
|
`{"due": […], "dry_run": true}`).
|
|
- The configured webhooks receive `post.published` for every post this
|
|
publishes, the same event the admin delivers.
|
|
- Exit code `1` when a post could not be written, so a timer notices.
|
|
|
|
## `volumen validate`
|
|
|
|
```text
|
|
volumen validate [--config <path>] [--json]
|
|
```
|
|
|
|
Scans the content directory and reports: files that cannot be parsed, posts
|
|
that fail to render, duplicate slugs, slug values that do not match the slug
|
|
format, missing titles, a `publish_at` that is not a date (which withholds the
|
|
post), and alias conflicts (an alias used twice or shadowing a live slug).
|
|
Prints `content OK` when clean; exit code `1` with a problem list otherwise.
|
|
`--json` prints `{"problems": [{"slug", "path", "error"}]}`, where `path` names
|
|
the file when there is no slug to name.
|
|
|
|
A file that cannot be parsed is invisible to every other command, which is why
|
|
it is named here first.
|
|
|
|
## `volumen version`
|
|
|
|
```text
|
|
volumen version
|
|
```
|
|
|
|
Prints `volumen <version>`: the release the toolchain recorded in the
|
|
binary's build information. A release binary reports its tag (`v1.0.0`); a
|
|
build from a plain checkout reports a pseudo-version naming the commit; a
|
|
build outside version control reports `(devel)`, and a dirty tree appends
|
|
`+dirty`. Nothing injects the version, so the reported value cannot go stale.
|
|
|
|
## Global flags
|
|
|
|
| Flag | Effect |
|
|
|---|---|
|
|
| `-h`, `--help`, `help` | prints the usage block and exits `0` |
|
|
| `-v`, `--version` | prints `volumen <version>` and exits `0` |
|
|
| `-h` on a subcommand | prints that subcommand's flags and exits `0`; `version` prints the version instead |
|
|
|
|
An unknown command and an unknown flag exit `2`. Every subcommand rejects a
|
|
stray positional argument with exit code `2`; `import` is the one command whose
|
|
positional argument (`<archive>`) is required.
|
|
|
|
## Exit codes
|
|
|
|
| Code | Meaning |
|
|
|---|---|
|
|
| `0` | success |
|
|
| `1` | a failure the program detected: an unreadable config, a failed write, a content directory with a problem, a release check that could not run |
|
|
| `2` | the arguments were wrong |
|
|
|
|
`check-update` is the exception that proves the rule: it exits `1` both when a
|
|
newer release exists and when the release check failed, so a monitoring probe
|
|
reads its `--json` output rather than its status alone.
|
|
|
|
## Examples
|
|
|
|
Serve a checkout against its own content, with the scheduler on:
|
|
|
|
```sh
|
|
volumen serve --config ./config.toml --content ./posts
|
|
```
|
|
|
|
Start a fresh per-user installation and open the wizard:
|
|
|
|
```sh
|
|
volumen serve
|
|
```
|
|
|
|
The server comes up on `http://localhost:9091`; `/admin` shows the
|
|
first-run wizard, which creates the administrator account and signs the
|
|
operator in. The state lives under `~/.local/share/volumen`, and the
|
|
session secret in `secret.key` beside it.
|
|
|
|
Publish what a timer missed, then check the content directory:
|
|
|
|
```sh
|
|
volumen publish-due --dry-run
|
|
volumen publish-due
|
|
volumen validate
|
|
```
|
|
|
|
Back up a deployment and restore it into a second one:
|
|
|
|
```sh
|
|
volumen export --config /etc/volumen/config.toml --out /backup/volumen.tar.gz
|
|
volumen import --config /srv/staging/config.toml /backup/volumen.tar.gz
|
|
```
|
|
|
|
Find out why a fresh install will not start:
|
|
|
|
```sh
|
|
volumen doctor --config /etc/volumen/config.toml
|
|
volumen status --config /etc/volumen/config.toml --json
|
|
```
|