config

package
v0.43.0 Latest Latest
Warning

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

Go to latest
Published: Sep 24, 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 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"`
	/* 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