defter 0.8.4

Self-hosted Zotero sync and file storage server, with metadata in SQLite and attachments in S3.
# defter configuration, e.g. /etc/defter/env for defter.service. Every setting
# is also a `defter start` flag (see `defter start --help`); environment
# variables are read when the flag is not given. Keep secrets in files that
# only root and the defter group can read (root:defter, mode 0640).

# ── Server ───────────────────────────────────────────────────────────────────
DEFTER_HOST=127.0.0.1
DEFTER_PORT=8189
# The address clients reach the server at (your reverse proxy or CDN), no
# trailing slash. Login, upload and download links are built on it.
DEFTER_PUBLIC_URL=https://defter.example.org
# HTTPS instead of plain HTTP, for a TLS pass-through in front (e.g.
# dragoman's --sni-route with DEFTER_PORT=8443), with a certificate the CDN
# trusts, such as a Cloudflare origin certificate.
# DEFTER_TLS_CERT=/etc/defter/origin.pem
# DEFTER_TLS_KEY=/etc/defter/origin-key.pem
# Or, with no CDN in front, a certificate from Let's Encrypt. Connections for the
# hostname on port 443 must reach defter, such as through dragoman's --sni-route.
# DEFTER_DOMAIN=defter.example.org
# DEFTER_EMAIL=you@example.org
# DEFTER_ACME_STAGING=true
# Databases (control.sqlite3, libraries/), generated API key and (without S3)
# attachment files. Under defter.service this is /var/lib/defter
# (StateDirectory) without setting it.
# DEFTER_DATA_DIR=/var/lib/defter
# The library database of defter 0.5.0, if not <data dir>/defter.sqlite3: only
# `defter migrate` reads it.
# DEFTER_DB=/var/lib/defter/defter.sqlite3
# How many libraries' databases stay open at most, beyond those in use.
# DEFTER_LIBRARY_CACHE=150

# ── Library ──────────────────────────────────────────────────────────────────
# The owner's zotero.org user ID (zotero.org → Settings → Security: "Your user
# ID for use in API calls"). Every user's ID is their zotero.org one. Required:
# defter and its commands do not start without it.
DEFTER_USER_ID=<your zotero.org user ID>
# The owner's user name, as Zotero shows it. Left out, it is their zotero.org
# one from their first sign-in; set, it renames them at every start. Their name
# comes from their ORCID record when they sign in.
# DEFTER_USERNAME=
# Publish a profile at /<orcid> with your ORCID record and every work in My
# Publications.
# DEFTER_ORCID=0000-0003-1419-2405

# ── API keys ─────────────────────────────────────────────────────────────────
# One read/write key; Zotero logins are approved by entering it on the login
# page. Generate it: openssl rand -hex 32
DEFTER_API_KEY=<64 hex characters>
# Or several keys as files, read/write (rw) or read-only (ro), comma-separated:
# DEFTER_KEYS=rw:/etc/defter/app-key,ro:/etc/defter/cli-key
# Without any key setting, a read/write key is generated in
# $DEFTER_DATA_DIR/api-key (print it with `defter key`).
# With SSO in front of /login, also require this identity to approve logins.
# DEFTER_LOGIN_AUTHORIZED_USER=you@example.org

# Sign in through an OpenID Connect provider such as Keycloak, with an ORCID iD in
# a claim: users, people an admin invited, and admins get in. The redirect URI to
# register is <public URL>/ui/oidc/callback. With a provider, an API key can only
# be typed into the web pages if DEFTER_API_KEY is set; the data API takes keys
# regardless.
# DEFTER_OIDC_ISSUER=https://auth.example.org/realms/<realm>
# DEFTER_OIDC_CLIENT_ID=defter
# DEFTER_OIDC_CLIENT_SECRET_FILE=/etc/defter/oidc-client-secret
# Admins sign in without an invitation, invite people and manage users. Without
# any, nor DEFTER_OIDC_ADMIN_VALUES, the owner (DEFTER_USER_ID) is the admin.
# DEFTER_ADMIN_ORCIDS=0000-0003-1419-2405
# Each user's storage quota for attachment files, in MiB, unless an admin sets
# theirs. The owner has none unless set.
# DEFTER_DEFAULT_QUOTA_MB=2048
# DEFTER_OIDC_ORCID_CLAIM=orcid
# DEFTER_OIDC_NAME=Keycloak
# Let a group or role at the provider decide who may use the server, instead of
# invitations, checked at every sign-in: someone without one of these values
# cannot get an account, and a user signing in without one is disabled (keys
# revoked, library kept) until they sign in with one again. The owner and
# DEFTER_ADMIN_ORCIDS are never disabled so. A claim missing altogether (a
# mapper gone) refuses the sign-in but disables nobody. See "Limiting sign-in to a
# Keycloak group or role" in the README.
# DEFTER_OIDC_USER_VALUES=/defter
# Values making someone an admin, and granting access too. Requires
# DEFTER_OIDC_USER_VALUES. With them, the owner is no admin unless named.
# DEFTER_OIDC_ADMIN_VALUES=/defter/admins
# The claim, in the ID token or else userinfo: a dotted path, such as
# realm_access.roles or resource_access.<client>.roles.
# DEFTER_OIDC_ACCESS_CLAIM=groups
# Where someone refused at sign-in (no group or role, no invitation, or
# disabled) is told to write to ask for access: the admins, or the
# institution's IT. Without it, they are told to ask the admins of this server.
# DEFTER_ADMIN_EMAIL=defter-admin@uni.example
# Where defter asks whose a zotero.org API key is: someone signing in for the
# first time pastes one, and becomes a user with its zotero.org user ID. The key
# is not stored.
# DEFTER_ZOTERO_API_URL=https://api.zotero.org/

# ── Attachment storage (S3-compatible) ───────────────────────────────────────
# Hetzner Object Storage: the bucket's location is both the endpoint and the
# region (fsn1, nbg1 or hel1); buckets are always addressed by host name.
DEFTER_S3_BUCKET=<your-bucket>
DEFTER_S3_ENDPOINT=https://fsn1.your-objectstorage.com
DEFTER_S3_REGION=fsn1
# Cloudflare R2: https://<account>.r2.cloudflarestorage.com, region auto.
# RustFS for development: http://127.0.0.1:9000, region us-east-1.
DEFTER_S3_ACCESS_KEY_ID_FILE=/etc/defter/s3-access-key-id
DEFTER_S3_SECRET_ACCESS_KEY_FILE=/etc/defter/s3-secret-access-key
# DEFTER_S3_PREFIX=defter
# DEFTER_S3_VIRTUAL_HOSTED_STYLE=true
# Lifetime of pre-signed download URLs, in seconds.
# DEFTER_PRESIGN_TTL=300
# Stream downloads through defter when clients cannot reach the bucket.
# DEFTER_PROXY_DOWNLOADS=true
# DEFTER_MAX_UPLOAD_MB=1024

# ── Backups ──────────────────────────────────────────────────────────────────
# The library database is backed up under backup/ in the files bucket, or in
# a bucket of its own (same endpoint and keys). See "Backups and restore".
# 0 turns scheduled backups off; deleted attachment files are then removed for
# good, so a restore cannot bring them back.
# DEFTER_BACKUP_INTERVAL_HOURS=6
# DEFTER_BACKUP_KEEP_DAYS=30
# DEFTER_BACKUP_S3_BUCKET=<backup-bucket>

# ── commonmeta sync ──────────────────────────────────────────────────────────
# The commonmeta store on this server turns on the commonmeta sync of the
# libraries whose users opt in on their dashboard. It is only read; see
# docs/commonmeta-sync.md for the permissions defter.service then needs. The
# daily run is `defter sync`, which commonmeta's crontab starts with this
# environment (`commonmeta jobs add defter --command …`).
# DEFTER_COMMONMETA_DB=/var/lib/commonmeta/commonmeta.sqlite3
# At most this many items changed or created per library and run (0: no
# limit); the rest are left for the next run.
# DEFTER_SYNC_LIMIT=1000
# At most this many PDFs attached per library and run.
# DEFTER_SYNC_MAX_PDFS=1000

# Log filter (tracing EnvFilter syntax).
# RUST_LOG=defter=info