{"id":168280,"date":"2026-06-02T02:08:33","date_gmt":"2026-06-01T23:08:33","guid":{"rendered":"https:\/\/computingforgeeks.com\/?p=168280"},"modified":"2026-06-02T02:08:34","modified_gmt":"2026-06-01T23:08:34","slug":"install-filebrowser-linux","status":"publish","type":"post","link":"https:\/\/computingforgeeks.com\/install-filebrowser-linux\/","title":{"rendered":"Install FileBrowser: Self-Hosted Web File Manager on Linux"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">FileBrowser turns any directory on a Linux server into a clean web interface for uploading, downloading, editing, and sharing files. It is a single static Go binary with no database server and no PHP stack behind it. Point it at a folder, open a browser, and you have a working file manager in a couple of minutes.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This guide shows how to install FileBrowser on Ubuntu and Debian, run it as a hardened systemd service behind Nginx with a Let&#8217;s Encrypt certificate, and cover the parts most write-ups skip: scoped users, allow and deny access rules, expiring public share links, custom branding, and the command runner that now ships disabled for security reasons. Every command and screenshot here came off a live server, not the documentation.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">One thing worth knowing up front. The original FileBrowser is in maintenance mode, meaning it still gets security and bug fixes but no new features. That makes it a stable, predictable choice for straightforward file serving. If you specifically need OIDC, LDAP, or two-factor login, the actively developed <a href=\"https:\/\/github.com\/gtsteffaniak\/filebrowser\" target=\"_blank\" rel=\"noreferrer noopener\">FileBrowser Quantum<\/a> fork covers those. For everything a single-binary file manager should do, the original is still the quickest path there. For how it stacks up against heavier platforms, see our <a href=\"https:\/\/computingforgeeks.com\/cloudreve-vs-nextcloud-seafile-filebrowser-immich\/\">comparison of Cloudreve, Nextcloud, Seafile, FileBrowser and Immich<\/a>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><em>This has been tested and verified to be working June 2026 on Ubuntu 24.04 and Debian 13, served over HTTPS behind Nginx proxy server.<\/em><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Prerequisites<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">You need a server running Linux server with a sudo user, and a domain name with an A record pointing at the server if you want HTTPS, which you do. Port 80 must be reachable for the certificate challenge, plus 443 for the live site. The binary itself is tiny and idles at around 10 MB of memory, so even a 1 vCPU box handles it comfortably.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>A Linux server (Ubuntu 26.04\/24\/04\/22.04 or Debian 13 \/ 12)<\/li>\n\n\n\n<li>A non-root user with <code>sudo<\/code><\/li>\n\n\n\n<li>A domain with an A record on the server (any DNS provider) for the HTTPS step<\/li>\n\n\n\n<li>Ports 80 and 443 open in your firewall and cloud security group<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Step 1: Set reusable shell variables<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The whole guide uses shell variables so you edit one block and paste the rest unchanged. Export these at the top of your SSH session and swap the values for your own:<\/p>\n\n\n\n<pre class=\"wp-block-code code\"><code>export FB_DB=\"\/etc\/filebrowser\/filebrowser.db\"\nexport FB_ROOT=\"\/srv\/filebrowser\"\nexport FB_ADDR=\"127.0.0.1\"\nexport FB_PORT=\"8080\"\nexport SITE_DOMAIN=\"files.example.com\"\nexport ADMIN_USER=\"admin\"\nexport ADMIN_PASS=\"ChangeThis-To-Something-Strong\"\nexport ADMIN_EMAIL=\"admin@example.com\"<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Confirm they are set before running anything that depends on them. These values live only in the current shell, so re-export them if you reconnect or jump into a root shell:<\/p>\n\n\n\n<pre class=\"wp-block-code code\"><code>echo \"DB:     ${FB_DB}\"\necho \"Root:   ${FB_ROOT}\"\necho \"Listen: ${FB_ADDR}:${FB_PORT}\"\necho \"Domain: ${SITE_DOMAIN}\"<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Step 2: Install FileBrowser<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The official installer downloads the right binary for your architecture and drops it in <code>\/usr\/local\/bin<\/code>. It always pulls the latest stable release, so there is no version to keep current in the command:<\/p>\n\n\n\n<pre class=\"wp-block-code code\"><code>curl -fsSL https:\/\/raw.githubusercontent.com\/filebrowser\/get\/master\/get.sh | sudo bash<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Prefer to inspect what you run? Download the script, read it, then execute it. You can also grab a tagged tarball straight from the <a href=\"https:\/\/github.com\/filebrowser\/filebrowser\/releases\" target=\"_blank\" rel=\"noreferrer noopener\">releases page<\/a> and drop the binary in place yourself. Either way, confirm the install:<\/p>\n\n\n\n<pre class=\"wp-block-code code\"><code>filebrowser version<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">You should see the version string printed back:<\/p>\n\n\n\n<pre class=\"wp-block-code code\"><code>File Browser v2.63.5\/a1e442ef<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Step 3: Create the database and base configuration<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">FileBrowser keeps its settings and users in a single embedded database file (Bolt), not a separate database server. Create a dedicated system user to own and run the service, then the directories for the database and the folder you want to serve:<\/p>\n\n\n\n<pre class=\"wp-block-code code\"><code>sudo useradd --system --no-create-home --shell \/usr\/sbin\/nologin filebrowser\nsudo mkdir -p \/etc\/filebrowser \"${FB_ROOT}\"\nsudo chown filebrowser:filebrowser \/etc\/filebrowser \"${FB_ROOT}\"<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Initialize the database as that user so ownership stays clean from the start:<\/p>\n\n\n\n<pre class=\"wp-block-code code\"><code>sudo -u filebrowser filebrowser -d \"${FB_DB}\" config init<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Now set the core options in one shot. Binding to <code>127.0.0.1<\/code> keeps FileBrowser off the public network so that Nginx is the only thing facing the internet, which is exactly what you want behind a reverse proxy:<\/p>\n\n\n\n<pre class=\"wp-block-code code\"><code>sudo -u filebrowser filebrowser -d \"${FB_DB}\" config set \\\n  --address \"${FB_ADDR}\" \\\n  --port \"${FB_PORT}\" \\\n  --root \"${FB_ROOT}\" \\\n  --branding.name \"My Files\"<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Create your administrator account. Pick a real password (the default minimum length is 12 characters):<\/p>\n\n\n\n<pre class=\"wp-block-code code\"><code>sudo -u filebrowser filebrowser -d \"${FB_DB}\" users add \"${ADMIN_USER}\" \"${ADMIN_PASS}\" --perm.admin<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">A quick note that saves confusion later. The Bolt database allows only one process to open it at a time. Any <code>filebrowser config<\/code> or <code>filebrowser users<\/code> command run while the service is live returns <code>Error: timeout<\/code>. During this first setup the service is not running yet, so you are fine. Once it is, stop it before using the CLI, or make those changes from the web interface instead.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Step 4: Run FileBrowser as a systemd service<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Running the binary by hand is fine for a quick look, but you want it to start on boot and restart on failure. Create a unit file:<\/p>\n\n\n\n<pre class=\"wp-block-code code\"><code>sudo nano \/etc\/systemd\/system\/filebrowser.service<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Paste the following. The address, port, and root all come from the database you configured above, so the command line only needs to point at the database. The hardening directives stop the service from writing anywhere except the two paths it actually needs:<\/p>\n\n\n\n<pre class=\"wp-block-code code\"><code>&#91;Unit]\nDescription=File Browser\nAfter=network.target\n\n&#91;Service]\nUser=filebrowser\nGroup=filebrowser\nExecStart=\/usr\/local\/bin\/filebrowser -d \/etc\/filebrowser\/filebrowser.db\nRestart=on-failure\nRestartSec=5\nNoNewPrivileges=true\nProtectSystem=full\nProtectHome=true\nPrivateTmp=true\nReadWritePaths=\/etc\/filebrowser \/srv\/filebrowser\n\n&#91;Install]\nWantedBy=multi-user.target<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Reload systemd, then enable and start the service so it comes up now and on every boot:<\/p>\n\n\n\n<pre class=\"wp-block-code code\"><code>sudo systemctl daemon-reload\nsudo systemctl enable --now filebrowser<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Check that it is active and listening on the loopback address only:<\/p>\n\n\n\n<pre class=\"wp-block-code code\"><code>sudo systemctl status filebrowser --no-pager\nsudo ss -tlnp | grep \"${FB_PORT}\"<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The status output should show <code>active (running)<\/code>, and the socket should be bound to <code>127.0.0.1<\/code>, not <code>0.0.0.0<\/code>:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"2560\" height=\"694\" src=\"https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/06\/wm-filebrowser-version-service-status-ubuntu.png\" alt=\"Terminal showing filebrowser version 2.63.5 and active systemd service listening on 127.0.0.1:8080\" class=\"wp-image-168271\" title=\"\" srcset=\"https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/06\/wm-filebrowser-version-service-status-ubuntu.png 2560w, https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/06\/wm-filebrowser-version-service-status-ubuntu-300x81.png 300w, https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/06\/wm-filebrowser-version-service-status-ubuntu-1024x278.png 1024w, https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/06\/wm-filebrowser-version-service-status-ubuntu-768x208.png 768w, https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/06\/wm-filebrowser-version-service-status-ubuntu-1536x416.png 1536w, https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/06\/wm-filebrowser-version-service-status-ubuntu-2048x555.png 2048w\" sizes=\"auto, (max-width: 2560px) 100vw, 2560px\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Step 5: First login<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Before Nginx is in front, you can reach the interface through an SSH tunnel from your laptop, which avoids exposing the port. Run this locally, replacing the host with your server address, then browse to <code>http:\/\/localhost:8080<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-code code\"><code>ssh -L 8080:127.0.0.1:8080 jdoe@10.0.1.50<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Log in with the administrator account you created. The instance name you set with <code>branding.name<\/code> shows above the form, which is the first sign your configuration took effect:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"2560\" height=\"1600\" src=\"https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/06\/wm-filebrowser-login-page-ubuntu-2404.png\" alt=\"FileBrowser branded login page served over HTTPS on Ubuntu 24.04\" class=\"wp-image-168272\" title=\"\" srcset=\"https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/06\/wm-filebrowser-login-page-ubuntu-2404.png 2560w, https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/06\/wm-filebrowser-login-page-ubuntu-2404-300x188.png 300w, https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/06\/wm-filebrowser-login-page-ubuntu-2404-1024x640.png 1024w, https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/06\/wm-filebrowser-login-page-ubuntu-2404-768x480.png 768w, https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/06\/wm-filebrowser-login-page-ubuntu-2404-1536x960.png 1536w, https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/06\/wm-filebrowser-login-page-ubuntu-2404-2048x1280.png 2048w\" sizes=\"auto, (max-width: 2560px) 100vw, 2560px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Inside, the contents of your served folder appear as a familiar file listing with size and modified columns, a sidebar for new files and folders, and a disk usage bar at the bottom. This is the whole point: a remote directory that behaves like a local file manager.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"2560\" height=\"1600\" src=\"https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/06\/wm-filebrowser-dashboard-file-listing-ubuntu.png\" alt=\"FileBrowser web dashboard showing folders, disk usage and version footer\" class=\"wp-image-168273\" title=\"\" srcset=\"https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/06\/wm-filebrowser-dashboard-file-listing-ubuntu.png 2560w, https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/06\/wm-filebrowser-dashboard-file-listing-ubuntu-300x188.png 300w, https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/06\/wm-filebrowser-dashboard-file-listing-ubuntu-1024x640.png 1024w, https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/06\/wm-filebrowser-dashboard-file-listing-ubuntu-768x480.png 768w, https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/06\/wm-filebrowser-dashboard-file-listing-ubuntu-1536x960.png 1536w, https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/06\/wm-filebrowser-dashboard-file-listing-ubuntu-2048x1280.png 2048w\" sizes=\"auto, (max-width: 2560px) 100vw, 2560px\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Work with files<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Selecting a file reveals the action toolbar in the top right: share, rename, copy, move, delete, and download. Folders can be downloaded as a zip, text and code files open in a built-in editor with syntax highlighting, and images, audio, and video preview inline. Uploads work by drag and drop or through the upload button, and large transfers resume thanks to the chunked upload protocol FileBrowser uses under the covers.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"2560\" height=\"1600\" src=\"https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/06\/wm-filebrowser-file-actions-toolbar-ubuntu.png\" alt=\"FileBrowser file selected showing share, edit, copy, move, delete and download actions\" class=\"wp-image-168274\" title=\"\" srcset=\"https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/06\/wm-filebrowser-file-actions-toolbar-ubuntu.png 2560w, https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/06\/wm-filebrowser-file-actions-toolbar-ubuntu-300x188.png 300w, https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/06\/wm-filebrowser-file-actions-toolbar-ubuntu-1024x640.png 1024w, https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/06\/wm-filebrowser-file-actions-toolbar-ubuntu-768x480.png 768w, https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/06\/wm-filebrowser-file-actions-toolbar-ubuntu-1536x960.png 1536w, https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/06\/wm-filebrowser-file-actions-toolbar-ubuntu-2048x1280.png 2048w\" sizes=\"auto, (max-width: 2560px) 100vw, 2560px\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Add users and scope them to a folder<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The real value of FileBrowser shows up when several people share one server but should not see each other&#8217;s files. Each user gets a <em>scope<\/em>, a path they are locked into, plus a set of permissions. Stop the service first so the CLI can open the database:<\/p>\n\n\n\n<pre class=\"wp-block-code code\"><code>sudo systemctl stop filebrowser<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Add a user confined to a subfolder, with delete turned off so they cannot remove anything:<\/p>\n\n\n\n<pre class=\"wp-block-code code\"><code>sudo -u filebrowser filebrowser -d \"${FB_DB}\" users add jdoe 'StrongPass-Here' \\\n  --scope \/documents --perm.admin=false --perm.delete=false<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">For a read-only account, strip every write permission and leave only download:<\/p>\n\n\n\n<pre class=\"wp-block-code code\"><code>sudo -u filebrowser filebrowser -d \"${FB_DB}\" users add viewer 'StrongPass-Here' \\\n  --scope \/photos --perm.create=false --perm.modify=false \\\n  --perm.rename=false --perm.delete=false --perm.share=false<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">List what you have, then start the service again:<\/p>\n\n\n\n<pre class=\"wp-block-code code\"><code>sudo -u filebrowser filebrowser -d \"${FB_DB}\" users ls\nsudo systemctl start filebrowser<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Everything you just did on the command line is also available under Settings, User Management, where admins can add, edit, and scope accounts without stopping the service. The list shows each user&#8217;s admin flag and the folder they are pinned to:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"2560\" height=\"1600\" src=\"https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/06\/wm-filebrowser-user-management-scopes-ubuntu.png\" alt=\"FileBrowser user management showing admin and scoped jdoe and viewer users\" class=\"wp-image-168275\" title=\"\" srcset=\"https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/06\/wm-filebrowser-user-management-scopes-ubuntu.png 2560w, https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/06\/wm-filebrowser-user-management-scopes-ubuntu-300x188.png 300w, https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/06\/wm-filebrowser-user-management-scopes-ubuntu-1024x640.png 1024w, https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/06\/wm-filebrowser-user-management-scopes-ubuntu-768x480.png 768w, https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/06\/wm-filebrowser-user-management-scopes-ubuntu-1536x960.png 1536w, https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/06\/wm-filebrowser-user-management-scopes-ubuntu-2048x1280.png 2048w\" sizes=\"auto, (max-width: 2560px) 100vw, 2560px\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Block files with access rules<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Scopes decide which folder a user sees. Rules decide which files are hidden inside it, using either a literal path or a regular expression. They apply globally by default and can be overridden per user. Two rules worth setting on almost any server hide environment files and dotfiles from the listing:<\/p>\n\n\n\n<pre class=\"wp-block-code code\"><code>sudo systemctl stop filebrowser\nsudo -u filebrowser filebrowser -d \"${FB_DB}\" rules add --allow=false '.*\\.env$'\nsudo -u filebrowser filebrowser -d \"${FB_DB}\" rules add --allow=false --regex '^\\.'\nsudo -u filebrowser filebrowser -d \"${FB_DB}\" rules ls\nsudo systemctl start filebrowser<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Those same rules appear under Settings, Global Settings, alongside the signup toggle, default permissions, and branding controls. This is also where you set the minimum password length and decide whether new accounts get a home folder automatically:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"2560\" height=\"1600\" src=\"https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/06\/wm-filebrowser-global-settings-access-rules.png\" alt=\"FileBrowser global settings with allow and deny rules, permissions and branding\" class=\"wp-image-168276\" title=\"\" srcset=\"https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/06\/wm-filebrowser-global-settings-access-rules.png 2560w, https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/06\/wm-filebrowser-global-settings-access-rules-300x188.png 300w, https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/06\/wm-filebrowser-global-settings-access-rules-1024x640.png 1024w, https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/06\/wm-filebrowser-global-settings-access-rules-768x480.png 768w, https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/06\/wm-filebrowser-global-settings-access-rules-1536x960.png 1536w, https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/06\/wm-filebrowser-global-settings-access-rules-2048x1280.png 2048w\" sizes=\"auto, (max-width: 2560px) 100vw, 2560px\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Share files with public links<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Select a file or folder and click the share icon to generate a public link that needs no account. You can set an expiry (in minutes, hours, or days) and an optional password, which is the difference between a link that leaks forever and one that dies on schedule:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"2560\" height=\"1600\" src=\"https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/06\/wm-filebrowser-create-share-link-expiry.png\" alt=\"FileBrowser share dialog with share duration and optional password fields\" class=\"wp-image-168277\" title=\"\" srcset=\"https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/06\/wm-filebrowser-create-share-link-expiry.png 2560w, https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/06\/wm-filebrowser-create-share-link-expiry-300x188.png 300w, https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/06\/wm-filebrowser-create-share-link-expiry-1024x640.png 1024w, https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/06\/wm-filebrowser-create-share-link-expiry-768x480.png 768w, https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/06\/wm-filebrowser-create-share-link-expiry-1536x960.png 1536w, https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/06\/wm-filebrowser-create-share-link-expiry-2048x1280.png 2048w\" sizes=\"auto, (max-width: 2560px) 100vw, 2560px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Anyone who opens the link gets a minimal download page with the file name, size, a download button, and a QR code for grabbing it on a phone. No sidebar, no login, nothing else on your server is exposed:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"2560\" height=\"1600\" src=\"https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/06\/wm-filebrowser-public-share-download-qr.png\" alt=\"FileBrowser public share page with download button, open file and QR code\" class=\"wp-image-168278\" title=\"\" srcset=\"https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/06\/wm-filebrowser-public-share-download-qr.png 2560w, https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/06\/wm-filebrowser-public-share-download-qr-300x188.png 300w, https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/06\/wm-filebrowser-public-share-download-qr-1024x640.png 1024w, https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/06\/wm-filebrowser-public-share-download-qr-768x480.png 768w, https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/06\/wm-filebrowser-public-share-download-qr-1536x960.png 1536w, https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/06\/wm-filebrowser-public-share-download-qr-2048x1280.png 2048w\" sizes=\"auto, (max-width: 2560px) 100vw, 2560px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Every active link is listed under Settings, Share Management, where you can copy it again or revoke it. Deleting a share kills the link immediately, even if the expiry has not passed.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Brand the interface<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">You already set the instance name. You can go further with a custom logo, a theme color, and a stylesheet of your own. Point FileBrowser at a branding directory that holds your assets:<\/p>\n\n\n\n<pre class=\"wp-block-code code\"><code>sudo mkdir -p \/etc\/filebrowser\/branding\/img\nsudo systemctl stop filebrowser\nsudo -u filebrowser filebrowser -d \"${FB_DB}\" config set \\\n  --branding.files \/etc\/filebrowser\/branding \\\n  --branding.color \"#2d7ff9\"\nsudo systemctl start filebrowser<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Drop a <code>logo.svg<\/code> inside the <code>img<\/code> subfolder to replace the default mark, and a <code>custom.css<\/code> in the branding root to override colors and spacing. The branding directory must be readable by the <code>filebrowser<\/code> user, and browsers cache the old logo aggressively, so a hard refresh is sometimes needed before the new one shows.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Put FileBrowser behind Nginx with HTTPS<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">FileBrowser is bound to localhost, so the last piece is a reverse proxy that terminates TLS and forwards traffic to it. Make sure your domain&#8217;s A record points at the server and that port 80 is reachable, then install Nginx:<\/p>\n\n\n\n<pre class=\"wp-block-code code\"><code>sudo apt update\nsudo apt install -y nginx<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Create a server block for the site:<\/p>\n\n\n\n<pre class=\"wp-block-code code\"><code>sudo nano \/etc\/nginx\/sites-available\/filebrowser<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Add the following. The <code>client_max_body_size 0<\/code> line lifts the upload limit so large files are not rejected by the proxy, and the upgrade headers let the editor and any websocket features work. Leave the placeholder for now, it gets replaced in the next command:<\/p>\n\n\n\n<pre class=\"wp-block-code code\"><code>server {\n    listen 80;\n    server_name SITE_DOMAIN_HERE;\n\n    client_max_body_size 0;\n\n    location \/ {\n        proxy_pass http:\/\/127.0.0.1:8080;\n        proxy_set_header Host $host;\n        proxy_set_header X-Real-IP $remote_addr;\n        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n        proxy_set_header X-Forwarded-Proto $scheme;\n        proxy_set_header Upgrade $http_upgrade;\n        proxy_set_header Connection \"upgrade\";\n    }\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Substitute your real domain from the variable, enable the site, drop the default, and reload Nginx:<\/p>\n\n\n\n<pre class=\"wp-block-code code\"><code>sudo sed -i \"s\/SITE_DOMAIN_HERE\/${SITE_DOMAIN}\/\" \/etc\/nginx\/sites-available\/filebrowser\nsudo ln -s \/etc\/nginx\/sites-available\/filebrowser \/etc\/nginx\/sites-enabled\/\nsudo rm -f \/etc\/nginx\/sites-enabled\/default\nsudo nginx -t\nsudo systemctl reload nginx<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Now issue the certificate. The Nginx plugin handles the HTTP-01 challenge, rewrites the server block for TLS, and adds the redirect from port 80 in one step:<\/p>\n\n\n\n<pre class=\"wp-block-code code\"><code>sudo apt install -y certbot python3-certbot-nginx\nsudo certbot --nginx -d \"${SITE_DOMAIN}\" --redirect \\\n  --non-interactive --agree-tos -m \"${ADMIN_EMAIL}\"<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Confirm automatic renewal is wired up, then browse to your domain over HTTPS and log in with the padlock showing:<\/p>\n\n\n\n<pre class=\"wp-block-code code\"><code>sudo certbot renew --dry-run<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">If you want to open the firewall explicitly, allow HTTP and HTTPS through UFW and you are done with the proxy. The same pattern works for any app you put behind Nginx, and it is covered in more depth in our <a href=\"https:\/\/computingforgeeks.com\/install-nginx-ubuntu-2604-lets-encrypt\/\">Nginx with Let&#8217;s Encrypt walkthrough<\/a>.<\/p>\n\n\n\n<pre class=\"wp-block-code code\"><code>sudo ufw allow 'Nginx Full'<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">No public port 80? Use a DNS challenge instead<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">If the server sits on a private network or behind NAT where port 80 is not reachable, swap the HTTP-01 challenge for DNS-01. Certbot has plugins for Cloudflare, Route 53, DigitalOcean, Google Cloud DNS, Linode, and more. With a Cloudflare-managed domain, install the plugin, drop an API token in a credentials file, and request the certificate over DNS:<\/p>\n\n\n\n<pre class=\"wp-block-code code\"><code>sudo apt install -y python3-certbot-dns-cloudflare\necho \"dns_cloudflare_api_token = YOUR_API_TOKEN\" | sudo tee \/etc\/letsencrypt\/cloudflare.ini\nsudo chmod 600 \/etc\/letsencrypt\/cloudflare.ini\nsudo certbot certonly --dns-cloudflare \\\n  --dns-cloudflare-credentials \/etc\/letsencrypt\/cloudflare.ini \\\n  -d \"${SITE_DOMAIN}\" --non-interactive --agree-tos -m \"${ADMIN_EMAIL}\"<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Substitute your own provider&#8217;s plugin if you are not on Cloudflare, then reference the issued certificate in your Nginx <code>ssl_certificate<\/code> and <code>ssl_certificate_key<\/code> directives.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Run FileBrowser with Docker Compose instead<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">If you would rather run it in a container, the official image covers it. This Compose file uses the s6 variant, which respects the <code>PUID<\/code> and <code>PGID<\/code> values so files written through the UI land with the right ownership on the host. Create a project directory and a <code>docker-compose.yml<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-code code\"><code>services:\n  filebrowser:\n    image: filebrowser\/filebrowser:s6\n    container_name: filebrowser\n    restart: unless-stopped\n    ports:\n      - \"8080:80\"\n    environment:\n      - PUID=1000\n      - PGID=1000\n    volumes:\n      - .\/srv:\/srv\n      - .\/database:\/database\n      - .\/config:\/config<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Bring it up and check the container is healthy:<\/p>\n\n\n\n<pre class=\"wp-block-code code\"><code>docker compose up -d\ndocker compose ps<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">On first start the container prints a randomly generated admin password to its logs, shown only once. Read it, then change it after you log in:<\/p>\n\n\n\n<pre class=\"wp-block-code code\"><code>docker compose logs filebrowser | grep -i password<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Put the same Nginx and Let&#8217;s Encrypt setup in front of the container, pointing the proxy at <code>127.0.0.1:8080<\/code>, and the container path is identical to the native one from the browser&#8217;s point of view.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Troubleshooting<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Error: timeout when running a CLI command<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">This means the service already holds the database open. The Bolt store is single-writer, so the running server and a CLI command cannot touch it at the same time. Stop the service with <code>sudo systemctl stop filebrowser<\/code>, run your <code>config<\/code> or <code>users<\/code> command, then start it again. For day-to-day user changes, the web interface avoids the dance entirely.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">The command runner and shell are disabled<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The hook runner (commands that fire on upload, copy, rename, and so on) and the in-browser shell have shipped disabled by default since v2.33.8 because of repeated security problems. That default is correct: an exposed shell on a file manager is a remote code execution surface. If you genuinely need a hook on an internal-only instance, you re-enable execution explicitly and allowlist exactly which commands are permitted, never the whole shell. Treat it as the sharp tool it is and leave it off unless you have a specific, contained reason.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">502 Bad Gateway from Nginx<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Nginx is up but cannot reach FileBrowser. Confirm the service is running and that <code>proxy_pass<\/code> matches the address and port FileBrowser is bound to. If you changed the listen address in the database, restart the service and re-check <code>ss -tlnp<\/code>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Forgotten admin password<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Reset it from the CLI. Stop the service, then update the user:<\/p>\n\n\n\n<pre class=\"wp-block-code code\"><code>sudo systemctl stop filebrowser\nsudo -u filebrowser filebrowser -d \"${FB_DB}\" users update admin --password 'NewStrongPass'\nsudo systemctl start filebrowser<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Security hardening checklist<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">FileBrowser hands out file access over the web, so the defaults matter. Before you point real users at it, walk this list:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Keep it bound to localhost.<\/strong> Let Nginx be the only public listener. A direct <code>0.0.0.0<\/code> bind skips your TLS and proxy protections.<\/li>\n\n\n\n<li><strong>Always serve over HTTPS.<\/strong> A login form on plain HTTP ships the password in clear text. The Let&#8217;s Encrypt step above is not optional for anything internet-facing.<\/li>\n\n\n\n<li><strong>Scope every non-admin user.<\/strong> Give each account the narrowest folder and the fewest permissions it needs. Admin is for you, not for the team.<\/li>\n\n\n\n<li><strong>Leave the command runner off.<\/strong> If you never enable it, there is no shell to abuse.<\/li>\n\n\n\n<li><strong>Rate-limit logins.<\/strong> Add a <a href=\"https:\/\/computingforgeeks.com\/install-fail2ban-ubuntu-2604\/\">Fail2ban<\/a> jail that watches the FileBrowser log for repeated <code>403<\/code> responses on <code>\/api\/login<\/code> and bans the source after a handful of failures.<\/li>\n\n\n\n<li><strong>Set sensible share expiries.<\/strong> Default to a duration and a password for anything sensitive, and revoke links from Share Management when they have served their purpose.<\/li>\n\n\n\n<li><strong>Restrict network reach where you can.<\/strong> For a private file drop, keep it on the LAN or behind a <a href=\"https:\/\/computingforgeeks.com\/install-wireguard-ubuntu-2604\/\">WireGuard tunnel<\/a> rather than the open internet.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">With that in place you have a fast, single-binary file manager that you fully control, serving a real directory over HTTPS with scoped users and expiring links. If your needs grow toward team collaboration, versioning, or single sign-on, FileBrowser Quantum, <a href=\"https:\/\/computingforgeeks.com\/install-nextcloud-ubuntu-2604\/\">Nextcloud<\/a>, and <a href=\"https:\/\/computingforgeeks.com\/install-seafile-server-ubuntu-docker\/\">Seafile<\/a> pick up where the original leaves off, but for putting a folder on the web quickly and safely, this is hard to beat.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>FileBrowser turns any directory on a Linux server into a clean web interface for uploading, downloading, editing, and sharing files. It is a single static Go binary with no database server and no PHP stack behind it. Point it at a folder, open a browser, and you have a working file manager in a couple &#8230; <a title=\"Install FileBrowser: Self-Hosted Web File Manager on Linux\" class=\"read-more\" href=\"https:\/\/computingforgeeks.com\/install-filebrowser-linux\/\" aria-label=\"Read more about Install FileBrowser: Self-Hosted Web File Manager on Linux\">Read more<\/a><\/p>\n","protected":false},"author":7,"featured_media":168279,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[47,50,349],"tags":[282,209,2254],"cfg_series":[39875],"class_list":["post-168280","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-linux","category-linux-tutorials","category-web-hosting","tag-linux","tag-storage","tag-ubuntu","cfg_series-filebrowser-self-hosting"],"_links":{"self":[{"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/posts\/168280","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/users\/7"}],"replies":[{"embeddable":true,"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/comments?post=168280"}],"version-history":[{"count":2,"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/posts\/168280\/revisions"}],"predecessor-version":[{"id":168283,"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/posts\/168280\/revisions\/168283"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/media\/168279"}],"wp:attachment":[{"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/media?parent=168280"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/categories?post=168280"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/tags?post=168280"},{"taxonomy":"cfg_series","embeddable":true,"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/cfg_series?post=168280"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}