Environment Reference
nextExplorer is configured almost entirely through environment variables. The backend (backend/src/config/env.js) centralizes the defaults you see here. Use this reference when you want to tune ports, paths, auth, integrations, or feature flags.
Secrets
Every credential listed below can be read from a file instead of the environment. Append _FILE to the variable name and point it at the file holding the value:
| Variable | File variant |
|---|---|
SESSION_SECRET (or AUTH_SESSION_SECRET) | SESSION_SECRET_FILE |
AUTH_ADMIN_PASSWORD (or ADMIN_PASSWORD) | AUTH_ADMIN_PASSWORD_FILE |
OIDC_CLIENT_SECRET | OIDC_CLIENT_SECRET_FILE |
ONLYOFFICE_SECRET | ONLYOFFICE_SECRET_FILE |
COLLABORA_SECRET | COLLABORA_SECRET_FILE |
docker inspect prints every environment variable a container was started with, so a secret passed inline is readable by anyone who can reach the Docker daemon and stays in the container's stored configuration. Mounting it as a file keeps it out of both:
services:
nextexplorer:
environment:
ONLYOFFICE_SECRET_FILE: /run/secrets/onlyoffice_secret
secrets:
- onlyoffice_secret
secrets:
onlyoffice_secret:
file: ./secrets/onlyoffice_secretThe plain variable wins when both are set. Surrounding whitespace is stripped, so a file written with echo secret > file behaves as expected. A _FILE naming a missing or empty file stops the server at startup instead of quietly running without the secret.
Server & networking
| Variable | Default | Description |
|---|---|---|
PORT | 3000 | Port the Express API and frontend listen on inside the container. |
ADDRESS | 0.0.0.0 | Interface the server binds to. Leave it alone unless you have a reason to reach only one network. |
HTTP_TIMEOUT | 0 | Node.js HTTP requestTimeout (ms). Use 0 to disable (avoids the Node 5-minute default that can abort large uploads). |
UPLOAD_INACTIVITY_TIMEOUT | 120000 | Classic upload inactivity timeout (ms). If no bytes are received for this delay, the request is aborted and .uploading is cleaned up. Use 0 to disable. |
UPLOAD_CHUNKED_ENABLED | false | Default for the admin upload setting. When enabled, browser uploads use TUS chunked transfer instead of one large request. |
UPLOAD_CHUNK_SIZE | 8M | Default TUS chunk size. Supports byte-size suffixes such as 4M, 16M, or 64M; keep it below reverse proxy body limits. |
MAX_CHUNK_SIZE_MIB | 512 | Upper bound (MiB) an admin may set for the chunk size; caps the settings slider/input and clamps saved values. Hard ceiling of 512 MiB. |
UPLOAD_STORAGE_RESERVE | 64M | Free-space reserve kept when accepting uploads. An upload is rejected with 507 when the destination — or, for a chunked upload, the temporary storage — cannot fit what is coming plus this reserve. The reserve is what keeps a full volume from taking the database down with it, where /config shares the filesystem. |
TUS_UPLOAD_DIR | <CACHE_DIR>/tus-uploads | Temporary storage directory for TUS chunked uploads. Put it on a volume large enough for the biggest in-progress uploads, and — importantly — on the same filesystem as the destination: chunks are assembled here and the finished file is then moved into place, which is instant within one filesystem but becomes a full byte-for-byte copy across two. With the default under CACHE_DIR, a multi-gigabyte upload appears to stall at 100% while that copy runs. Across filesystems the copy is written under a hidden .upload-<random>.uploading name beside the destination and takes its name only once whole, never replacing a file already there (it becomes “name (1)”); one left by a killed process is removed when the next upload to that folder is created. |
TUS_INCOMPLETE_UPLOAD_TTL_MS | 3600000 | Age after which an abandoned chunked upload, or a finished one that could not be moved into its folder, is deleted from the temporary directory (1 hour). An upload being moved into place is never deleted, whatever its age. |
TUS_CLEANUP_INTERVAL_MS | 600000 | Delay between sweeps of the chunked-upload temporary directory (10 minutes). It is also swept at startup and when an upload is created; 0 sweeps only then. |
PUBLIC_URL | none | External URL (no trailing slash). Drives cookie settings, CORS defaults, and derived callback URLs (OIDC/OnlyOffice). |
INTERNAL_URL | none | Additional comma-separated origins. They are accepted by CORS and OIDC returns to the configured origin where login began. |
TRUST_PROXY | loopback,uniquelocal when PUBLIC_URL is set | Express trust proxy configuration. Accepts false, numbers, CIDRs, or lists. |
CORS_ORIGIN, CORS_ORIGINS, ALLOWED_ORIGINS | empty | Comma-separated list of allowed CORS origins. Defaults to the PUBLIC_URL / INTERNAL_URL origins when set. When none of them is set, no cross-origin caller is allowed — same-origin use (frontend and API on one host) is unaffected. Use * only if you deliberately want to reflect any origin. |
Logging & debugging
| Variable | Default | Description |
|---|---|---|
LOG_LEVEL | info (or debug when DEBUG=true) | Application log level: trace, debug, info, warn, or error. |
DEBUG | false | When true, forces LOG_LEVEL=debug and shows more verbose diagnostics (including more detailed error output in development). |
ENABLE_HTTP_LOGGING | false | When true, enables HTTP request logging in the backend (use with centralized log collection in production). |
Paths & volumes
| Variable | Default | Description |
|---|---|---|
VOLUME_ROOT | /mnt | Root directory that houses all mounted volumes. |
CONFIG_DIR | /config | Location for app.db (accounts, shares, settings), logos/ and session-secret. The folder to back up. |
CACHE_DIR | /cache | Location for thumbnails, RAW previews, sessions, index.db (the search index and folder sizes), and temporary data, including in-flight/: what a save, an extraction or a compression is writing, so that the next start removes what a stop interrupted. Everything in it can be rebuilt, but the indexes take a pass over the volumes to do so: mount it persistently. |
USER_ROOT | <VOLUME_ROOT>/_users when unset | Root directory for per-user personal folders. Each authenticated user gets their own subdirectory under this path. |
USER_FOLDER_NAME_ORDER | id,username,email_local | Preference order for per-user folder names (e.g. set username,id to reuse /home/<username> when USER_ROOT=/home). A name is given once and kept; an account whose preferred name is already taken takes the next in the order, so two accounts never share a folder. See personal folders. |
HIDDEN_FILE_PATTERNS | .,regex:\\.download$,regex:\\.uploading$ | Comma- or space-separated hidden filename patterns used by directory listings, volume pickers, and search. Plain values are fast filename prefixes, e.g. .,@ hides dotfiles and Synology @... entries. Advanced entries can use regex:<source> or /source/flags; by default, the artifacts of a transfer in progress — .download while a file is being fetched, .uploading while one is being written — are hidden through this same configurable policy. Overriding this variable replaces the defaults, so include those two patterns in your own list to keep them hidden. Set to an empty value to disable pattern hiding. |
Copying & moving
| Variable | Default | Description |
|---|---|---|
FILE_TRANSFER_ENGINE | native on Linux, stream elsewhere | stream copies in the application rather than through rsync; native asks for rsync and rm whatever the platform. Slower on large transfers, and useful where a native tool is unwanted. Setting it is rarely necessary: a native tool that is missing, or too old to understand what it is asked for — --info=progress2 arrived in rsync 3.1, and RHEL 7 ships 3.0.9 — is detected on the first copy and the application falls back on its own, saying so in the log. Either way, a copy is written under a hidden .nextexplorer-copying-* name beside where it goes and takes its name only once whole, never replacing what holds it (it becomes “name (1)”); a cancelled or failed copy removes only that hidden entry, and one left by a stop is removed at the next start. |
Folder-size index
| Variable | Default | Description |
|---|---|---|
FOLDER_SIZE_MODE | off | Enables indexed folder sizes: full is recursive, shallow counts direct entries only. Also a choice in Settings → Folder sizes: when this variable is set it decides, and the page shows it and cannot change it; when it is not, the page does. Moving between shallow and full measures again, since a size counted one way is wrong read the other. |
FOLDER_SIZE_EXCLUDE_PATHS | empty | Comma- or newline-separated paths relative to VOLUME_ROOT excluded from folder-size scans. |
FOLDER_SIZE_RECONCILE_BATCH | 100 | Number of indexed folders checked per periodic reconciliation page. |
FOLDER_SIZE_RECONCILE_PAUSE_MS | 200 | Delay between reconciliation pages, used to smooth background I/O. |
FOLDER_SIZE_RECONCILE_MAX_DIRECTORIES | 200 | Maximum indexed folders checked by one scheduled reconciliation slice. 0 restores a full sweep. |
FOLDER_SIZE_IO_TIMEOUT_MS | 30000 | Deadline for one indexed folder-size filesystem operation; 0 disables this protection. |
FOLDER_SIZE_MAX_STALLED_IO | 2 | Timed-out folder-size operations allowed before the indexer pauses further filesystem work. |
FOLDER_SIZE_SUBTREE_BATCH | reconciliation batch | Metadata checks per batch while recovering a folder tree created or changed outside NextExplorer. |
FOLDER_SIZE_CONCURRENCY | 6 | Parallel folder-size scans on local storage. |
FOLDER_SIZE_NETWORK_CONCURRENCY | 2 | Parallel folder-size scans on network storage, where seek latency dominates. |
FOLDER_SIZE_FLUSH_MS | 3000 | Delay before pending folder-size updates are written to the index. |
FOLDER_SIZE_RECONCILE_MS | 0 | Fixed interval between reconciliation sweeps. 0 uses the adaptive interval below. |
FOLDER_SIZE_RECONCILE_MIN_MS | 900000 | Shortest adaptive reconciliation interval (15 minutes). |
FOLDER_SIZE_RECONCILE_MAX_MS | 43200000 | Longest adaptive reconciliation interval (12 hours). |
FOLDER_SIZE_REBUILD | false | Drop and rebuild the folder-size index at startup. |
FOLDER_SIZE_SUBTREE_PAUSE_MS | reconciliation pause | Delay between targeted recovery batches. Leave unset to inherit the reconciliation pacing. |
FOLDER_SIZE_SUBTREE_SLOW_LOG_MS | 5000 | Duration after which a targeted recovery emits one info performance summary. |
Targeted subtree recoveries are always serialized so concurrent external changes cannot race their SQLite ancestor updates. The batch and pause settings govern their I/O intensity without affecting the normal list-view reads.
Authentication
| Variable | Default | Description |
|---|---|---|
AUTH_ENABLED | true (in prod) | Toggles authentication; disabling makes all APIs public. Deprecated: use AUTH_MODE=disabled instead. |
AUTH_MODE | both (or local if OIDC not configured) | Controls which authentication methods are available: local (username/password only), oidc (SSO only), both (both methods), or disabled (skip login entirely, same as AUTH_ENABLED=false). |
SESSION_SECRET, AUTH_SESSION_SECRET | generated once, kept in CONFIG_DIR/session-secret | Cryptographic secret used by Express to sign session cookies and related tokens. When unset, one is generated at the first start and kept in CONFIG_DIR/session-secret, readable by the server’s user only, so sessions survive restarts. A configured value always wins, and nothing is written then: set one — long, random, at least 32 characters — to choose it, or when several replicas share the sessions. If CONFIG_DIR cannot be written, a warning is logged and the secret lasts until the next restart. |
SESSION_MAX_AGE_DAYS | 30 | Duration (in days) that user sessions remain valid. Sessions persist across browser restarts and server reboots. Set to a lower value (e.g., 7) for stricter security, or higher (e.g., 90) for convenience. Applies to both local authentication and OIDC sessions. |
AUTH_MAX_FAILED | 5 | Failed login attempts before temporary lockout. |
AUTH_LOCK_MINUTES | 15 | Lockout duration in minutes when max failures reached. |
AUTH_ADMIN_EMAIL | none | Optional first-run bootstrap for local auth: when set with AUTH_ADMIN_PASSWORD, the backend creates an admin user on startup (and the setup wizard is skipped). |
AUTH_ADMIN_PASSWORD | none | Password used for AUTH_ADMIN_EMAIL bootstrap. If a user already exists with the same email, this value overrides/resets the local password on startup. (Minimum 6 chars; avoid leaving this set unless you want the password enforced on every restart.) |
Passkeys
A passkey is bound to the hostname it was made on. Nothing here is required for a single-hostname installation: PUBLIC_URL already answers it where it is set, and the name the request arrived on answers it where it is not. See Admin & Access.
| Variable | Default | Description |
|---|---|---|
WEBAUTHN_RP_ID | (from PUBLIC_URL, else the request's host) | The hostname passkeys are bound to. Set it where an installation is reached through more than one name, so a passkey made on one works on the others. Changing it stops the passkeys already made from working. |
WEBAUTHN_RP_NAME | NextExplorer | The name the browser shows while asking for a fingerprint or a PIN. |
Activity log
Off unless somebody asks for it. These are the defaults; administrators change what is in force under Settings → Activity log.
| Variable | Default | Description |
|---|---|---|
ACTIVITY_ENABLED | false | Record who did what: sign-ins, downloads, share links, deletions and account changes. Nothing from before it was switched on is kept. |
ACTIVITY_RETENTION_DAYS | 90 | How long a line is kept, from 1 to 3650 days. Swept hourly, whether the log is on or off. |
OIDC & SSO
| Variable | Default | Description |
|---|---|---|
OIDC_ENABLED | false | Enable Express OpenID Connect authentication flow. |
OIDC_ISSUER | none | IdP issuer URL (discovery). |
OIDC_AUTHORIZATION_URL, OIDC_TOKEN_URL, OIDC_USERINFO_URL | none | Optional overrides for discovery endpoints. |
OIDC_LOGOUT_URL | none | Optional custom IdP logout URL. When set, logout requests redirect to this URL with a post_logout_redirect_uri parameter (OIDC standard). If not set, logout only clears the local session. |
OIDC_CLIENT_ID, OIDC_CLIENT_SECRET | none | IdP credentials. |
OIDC_CALLBACK_URL | ${PUBLIC_URL}/callback when PUBLIC_URL is set | Explicit canonical callback path; defaults to /callback under PUBLIC_URL. Register every <INTERNAL_URL>/callback with the IdP when internal origins are configured. |
OIDC_SCOPES | openid profile email | Default scopes; add groups to propagate group claims. |
OIDC_ADMIN_GROUPS | none | Space/comma-separated names that grant admin rights when found in groups, roles, or entitlements. |
OIDC_REQUIRE_EMAIL_VERIFIED | false | When true, requires the IdP to verify the user's email before allowing user creation or auto-linking. Some providers like newer Authentik versions set email_verified to false by default. |
OIDC_AUTO_CREATE_USERS | true | When false, the user must already exist in the nextExplorer database (local or previously OIDC-linked), otherwise OIDC login is denied. |
OIDC_MOBILE_REDIRECT_URIS | nextexplorer://oidc-callback | Comma-separated allowlist of custom-scheme URIs a native app may receive the mobile sign-in code at. http(s) URIs are refused, so the code can never be handed to a web address. Only used by the mobile bridge; see OIDC. |
Upload & archive limits
These are safety ceilings, not tuning knobs: they exist so a single request cannot fill the volume. The defaults are high enough for normal use.
| Variable | Default | Description |
|---|---|---|
MAX_DIRECT_UPLOAD_SIZE | 64GB | Largest single file accepted by a direct (non-chunked) upload, e.g. 10GB. Chunked/TUS uploads are bounded by their storage guard. |
MAX_FILES_PER_UPLOAD | 50 | Maximum number of files in one direct upload request. |
MAX_JSON_BODY_SIZE | 8MB | Largest JSON request body accepted. These carry lists of paths — deleting or copying a few thousand files needs a few hundred kB — not file content. Saving from the text editor is the exception: the file travels in one, so leaving this unset lets it rise to carry whatever EDITOR_MAX_FILESIZE opens, while a value set here is a ceiling that is kept and lowers the editor instead. |
MAX_EXTRACTED_ARCHIVE_SIZE | 32GB | Refuse to extract an archive whose declared uncompressed size exceeds this ("zip bomb" guard). |
MAX_ARCHIVE_ENTRIES | 100000 | Refuse to extract an archive holding more entries than this. |
Feature toggles
| Variable | Default | Description |
|---|---|---|
SEARCH_DEEP | false | Enables deep content search; ripgrep is used when SEARCH_RIPGREP is true. |
SEARCH_RIPGREP | true | Prefer ripgrep for fast searches; fallback search is used when unavailable. |
SEARCH_MAX_FILESIZE | 5M | Skip files larger than this when searching their contents. Accepts 5MB, 5M, 5mb or a plain byte count. |
SEARCH_TIMEOUT_MS | 5000 | How long one search may spend looking before answering with what it has. Reading a large tree to be certain there is nothing more is worse than an answer that arrives; the response is marked truncated when this ended it, and the panel says so rather than letting a short list look like the whole answer. |
SEARCH_INDEX | false | Keep an index of the volume instead of reading it on every search: the words inside documents, and the name of every file and folder whether or not any words could be taken out of them — a folder nobody has filled yet is findable, and one the application has just made is findable at once. Searching a name then costs a query rather than a walk of the storage, which is what makes it bearable on a network share — half a million names answer in about forty milliseconds, where the walk is one round trip per folder. Built by a paced background pass that skips anything it has already read, and stops when the server is asked to. Results are as fresh as the last pass, except in the folder being searched, which is read directly so that a file dropped there a moment ago is still found; a share, a personal folder or an assigned volume is answered from the index too when it lies inside the volume, and read as the search goes when it is mounted somewhere else, since the pass indexes the volume and nothing outside it; so is a search by a reader who has asked to see hidden files, since the pass does not walk into dot-folders. Reckon about 240 bytes of index per file or folder. Searching contents through the index matches whole words and the beginnings of them, where reading the files matches any run of characters: azul finds azules either way, ules only by reading. Also a switch in Settings → Search index: when this variable is set it decides, and the switch shows it and cannot move it; when it is not, the switch does. |
SEARCH_INDEX_BATCH | 25 | Documents written per transaction while indexing. |
SEARCH_INDEX_CPU_PERCENT | 25 | The share of one core a background pass may take. It works for a slice of time and then stands aside for the rest, so the load is what you chose whatever the files are. Raising it shortens the first pass and is felt while it runs. |
SEARCH_INDEX_EXCLUDE | (none) | Folders search leaves alone, comma or newline separated, relative to the volume root. Neither the index nor a filename search walks into them — the exception being when one of them is the folder the search was started from, since navigating into it is asking to look. A build tree, a mail spool, a machine backup — hundreds of thousands of files nobody searches by content, and reading them is the whole overhead. Set here they cannot be removed from the interface; Settings → Search index holds a second list an administrator can edit. Nothing is excluded by default: with the index answering in place of the live scan, a folder left out is one that cannot be found by content. |
SEARCH_INDEX_REBUILD | false | Empty the index at startup and read everything again. It is derived data — every row was read from a file that is still there — so the only cost of being wrong about needing this is one pass. Unset it once the rebuild has finished, or it happens on every start. |
SEARCH_INDEX_MEMORY_MB | 256 | What a background pass may add to the process before it stops and carries on a couple of minutes later. Only consulted when the container enforces no memory limit of its own — where it does, three quarters of that limit is the ceiling instead. What the pass wrote is kept either way, so the next one resumes from there. |
SEARCH_INDEX_RECONCILE_MS | 3600000 | How often to walk the volume again, for changes made outside the application — an rsync, a network share. |
SHOW_VOLUME_USAGE | false | Show volume usage badges in the sidebar. |
FAVORITES_DEFAULT_ICON | outline:StarIcon | Icon a new favorite starts with, as variant:IconName (outline or solid, and any Heroicons name). Each favorite can be given its own icon afterwards from the sidebar's edit mode. |
USER_DIR_ENABLED | false | When true, enables a personal “My Files” space for each authenticated user under USER_ROOT. The frontend shows a “My Files” entry when this flag is on. |
USER_VOLUMES | false | When true, non-admin users only see volumes assigned to them by an admin. See User volumes. |
SKIP_HOME | false | When true, visits to the home view (/browse/) automatically redirect into the first volume instead. |
TERMINAL_ENABLED | true | Controls the admin terminal feature. When false, terminal routes/UI are disabled. When true, nextExplorer attempts to load terminal dependencies and automatically hides/disables terminal if dependencies are unavailable (startup continues). |
TERMINAL_FILE_EXTENSIONS | sh | Comma-separated list of file extensions that show the context-menu action to open the file in the admin terminal (for example sh,bash or .sh,.bash). |
The sharing system (toolbar Share button, guest links such as /share/:token, and the Shared with me page) works out of the box with the feature flags above. Advanced share tuning knobs are documented under Sharing (advanced) below.
Trash
Deleting moves an item into a hidden .nextexplorer folder at the root of its volume — a rename on the same disk, never a copy. These variables set the defaults; administrators change what is in force under Settings → Trash. See Trash.
| Variable | Default | Description |
|---|---|---|
TRASH_ENABLED | true | Send deleted items to the trash. When false, deleting removes items for good; items already in the trash still expire. |
TRASH_RETENTION_DAYS | 30 | How long an item stays in the trash before it is removed for good, from 1 to 3650 days. |
TRASH_MAX_PERCENT | 10 | The most the trash may hold on each volume, as a share of that volume's size (1 to 90). The oldest items go first when it is exceeded. |
TRASH_MAX_SIZE | (none) | An optional size cap per volume, such as 50G. The smaller of this and TRASH_MAX_PERCENT applies. An item larger than the whole trash is never silently removed: the person deleting it is asked. |
File versions
Saving over a file keeps what the save replaces as a version, in the same .nextexplorer zone and the same reserved space as the trash. These variables set the defaults; administrators change what is in force under Settings → Trash and versions. See File versions.
| Variable | Default | Description |
|---|---|---|
VERSIONS_ENABLED | true | Keep earlier versions of files. Independent of TRASH_ENABLED. |
VERSIONS_KEEP_ALL_HOURS | 24 | Every version is kept for this many hours (1 to 720). |
VERSIONS_HOURLY_DAYS | 7 | Then the newest of each hour, up to this many days (1 to 365). |
VERSIONS_DAILY_DAYS | 30 | Then the newest of each day, up to this many days (1 to 3650); after that, the newest of each week. |
VERSIONS_MAX_PER_FILE | 50 | The most versions a file keeps (1 to 1000). Pinned versions do not count. |
VERSIONS_SESSION_CHECKPOINT_MINUTES | 10 | In a long ONLYOFFICE or Collabora session, a version is kept at most this often (1 to 1440 minutes). |
Editor
| Variable | Default | Description |
|---|---|---|
EDITOR_EXTENSIONS | empty | Comma-separated list of additional file extensions to support in the inline text editor (e.g., toml,proto,graphql or .toml,.proto). These are added to the built-in defaults (txt, md, json, js, ts, py, etc.), not replacing them. Changes take effect on container restart—no frontend rebuild required. |
EDITOR_MAX_FILESIZE | 2M | Maximum file size allowed to open in the inline text editor. Accepts a byte count or a size with K, M, G, T suffix (base 1024), e.g. 512K, 2M, 1G. Files larger than this will show “This file is too large to open in the text editor.” |
Archives
| Variable | Default | Description |
|---|---|---|
ARCHIVE_EXTENSIONS | 7z,zip,iso,rar,tar,gz,tgz,bz2,tbz2,xz,txz,cab,wim,cpio,rpm,deb,z,lzh,arj,zst | Extensions offered for the “Extract archive” action, and for looking inside one. A plain list (e.g. zip,iso,7z) replaces the defaults; prefix the list with + (e.g. +udf,squashfs) to extend them instead. Whatever the list says, a format is only offered when the bundled 7-Zip build actually supports it (probed at startup). Password-protected ZIP, 7z and RAR archives are supported through the extraction dialog; passwords are not persisted. |
OnlyOffice & thumbnails
| Variable | Default | Description |
|---|---|---|
ONLYOFFICE_URL | none | Public URL for Document Server (must reach your app's PUBLIC_URL). |
ONLYOFFICE_SECRET | none | JWT secret shared with OnlyOffice Document Server for /api/onlyoffice calls. |
ONLYOFFICE_DOWNLOAD_ORIGINS | none | Comma-separated extra origins the Document Server may serve saved documents from. Set it when the callback URL host differs from ONLYOFFICE_URL; that origin is always allowed. |
ONLYOFFICE_LANG | en | Language code for the editor UI. |
ONLYOFFICE_FORCE_SAVE | false | When true, the OnlyOffice Save button writes the current version immediately. |
ONLYOFFICE_AUTO_SAVE_INTERVAL_MS | 30000 | Minimum delay in milliseconds between background force-saves after OnlyOffice has synchronized changes. Set 0 to save only when closing; capped at 300000. |
ONLYOFFICE_FORCE_SAVE_TIMEOUT_MS | 10000 | Retry window in milliseconds when a force-save reaches Document Server before its final changes. Minimum 7000; the interface does not wait for the callback. |
ONLYOFFICE_FILE_EXTENSIONS | default list | Extra file extensions to surface to the Document Server. |
FFMPEG_PATH, FFPROBE_PATH | bundled binaries | Point to custom ffmpeg/ffprobe if the bundle doesn't suit your needs. |
SEVEN_ZIP_PATH | 7z on PATH | The 7-Zip to run. Which archive formats can be opened is read from 7z i at startup and written to the log, so a build without the RAR codec loses RAR and nothing else. |
EXIFTOOL_PATH | bundled ExifTool | The ExifTool to run, for RAW photo metadata. Rarely needed: the bundled copy is used when it is there, and when it is not — the minimal archive leaves its 21 MB of Perl behind — /usr/bin/exiftool, /usr/local/bin/exiftool and /opt/homebrew/bin/exiftool are tried in that order, so apt install libimage-exiftool-perl is the whole of it. Set this only for one kept somewhere else. Absolute paths and not PATH, which a service inherits from whatever started it. |
FFMPEG_HWACCEL | none | Optional ffmpeg -hwaccel value used for video thumbnail generation when supported by your ffmpeg build (e.g. vaapi, qsv, cuda). |
FFMPEG_HWACCEL_DEVICE | none | Optional ffmpeg -hwaccel_device value used with FFMPEG_HWACCEL (e.g. 0 or /dev/dri/renderD128). |
FFMPEG_HWACCEL_OUTPUT_FORMAT | none | Optional ffmpeg -hwaccel_output_format value, used with FFMPEG_HWACCEL. Some hardware pipelines need it (for example vaapi) to hand frames back in a format the encoder accepts. |
THUMBNAILS_ENABLED | true | Set to false to disable thumbnail generation globally, regardless of the UI setting. |
THUMBNAIL_CACHE_MAX_FILES | 3000 | Maximum number of files kept in the thumbnail cache; past it, the least recently written go first. Thumbnails written by releases up to 2.0.3, and temporary files untouched for an hour, are removed too. Set 0 to lift the limit on the count; outdated, expired and abandoned files are still removed. |
THUMBNAIL_CACHE_CLEANUP_INTERVAL_MS | 3600000 | Delay between thumbnail and RAW preview cache cleanup passes. They run on their own, whether or not anything is being generated. |
THUMBNAIL_CACHE_CLEANUP_BATCH_SIZE | 500 | Maximum number of thumbnail or RAW preview cache files deleted per cleanup pass. |
THUMBNAIL_CACHE_TTL_DAYS | 30 | Remove thumbnails and RAW previews older than this age during the periodic cleanup. Set 0 to keep entries until the file-count limit is reached. |
RAW_PREVIEW_CACHE_MAX_FILES | 500 | Maximum number of embedded RAW previews kept in /cache/raw-previews, full-size JPEGs; the oldest go first. Set 0 to lift the limit on the count; outdated, expired and abandoned previews are still removed. |
THUMBNAIL_SHARP_CACHE_MEMORY_MB | 0 | Memory in MB allowed for Sharp/libvips thumbnail cache. Keep 0 to minimize idle RSS after thumbnail generation. |
THUMBNAIL_VIDEO_CONCURRENCY | 1 | Maximum number of concurrent ffmpeg thumbnail jobs. Keep low on small hosts to avoid memory spikes. |
THUMBNAIL_DIAGNOSTICS_ENABLED | false | Enable periodic thumbnail diagnostics logs with queue, memory, active job, external process, and cache cleanup counters. |
THUMBNAIL_DIAGNOSTICS_INTERVAL_MS | 30000 | Interval between thumbnail diagnostics logs when diagnostics are enabled. |
THUMBNAIL_BACKGROUND_QUEUE_LIMIT | 200 | Maximum thumbnails queued for background generation before new requests are dropped. |
THUMBNAIL_PROCESS_NICE | 10 | nice value applied to external thumbnail processes, so they yield to interactive work. |
THUMBNAIL_VIDEO_SEEK_PERCENT | 10 | Position in the video, as a percentage of its duration, used to grab the thumbnail frame. |
THUMBNAIL_VIDEO_SCALE_FLAGS | fast_bilinear | ffmpeg scaling algorithm for video thumbnails. Slower flags give a sharper image. |
THUMBNAIL_VIDEO_SEEK_SECONDS | 5 | Fixed position in the video used to grab the thumbnail frame, when no percentage is set. |
THUMBNAIL_VIDEO_THREADS | 2 | Threads allowed to one ffmpeg thumbnail job. |
THUMBNAIL_SLOW_JOB_MS | 10000 | Duration threshold after which a thumbnail job/process is logged even when diagnostics are disabled. |
THUMBNAIL_FFMPEG_TIMEOUT_MS | 300000 | Longest one ffmpeg may take over a single thumbnail before it is killed and the thumbnail marked failed. Raise it if very large videos on slow storage are being cut short; the minimum is 1000. |
Collabora (WOPI)
| Variable | Default | Description |
|---|---|---|
COLLABORA_URL | none | Public base URL of your Collabora CODE server (used to build the iframe URL). |
COLLABORA_DISCOVERY_URL | derived | Override for discovery. Defaults to ${COLLABORA_URL}/hosting/discovery. |
COLLABORA_SECRET | none | JWT secret used to sign WOPI access_token values for /api/collabora/wopi/*. |
COLLABORA_LANG | en | Language code for the Collabora UI. |
COLLABORA_FILE_EXTENSIONS | empty | Comma-separated list of extensions to expose (e.g. doc,docx,xls,xlsx,ppt,pptx). |
Container user mapping
| Variable | Description |
|---|---|
PUID, PGID | Map container processes to host user/group IDs so created files have consistent ownership. Defaults to 1000. The entrypoint adjusts ownership of /app, /config, and /cache accordingly. Set both to 0 to run as root — see Running as root. |
Running as root
The entrypoint always finishes with gosu appuser, so the application runs as appuser whatever Compose's user: says. Setting user: root therefore changes who runs the entrypoint — which was already root — and not who runs the server. The knob is PUID and PGID:
environment:
- PUID=0
- PGID=0The entrypoint renumbers appuser to those ids before dropping to it, so the server runs as root and can read and write anything the mounts expose.
Compose's user: is a different thing and does not do this. It decides who runs the entrypoint, which was already root; the entrypoint then drops to appuser whatever it says.
That is a real choice rather than a default, and worth making deliberately:
- Every file NextExplorer creates on the host is owned by root.
- A mount of
/gives it the whole host,/etcincluded, with write access wherever the share or the volume allows writing.
Where the aim is only to reach a folder the container cannot currently read, matching its owner is usually enough — PUID and PGID set to that owner's ids, which is what they are for.
Starting the container as a fixed user
Giving the container a user of its own — docker run --user, Compose's user: 1000:1000, a Kubernetes securityContext — is supported and means something different from PUID/PGID.
The entrypoint notices, and does none of the things only root can do: it does not renumber appuser, does not take ownership of /config and /cache, and does not drop to another user. The application runs as whoever the container was started as, which is what was asked for. PUID and PGID are ignored in that case, and the log says so when they were set.
What that leaves to the deployment is ownership of the mounts. Under Docker, the directories must already be readable and writable by that user. Under Kubernetes, fsGroup does the job PUID/PGID do here — which is also what makes the image usable on a cluster enforcing the restricted Pod Security Standard, where running as root is refused outright.
