Storage Backends
Meowbert can store workspaces and projects on different filesystem backends:
- Local — the current built-in runtime folders on the host.
- Mounted path — any filesystem that is already mounted on the host and visible inside the API/worker containers.
A mounted path backend is intentionally simple. Meowbert does not mount NFS, rclone, SSHFS, SMB, or any other network filesystem for you.
Instead, you mount that storage on the host first, then point Meowbert at the directory path that is already mounted.
This is a platform-admin feature. After a backend is configured in config/global.json, super admins can:
- set the default backend for new workspaces
- move an existing workspace onto another backend from Admin → Storage
If you want hard per-workspace storage limits on a local backend, see XFS Project Quotas.
How mounted-path backends work
A mounted-path backend only needs:
- a backend id
- a mounted directory path such as
/app/runtime/storage/mounted-onedrive - optional
workspacesDir/projectsDirsubfolder names
Meowbert expects that path to already be mounted and visible from inside the API and worker containers.
That means the normal setup flow is:
- mount the remote filesystem on the host
- make sure that mounted directory is inside the host path that is bind-mounted into
/app/runtime - point
storage.backends[].mountPathat the corresponding container path - restart API + worker
- switch the backend in Admin → Storage
Before you start
For mounted-path backends, check:
- API and worker services can both see the same
/app/runtimebind mount - the host-side mounted directory lives under that bind-mounted runtime tree
- the mounted path stays available after reboot, usually via
/etc/fstabor a system service - the service user/container has read/write access to the mounted filesystem
Example config
{
"storage": {
"defaultWorkspaceBackendId": "local-default",
"backends": [
{
"id": "mounted-shared",
"label": "Mounted Shared Runtime",
"type": "mounted",
"mountPath": "/app/runtime/storage/mounted-shared",
"workspacesDir": "workspaces",
"projectsDir": "projects"
},
{
"id": "onedrive-main",
"label": "Mounted OneDrive Runtime",
"type": "mounted",
"mountPath": "/app/runtime/storage/onedrive-main",
"workspacesDir": "workspaces",
"projectsDir": "projects"
}
]
}
}What each field does
| Field | Meaning |
|---|---|
id | Backend id shown in Admin → Storage |
mountPath | Existing mounted directory inside the API/worker container |
workspacesDir / projectsDir | Subfolders created under that mounted storage |
Host mount examples
Use whatever host-level mount mechanism you prefer, as long as the final mounted path is visible to Meowbert.
Example: mount NFS on the host
sudo mkdir -p /srv/meowbert/runtime/storage/mounted-shared
sudo mount -t nfs -o hard,noatime 10.0.0.25:/exports/meowbert /srv/meowbert/runtime/storage/mounted-sharedThen in Meowbert config, use:
{
"id": "mounted-shared",
"type": "mounted",
"mountPath": "/app/runtime/storage/mounted-shared"
}Example: mount OneDrive with rclone on the host
sudo mkdir -p /srv/meowbert/runtime/storage/onedrive-main
sudo rclone mount meowbert_onedrive:meowbert-data /srv/meowbert/runtime/storage/onedrive-main \
--allow-other \
--vfs-cache-mode writes \
--vfs-cache-max-size 8G \
--dir-cache-time 5m \
--vfs-links \
--daemonThen in Meowbert config, use:
{
"id": "onedrive-main",
"type": "mounted",
"mountPath": "/app/runtime/storage/onedrive-main"
}Persisting host mounts
The best option depends on the storage type:
- NFS / CIFS / block devices: usually
/etc/fstab - rclone mount: usually a
systemdservice on the host
Meowbert only needs the final mounted directory to be present before API + worker start.
Step 1: mount the storage on the host
Make sure the host path lives under the runtime bind source. For example, if your host runtime root is:
/srv/meowbert/runtimethen a mounted backend path could be:
/srv/meowbert/runtime/storage/onedrive-mainwhich becomes this inside the container:
/app/runtime/storage/onedrive-mainStep 2: add the backend to config/global.json
Use the mounted-path backend type and point it at the container-visible path.
Step 3: restart API and worker
After saving config/global.json, restart both services so they reload the backend definitions.
With Docker Compose:
docker compose up -d --build api workerStep 4: enable it in the admin panel
Open Admin → Storage.
From there you can:
- choose the new mounted backend as the default for future workspaces
- queue a workspace migration for any existing workspace
Changing the global default only affects new workspaces. Existing workspaces stay where they are unless you explicitly queue a migration.
Troubleshooting
Backend health says the mount is not active
Check:
- the host mount is actually mounted
- the mounted directory exists under the host runtime bind source
- the container path in
mountPathmatches the mounted host path - API and worker both see the same bind-mounted runtime tree
mountpoint -q <mountPath>succeeds from inside the API and worker containers- the runtime bind mount uses shared propagation, such as
rshared, so host mounts under the runtime directory propagate into running containers
The path exists, but Meowbert still says it is not mounted
Meowbert checks that mountPath itself is a real mountpoint.
So if your real host mount is:
/app/runtime/storageand your backend points at:
/app/runtime/storage/onedrive-mainthat subdirectory will not count as a mountpoint.
Point mountPath at the actual mounted directory instead.
I mounted OneDrive with rclone on the host. Does Meowbert still need rclone config fields?
No.
Those old in-app mounting fields are gone. Meowbert only needs the mounted directory path now.
File writes or random-access edits behave badly on rclone mounts
Tune the host-side rclone command, not Meowbert config.
A good starting point is:
--vfs-cache-mode writes --vfs-cache-max-size 8G --dir-cache-time 5m --vfs-linksGood defaults for first deployment
Start simple:
- keep
local-defaultas the platform default first - add one mounted backend such as
onedrive-main - verify it is healthy in Admin → Storage
- switch new workspaces over first
- migrate existing workspaces in batches