config

package
v0.46.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 26, 2026 License: MIT Imports: 9 Imported by: 0

Documentation

Overview

Package config loads filex configuration from a YAML file with environment variable overrides (FILEX_*).

Precedence (highest first):

  1. Environment variables (FILEX_LISTEN, FILEX_DB_DRIVER, …)
  2. config.yaml (path passed via --config or default ~/.filex/config.yaml)
  3. Hard-coded defaults

Some settings live in the DB (settings table) instead of config.yaml — e.g. instance branding, default thumbnail policy. Those are read by individual services via db.Store.GetSetting and are NOT modeled here.

Index

Constants

View Source
const DefaultPublicURL = "http://localhost:5212"

DefaultPublicURL is the address filex assumes when nobody says otherwise. ⚠ It is a guess, and anything derived from it must be able to tell that it is one -- see Config.PublicURLSet.

Variables

This section is empty.

Functions

func ParseDurationDays

func ParseDurationDays(v string) (time.Duration, error)

ParseDurationDays is time.ParseDuration plus a `d` (day) suffix, which Go's parser lacks and which is the unit people actually write retention in. "7d" = 168h. A bare number is also accepted as days, so FILEX_SHARE_MAX_TTL=7 and =7d mean the same thing.

Types

type ArchiveConfig added in v0.44.2

type ArchiveConfig struct {
	SevenZipBin string `yaml:"sevenzip_bin"`
	WorkDir     string `yaml:"work_dir"`
}

ArchiveConfig contains only operator-owned process settings. User-facing policy (enabled formats and resource limits) lives in the settings table so the Archives admin page can change it live. Binary paths remain here because allowing an HTTP caller to choose a program for filex to execute is remote command execution by design.

type AuthConfig

type AuthConfig struct {
	Drivers []string `yaml:"drivers"`
	// DriversFrom says where Drivers came from: "FILEX_AUTH_DRIVERS",
	// "file:<path>" or "default". The Identity providers page shows it, in
	// the reader's words (authsetup.FromWords), beside every provider the
	// environment defines, so an operator knows where to change one the page
	// cannot (Load sets it).
	DriversFrom string `yaml:"-"`
	// RecoveryLogin keeps password sign-in open for the bootstrap
	// administrator — and nobody else — when no `local` driver is enabled, so
	// an SSO-only installation whose identity provider is down can still be
	// reached by the person who has to fix it (local.RecoveryLogin). ON by
	// default; FILEX_AUTH_RECOVERY_LOGIN=false turns it off.
	RecoveryLogin bool              `yaml:"recovery_login"`
	OIDC          OIDCConfig        `yaml:"oidc"`
	LDAP          LDAPConfig        `yaml:"ldap"`
	Header        HeaderProxyConfig `yaml:"header_proxy"`
}

AuthConfig — enabled drivers and per-driver options.

type CORSConfig

type CORSConfig struct {
	AllowedOrigins []string `yaml:"allowed_origins"`
	AllowedMethods []string `yaml:"allowed_methods"`
	AllowedHeaders []string `yaml:"allowed_headers"`
}

CORSConfig — origin allowlist.

type CacheConfig

type CacheConfig struct {
	// Dir is where prepared copies live. Defaults to <data_dir>/cache.
	Dir string `yaml:"dir"`
	// MinSize is the smallest file worth preparing (FILEX_CACHE_MIN_SIZE,
	// default 64 MiB). Below it the preparation costs more than the transfer
	// it saves.
	MinSize int64 `yaml:"min_size"`
	// MaxBytes is the GLOBAL ceiling on the cache directory
	// (FILEX_CACHE_MAX_BYTES, default 20 GiB), enforced with LRU eviction. It
	// is never unlimited: a per-file cache with no global cap is a disk
	// incident, and this project has had one (29 GB of leaked multipart temp
	// files, v0.13.4).
	MaxBytes int64 `yaml:"max_bytes"`
	// SlowBytesPerSec is the measured throughput below which a storage counts
	// as slow (FILEX_CACHE_SLOW_BPS, default 10 MiB/s).
	SlowBytesPerSec int64 `yaml:"slow_bytes_per_sec"`
	// Disabled turns the whole thing off (FILEX_CACHE=0). With no slow
	// storage configured it never does anything anyway.
	Disabled bool `yaml:"disabled"`

	// ShareZipWarmMaxBytes is the largest folder (sum of file sizes) the
	// folder-share ZIP warmer pre-builds (FILEX_SHAREZIP_WARM_MAX_BYTES,
	// default 2 GiB; 0 = no ceiling). Bigger folders are still zipped — on
	// demand, when a visitor clicks download — they are just not built
	// speculatively. See docs/SHARING.md.
	ShareZipWarmMaxBytes int64 `yaml:"sharezip_warm_max_bytes"`
	// ShareZipMaxAge is how long a cached folder-share ZIP may sit on disk
	// before the sweeper removes it even though its share is still live
	// (FILEX_SHAREZIP_MAX_AGE, default 7d; 0 = keep for the share's life).
	// Accepts Go durations plus a `d` suffix ("7d", "36h").
	ShareZipMaxAge time.Duration `yaml:"sharezip_max_age"`
}

CacheConfig — the local copy filex prepares for a big file that lives on a slow backend (internal/filecache). See docs/CONFIGURATION.md.

type CloudConfig

type CloudConfig struct {
	// Enabled is the master flag (FILEX_CLOUD=1). Default false.
	Enabled bool `yaml:"enabled"`
	// PlansJSON is the config-driven plan catalog (FILEX_CLOUD_PLANS), a JSON
	// array of {id,name,price_monthly,stripe_price_id,limits:{storage_bytes,
	// max_users}}. Empty → a single built-in "free" skeleton plan.
	PlansJSON string `yaml:"plans"`
	// StripeSecret is the Stripe API secret key (STRIPE_SECRET /
	// FILEX_STRIPE_SECRET). Empty → billing endpoints answer 503
	// "not configured".
	StripeSecret string `yaml:"stripe_secret"`
	// BaseHost, when set (FILEX_CLOUD_BASE_HOST, e.g. "filex.cloud"), derives
	// each signed-up tenant's host as <slug>.<BaseHost>. Empty → the tenant is
	// provisioned without a host (operator assigns one later).
	BaseHost string `yaml:"base_host"`
}

CloudConfig — self-serve cloud/SaaS PREPARATION (v0.7 "Kimlik" E3, see docs/CLOUD.md). Master-gated by Enabled (FILEX_CLOUD): while it is false — the default — nothing in the cloud package is constructed, no /api/cloud route registers, capabilities carry no cloud field and the migration-00021 columns stay untouched. This is a skeleton for a FUTURE hosted offering, not a live service.

type Config

type Config struct {
	Listen    string `yaml:"listen"`
	PublicURL string `yaml:"public_url"`
	// PublicURLSet reports whether the operator actually chose PublicURL,
	// rather than inheriting DefaultPublicURL.
	//
	// ⚠ It matters because the default is a GUESS and filex hands it out as
	// fact: the realtime ticket derives `ws_url` from it, so an instance on any
	// other port told every browser to connect to :5212, the connection was
	// refused, and the client fell back to 12-second polling with no error
	// raised anywhere. Not serialised -- it describes how the config was
	// loaded, not the deployment.
	PublicURLSet  bool   `yaml:"-"`
	DataDir       string `yaml:"data_dir"`
	DefaultLocale string `yaml:"default_locale"`
	// CookieDomain sets the Domain attribute on the filex_session cookie
	// (e.g. ".example.com" to share the session across subdomains). Empty =
	// host-only cookie, the historical behavior. Applied on both set and
	// clear so logout removes the same cookie it created.
	CookieDomain string `yaml:"cookie_domain"`
	// MultiTenant turns on native multi-tenancy (host-resolved provider =
	// tenant, per-provider storage confinement, scoped user directory). OFF by
	// default — a single-tenant install behaves exactly as before. See
	// docs/MULTI-TENANCY.md.
	MultiTenant bool `yaml:"multi_tenant"`
	// PluginsDisabled (FILEX_PLUGINS_DISABLED=1) turns the storage-plugin
	// subsystem off: nothing under <data-dir>/plugins is launched, no remote
	// plugin is contacted, and the admin API answers 503.
	//
	// ⚠ DEMO MODE FLIPS THE DEFAULT: with FILEX_DEMO_MODE on, plugins are off
	// unless this variable explicitly says otherwise, because a demo hands an
	// admin account to strangers and installing a plugin runs a program on the
	// host. Set FILEX_PLUGINS_DISABLED=0 to override that deliberately.
	//
	// Otherwise ON by default,
	// because a plugin is only ever installed by an admin — but an operator
	// hardening a shared instance may not want the admin role to include
	// "run a program on the server". See docs/PLUGINS.md.
	PluginsDisabled bool `yaml:"plugins_disabled"`
	// PluginConformance (FILEX_PLUGIN_CONFORMANCE) is enforce | warn | off.
	//
	// enforce (default): a plugin that fails a probe of a capability IT
	// DECLARED is refused, and a storage cannot be saved on it. The reason a
	// half-working plugin must not be usable is that the user cannot tell
	// whose fault it is: they meet an upload button that fails and read it as
	// filex being broken. warn registers it anyway and keeps the report (for
	// somebody writing a plugin); off skips the probes.
	PluginConformance string `yaml:"plugin_conformance"`
	// PluginTrustedKeys (FILEX_PLUGIN_TRUSTED_KEYS, comma-separated) are
	// ed25519 public keys, hex or base64. Set ANY key and filex refuses a
	// plugin binary that is not signed by one of them.
	//
	// ⚠ The sha256 an install already records proves only that the file has
	// not changed since it arrived — never that it came from somebody you
	// trust. This is the setting that answers the second question, and until
	// it is set nothing is asked.
	PluginTrustedKeys []string `yaml:"plugin_trusted_keys"`
	// PluginMaxInFlight (FILEX_PLUGIN_MAX_INFLIGHT) bounds concurrent
	// operations per plugin. 0 keeps the default; a plugin at its ceiling
	// refuses new work rather than queueing it, which is what stops one slow
	// plugin from becoming one slow filex.
	PluginMaxInFlight int `yaml:"plugin_max_in_flight"`
	// AppPluginsDisabled (FILEX_APP_PLUGINS_DISABLED=1) turns the in-process
	// WebAssembly app-plugin runtime off (internal/wasmplugin): nothing under
	// <data-dir>/app-plugins is loaded, the user routes answer 404 and the
	// admin routes 503. Demo mode flips the default to ON for the same
	// reason storage plugins are off there: the demo's admin account is
	// public, and an installed plugin runs code — sandboxed, but still code
	// somebody else chose — for every visitor. Set the variable to 0 to
	// override that deliberately. See docs/APP-PLUGINS.md.
	AppPluginsDisabled bool `yaml:"app_plugins_disabled"`
	// AppPluginMaxInputMB / AppPluginMaxOutputMB / AppPluginMaxWasmMB cap,
	// per file, what a plugin job may read, what it may produce, and how big
	// an installed module may be (FILEX_APP_PLUGIN_MAX_INPUT_MB etc.). Zero
	// takes the defaults 256 / 512 / 64.
	AppPluginMaxInputMB  int `yaml:"app_plugin_max_input_mb"`
	AppPluginMaxOutputMB int `yaml:"app_plugin_max_output_mb"`
	AppPluginMaxWasmMB   int `yaml:"app_plugin_max_wasm_mb"`
	// SecretKey (FILEX_SECRET_KEY) encrypts the secrets filex has to be able to
	// read back rather than merely compare — today the S3 access keys, because
	// SigV4 derives an HMAC chain from the secret and so cannot work off a
	// one-way hash. See internal/secretbox for what this does and does not buy.
	//
	// ⚠ Losing it makes every credential sealed under it unusable; they must be
	// re-issued. It is not a password to rotate casually — treat it like the
	// database, because losing one is as bad as losing the other.
	SecretKey        string        `yaml:"secret_key"`
	Log              LogConfig     `yaml:"log"`
	DB               DBConfig      `yaml:"db"`
	Auth             AuthConfig    `yaml:"auth"`
	ExternalServices ExtServices   `yaml:"external_services"`
	Sync             SyncConfig    `yaml:"sync"`
	Thumbs           ThumbsConfig  `yaml:"thumbs"`
	Search           SearchConfig  `yaml:"search"`
	CORS             CORSConfig    `yaml:"cors"`
	Queue            QueueConfig   `yaml:"queue"`
	Ops              OpsConfig     `yaml:"ops"`
	Notify           NotifyConfig  `yaml:"notify"`
	Demo             DemoConfig    `yaml:"demo"`
	Sentry           SentryConfig  `yaml:"sentry"`
	Seed             SeedConfig    `yaml:"seed"`
	DAV              DAVConfig     `yaml:"dav"`
	S3               S3Config      `yaml:"s3"`
	SFTP             SFTPConfig    `yaml:"sftp"`
	FTPS             FTPSConfig    `yaml:"ftps"`
	NFS              NFSConfig     `yaml:"nfs"`
	Update           UpdateConfig  `yaml:"update"`
	Upload           UploadConfig  `yaml:"upload"`
	Cache            CacheConfig   `yaml:"cache"`
	Archive          ArchiveConfig `yaml:"archive"`
	/* kimlik:e3 cloud */
	Cloud CloudConfig `yaml:"cloud"`
	// VersionsOnOverwrite installs the pre-write versioning guard. Default on.
	// FILEX_VERSIONS_ON_OVERWRITE=0 turns it off -- the escape hatch for a
	// deployment where a broken or full object store would otherwise refuse
	// writes -- and =1 turns it back on, including over a config.yaml that set
	// versions_on_overwrite: false (env wins; see applyEnv).
	// NOTE: versions.keep_n=0 does NOT do this (0 means "unlimited"; the
	// snapshot path falls back to DefaultRetention).
	VersionsOnOverwrite bool `yaml:"versions_on_overwrite"`
	// VersionsFailOpen lets a snapshot failure fall through to the write
	// instead of refusing it. Default false -- Service.Snapshot's own contract
	// is that a caller must NOT proceed past a failed snapshot. It exists
	// because the fail-closed default has a sharp edge: if the object store
	// fills up, snapshots start failing and EVERY overwrite on the instance is
	// refused (desktop sync, WebDAV, OnlyOffice saves, the browser) and the
	// only other lever is an env var plus a restart.
	VersionsFailOpen bool `yaml:"versions_fail_open"`
}

Config is the top-level runtime configuration object.

func Default

func Default() Config

Default returns a Config populated with sensible defaults.

func Load

func Load(path string) (Config, error)

Load reads a YAML file and applies environment overrides. Pass empty path for defaults + env only.

type ConvertConfig

type ConvertConfig struct {
	URL string `yaml:"url"`
}

ConvertConfig — universal converter (p2r3/convert fork) embed URL.

type DAVConfig

type DAVConfig struct {
	Enabled bool `yaml:"enabled"`
}

DAVConfig — the WebDAV server surface at /dav (v0.3 "Bağlan" (Connect)). ON by default; FILEX_DAV=0 is the kill switch (the handler then answers 404).

type DBConfig

type DBConfig struct {
	Driver string `yaml:"driver"`
	DSN    string `yaml:"dsn"`
}

DBConfig — driver and DSN.

type DemoConfig

type DemoConfig struct {
	// Mode flips the UI into the demo presentation. Backend itself
	// stays a normal install — auth still happens against the local
	// driver, the demo creds are just a regular user.
	Mode bool `yaml:"mode"`
	// User + Pass are the credentials the "Open the demo" CTA submits.
	// Defaults: demo@demo.com / demo (operators must keep DB in sync).
	User string `yaml:"user"`
	Pass string `yaml:"pass"`
}

DemoConfig — public-demo affordances. When Mode=true the login page renders an "Open the demo" CTA that auto-submits the supplied credentials, plus a feature-tour card above the form.

type DrawioConfig

type DrawioConfig struct {
	URL string `yaml:"url"`
}

DrawioConfig — embed URL.

type ExtServices

type ExtServices struct {
	OnlyOffice OnlyOfficeConfig `yaml:"onlyoffice"`
	Drawio     DrawioConfig     `yaml:"drawio"`
	Convert    ConvertConfig    `yaml:"convert"`
}

ExtServices — plug-and-play.

type FTPSConfig

type FTPSConfig struct {
	// Enabled — FILEX_FTPS. OFF by default: this one opens a control port AND
	// a range of data ports.
	Enabled bool `yaml:"enabled"`
	// Addr is the control channel (2121 by convention; 21 needs root).
	Addr string `yaml:"addr"`
	// PublicHost is what passive-mode replies advertise.
	//
	// ⚠⚠ The setting FTP deployments get wrong, and it fails as a HANG rather
	// than an error: the server answers PASV with an address the client cannot
	// route to and the client waits until it times out. Behind NAT or in Docker
	// it must be the address the CLIENT would use.
	PublicHost string `yaml:"public_host"`
	// PassivePortMin/Max bound the data ports. They must be open in the
	// firewall and, under Docker, published one-for-one — a range open on the
	// server and closed at the edge is the same hang.
	PassivePortMin int `yaml:"passive_port_min"`
	PassivePortMax int `yaml:"passive_port_max"`
	// CertFile/KeyFile are the TLS material. Empty generates a self-signed pair
	// into the data dir — encrypted but unverified, and the guide says so.
	CertFile string `yaml:"cert_file"`
	KeyFile  string `yaml:"key_file"`
	// Banner is the greeting line.
	Banner string `yaml:"banner"`
	// IdleTimeout in seconds; 0 uses the package default.
	IdleTimeout int `yaml:"idle_timeout"`
}

FTPSConfig controls the FTPS endpoint (internal/ftpsrv).

⚠⚠ There is no "plain FTP" switch and there will not be one. Plain FTP sends the password in the clear and the file after it; a flag that turned TLS off would be a flag that publishes a user's credentials to anything on the path.

type HeaderProxyConfig

type HeaderProxyConfig struct {
	EmailHeader string   `yaml:"email_header"`
	GroupHeader string   `yaml:"group_header"`
	TrustedIPs  []string `yaml:"trusted_ips"`
	AdminGroup  string   `yaml:"admin_group"`
	// Provider is the tenant SLUG a just-in-time account is homed in when the
	// request Host maps to no tenant. See LDAPConfig.Provider — same rule, and
	// on this driver the Host is almost always there, so it is rarely needed.
	Provider string `yaml:"provider"`
}

HeaderProxyConfig — accept Cloudflare Access / Authelia headers.

type LDAPConfig

type LDAPConfig struct {
	URL          string `yaml:"url"`
	BindDN       string `yaml:"bind_dn"`
	BindPassword string `yaml:"bind_password"`
	BaseDN       string `yaml:"base_dn"`
	UserFilter   string `yaml:"user_filter"`
	EmailAttr    string `yaml:"email_attr"`
	StartTLS     bool   `yaml:"start_tls"`
	// CAFile is a PEM bundle holding the CA that signed the directory's
	// certificate. Empty verifies against the system trust store, which is what
	// the driver always did — and what forced installs with a private/internal
	// CA to rebuild the container's /etc/ssl/certs/ca-certificates.crt just to
	// reach their own AD. Appended to the system pool, not substituted for it.
	CAFile string `yaml:"ca_file"`
	// ProtocolLogin lets directory accounts authenticate over the non-HTTP
	// protocols (WebDAV, SFTP, FTPS, S3, NFS) with their directory password.
	// ON by default: with it off, an account that can sign in to the web UI is
	// answered 401 everywhere else, which is indistinguishable from a wrong
	// password. Turn it off to keep the directory password on the login form
	// only and require an API token everywhere else.
	//
	// ⚠ Accounts with TOTP enabled are refused on those protocols regardless,
	// exactly as local passwords are — none of them has a second-factor
	// channel. See internal/protocolauth.
	ProtocolLogin bool `yaml:"protocol_login"`
	// Provider is the tenant SLUG a just-in-time directory account is homed in
	// when the login carries no Host that maps to one — i.e. the protocol
	// logins (SFTP, FTPS, NFS), which present a password on a socket.
	//
	// ⚠ Multi-tenant installs only, and only for ACCOUNT CREATION. Empty means
	// "refuse to create one", which is the safe default: the alternative
	// fallback is `default`, and `default` is the confine-exempt supertenant.
	// An account that already exists signs in over every protocol either way.
	Provider string `yaml:"provider"`
}

LDAPConfig — directory bind.

type LogConfig

type LogConfig struct {
	Level  string `yaml:"level"`  // debug, info, warn, error
	Format string `yaml:"format"` // text, json
}

LogConfig — slog level + format.

type NFSConfig

type NFSConfig struct {
	// Enabled — FILEX_NFS. OFF by default, and more emphatically than the
	// others: switching it on is a decision about the network it sits on.
	Enabled bool `yaml:"enabled"`
	// Addr is the listen address. 2049 is the registered port and what clients
	// assume; anything else needs `-o port=` on every mount.
	Addr string `yaml:"addr"`
}

NFSConfig controls the NFSv3 endpoint (internal/nfssrv).

⚠⚠ NFSv3 is unencrypted and unauthenticated on the wire. filex binds identity to the EXPORT PATH (32 bytes of entropy, see model.NFSExport) rather than trusting the uid a client asserts — but the traffic itself is still readable by anything on the path. This is the NAS-on-the-LAN protocol; `filex mount` (FUSE over HTTPS) is the answer for anything off-LAN.

type NotifyConfig

type NotifyConfig struct {
	// Enabled toggles the entire subsystem. When false the API returns
	// 503 from /api/notifications/... and Service.Send is a no-op.
	Enabled bool `yaml:"enabled"`
	// WebhookURL receives a generic JSON POST per event.
	WebhookURL string `yaml:"webhook_url"`
	// WebhookToken — optional Authorization: Bearer <token>.
	WebhookToken string `yaml:"webhook_token"`
}

NotifyConfig — webhook + in-app channel configuration. Both are optional; leaving WebhookURL empty disables outbound delivery while the in-app bell continues to record events.

type OIDCConfig

type OIDCConfig struct {
	Issuer       string `yaml:"issuer"`
	ClientID     string `yaml:"client_id"`
	ClientSecret string `yaml:"client_secret"`
	RedirectURL  string `yaml:"redirect_url"`
	RoleClaim    string `yaml:"role_claim"`
	AdminGroup   string `yaml:"admin_group"`
	// AutoRedirect makes the login page start the OIDC flow immediately
	// (SSO-first installs). The password form stays reachable via ?local=1
	// for break-glass/admin logins. OFF by default — unchanged behavior.
	AutoRedirect bool `yaml:"auto_redirect"`
	// Logout picks what signing out of an OIDC session ends (FILEX_OIDC_LOGOUT):
	//   "idp" (default) — filex's session AND the IdP's, when the IdP
	//                     advertises an end_session_endpoint (RP-initiated
	//                     logout; the IdP must allow the post-logout redirect,
	//                     docs/SSO.md);
	//   "local"         — filex's session only; the person stays signed in at
	//                     the IdP (the behavior before this option existed).
	// Anything else means the default.
	Logout string `yaml:"logout"`
}

OIDCConfig — Keycloak/Auth0/etc.

func (OIDCConfig) LocalLogout

func (o OIDCConfig) LocalLogout() bool

LocalLogout reports whether signing out leaves the IdP's session alone.

type OnlyOfficeConfig

type OnlyOfficeConfig struct {
	URL       string `yaml:"url"`
	JWTSecret string `yaml:"jwt_secret"`
	// CallbackURL is the address the DOCUMENT SERVER uses to reach filex for
	// the document bytes and the save. Empty means "the public URL", which is
	// right wherever one address serves both the browser and the container.
	//
	// ⚠ It is not always the same address. FILEX_PUBLIC_URL also builds every
	// share link a person receives, so an install whose document server cannot
	// resolve the public hostname had no way to express the difference and its
	// saves were silently lost (issue #17).
	CallbackURL string `yaml:"callback_url"`
}

OnlyOfficeConfig — Document Server URL + JWT secret.

type OpsConfig

type OpsConfig struct {
	// DeleteWorkers is how many items of ONE delete job are put in the trash
	// at the same time. FILEX_OPS_DELETE_WORKERS, default 4; anything below 1
	// means the default.
	//
	// Jobs still run one after another, in the order they were queued — only
	// the items inside a delete job overlap. On an object store every trashed
	// file is several round trips, so a large delete is almost all waiting,
	// and one item at a time made a delete of tens of thousands of files run
	// for hours while every other queued job waited behind it.
	DeleteWorkers int `yaml:"delete_workers"`
}

OpsConfig — the copy/move/delete queue (internal/ops).

type QueueConfig

type QueueConfig struct {
	// Driver selects the queue backend: sqlite | postgres | redis.
	// Empty follows the DATABASE driver (sqlite→sqlite, postgres→postgres);
	// on MySQL there is no shared-database driver, so empty means "no
	// persistent queue" until an operator configures redis.
	Driver string `yaml:"driver"`
	// DSN is the connection string for postgres ("postgres://...") or
	// redis ("redis://..."). For sqlite the application DB handle is
	// shared automatically and DSN is ignored.
	DSN string `yaml:"dsn"`
	// Workers controls Pool size. <=0 → 4.
	Workers int `yaml:"workers"`
	// Enabled lets operators turn the persistent queue off entirely
	// (the legacy ops.Service still handles copy/move/delete in that
	// case). Default: true.
	Enabled bool `yaml:"enabled"`
}

QueueConfig — persistent op queue. Driver "sqlite" (default) shares the application DB; "postgres" / "redis" can be wired for production or HA setups (see internal/queue/drivers/{postgres,redis}).

type S3Config

type S3Config struct {
	// Enabled — FILEX_S3 kill switch. ON by default like /dav: the endpoint
	// refuses every unsigned request anyway, and an access key has to be
	// minted before anything can reach it.
	Enabled bool `yaml:"enabled"`
	// Domain enables virtual-hosted-style addressing (bucket.s3.example.com).
	// Empty leaves path-style only, which is what restic and the older SDKs
	// use — so an install without a wildcard DNS record still works, it just
	// needs `path_style` in the client config.
	//
	// ⚠ Setting it requires a wildcard A record AND a wildcard certificate for
	// *.<domain>; without both, current SDKs (which default to virtual-hosted)
	// fail at TLS rather than with anything that names the cause.
	Domain string `yaml:"domain"`
}

S3Config controls the S3-compatible endpoint (internal/s3api).

type SFTPConfig

type SFTPConfig struct {
	// Enabled — FILEX_SFTP. OFF by default, unlike /dav and S3: this surface
	// opens a TCP port of its own, and a port nobody asked for is not something
	// to switch on for them.
	Enabled bool `yaml:"enabled"`
	// Addr is the listen address. 2022 by convention — sftpgo and
	// `rclone serve sftp` both use it, while 2222 means "SSH in a container".
	Addr string `yaml:"addr"`
	// HostKeyDir holds the server's host keys.
	//
	// ⚠ It must survive a rebuild. Regenerating host keys gives every user
	// REMOTE HOST IDENTIFICATION HAS CHANGED — indistinguishable from an attack,
	// and usually "fixed" by deleting the known_hosts line, which trains people
	// to ignore the one warning that matters. Empty puts them in the data dir.
	HostKeyDir string `yaml:"host_key_dir"`
	// Banner is shown before authentication. Empty sends none.
	Banner string `yaml:"banner"`
	// MaxSpool caps one upload's spool file. 0 uses the package default.
	MaxSpool int64 `yaml:"max_spool"`
}

SFTPConfig controls the SFTP endpoint (internal/sftpsrv).

type SearchConfig

type SearchConfig struct {
	Enabled   bool   `yaml:"enabled"`
	IndexPath string `yaml:"index_path"`
	// Content toggles async file-content extraction into the index ("Bul"
	// wave). ON by default; FILEX_SEARCH_CONTENT=0 is the kill-switch.
	Content bool `yaml:"content"`
	// ContentMaxBytes caps the SOURCE file size eligible for extraction
	// (FILEX_SEARCH_CONTENT_MAX). <=0 falls back to 5 MiB. The extracted
	// text itself is always capped at 200 KiB.
	ContentMaxBytes int64 `yaml:"content_max_bytes"`
	// AutoRebuild lets filex repair an index written by an older document
	// schema, in the background, at startup. ON by default;
	// FILEX_SEARCH_AUTO_REBUILD=0 is the kill-switch.
	//
	// It is on by default because the alternative shipped once and did not
	// work: v0.29.0 improved filename matching for everyone EXCEPT the
	// installations that already had an index, told them so in an admin
	// endpoint nobody reads, and the issue reporter upgraded and correctly
	// said nothing had changed.
	AutoRebuild bool `yaml:"auto_rebuild"`
}

SearchConfig — bleve index.

type SeedConfig

type SeedConfig struct {
	AdminEmail    string `yaml:"admin_email"`
	AdminPassword string `yaml:"admin_password"`
	SiteName      string `yaml:"site_name"`
	TrashDays     string `yaml:"trash_retention_days"`
	// ShareMaxTTLDays seeds the `share.max_ttl_days` setting — the longest
	// life a NEW share link may be given (FILEX_SHARE_MAX_TTL, e.g. "7" or
	// "30d"; "0" = unlimited). Like the other seeds it only applies when the
	// setting has never been written; after that the admin UI owns it.
	ShareMaxTTLDays string      `yaml:"share_max_ttl_days"`
	SMTP            SeedSMTP    `yaml:"smtp"`
	Storage         SeedStorage `yaml:"storage"`
}

SeedConfig holds one-time bootstrap values applied to the DB on first boot, only when the target record is ABSENT (operator UI edits are never clobbered). It lets a fresh `helm install` / `docker compose up` come up fully configured from env alone — admin user, SMTP, branding, trash policy and an initial storage — with zero admin-UI clicks. Consumed by internal/server/seed.go. (Auth/OIDC is env-authoritative already via AuthConfig, so it is not duplicated here.)

type SeedSMTP

type SeedSMTP struct {
	Host     string `yaml:"host"`
	Port     string `yaml:"port"`
	Username string `yaml:"username"`
	Password string `yaml:"password"`
	From     string `yaml:"from"`
	TLS      string `yaml:"tls"` // starttls | tls | none
}

SeedSMTP mirrors the mailer's smtp.* settings keys.

func (SeedSMTP) Configured

func (s SeedSMTP) Configured() bool

Configured reports whether enough SMTP fields are set to seed a row.

type SeedStorage

type SeedStorage struct {
	Driver    string `yaml:"driver"` // local | s3 | sftp | webdav | ftp | "" (none)
	Name      string `yaml:"name"`
	MountPath string `yaml:"mount_path"`
	// Config is a raw JSON object used verbatim as the storage's driver config.
	// Set it for sftp/webdav/ftp (or advanced s3); overrides the fields below.
	Config string `yaml:"config"`
	Path   string `yaml:"path"` // local driver on-disk root
	// s3 driver:
	Bucket    string `yaml:"bucket"`
	Prefix    string `yaml:"prefix"`
	Endpoint  string `yaml:"endpoint"`
	Region    string `yaml:"region"`
	AccessKey string `yaml:"access_key"`
	SecretKey string `yaml:"secret_key"`
	PathStyle bool   `yaml:"path_style"`
}

SeedStorage describes an initial storage row to create when no storage exists yet. Driver "" (default) seeds nothing.

For local + s3 the ergonomic fields below are enough. To seed ANY other driver (sftp, webdav, ftp) — i.e. connect an EXISTING external storage — set Driver plus Config to the driver's raw config JSON; it is used verbatim.

type SentryConfig

type SentryConfig struct {
	DSN         string `yaml:"dsn"`
	Environment string `yaml:"environment"`
}

SentryConfig — optional Sentry-wire error reporting (self-hosted GlitchTip at errors.example.com). An empty DSN disables it entirely (default build reports nothing). Environment tags events (e.g. production / demo) so one project can serve multiple deployments.

type SyncConfig

type SyncConfig struct {
	// DefaultInterval is the poll cadence for storages with no
	// sync_interval_s of their own. FILEX_SYNC_INTERVAL.
	DefaultInterval time.Duration `yaml:"default_interval"`
}

SyncConfig — storage sync settings.

⚠ There is deliberately no `Workers` here any more. FILEX_SYNC_WORKERS was parsed into a field that nothing read, while CONFIGURATION.md advertised it as "concurrent storage sync workers" — there is no pool to size: the sync worker runs one goroutine per enabled storage (internal/sync.Worker.startOne) and always has. Inventing a pool to justify the variable would be a redesign; documenting a knob that does nothing is worse than either, so the knob is gone and the doc says what actually happens.

type ThumbsConfig

type ThumbsConfig struct {
	Enabled  bool     `yaml:"enabled"`
	Formats  []string `yaml:"formats"`
	CacheDir string   `yaml:"cache_dir"`
	// SweepInterval is how often the cached JPEGs are reconciled against the
	// node catalogue, so a file whose node no longer exists stops occupying
	// disk (FILEX_THUMBS_SWEEP_INTERVAL, default 6h, 0 = never).
	//
	// ⚠ The sweeper is deliberately independent of Enabled: an operator who
	// turns thumbnails OFF still has whatever the cache accumulated while they
	// were on, and that is exactly when nobody is watching it.
	SweepInterval time.Duration `yaml:"sweep_interval"`
	// URLTTL is how long a stamped `thumb_url` stays valid
	// (FILEX_THUMBS_URL_TTL, default 24h).
	//
	// The stamp is what lets a bare <img src> fetch a preview with no header
	// and no cookie -- see internal/thumb/sign.go. Shortening it narrows the
	// window in which a leaked URL still resolves; it never locks out the SPA,
	// the desktop app or an embedded explorer, all of which fetch thumbnails
	// with credentials and are authorized per request.
	//
	// ⚠ 0 means "use the default", not "never expires": an unbounded stamp
	// would be a permanent bearer capability for that node's preview.
	URLTTL time.Duration `yaml:"url_ttl"`
}

ThumbsConfig — generation policy.

type UpdateConfig

type UpdateConfig struct {
	// Enabled controls the periodic check. False = no outbound request at all.
	Enabled bool `yaml:"enabled"`
	// Policy: off | manual | patch | minor. Which part of x.y.z may be applied
	// without asking. "patch" is what AUTO_UPGRADE=true selects.
	Policy string `yaml:"policy"`
	// Channel selects the manifest flavor ("stable").
	Channel string `yaml:"channel"`
	// ManifestURL overrides the default release index (mirrors, forks,
	// air-gapped installs that publish their own).
	ManifestURL string `yaml:"manifest_url"`
	// Window is a daily maintenance window for automatic upgrades,
	// "03:00-05:00" in the server's local time. Empty = any time.
	Window string `yaml:"window"`
	// Interval between checks. Zero → 24h; anything under an hour is raised to
	// an hour (a self-hosted install has no reason to poll harder).
	Interval time.Duration `yaml:"interval"`
}

UpdateConfig — release awareness and (where the install owns its binary) self-upgrade. See docs/UPDATES.md.

The default is "check and tell me, change nothing": Enabled=true with Policy="manual". Nothing moves on its own until the operator opts in with AUTO_UPGRADE=true (= policy "patch"). Checking can be turned off entirely with FILEX_UPDATE_CHECK=0, which stops all outbound requests.

type UploadConfig

type UploadConfig struct {
	// StagingDir is where in-flight upload parts live. Defaults to
	// <data_dir>/uploads. Must be on a filesystem with room for the largest
	// upload you expect — the whole object passes through it.
	StagingDir string `yaml:"staging_dir"`
	// ChunkSize is the part size handed to clients that do not ask for one.
	// Clients may request a different size; the server's answer is binding.
	ChunkSize int64 `yaml:"chunk_size"`
	// StagingTTL is how long a staging directory may sit with no activity
	// before the sweeper removes it. FILEX_UPLOAD_STAGING_TTL.
	StagingTTL time.Duration `yaml:"staging_ttl"`
	// SweepInterval is how often the sweeper runs.
	SweepInterval time.Duration `yaml:"sweep_interval"`
}

UploadConfig — staged (resumable, driver-agnostic) uploads. See docs/UPLOADS.md.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL