A Docker container that provides a unified filesystem using rclone and mergerfs, with automatic daily synchronization from local to remote storage.
- Rclone Mount: Mounts any rclone-supported remote (Google Drive, S3, etc.)
- MergerFS Overlay: Provides a merged view with local filesystem overlaid on remote
- Write-Local Strategy: All writes go to local storage for fast performance
- Daily Move Job: Automatically moves files from local to remote on a schedule
- Supervisor Management: All services managed by supervisord for reliability
graph TD
A["Merged Filesystem<br/>/mnt/merged<br/>(Use this for your applications)"]
B["Local Storage<br/>/mnt/local<br/>(Read/Write)<br/>Fast Local Storage"]
C["Rclone Mount<br/>/mnt/rclone<br/>(Read Only)<br/>Cloud Remote<br/>(S3, GDrive, etc.)"]
D["Daily Move Job<br/>(Transfers local → remote)"]
A --> B
A --> C
B --> D
C --> D
- Writes: All write operations go to
/mnt/local(fast local storage) - Reads: Files are read from local first, then from remote if not found locally
- Move Job: Daily cron job moves files from local to remote using
rclone movewith:--fast-listfor improved performance on large directories- 4 parallel transfers and 8 parallel checkers
- Automatic deletion of empty source directories
- Unified View: Applications see a single merged filesystem at
/mnt/merged
- Docker and Docker Compose
- A valid rclone configuration file
- Sufficient local storage for buffering writes
# Create a sample rclone.conf or copy your existing one
rclone config file # Shows where your config is located
cp ~/.config/rclone/rclone.conf ./rclone.confEdit docker-compose.yml or create a .env file:
environment:
- RCLONE_REMOTE=myremote # Name of remote in rclone.conf
- RCLONE_REMOTE_PATH=/backup # Path within the remote
- MOVE_SCHEDULE=0 2 * * * # Cron schedule (2 AM daily)docker-compose up -dThe merged filesystem is available at ./data/merged (mapped to /mnt/merged in container).
# Write a file (goes to local storage)
echo "Hello World" > ./data/merged/test.txt
# File is immediately available
cat ./data/merged/test.txt
# After the daily move job runs, it will be transferred to remoteThe project includes comprehensive integration tests using Node.js 24, Vitest, and TypeScript.
- Node.js 24+ installed
- pnpm installed
- Docker running
# Install dependencies
pnpm install
# Run integration tests
pnpm test
# Run performance tests
pnpm test:perf
# Run all tests
pnpm test:all
# Watch mode
pnpm test:watch
# UI mode
pnpm test:ui
# Clean test artifacts
pnpm cleanSee tests/README.md for more details.
| Variable | Default | Description |
|---|---|---|
RCLONE_REMOTE |
remote |
Name of the rclone remote (must exist in rclone.conf) |
RCLONE_REMOTE_PATH |
`` (empty) | Path within the remote to mount (empty = root of remote) |
MOVE_SCHEDULE |
0 2 * * * |
Cron schedule for move job (default: 2 AM daily) |
RCLONE_MOUNT_ARGS |
See below | Custom rclone mount arguments (optional) |
MERGERFS_MOUNT_ARGS |
See below | Custom mergerfs mount arguments (optional) |
LOCAL_PATH |
/mnt/local |
Path for local storage inside container |
RCLONE_MOUNT_PATH |
/mnt/rclone |
Path for rclone mount inside container |
MERGED_PATH |
/mnt/merged |
Path for merged filesystem inside container |
0 2 * * *- Daily at 2:00 AM0 */6 * * *- Every 6 hours0 0 * * 0- Weekly on Sunday at midnight*/30 * * * *- Every 30 minutes
The rclone mount is configured with these default options optimized for high-bandwidth video streaming:
--vfs-cache-mode full- Full VFS caching for best performance--vfs-cache-max-age 72h- Keep cache for 72 hours (3 days)--vfs-cache-max-size 100G- Maximum cache size of 100GB--dir-cache-time 1h- Cache directory listings for 1 hour--poll-interval 30s- Poll for changes every 30 seconds--attr-timeout 1h- Cache file attributes for 1 hour--allow-other- Allow other users to access the mount--allow-non-empty- Allow mounting on non-empty directories--log-level INFO- Log level set to INFO
Note: The default configuration does NOT include --vfs-read-ahead, --vfs-read-chunk-size, --vfs-read-chunk-streams, or --buffer-size. These can be added via RCLONE_MOUNT_ARGS if needed for specific use cases.
Note: The default of 4 parallel streams is conservative to avoid API rate limits on Google Drive. For high-performance object stores like S3, you can increase this to 16 or more via RCLONE_MOUNT_ARGS.
Custom Arguments:
You can override the default rclone mount arguments using the RCLONE_MOUNT_ARGS environment variable:
environment:
- RCLONE_MOUNT_ARGS=--vfs-cache-mode off --dir-cache-time 1sNote: Core arguments (--config, --allow-other, --allow-non-empty, --log-level INFO) are always included.
The mergerfs mount uses minimal configuration, relying on sensible defaults:
Custom (non-default) options:
func.getattr=newest- Use newest file when duplicates existminfreespace=10G- Require 10GB free space for writes (default: 4G)category.action=all- Apply category rules to all operationscategory.create=ff- First-found policy for file creationrw- Read-write mode
Default options used:
- Local branch is mounted as RW (read-write)
- Rclone branch is mounted as NC (no-create, read-only for writes)
Custom Arguments:
You can override the default mergerfs mount arguments using the MERGERFS_MOUNT_ARGS environment variable:
environment:
- MERGERFS_MOUNT_ARGS=-o use_ino -o cache.files=off -o category.create=ffNote: Core arguments (-f, -o allow_other) are always included.
docker exec neomount /scripts/move-job.sh# All supervisor logs
docker exec neomount tail -f /var/log/supervisor/supervisord.log
# Rclone mount logs (stdout)
docker exec neomount tail -f /var/log/supervisor/rclone.log
# Rclone errors
docker exec neomount tail -f /var/log/supervisor/rclone_error.log
# MergerFS logs (stdout)
docker exec neomount tail -f /var/log/supervisor/mergerfs.log
# MergerFS errors
docker exec neomount tail -f /var/log/supervisor/mergerfs_error.log
# Cron logs
docker exec neomount tail -f /var/log/supervisor/cron.log
# Move job logs (written by the script itself)
docker exec neomount tail -f /var/log/move-job.logdocker exec neomount mount | grep -E "(rclone|mergerfs)"docker exec neomount rclone --config /config/rclone.conf listremotes- Check that
rclone.confexists and is valid - Verify the remote name matches what's in your config
- Check logs:
docker-compose logs neomount
# Check rclone logs
docker exec neomount cat /var/log/supervisor/rclone_error.log
# Verify remote is accessible
docker exec neomount rclone --config /config/rclone.conf lsd myremote:# Check mergerfs logs
docker exec neomount cat /var/log/supervisor/mergerfs_error.log
# Verify rclone mount is working
docker exec neomount ls /mnt/rclone# Check cron configuration
docker exec neomount cat /etc/cron.d/move-job
# Check cron logs
docker exec neomount cat /var/log/supervisor/cron.log
# Verify cron is running
docker exec neomount ps aux | grep cron- Never commit
rclone.conf- It contains sensitive credentials - The container runs in privileged mode for FUSE mounts
- Consider using Docker secrets for production deployments
- Restrict access to the merged filesystem directory
The default configuration is optimized for high-bandwidth video streaming with:
Rclone:
- 100GB VFS cache - Stores frequently accessed files locally
- 72-hour cache retention - Keeps cached files for 3 days
- 1-hour directory cache - Caches directory listings for faster navigation
- 30-second poll interval - Detects remote changes frequently
MergerFS:
- No caching overhead - Relies on rclone's VFS cache instead
- Async reads - Non-blocking reads for better throughput
- Smart file placement - Writes to branch with most free space
Recommended System Requirements for 4K Streaming:
- 8GB+ RAM (for VFS cache)
- 100GB+ free disk space (for cache storage)
- Fast SSD for local storage (NVMe preferred)
- 100Mbps+ internet connection
If you have limited resources, use these lighter settings:
environment:
# Reduce cache size and read-ahead
- RCLONE_MOUNT_ARGS=--vfs-cache-mode writes --vfs-cache-max-size 10G --vfs-read-ahead 128M --buffer-size 128M
# MergerFS already has minimal overhead with cache.files=off by defaultUse environment variables to customize mount behavior without editing scripts:
environment:
# Disable rclone caching for testing
- RCLONE_MOUNT_ARGS=--vfs-cache-mode off --dir-cache-time 1s
# Optimize mergerfs for SSDs
- MERGERFS_MOUNT_ARGS=-o use_ino -o cache.files=off -o direct_ioAlternatively, you can edit scripts/rclone-mount.sh or scripts/mergerfs-mount.sh directly for permanent changes.
To use multiple remotes, you can run multiple instances with different configurations:
# Copy docker-compose.yml to docker-compose-remote2.yml
# Update the remote name and paths
docker-compose -f docker-compose-remote2.yml up -dAdd health checks to docker-compose.yml:
healthcheck:
test: ["CMD", "mountpoint", "-q", "/mnt/merged"]
interval: 30s
timeout: 10s
retries: 3MIT
Contributions welcome! Please open an issue or PR.