Context
Recently I've had the opportunity to work on a few long-form media projects. These projects required us to collect what I would consider a fair bit of media for what are relatively small theatre companies that wanted to try their hand at increasing their social media exposure for shows. To give you an idea, one project required multiple photo shoots, which resulted in hundreds of photos, and then required full recordings of a tech run and a final recording of the full show on closing night. The stills and video needed to be processed like normal, but the videos needed to be taken further to create trailers and social media content, and also cut into clips so that actors could show off their performances in their portfolios.
To give you a sense of how the data scaled, a single 3-hour show run in 4K ProRes 422 HQ comes to roughly 800GB. Multiply this by two because we have to do closing night too, and we have ~1.6TB of footage. The 600 Fuji RAW files then add another ~10GB.
After a few days of editing we can shrink this down to a few ~25GB renders, each with different colour grades and feels, and about 4GB of stills. This is great, that's a lot of space saved. Final project files end up being ~80GB give or take. Oh, and those renders are H.265. Yes, I know AV1 exists, but we have to stay compatible with client hardware. And nobody is building new PCs with the current price of hardware.
The problem
Typically my projects don't require 3 hours of straight recording, so I've been able to get away with juggling cloud services. If the final render is under 15GB I can just use Google Drive and let Google handle security and links. If not, maybe we need to split project files and put the stills on Dropbox to make it all work.
But free tiers only go so far, and growing them 500MB at a time with referrals isn't a plan. And what happens when a client asks for the raw footage?
If you've made it this far, thank you, and you can probably guess where this is going: how do I get these files to clients without mailing or lending out my 2TB NVMe?
The obvious answer is yet another monthly subscription for 1–2TB of cloud storage. The responsible answer might be Azure Storage, handing out SAS URLs to blobs, and wrapping everything in password-protected zips.
But that's boring, and I've got a Dell R730xd under my desk that's spent far too long as a footrest.
Part 1 - The setup
The server I received already came with ESXi installed and a few TBs that are managed through an internal RAID controller. I won't go into too much detail about the server itself, since the same result can be achieved on bare metal, a VM or containers. The main requirement is a place you can install OpenMediaVault (OMV) and a big storage pool. I was lucky enough that the server came with an HDD1 store of 12TB, and I've added HDD2 and HDD3 as supplementary storage for apps, config backups and other things.
I've chosen to separate the data by using HDD1 as the main storage location for FileBrowser Quantum and HDD2 for Docker components and any other configs, because I prefer the physical boundary. You don't have to do it this way. You may well only have one giant pool; you'll still be able to separate the locations using OMV's shared folder functionality.
Installing the OS
OMV has a lot of useful documentation, and the installation process is pretty straightforward with their installer. You burn the ISO to a USB and boot into the installer. If you're on Windows, Rufus is the tool I use; otherwise Etcher or dd can be used on Linux.
Through ESXi we can skip all that and upload the ISO image directly to one of our datastores, so that we can bind it to the VM during the creation step. We then run through the VM creation steps, choosing Linux as the guest OS family, Debian as the OS version, and binding the ISO.
Another great tweak is to enable the VM to start on boot, so if the server restarts or something happens the VM automagically comes back online.
You should now be able to follow the standard installation guide from OMV and end up with a similar-looking terminal displaying an IP that hosts the web frontend, and some credentials to use on the login page.
Install done.
Configuring OpenMediaVault
At this stage you should be able to log in to OMV through your browser and click around to familiarise yourself with the interface. I would also strongly recommend you check for updates under
System -> Update Management -> Updates
so that you have the latest security fixes and features. Oh, and make sure all your disks show up under
Storage -> Disks
We should now be able to start creating Shared Folders and set up SMB. I will create three Shared Folders:
DockerAppData - Where we store our Docker compose files
FileBrowserShares - Where we store what we want to share
Media1 - The original location of all our data (optional)
I have Media1 here because I was already using OMV for storing the giant RAW footage. Everything can work off a single share, but then all of it will be exposed to the container.
Now we just need to enable a way to move files over the network to OMV. Personally I picked SMB for this, since NFS permissions are IP-based and file ownership uses user IDs. Rsync is also a really good option for large files.
Head down to
Services -> SMB/CIFS -> Settings
and enable it there. You should now be able to create SMB shares under
Services -> SMB/CIFS -> Shares
Another optional step is to create a user or a group if you want to limit actions. You should only need one or two shares depending on your setup. Point them at the correct Shared Folders from the previous step:
FileBrowserShares - Where we drop our final render
Media1 - Where we store the raw footage
Add it to your file browser of choice or your fstab file and test.
Setting up OMV Docker
With OMV Shared Folders done and SMB set up, we now need to set up Docker and omv-extras, a set of community-maintained packages that add extra functionality.
In a terminal, either directly or through SSH, we need to run the install script.
wget -O - https://github.com/OpenMediaVault-Plugin-Developers/packages/raw/master/install | bash
You should now have a new option in your sidebar under
System -> omv-extras
Tick the Docker repo box and click the big blue Save button. Then run apt clean and wait until it says done.
With omv-extras enabled we should now be able to install openmediavault-compose, which will let us create our Docker containers from compose files. Install the plugin under System -> Plugins and refresh the page. If you get a connection lost message, it's because OMV restarts its web UI server; just refresh the browser.
In your sidebar you should now see a new
Services -> Compose -> Settings
page, which we will need to set up. The first thing you'll want to change is your compose files shared folder. Point this to your DockerAppData shared folder and hit Save. Then hit Install or Reinstall Docker.
DON'T FORGET TO HIT INSTALL OR REINSTALL DOCKER AT THE BOTTOM
Part 2 - Installing FileBrowser and cloudflared
At this point you should have OMV installed with SSH or direct terminal access, a few Shared Folders set up, SMB or some other way to sync files over the network, and omv-extras with Docker enabled and configured for compose files.
One hard requirement for this second part is a domain using Cloudflare DNS (the free plan is fine), which gives you access to Cloudflare Zero Trust tunnels. With that said, we're going to start this section by getting the tunnel set up before continuing with OMV. So go ahead and open a new tab or browser window.
We're going to start by creating a tunnel through the Cloudflare dashboard. You should be able to find the option under
Protect and Connect -> Zero Trust
This should redirect you to a new page with a different nav bar that should have
Networks -> Tunnels
Here you should be able to create a new tunnel of type Cloudflared, then for your connector make sure you select Docker.
IMPORTANT: Save the token displayed on this page, as it will be used in our compose file later.
Finally, at the publish step you should be able to set a subdomain and a path. I've chosen files as my subdomain, so I get files.[my-domain].com.
The other crucial step here, if you want to narrow access to just the generated links, is to set the Path field to ^/public/.*. This stops intruders from spamming your login page and scraping anything that's outside of FileBrowser's public folder. The tradeoff is that you also won't be able to access the login page or application externally. For me this isn't an issue, as 90% of the time I will be accessing it locally.
Lastly, the service section is the connection between our cloudflared container and FileBrowser Quantum container. We want to set the type to HTTP because FileBrowser serves plain HTTP and this hop never leaves the VM. Visitors still get HTTPS via Cloudflare, and the tunnel itself is encrypted. Set the URL to filebrowser:80 (we can use the container names here since Docker provides name resolution between containers; alternatively you could use [server-ip]:8080).
With the tunnel all set up, we can go back to OMV and start writing our compose file!
Final steps - Back to OMV
OK, we're nearly done. Hopefully you haven't run into any issues! With the tunnel all set up, we can write our configs and compose files and try to spin up our containers!
For this step, make sure you have that tunnel connector token handy.
First we're going to create the FileBrowser config file, so that when the container spins up it's ready to go. This typically lives under a /data folder in FileBrowser. We're also going to create a separate volume in our container called /deliveries that will be the publicly exposed directory.
Create a new folder under DockerAppData/filebrowser/data:
mkdir -p "/srv/dev-disk-by-uuid-[disk-uuid]/DockerAppData/filebrowser/data"
Now create a new config.yaml file inside this folder using a text editor such as nano or vim. Make sure you set your external URL correctly.
http:
externalUrl: "https://files.[domain].com"
trustProxyHeaders: true
disableWebDAV: true
server:
cacheDir: /home/filebrowser/data/tmp
sources:
- path: /deliveries
name: Deliveries
config:
defaultEnabled: true
frontend:
name: "MySiteName"
description: "Client video delivery"
The path here needs to match the compose file's volume from our next step, so take note.
Lastly, we need to set the owner to the container's user so it can read and write to its database.
chown -R 1000:1000 "/srv/dev-disk-by-uuid-[disk-uuid]/DockerAppData/filebrowser/data"
Now for our compose file. Back in OMV's web UI we can create compose files directly by navigating to
Services -> Compose -> Files
You should get a form where you can copy and paste the following YAML, substituting your disk UUIDs and your token from Cloudflare's tunnel setup.
services:
filebrowser:
image: ghcr.io/gtsteffaniak/filebrowser:2.0-stable
container_name: filebrowser
restart: unless-stopped
ports:
- "8080:80"
volumes:
- /srv/dev-disk-by-uuid-[disk-uuid]/FileBrowserShares:/deliveries:ro
- /srv/dev-disk-by-uuid-[disk-uuid]/DockerAppData/filebrowser/data:/home/filebrowser/data
cloudflared:
image: cloudflare/cloudflared:latest
container_name: cloudflared
restart: unless-stopped
command: tunnel --no-autoupdate run --token [MyBigToken]
depends_on:
- filebrowser
You'll notice here that we mount /deliveries and /data from our previous step. The rest of the YAML is pretty self-explanatory. Hit that Save button.
The
:roat the end of the/deliveriesvolume mounts it read-only. FileBrowser can show and share your files, but it can never modify or delete them, even if something goes wrong. I've done this because I'm testing and didn't want to accidentally delete files. Once you're happy you can remove this
Back in the main list you should be able to see a new row containing the new FileBrowser compose file. Select the row and click the "Up" button in the toolbar. This will download the images and spin up our containers!
Part 3 - The fun part!
If everything went well, you should see a green "Up" status and the bound ports on the right. You can click the URLs or navigate to your server's IP on port 8080 and see a login screen!
You'll need to grab the credentials from the Docker logs, as they are auto-generated by default. You can do this in the terminal using:
docker logs filebrowser 2>&1 | grep -i password
Log in as admin using that password (you'll be asked to set a new one straight away), and you should be greeted with an empty dashboard! You can now prep some files and drag them through SMB, or whatever network method you chose before, into your FileBrowserShares shared folder and they will appear!
Back in Cloudflare Tunnels you should now be able to see a Healthy status and one active connector, which confirms everything is hooked up correctly.
Testing Links
The final step is to right-click a directory or file and hit Share to generate a link! Give it an expiration time and a password and test it internally. You can then send it to someone, or test it on your phone, to make sure it works externally.
You should also test that hitting files.[domain].com directly results in a 404, as we don't want direct traffic.
If you've reached the end, everything should be working, and your FileBrowser instance should be tunnelled and only allow publicly served content and links in and out.
Conclusion
This was quite a journey, I'm not going to lie. It was my first time working with Cloudflare and its many features, and frankly I'm not convinced it's the absolute best solution to my problem. Maybe blob storage in a cloud provider would have been way easier, who knows. But it was an interesting mini project that taught me a lot, and I'll be testing it out for a few months.
Ive heard Cloudflare could potentially throttle this solution since serving large video is restricted and has to be routed through their paid services like Stream or R2 but the writing on the wall is that it only applies to 'disproportionate' usage. it will be interesting to see if this applies to my case of a few files a month.
If anybody knows of any other similar solutions, let me know! I'd love to see how other people have solved this.
References



















Top comments (0)