Skip to content

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:

VariableFile variant
SESSION_SECRET (or AUTH_SESSION_SECRET)SESSION_SECRET_FILE
AUTH_ADMIN_PASSWORD (or ADMIN_PASSWORD)AUTH_ADMIN_PASSWORD_FILE
OIDC_CLIENT_SECRETOIDC_CLIENT_SECRET_FILE
ONLYOFFICE_SECRETONLYOFFICE_SECRET_FILE
COLLABORA_SECRETCOLLABORA_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:

yaml
services:
  nextexplorer:
    environment:
      ONLYOFFICE_SECRET_FILE: /run/secrets/onlyoffice_secret
    secrets:
      - onlyoffice_secret

secrets:
  onlyoffice_secret:
    file: ./secrets/onlyoffice_secret

The 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 ​

VariableDefaultDescription
PORT3000Port the Express API and frontend listen on inside the container.
ADDRESS0.0.0.0Interface the server binds to. Leave it alone unless you have a reason to reach only one network.
HTTP_TIMEOUT0Node.js HTTP requestTimeout (ms). Use 0 to disable (avoids the Node 5-minute default that can abort large uploads).
UPLOAD_INACTIVITY_TIMEOUT120000Classic 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_ENABLEDfalseDefault for the admin upload setting. When enabled, browser uploads use TUS chunked transfer instead of one large request.
UPLOAD_CHUNK_SIZE8MDefault TUS chunk size. Supports byte-size suffixes such as 4M, 16M, or 64M; keep it below reverse proxy body limits.
MAX_CHUNK_SIZE_MIB512Upper 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_RESERVE64MFree-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-uploadsTemporary 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_MS3600000Age 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_MS600000Delay 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_URLnoneExternal URL (no trailing slash). Drives cookie settings, CORS defaults, and derived callback URLs (OIDC/OnlyOffice).
INTERNAL_URLnoneAdditional comma-separated origins. They are accepted by CORS and OIDC returns to the configured origin where login began.
TRUST_PROXYloopback,uniquelocal when PUBLIC_URL is setExpress trust proxy configuration. Accepts false, numbers, CIDRs, or lists.
CORS_ORIGIN, CORS_ORIGINS, ALLOWED_ORIGINSemptyComma-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 ​

VariableDefaultDescription
LOG_LEVELinfo (or debug when DEBUG=true)Application log level: trace, debug, info, warn, or error.
DEBUGfalseWhen true, forces LOG_LEVEL=debug and shows more verbose diagnostics (including more detailed error output in development).
ENABLE_HTTP_LOGGINGfalseWhen true, enables HTTP request logging in the backend (use with centralized log collection in production).

Paths & volumes ​

VariableDefaultDescription
VOLUME_ROOT/mntRoot directory that houses all mounted volumes.
CONFIG_DIR/configLocation for app.db (accounts, shares, settings), logos/ and session-secret. The folder to back up.
CACHE_DIR/cacheLocation 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 unsetRoot directory for per-user personal folders. Each authenticated user gets their own subdirectory under this path.
USER_FOLDER_NAME_ORDERid,username,email_localPreference 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 ​

VariableDefaultDescription
FILE_TRANSFER_ENGINEnative on Linux, stream elsewherestream 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 ​

VariableDefaultDescription
FOLDER_SIZE_MODEoffEnables 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_PATHSemptyComma- or newline-separated paths relative to VOLUME_ROOT excluded from folder-size scans.
FOLDER_SIZE_RECONCILE_BATCH100Number of indexed folders checked per periodic reconciliation page.
FOLDER_SIZE_RECONCILE_PAUSE_MS200Delay between reconciliation pages, used to smooth background I/O.
FOLDER_SIZE_RECONCILE_MAX_DIRECTORIES200Maximum indexed folders checked by one scheduled reconciliation slice. 0 restores a full sweep.
FOLDER_SIZE_IO_TIMEOUT_MS30000Deadline for one indexed folder-size filesystem operation; 0 disables this protection.
FOLDER_SIZE_MAX_STALLED_IO2Timed-out folder-size operations allowed before the indexer pauses further filesystem work.
FOLDER_SIZE_SUBTREE_BATCHreconciliation batchMetadata checks per batch while recovering a folder tree created or changed outside NextExplorer.
FOLDER_SIZE_CONCURRENCY6Parallel folder-size scans on local storage.
FOLDER_SIZE_NETWORK_CONCURRENCY2Parallel folder-size scans on network storage, where seek latency dominates.
FOLDER_SIZE_FLUSH_MS3000Delay before pending folder-size updates are written to the index.
FOLDER_SIZE_RECONCILE_MS0Fixed interval between reconciliation sweeps. 0 uses the adaptive interval below.
FOLDER_SIZE_RECONCILE_MIN_MS900000Shortest adaptive reconciliation interval (15 minutes).
FOLDER_SIZE_RECONCILE_MAX_MS43200000Longest adaptive reconciliation interval (12 hours).
FOLDER_SIZE_REBUILDfalseDrop and rebuild the folder-size index at startup.
FOLDER_SIZE_SUBTREE_PAUSE_MSreconciliation pauseDelay between targeted recovery batches. Leave unset to inherit the reconciliation pacing.
FOLDER_SIZE_SUBTREE_SLOW_LOG_MS5000Duration 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 ​

VariableDefaultDescription
AUTH_ENABLEDtrue (in prod)Toggles authentication; disabling makes all APIs public. Deprecated: use AUTH_MODE=disabled instead.
AUTH_MODEboth (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_SECRETgenerated once, kept in CONFIG_DIR/session-secretCryptographic 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_DAYS30Duration (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_FAILED5Failed login attempts before temporary lockout.
AUTH_LOCK_MINUTES15Lockout duration in minutes when max failures reached.
AUTH_ADMIN_EMAILnoneOptional 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_PASSWORDnonePassword 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.

VariableDefaultDescription
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_NAMENextExplorerThe 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.

VariableDefaultDescription
ACTIVITY_ENABLEDfalseRecord who did what: sign-ins, downloads, share links, deletions and account changes. Nothing from before it was switched on is kept.
ACTIVITY_RETENTION_DAYS90How long a line is kept, from 1 to 3650 days. Swept hourly, whether the log is on or off.

OIDC & SSO ​

VariableDefaultDescription
OIDC_ENABLEDfalseEnable Express OpenID Connect authentication flow.
OIDC_ISSUERnoneIdP issuer URL (discovery).
OIDC_AUTHORIZATION_URL, OIDC_TOKEN_URL, OIDC_USERINFO_URLnoneOptional overrides for discovery endpoints.
OIDC_LOGOUT_URLnoneOptional 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_SECRETnoneIdP credentials.
OIDC_CALLBACK_URL${PUBLIC_URL}/callback when PUBLIC_URL is setExplicit canonical callback path; defaults to /callback under PUBLIC_URL. Register every <INTERNAL_URL>/callback with the IdP when internal origins are configured.
OIDC_SCOPESopenid profile emailDefault scopes; add groups to propagate group claims.
OIDC_ADMIN_GROUPSnoneSpace/comma-separated names that grant admin rights when found in groups, roles, or entitlements.
OIDC_REQUIRE_EMAIL_VERIFIEDfalseWhen 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_USERStrueWhen false, the user must already exist in the nextExplorer database (local or previously OIDC-linked), otherwise OIDC login is denied.
OIDC_MOBILE_REDIRECT_URISnextexplorer://oidc-callbackComma-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.

VariableDefaultDescription
MAX_DIRECT_UPLOAD_SIZE64GBLargest single file accepted by a direct (non-chunked) upload, e.g. 10GB. Chunked/TUS uploads are bounded by their storage guard.
MAX_FILES_PER_UPLOAD50Maximum number of files in one direct upload request.
MAX_JSON_BODY_SIZE8MBLargest 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_SIZE32GBRefuse to extract an archive whose declared uncompressed size exceeds this ("zip bomb" guard).
MAX_ARCHIVE_ENTRIES100000Refuse to extract an archive holding more entries than this.

Feature toggles ​

VariableDefaultDescription
SEARCH_DEEPfalseEnables deep content search; ripgrep is used when SEARCH_RIPGREP is true.
SEARCH_RIPGREPtruePrefer ripgrep for fast searches; fallback search is used when unavailable.
SEARCH_MAX_FILESIZE5MSkip files larger than this when searching their contents. Accepts 5MB, 5M, 5mb or a plain byte count.
SEARCH_TIMEOUT_MS5000How 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_INDEXfalseKeep 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_BATCH25Documents written per transaction while indexing.
SEARCH_INDEX_CPU_PERCENT25The 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_REBUILDfalseEmpty 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_MB256What 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_MS3600000How often to walk the volume again, for changes made outside the application — an rsync, a network share.
SHOW_VOLUME_USAGEfalseShow volume usage badges in the sidebar.
FAVORITES_DEFAULT_ICONoutline:StarIconIcon 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_ENABLEDfalseWhen 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_VOLUMESfalseWhen true, non-admin users only see volumes assigned to them by an admin. See User volumes.
SKIP_HOMEfalseWhen true, visits to the home view (/browse/) automatically redirect into the first volume instead.
TERMINAL_ENABLEDtrueControls 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_EXTENSIONSshComma-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.

VariableDefaultDescription
TRASH_ENABLEDtrueSend deleted items to the trash. When false, deleting removes items for good; items already in the trash still expire.
TRASH_RETENTION_DAYS30How long an item stays in the trash before it is removed for good, from 1 to 3650 days.
TRASH_MAX_PERCENT10The 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.

VariableDefaultDescription
VERSIONS_ENABLEDtrueKeep earlier versions of files. Independent of TRASH_ENABLED.
VERSIONS_KEEP_ALL_HOURS24Every version is kept for this many hours (1 to 720).
VERSIONS_HOURLY_DAYS7Then the newest of each hour, up to this many days (1 to 365).
VERSIONS_DAILY_DAYS30Then the newest of each day, up to this many days (1 to 3650); after that, the newest of each week.
VERSIONS_MAX_PER_FILE50The most versions a file keeps (1 to 1000). Pinned versions do not count.
VERSIONS_SESSION_CHECKPOINT_MINUTES10In a long ONLYOFFICE or Collabora session, a version is kept at most this often (1 to 1440 minutes).

Editor ​

VariableDefaultDescription
EDITOR_EXTENSIONSemptyComma-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_FILESIZE2MMaximum 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 ​

VariableDefaultDescription
ARCHIVE_EXTENSIONS7z,zip,iso,rar,tar,gz,tgz,bz2,tbz2,xz,txz,cab,wim,cpio,rpm,deb,z,lzh,arj,zstExtensions 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 ​

VariableDefaultDescription
ONLYOFFICE_URLnonePublic URL for Document Server (must reach your app's PUBLIC_URL).
ONLYOFFICE_SECRETnoneJWT secret shared with OnlyOffice Document Server for /api/onlyoffice calls.
ONLYOFFICE_DOWNLOAD_ORIGINSnoneComma-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_LANGenLanguage code for the editor UI.
ONLYOFFICE_FORCE_SAVEfalseWhen true, the OnlyOffice Save button writes the current version immediately.
ONLYOFFICE_AUTO_SAVE_INTERVAL_MS30000Minimum 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_MS10000Retry 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_EXTENSIONSdefault listExtra file extensions to surface to the Document Server.
FFMPEG_PATH, FFPROBE_PATHbundled binariesPoint to custom ffmpeg/ffprobe if the bundle doesn't suit your needs.
SEVEN_ZIP_PATH7z on PATHThe 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_PATHbundled ExifToolThe 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_HWACCELnoneOptional ffmpeg -hwaccel value used for video thumbnail generation when supported by your ffmpeg build (e.g. vaapi, qsv, cuda).
FFMPEG_HWACCEL_DEVICEnoneOptional ffmpeg -hwaccel_device value used with FFMPEG_HWACCEL (e.g. 0 or /dev/dri/renderD128).
FFMPEG_HWACCEL_OUTPUT_FORMATnoneOptional 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_ENABLEDtrueSet to false to disable thumbnail generation globally, regardless of the UI setting.
THUMBNAIL_CACHE_MAX_FILES3000Maximum 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_MS3600000Delay between thumbnail and RAW preview cache cleanup passes. They run on their own, whether or not anything is being generated.
THUMBNAIL_CACHE_CLEANUP_BATCH_SIZE500Maximum number of thumbnail or RAW preview cache files deleted per cleanup pass.
THUMBNAIL_CACHE_TTL_DAYS30Remove 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_FILES500Maximum 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_MB0Memory in MB allowed for Sharp/libvips thumbnail cache. Keep 0 to minimize idle RSS after thumbnail generation.
THUMBNAIL_VIDEO_CONCURRENCY1Maximum number of concurrent ffmpeg thumbnail jobs. Keep low on small hosts to avoid memory spikes.
THUMBNAIL_DIAGNOSTICS_ENABLEDfalseEnable periodic thumbnail diagnostics logs with queue, memory, active job, external process, and cache cleanup counters.
THUMBNAIL_DIAGNOSTICS_INTERVAL_MS30000Interval between thumbnail diagnostics logs when diagnostics are enabled.
THUMBNAIL_BACKGROUND_QUEUE_LIMIT200Maximum thumbnails queued for background generation before new requests are dropped.
THUMBNAIL_PROCESS_NICE10nice value applied to external thumbnail processes, so they yield to interactive work.
THUMBNAIL_VIDEO_SEEK_PERCENT10Position in the video, as a percentage of its duration, used to grab the thumbnail frame.
THUMBNAIL_VIDEO_SCALE_FLAGSfast_bilinearffmpeg scaling algorithm for video thumbnails. Slower flags give a sharper image.
THUMBNAIL_VIDEO_SEEK_SECONDS5Fixed position in the video used to grab the thumbnail frame, when no percentage is set.
THUMBNAIL_VIDEO_THREADS2Threads allowed to one ffmpeg thumbnail job.
THUMBNAIL_SLOW_JOB_MS10000Duration threshold after which a thumbnail job/process is logged even when diagnostics are disabled.
THUMBNAIL_FFMPEG_TIMEOUT_MS300000Longest 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) ​

VariableDefaultDescription
COLLABORA_URLnonePublic base URL of your Collabora CODE server (used to build the iframe URL).
COLLABORA_DISCOVERY_URLderivedOverride for discovery. Defaults to ${COLLABORA_URL}/hosting/discovery.
COLLABORA_SECRETnoneJWT secret used to sign WOPI access_token values for /api/collabora/wopi/*.
COLLABORA_LANGenLanguage code for the Collabora UI.
COLLABORA_FILE_EXTENSIONSemptyComma-separated list of extensions to expose (e.g. doc,docx,xls,xlsx,ppt,pptx).

Container user mapping ​

VariableDescription
PUID, PGIDMap 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:

yaml
environment:
  - PUID=0
  - PGID=0

The 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, /etc included, 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.