Setting up a secure & public-facing Filebrowser instance


  • Filebrowser Setup
  • oemb1905
  • filebrowser-pub
  • webmaster@gnulinux.studio

//filebrowser-pub//


Latest Updates: https://wiki.haacksnetworking.org/doku.php?id=computing:filebrowser


This tutorial is for Debian Trixie users seeking to set up a secure and public-facing Filebrowser instance. This is to assist with uploading and managing music/media on Navidrome, Jellyfin, and other similar instances. Do not proceed with this tutorial until you’ve learned how to set up a public facing VM/VPS and harden it appropriately. If you have not done that, start with Apache Survival. So long as that’s in place, you can safely begin. You can install Filebrowser manually, or use their automated bash script. I chose the latter. Make sure to verify the checksums and code before using the pipe-to-bash approach like me:

curl -fsSL https://raw.githubusercontent.com/filebrowser/get/master/get.sh | bash
sudo mkdir -p /var/lib/filebrowser
sudo chown -R filebrowser:filebrowser /var/lib/filebrowser
sudo chmod 755 /var/lib/filebrowser

The system will give you an auto-generated user and password upon completion of the installer. Let’s change that before we proceed:

sudo systemctl stop filebrowser
sudo filebrowser users update admin --password yournewpassword
sudo systemctl start filebrowser

Make sure to pick a 16+ character password; this is public facing. To be clear, this is invoking the filebrowser service to update the admin user in the sql-lite database it just created. The service does, however, required a dedicated simple UNIX user, which we will now create and make sure to turn off home directory and shell access for:

sudo adduser --system --group --no-create-home filebrowser

Once the dedicated user is created, let’s create the systemd unit to control starting/stopping the service. Let’s create a unit file here sudo nano/etc/systemd/system/filebrowser.service and drop these contents inside:

[Unit]
Description=File Browser
After=network.target

[Service]
User=filebrowser
Group=filebrowser
WorkingDirectory=/var/lib/filebrowser
ExecStart=/usr/local/bin/filebrowser \
  --address 127.0.0.1 \
  --port 8080 \
  --root /opt/navidrome/music \
  --database /var/lib/filebrowser/filebrowser.db

#Anyone talking about the "put credentials" ^^
#is mistaken - anything after first install 
#uses creds in filebrowser.db and thus bypasses any here

Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target

Once that’s in place, load the unit and start the service:

sudo systemctl daemon-reload
sudo systemctl enable --now filebrowser

Make sure to customize the unit file for your own use-case. For example, you might have a different startup directory, different listening port, and so on. Once the unit file is created and the service has started, let’s make sure that ACL is installed so we can set a custom rule for the filebrowser UNIX user, which the filebrowser’s GUI / sql lite database will send commands to via your web session, which is behind a reverse proxy in apache. Let’s get that done:

sudo apt install acl
sudo setfacl -R -m u:filebrowser:rwx /opt/navidrome/music
sudo setfacl -R -m d:u:filebrowser:rwx /opt/navidrome/music

UPDATE: This is actually overkill. You can simply sudo chown -R filebrowser:navidrome /opt/navidrome and nothing else. Filebrowser owns the directory and is behind SQL-lite and the authorized user and navidrome can read via the group privs.

This assumes /opt/navidrome/music is already established and running. If not, then consult the Navidrome tutorial first. The ACL above gives every current file read and write access (first stanza) and all future users read and write access (second stanza). At this time, filebrowser is already running, but behind port 8080. Now, one could simply access it with http://domain:com:8080 but that won’t be TLS secured and is just kind of janky. So, for these cases, we create a reverse proxy that sits facing the public and receiving requests, and then pushes incoming requests upstream to the filebrowser service running locally on port 8080. To do that, let’s first edit /etc/apache2/000-default.conf and edit the ServerName to domain.com, change the web root to /var/www/domain.com/public_html and leave everything else as is. Restart the service with systemctl restart apache2 and then let’s create a Let’s Encrypt cert on the thusly adjusted default virtual host:

sudo apt install certbot letsencrypt python3-certbot-apache
sudo certbot --authenticator standalone --installer apache -d domain.com --pre-hook "systemctl stop apache2" --post-hook "systemctl start apache2"

This will create another virtual host at 000-default-le.conf or something similar. It will be automatically activated along with 000-default.conf by default. But, this is serving requests from /var/www/domain.com/public_html, and so the upstream filebrowser service is entirely ignored. But/and, the dirty work of creating the TLS cert is now done, so we can simply drop in some replacement configurations into both vhosts and restart the apache2 service and everything will automagically work. Open /etc/apache2/sites-available/000-default.conf and drop this inside:

<VirtualHost *:80>
    ServerName upload.gnulinux.studio

    RewriteEngine On
    RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [L,R=301]
</VirtualHost>

Now, let’s do the same trick with the https virtual host. Open up nano /etc/apache2/sites-available/000-default-le.conf and drop this inside:

<VirtualHost *:443>
    ServerName upload.gnulinux.studio

    SSLEngine on
    SSLCertificateFile      /etc/letsencrypt/live/upload.gnulinux.studio/fullchain.pem
    SSLCertificateKeyFile   /etc/letsencrypt/live/upload.gnulinux.studio/privkey.pem

    ProxyPreserveHost On
    ProxyPass / http://127.0.0.1:8080/
    ProxyPassReverse / http://127.0.0.1:8080/

    # WebSocket (required for live uploads/previews)
    RewriteEngine On
    RewriteCond %{HTTP:Upgrade} websocket [NC]
    RewriteCond %{HTTP:Connection} upgrade [NC]
    RewriteRule ^/?(.*) ws://127.0.0.1:8080/$1 [P,L]
</VirtualHost>

Once this is done, you should be good to go. Make sure that:

  • If you already using domain.com, then change the above to sub.domain.com
  • LAMP stack won’t work unless all modules, headers, and mpm_event/fpm working
  • Have fail2ban configured

This tutorial is not designed to provide a full tutorial on these topics, but generally these modules are enough:

sudo a2enmod ssl
sudo a2enmod proxy
sudo a2enmod proxy_http
sudo a2enmod proxy_wstunnel
sudo a2enmod headers
sudo a2enmod rewrite
sudo a2enmod remoteip
sudo a2enmod proxy_fcgi
sudo a2enmod setenvif

If you need more guidance, see the Apache Survival Tutorial already linked at the top. If you need help with mpm_event and fpm, use my WordPress tutorial. The only other thing you can optionally do is setup a rule to stop repeat brute-force attackers on Filebrowser’s auth mechanism. This is optional, but here’s a recipe I got off Reddit and adjusted. Open up /etc/fail2ban/jail.d/filebrowser.conf and create the jail:

[filebrowser]
enabled = true
backend = systemd
port = 8080
filter = filebrowser
logpath = /var/log/filebrowser/filebrowser.log
maxretry = 3
findtime = 3w
bantime = 20w
action = iptables-allports[name=filebrowser]

After the jail is established, we need to create the filter that the jail leverages to decide on whether it bans the request. To do that, open up /etc/fail2ban/filter.d/filebrowser.conf and drop the filter rules in it:

[INCLUDES]
before = common.conf

[Definition]
datepattern = ^%%Y/%%m/%%d %%H:%%M:%%S
failregex = /api/login: 403 <HOST> .*
ignoreregex =

Make sure to adjust bantime, maxretry, and findtime to your preferences. Also, apache-auth’s default jail is not designed for reverse proxies. So, let’s create one more jail+filter to block repeat offenders against the proxy, which will trigger a 401 and/or 403 due to them trying to access something that does not exist. Let’s open up the jail file /etc/fail2ban/jail.d/apache-auth.conf and drop this inside:

# /etc/fail2ban/jail.d/apache-proxy.conf
[apache-proxy]
enabled  = true
port     = http,https
filter   = apache-proxy
logpath  = /var/log/apache2/*error.log
           /var/log/apache2/*access.log
maxretry = 3
findtime = 3w
bantime  = 20w
action   = iptables-allports[name=apache-proxy]

Now, for the filter, let’s open /etc/fail2ban/filter.d/apache-auth.conf and drop the following inside:

[Definition]
failregex = ^ -."(GET|POST|HEAD). 401
            ^ -."(GET|POST|HEAD). 403
ignoreregex =

This creates a separate jail for common errors brute-forcers will receive when they are trying to access your instance’s directories etc. Restart the service systemctl restart fail2ban and you should be good to go. If you need help, hit me up on Matrix; I’ll be happy to help!

Happy Hacking !!!

Leave a Reply

Your email address will not be published. Required fields are marked *

Close