The README grew a section per feature and is a good reference, but nothing said where to begin. docs/wiki now has a getting-started page, a guide that walks through one day with the workspace and explains each part where it comes up, and a page per part of the app, each with screenshots of what it describes. Three pages are read out of the code rather than written, so they cannot drift from it: the keys and commands from Help.svelte and commands.ts, the same lists `:help` draws; the settings from .env.example, which gains a heading for the vault, trash and history settings so they no longer sit under mail; and the API from the README's table. `make wiki` writes them, and `--check` fails when one is stale or a link between pages leads nowhere. `--publish` lays the pages out for a GitHub wiki: links without `.md`, images beside them, `[[` escaped so the wiki does not take a command's help text for a link to a page. The screenshots are taken by `make screenshots`: the debug binary on a temporary data directory, with a password made up for the run, filled with an example workspace over the API, and a headless Chromium driven over the DevTools protocol through the views the docs show. Nothing outside the temporary directory is touched but docs/images, and the pictures are cut to 256 colours, a third of their size, which a dark UI does not show. The README opens with the banner, a CI badge, the guide, the features grouped by what they are for, and six of the screenshots.
2.4 KiB
Deploying
The workspace is one binary with the frontend inside, and one data directory. It needs no database server and no runtime on the host.
On a server
- Build it:
make buildmakestarget/release/narl-workspace. - Copy the binary and a
.envto the server. SetWORKSPACE_USER,WORKSPACE_PASSWORDandWORKSPACE_SECRET; the server will not start with the examples from.env.example. - Put a reverse proxy that terminates TLS in front of
WORKSPACE_BIND, and setWORKSPACE_SECURE_COOKIE=1. - Keep
WORKSPACE_DATA_DIRsafe. It is the whole state: the database and the uploads.
The proxy must:
- pass the
Hostheader through unchanged, because a write that a browser says came from another origin is refused; - allow request bodies as large as
WORKSPACE_MAX_UPLOAD_MB; - not weaken the security headers the app sends (
Content-Security-Policy,Referrer-Policy: no-referrerand the rest).
GET /api/health answers without a login, for a supervisor. SIGTERM gives
requests in flight eight seconds to finish.
Docker
cp .env.example .env # set WORKSPACE_USER, WORKSPACE_PASSWORD, WORKSPACE_SECRET
docker compose up -d --build
The image builds the frontend with bun and the binary with cargo, then ships
only the binary on debian:trixie-slim, running as an unprivileged user. The
database and uploads live in the diary-data volume. Keep
COMPOSE_PROJECT_NAME=narl-diary if you rename the directory, or compose looks
for the volume under a new name and finds an empty one.
The port is published on 127.0.0.1:4242 only. To serve it through traefik,
copy compose.override.yml.example to compose.override.yml and set the host.
It joins the external narl network, drops the published port, and sets
WORKSPACE_SECURE_COOKIE=1.
Sessions and security
- Every signed-in browser is a row on the server.
:sessionslists them,:sessions rm <n>signs one out and locks the vault, and:logout!signs out every one. - Changing
WORKSPACE_SECRETorWORKSPACE_PASSWORDalso signs everyone out. - Wrong passwords are answered more slowly each time, up to 30 seconds. A browser that has logged in before is slowed only by its own mistakes.
- With
WORKSPACE_SECURE_COOKIE=1the cookie isSecureand__Host-prefixed, and every answer carries HSTS for a year. - Uploads are only served as types that cannot run in the browser.
See Configuration for every setting.