tessera

Configuration

Where settings come from and what overrides what

Settings live in two places, and they do not overlap.

  • The environment carries what cannot change while the process runs, plus a few secrets the database must never hold.
  • The admin panel, at /admin/, carries everything else. It is stored in the database and applied without a restart.

If it is in the panel, changing it works. A setting that would need a restart is shown read-only with the reason.

There is no config file

tessera.yaml and tessera.toml are not read. An instance still setting TESSERA_CONFIG_FILE boots and logs a warning; whatever that file says is ignored.

What must come from the environment

Fixed at boot. The socket is already bound, the pool is already built, the log subscriber is installed once.

  • server.host, server.port, server.data_dir, server.max_body_bytes, server.cors_allowed_origins, server.assets_dir
  • features.docs
  • everything under database. and telemetry.

Secrets the database must not hold.

  • database.url, auth.admin_password, security.secret_key

Everything else is editable while the instance runs.

Credentials kept in the panel

Mail relay credentials, the scanner's authorization header, sign-in providers' client secrets and storage backend addresses are set in the panel like anything else. The panel can tell you whether one is set but never shows it again, so anybody able to read settings cannot read a password out of them.

The key that seals credentials

Those credentials are stored encrypted. The key is security.secret_key; leave it empty and the instance generates one on first start and keeps it as secret.key in server.data_dir.

Lose the key and every sealed credential is gone

Backups of the database are useless for those values without it, and restoring onto a new machine without the key means entering every backend and secret again. Back up secret.key with the database, or set TESSERA_SECURITY__SECRET_KEY (openssl rand -hex 32) and keep it somewhere the backups are not.

Writing environment variables

TESSERA_SERVER__PORT=9000
TESSERA_DATABASE__URL=postgres://…

Prefix TESSERA_, two underscores for nesting. Lists take commas or a JSON array:

TESSERA_SERVER__CORS_ALLOWED_ORIGINS='https://a.example, https://b.example'
TESSERA_SERVER__CORS_ALLOWED_ORIGINS='["https://a.example","https://b.example"]'

A key that is not a setting stops the process rather than being ignored, so a typo is caught at boot.

For systemd, EnvironmentFile= still points at a file. contrib/tessera.service in the repository has a working unit.

The main repository has two files to start from: tessera.personal.env.example for an instance only you and people you trust use, and tessera.public.env.example for one strangers can upload to. The comments in them are in Chinese.

Changing the rest

Three ways into the same store:

Every setting, with the value in force and where it came from. Ones that can only come from the environment are shown read-only.

What overrides what

Lowest to highest: built-in defaults, then the environment, then stored settings.

Stored settings beat the environment

They are the only layer somebody edited on purpose on this instance. A container image sets variables of its own, so letting those win would make the panel a screen that reports success and changes nothing.

A stored value this version refuses, from a downgrade or a bad edit, is dropped one key at a time and logged. The layer below decides instead, and the rest of the settings survive.

Some changes destroy something

Shortening a retention window throws away what is already past the new line. The panel refuses until you confirm, and tells you how much would go first.

overridden by overridden by Built-in default Environment variable Value saved in the panel Effective value

The ones worth changing first

Prop

Type

Anonymous uploads with no quota

With features.anonymous_upload on and storage.max_total_bytes unset, anyone who can reach the instance can fill the disk. Start-up warns about it.

server.request_timeout_secs does not apply to uploads. One wall-clock budget cannot both let a 5 GB upload finish and stop a client that connects and sends nothing, so uploads are held to server.upload_stall_secs instead: how long they may go without a byte arriving.

On this page