Skip to main content

Configuration

All configuration goes through environment variables, validated at startup. Immediate failure with an explicit message rather than a breakdown in use: a crisis tool does not discover its own misconfiguration on the day.

The variables

Instance identity

VariablePurpose
KASTELL_URL_PUBLIQUEThe address your users type. It also builds the links sent by email.
KASTELL_ENVdeveloppement or production. In production, no example value is tolerated.
KASTELL_PORT8080 by default.
SECRET_SESSION32 characters minimum. openssl rand -hex 32.
Do not lose SECRET_SESSION

It also encrypts the credentials of your delivery gateways. Losing it makes them unreadable — that is intended, and it must be backed up somewhere other than the database it protects.

Source offer — AGPL, section 13

VariablePurpose
KASTELL_SOURCE_URLWhere to find the code of this instance. If you modified it, point at your own repository.
KASTELL_REVISIONThe exact revision, stamped at build time.

See Licence.

Database, cache, storage

DATABASE_URL, REDIS_URL, S3_ENDPOINT, S3_BUCKET, S3_ACCES, S3_SECRET, S3_REGION.

Without Redis the real-time feed degrades: each screen refreshes on action, without immediate propagation. The instance stays usable.

Video

VariablePurpose
LIVEKIT_URLWhat the browser dials.
LIVEKIT_URL_INTERNEWhat the server dials — inside a Docker compose, http://livekit:7880.
LIVEKIT_CLE, LIVEKIT_SECRETThe credentials.
Two addresses, and it matters

"localhost", seen from the application container, means the container itself. Confusing the two yields an ECONNREFUSED that the interface would otherwise report as a network failure.

In production, enable the TURN relay on port 443 in docker/livekit.yaml: it is the only port every firewall lets through, and often the only route from the hotel the team has fallen back to.

Antivirus scanning

CLAMAV_HOTE, CLAMAV_PORT. With no scanner, uploads are marked "not scanned" — never "clean".

On first start, ClamAV downloads its signatures for a few minutes. Uploads remain possible meanwhile.

Mobile notifications

KASTELL_RELAIS_POUSSEE, KASTELL_RELAIS_CLE. Without a relay the instance is whole: it simply wakes nobody, and says so.

Delivery channels, per organisation

Each organisation plugs in its own gateways from Settings → Delivery channels: OVHcloud for SMS, Brevo for email, or any HTTP provider described by a template.

Credentials are encrypted at rest and never come back out: not through the API, not through the root console. Administering an instance is not reading your customers' secrets.

Test the channel before you need it

A channel never tested is a hypothesis. The "Test" button sends a message to you, and only to you.

Mobile notifications: the knock relay

Apple's servers only accept messages signed with the app publisher's key. A self-hosted instance therefore cannot, on its own, make the Kastell app ring on a phone: it goes through a relay that holds that key.

Without a relay, the instance is still whole. Reading, logging, calling: nothing is lost. It wakes nobody, and says so — on its status probe, and therefore in the app at the moment someone picks their instance. SMS and voice calls remain the first-rank call-out channels.

To start it with the composition:

docker compose --profile mobile up -d
VariablePurpose
KASTELL_RELAIS_POUSSEEThe relay's address, as seen from the instance.
KASTELL_RELAIS_CLEThe key the instance presents to the relay.
APNS_CLE, APNS_CLE_ID, APNS_EQUIPE_ID, APNS_PAQUETThe relay's Apple credentials.
APNS_ALERTE_CRITIQUEtrue only once Apple has granted the entitlement.

The relay receives nothing but a device token, an opaque identifier and a degree of urgency: no organisation, no crisis, no person. It stores nothing. Its code and protocol live in apps/relais/ — you can run your own, or check what the one you use actually does.