Skip to main content

Config

Struct Config 

Source
pub struct Config {
Show 18 fields pub addr: String, pub token: String, pub db_path: String, pub git_commit: String, pub backup_dir: String, pub backup_interval: Duration, pub backup_keep: usize, pub rate_limit_window: Duration, pub rate_limit_max: u32, pub trusted_ip_header: String, pub merge_enabled: bool, pub merge_timeout: Duration, pub claude_bin: String, pub claude_status_interval: Duration, pub ephemeral_device_ttl: Duration, pub public_url: String, pub tls: TlsMode, pub tls_max_connections: usize,
}
Expand description

What recall-server needs.

Every field has a default that is safe to run with, except token, which has none — see ConfigError::MissingToken.

FieldVariableDefault
addrRECALL_HOST, RECALL_PORT0.0.0.0:8787
tokenRECALL_TOKENrequired
db_pathRECALL_DB_PATHdata/recall.db
git_commitRECALL_GIT_COMMITthe commit the binary was built from, else unknown
backup_dirRECALL_BACKUP_DIRoff
backup_intervalRECALL_BACKUP_INTERVAL_MS24h
backup_keepRECALL_BACKUP_KEEP7
rate_limit_windowRECALL_RATE_LIMIT_WINDOW_MS60s
rate_limit_maxRECALL_RATE_LIMIT_MAX60
trusted_ip_headerRECALL_TRUSTED_IP_HEADERcf-connecting-ip, forced empty when tls is on
merge_enabledRECALL_MERGE_ENABLEDon
merge_timeoutRECALL_MERGE_TIMEOUT_MS45s
claude_binRECALL_CLAUDE_BINclaude
claude_status_intervalRECALL_CLAUDE_STATUS_INTERVAL_MS30m
ephemeral_device_ttlRECALL_EPHEMERAL_DEVICE_TTL_HOURS24h
public_urlRECALL_PUBLIC_URLunset: passkey sign-in off
tlsRECALL_TLS_CERT/RECALL_TLS_KEY, or RECALL_TLS_ACME_DOMAINS/RECALL_TLS_ACME_EMAIL/RECALL_TLS_ACME_DIR/RECALL_TLS_ACME_STAGINGoff
tls_max_connectionsRECALL_TLS_MAX_CONNECTIONS512

RECALL_TLS_REQUIRED is read but not stored: when it is true, a config with tls off refuses to start (ConfigError::TlsRequired).

Fields§

§addr: String

The socket to bind, assembled from host and port.

§token: String

The single bearer token. There is no second one, by design.

§db_path: String

The SQLite file. Opened, never created from a schema migration — it is the same file the Node server wrote. Kept in WAL mode, with its -wal and -shm files beside it, so it must be on a local filesystem (see Store::open).

§git_commit: String

Reported by GET /health so a deploy can be confirmed from outside. A release binary knows its own commit, stamped at build time; the variable overrides it, for an image built from a checkout.

§backup_dir: String

Where periodic database snapshots go. Empty disables backups.

§backup_interval: Duration

How often to take one.

§backup_keep: usize

How many to keep before deleting the oldest.

§rate_limit_window: Duration

The window rate limiting counts requests over.

§rate_limit_max: u32

How many requests one client may make in that window.

§trusted_ip_header: String

The one request header whose value is taken as the client’s address, or empty to trust none and use the socket’s peer address.

Rate limiting keys off this, and rate limiting runs before auth precisely so a flood of invalid tokens is limited too — so a client that can choose its own value here can rotate it and get unlimited attempts at guessing the token.

That makes this a statement about the deployment, not a preference: it names the header the ingress sets, and it is only safe when nothing can reach this server except through that ingress. Exactly one header is read, so a value the client supplies under any other name is ignored.

IngressSet this to
Cloudflare Tunnelcf-connecting-ip (the default)
Traefik, nginx, Caddyx-real-ip
None — reached directlyempty

Deliberately not x-forwarded-for: a proxy appends to it, so the first entry is whatever the client sent. Reading it as one value is the classic way to make this setting useless.

§merge_enabled: bool

Whether to attempt semantic merge at all. Off means last-write-wins.

§merge_timeout: Duration

How long a merge may take before it is abandoned — and, like every other merge failure, degraded to last-write-wins.

§claude_bin: String

The claude binary to shell out to. Never the Anthropic API.

§claude_status_interval: Duration

How often to re-check that the binary is present and logged in.

§ephemeral_device_ttl: Duration

How long an ephemeral device, one a cloud session enrolled with an ephemeral authkey, may go without a signed request before it is removed.

A day by default. A cloud session left open over lunch, a meeting or a night keeps its device; a day’s worth of finished sessions does not pile up in the device list; and the key a finished session left in its container stops working within a day of its last use.

§public_url: String

The address people reach this server at, such as https://recall.example.com: an origin, with no path.

Passkeys are bound to a site, and the server cannot learn which one from a request: behind Traefik it sees plain HTTP, and a Host header is whatever the client sent. So the site is configured. The WebAuthn relying party id is its host and the origin a passkey must be used from is the whole of it. Empty leaves passkey sign-in on /admin off, and the page says so; nothing else depends on it.

§tls: TlsMode

Whether this server terminates TLS itself. Off by default: the two existing deployments (deploy/docker-compose.yml, docker-compose.traefik.yml) put an ingress in front instead, and that stays the default. See TlsMode.

§tls_max_connections: usize

How many connections the direct-TLS listener holds open at once, counting ones still in their TLS handshake. Ignored with TLS off, where the ingress in front owns this problem.

With no ingress, every idle or half-open socket an attacker opens costs this process a file descriptor and a task; this bound turns “exhaust the process’s descriptors” into “fill these slots until the timeouts in server/tls.rs close them”. A single owner’s machines need a handful; the default leaves generous room below the nofile limit docker-compose.direct.yml sets.

Implementations§

Source§

impl Config

Source

pub fn from_env() -> Result<Self, ConfigError>

Reads configuration from the real process environment.

Source

pub fn from_lookup<F>(lookup: F) -> Result<Self, ConfigError>
where F: Fn(&str) -> Option<String>,

Reads configuration through a caller-supplied lookup, applying the same defaults the Node implementation used.

The lookup is injected rather than read from std::env inside so the clamping below is testable: set_var is process-global, and Rust runs tests in parallel threads, so an env-reading test races every other test in the binary.

An unparseable value falls back rather than failing the boot, matching the Node and Go implementations — a typo in one tunable should not be the reason a server won’t start.

Trait Implementations§

Source§

impl Clone for Config

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Config

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for Config

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<'a, T, E> AsTaggedExplicit<'a, E> for T
where T: 'a,

Source§

fn explicit(self, class: Class, tag: u32) -> TaggedParser<'a, Explicit, Self, E>

Source§

impl<'a, T, E> AsTaggedExplicit<'a, E> for T
where T: 'a,

Source§

fn explicit(self, class: Class, tag: u32) -> TaggedParser<'a, Explicit, Self, E>

Source§

impl<'a, T, E> AsTaggedImplicit<'a, E> for T
where T: 'a,

Source§

fn implicit( self, class: Class, constructed: bool, tag: u32, ) -> TaggedParser<'a, Implicit, Self, E>

Source§

impl<'a, T, E> AsTaggedImplicit<'a, E> for T
where T: 'a,

Source§

fn implicit( self, class: Class, constructed: bool, tag: u32, ) -> TaggedParser<'a, Implicit, Self, E>

Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> FromRef<T> for T
where T: Clone,

Source§

fn from_ref(input: &T) -> T

Converts to this type from a reference to the input type.
Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more