FUSE (Filesystem in Userspace) - Complete Guide for Raspberry Pi
Introduction
FUSE (Filesystem in Userspace) is a powerful Linux kernel module that enables users to create custom filesystems without kernel programming or root privileges. Instead of writing kernel code, you can implement filesystems in any programming language, running them safely in user space.
This opens up incredible possibilities for Raspberry Pi users:
- Mount cloud storage as local directories (Google Drive, Dropbox, OneDrive)
- Access remote servers via SSHFS as if they were local drives
- Create encrypted filesystems for sensitive data protection
- Archive file mounting - browse ZIP/TAR files without extraction
- Custom data transformations - compress, encrypt, or modify files on-the-fly
- Network protocols as filesystems - FTP, WebDAV, S3 buckets
- Device abstraction - represent hardware devices as file hierarchies
This comprehensive guide covers:
- FUSE Architecture: How userspace filesystems work
- Popular FUSE Tools: SSHFS, rclone, GocryptFS, NTFS-3G, BindFS
- Cloud Storage Integration: Mount Google Drive, OneDrive, S3, Dropbox
- Remote Access: SSHFS for transparent remote file access
- Encryption: Secure filesystems with GocryptFS and EncFS
- Custom Filesystems: Build your own FUSE filesystem in Python/C++
- Performance Tuning: Optimize FUSE for Raspberry Pi
- Production Deployment: Systemd integration and monitoring
Perfect for:
- Home Media Centers: Access cloud-stored movies and music
- Backup Solutions: Transparent cloud backup integration
- Development Workflows: Mount remote development servers
- Privacy-Focused Storage: End-to-end encrypted cloud storage
- IoT Data Collection: Custom filesystems for sensor data
- Network Attached Storage: Enhanced NAS capabilities
- Cross-Platform Access: Windows NTFS drives on Raspberry Pi
Understanding FUSE Architecture
How Traditional Filesystems Work
| ┌─────────────────┐
│ Application │
└────────┬────────┘
│ open("/data/file.txt")
▼
┌─────────────────┐
│ VFS Layer │ (Virtual File System)
└────────┬────────┘
│
▼
┌─────────────────┐
│ Kernel Filesystem│ (ext4, btrfs, FAT32)
│ Driver │ <- Runs in kernel space
└────────┬────────┘
│
▼
┌─────────────────┐
│ Block Device │ (/dev/sda1, /dev/mmcblk0p2)
└─────────────────┘
|
Limitations:
- Requires kernel module development (C programming, complex APIs)
- Kernel bugs can crash entire system
- Must be loaded with root privileges
- Difficult to debug and test
- Kernel recompilation often needed
How FUSE Works
| ┌─────────────────┐
│ Application │
└────────┬────────┘
│ open("/fuse/file.txt")
▼
┌─────────────────┐
│ VFS Layer │
└────────┬────────┘
│
▼
┌─────────────────┐
│ FUSE Kernel │ <- Small kernel module (stable, generic)
│ Module │
└────────┬────────┘
│ /dev/fuse (device file communication)
▼
┌─────────────────┐
│ FUSE Userspace │ <- Your custom filesystem
│ Daemon │ (Python, C++, Go, Rust, etc.)
│ (Your Code) │ Runs as regular process
└────────┬────────┘
│
▼
┌─────────────────┐
│ Backend │ (Local files, network, cloud API, etc.)
└─────────────────┘
|
Advantages:
- Safety: Crashes don't affect kernel
- Easy Development: Use any programming language
- No Root Required: For mounting (with proper setup)
- Rapid Prototyping: Debug with standard tools
- Cross-Platform: Works on Linux, macOS, FreeBSD
Trade-offs:
- Performance: Extra context switches (kernel ↔ userspace)
- Overhead: ~5-15% slower than native kernel filesystems
- Latency: Additional layers add microsecond delays
FUSE Operations Flow
| // User application does:
int fd = open("/mnt/fuse/photo.jpg", O_RDONLY);
// FUSE kernel module intercepts and forwards to userspace daemon:
// Your FUSE daemon receives:
fuse_operations.open(path="/photo.jpg", flags=O_RDONLY)
{
// Your custom logic:
// - Check permissions
// - Download from cloud
// - Decrypt file
// - Open network connection
// etc.
return file_descriptor;
}
// Then application reads:
read(fd, buffer, 4096);
// FUSE forwards:
fuse_operations.read(path="/photo.jpg", offset=0, size=4096)
{
// Your custom logic:
// - Fetch data from backend
// - Decompress on-the-fly
// - Transform data
return data_bytes;
}
|
Installing FUSE
Basic Installation
| # Update system
sudo apt update
# Install FUSE library and development files
sudo apt install -y fuse3 libfuse3-dev
# Install common FUSE utilities
sudo apt install -y \
sshfs \
curlftpfs \
ntfs-3g \
exfat-fuse
# Verify installation
fusermount3 --version
# Should show: fusermount3 version: 3.x.x
# Check FUSE kernel module
lsmod | grep fuse
# Should show: fuse
|
Enable User Mounting
| # Add your user to 'fuse' group (if exists)
sudo usermod -a -G fuse $USER
# Configure fuse.conf
sudo nano /etc/fuse.conf
# Uncomment or add:
user_allow_other
# This allows non-root users to specify allow_other option
# Enables other users to access FUSE mounts
# Log out and back in for group changes to take effect
|
Verify FUSE Setup
| # Check FUSE device
ls -l /dev/fuse
# Should show: crw-rw-rw- 1 root root 10, 229 ... /dev/fuse
# Test basic FUSE mount (hello world example)
mkdir -p ~/fuse-test
# We'll create a test mount later with actual FUSE tools
|
Popular FUSE Filesystems
1. SSHFS - Remote Directory Access
Mount remote directories over SSH.
Installation:
| sudo apt install -y sshfs
|
Basic Usage:
| # Create mount point
mkdir -p ~/remote-server
# Mount remote directory
sshfs username@192.168.1.100:/home/username ~/remote-server
# Now access remote files locally:
ls ~/remote-server
cd ~/remote-server
nano ~/remote-server/file.txt
# Unmount
fusermount3 -u ~/remote-server
|
Advanced Options:
| # Mount with compression (faster over slow networks)
sshfs username@server.com:/data ~/remote \
-C \
-o compression=yes
# Mount with specific SSH key
sshfs username@server.com:/data ~/remote \
-o IdentityFile=~/.ssh/id_rsa_server
# Mount with reconnection (survives network interruptions)
sshfs username@server.com:/data ~/remote \
-o reconnect,ServerAliveInterval=15,ServerAliveCountMax=3
# Read-only mount
sshfs username@server.com:/data ~/remote \
-o ro
# Mount with specific permissions
sshfs username@server.com:/data ~/remote \
-o uid=$(id -u),gid=$(id -g),umask=022
# Performance tuning for large files
sshfs username@server.com:/data ~/remote \
-o cache=yes,kernel_cache,Ciphers=aes128-gcm@openssh.com
|
Auto-mount on Boot (fstab):
| # Edit fstab
sudo nano /etc/fstab
# Add line:
username@server.com:/remote/path /home/pi/remote fuse.sshfs defaults,_netdev,allow_other,IdentityFile=/home/pi/.ssh/id_rsa 0 0
# Test mount
sudo mount -a
|
2. rclone - Cloud Storage Mount
Mount virtually any cloud storage provider.
Installation:
| # Install rclone
sudo apt install -y rclone
# Or get latest version:
curl https://rclone.org/install.sh | sudo bash
|
Supported Providers:
- Google Drive
- OneDrive (Personal & Business)
- Dropbox
- Amazon S3
- Google Cloud Storage
- Microsoft Azure
- Backblaze B2
- SFTP
- WebDAV
- And 40+ more...
Setup Google Drive:
| # Interactive configuration
rclone config
# Follow prompts:
# n) New remote
# name> gdrive
# Storage> drive (select Google Drive)
# client_id> (press Enter to use default)
# client_secret> (press Enter)
# scope> 1 (Full access)
# root_folder_id> (press Enter)
# service_account_file> (press Enter)
# Edit advanced config? n
# Use auto config? n (for headless Raspberry Pi)
# This will give you a URL - open on another computer:
# Go to: https://accounts.google.com/o/oauth2/auth?client_id=...
# Authorize and copy the verification code
# Paste verification code back to Raspberry Pi
# Configure this as a team drive? n
# Confirm: y
|
Mount Google Drive:
| # Create mount point
mkdir -p ~/GoogleDrive
# Mount
rclone mount gdrive: ~/GoogleDrive \
--vfs-cache-mode writes \
--daemon
# Access files
ls ~/GoogleDrive
cd ~/GoogleDrive/Photos
# Unmount
fusermount3 -u ~/GoogleDrive
|
Optimized Mount Options:
| # High-performance configuration
rclone mount gdrive: ~/GoogleDrive \
--vfs-cache-mode full \
--vfs-cache-max-size 10G \
--vfs-cache-max-age 24h \
--buffer-size 256M \
--dir-cache-time 72h \
--drive-chunk-size 128M \
--transfers 4 \
--checkers 8 \
--low-level-retries 10 \
--log-file ~/rclone.log \
--log-level INFO \
--daemon
# Low-memory configuration (for older Pis)
rclone mount gdrive: ~/GoogleDrive \
--vfs-cache-mode writes \
--buffer-size 16M \
--dir-cache-time 1h \
--daemon
|
Setup Other Providers:
OneDrive:
| rclone config
# name> onedrive
# Storage> onedrive
# client_id> (Enter)
# client_secret> (Enter)
# region> 1 (Microsoft Cloud Global)
# Edit advanced? n
# Use auto config? n
# Follow authorization URL...
# Choose account type: 1 (OneDrive Personal)
|
Dropbox:
| rclone config
# name> dropbox
# Storage> dropbox
# client_id> (Enter)
# client_secret> (Enter)
# Edit advanced? n
# Use auto config? n
# Follow authorization URL...
|
Amazon S3:
| rclone config
# name> s3
# Storage> s3
# provider> 1 (Amazon S3)
# env_auth> 1 (Enter AWS credentials)
# access_key_id> YOUR_ACCESS_KEY
# secret_access_key> YOUR_SECRET_KEY
# region> us-east-1 (or your region)
# endpoint> (Enter for default)
|
3. GocryptFS - Encrypted Filesystem
Strong encryption for cloud-synced folders.
Installation:
| sudo apt install -y gocryptfs
|
Create Encrypted Storage:
| # Create encrypted directory
mkdir -p ~/encrypted-data
# Initialize (creates encryption keys)
gocryptfs -init ~/encrypted-data
# Enter and confirm passphrase
# IMPORTANT: Save the master key shown!
# Master key: 1a2b3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d
# Create mount point
mkdir -p ~/decrypted-data
# Mount encrypted filesystem
gocryptfs ~/encrypted-data ~/decrypted-data
# Enter passphrase
# Now files in ~/decrypted-data are automatically encrypted to ~/encrypted-data
# Test
echo "Secret data" > ~/decrypted-data/secret.txt
ls ~/encrypted-data/
# Shows: gocryptfs.conf gocryptfs.diriv encrypted_filename_abc123
# View encrypted
cat ~/encrypted-data/encrypted_filename_abc123
# Shows: binary garbage (encrypted)
# View decrypted
cat ~/decrypted-data/secret.txt
# Shows: Secret data
# Unmount
fusermount3 -u ~/decrypted-data
|
Sync Encrypted Data to Cloud:
| # Perfect workflow: encrypt locally, sync encrypted files to cloud
# 1. Create encrypted directory in cloud mount
mkdir -p ~/GoogleDrive/encrypted-vault
gocryptfs -init ~/GoogleDrive/encrypted-vault
# 2. Mount for use
mkdir -p ~/secure-files
gocryptfs ~/GoogleDrive/encrypted-vault ~/secure-files
# 3. Use normally
cp ~/Documents/*.pdf ~/secure-files/
# Files are automatically:
# - Encrypted by gocryptfs
# - Synced to Google Drive by rclone
# - Zero-knowledge (Google can't read them)
|
Advanced Options:
| # Mount read-only
gocryptfs -ro ~/encrypted-data ~/decrypted-data
# Reverse mode (encrypt existing files)
gocryptfs -reverse ~/plain-data ~/encrypted-view
# Disable filename encryption (faster, less secure)
gocryptfs -init -plaintextnames ~/encrypted-data
# Use custom cipher
gocryptfs -init -aessiv ~/encrypted-data
|
4. BindFS - Permission Remapping
Change ownership and permissions on the fly.
Installation:
| sudo apt install -y bindfs
|
Use Cases:
| # 1. Make read-only directory writable (for testing)
mkdir -p ~/writable-view
bindfs -o perms=0777 /media/readonly ~/writable-view
# 2. Change file ownership
# Useful for Docker volumes, Samba shares
bindfs -u $(id -u) -g $(id -g) /mnt/external ~/my-files
# 3. Force specific user/group
bindfs --force-user=www-data --force-group=www-data \
/home/pi/website /var/www/html
# 4. Mirror with different permissions
bindfs --create-for-user=$(id -u) --create-for-group=$(id -g) \
--create-with-perms=0644:u+D \
/source /destination
# 5. Hide specific files
bindfs --hide-pattern='*.tmp' --hide-pattern='.git' \
~/project ~/project-clean
|
5. NTFS-3G - Windows Filesystem Support
Read/write NTFS drives (USB, external HDDs).
| # Already installed in most cases
sudo apt install -y ntfs-3g
# Auto-mount NTFS drives
# Usually handled automatically by Raspberry Pi OS
# Manual mount
sudo mkdir -p /mnt/windows-drive
sudo ntfs-3g /dev/sda1 /mnt/windows-drive
# Mount with specific permissions
sudo ntfs-3g /dev/sda1 /mnt/windows-drive \
-o uid=$(id -u),gid=$(id -g),umask=022
# Read-only mount (safer)
sudo ntfs-3g /dev/sda1 /mnt/windows-drive -o ro
# Performance options
sudo ntfs-3g /dev/sda1 /mnt/windows-drive \
-o big_writes,compression
|
6. ArchiveMount - Browse Archives as Directories
Access ZIP/TAR files without extraction.
Installation:
| sudo apt install -y archivemount
|
Usage:
| # Mount ZIP file
mkdir -p ~/archive-view
archivemount ~/backup.zip ~/archive-view
# Browse
ls ~/archive-view
cd ~/archive-view/documents
cat ~/archive-view/readme.txt
# Unmount
fusermount3 -u ~/archive-view
# Works with TAR, TAR.GZ, TAR.BZ2, etc.
archivemount ~/data.tar.gz ~/archive-view
|
Building Custom FUSE Filesystem
Simple Python FUSE Example
Installation:
| # Install Python FUSE bindings
sudo apt install -y python3-pip
pip3 install fusepy
|
Hello World Filesystem:
| #!/usr/bin/env python3
# hello_fs.py - Simplest FUSE filesystem
from fuse import FUSE, FuseOSError, Operations
import errno
import stat
import time
class HelloFS(Operations):
def __init__(self):
self.files = {
'/': {
'st_mode': (stat.S_IFDIR | 0o755),
'st_nlink': 2,
},
'/hello.txt': {
'st_mode': (stat.S_IFREG | 0o644),
'st_nlink': 1,
'st_size': 13,
'content': b'Hello, FUSE!\n'
}
}
def getattr(self, path, fh=None):
if path not in self.files:
raise FuseOSError(errno.ENOENT)
st = self.files[path].copy()
st['st_ctime'] = st['st_mtime'] = st['st_atime'] = time.time()
return st
def readdir(self, path, fh):
return ['.', '..', 'hello.txt']
def read(self, path, size, offset, fh):
if path not in self.files:
raise FuseOSError(errno.ENOENT)
content = self.files[path].get('content', b'')
return content[offset:offset + size]
if __name__ == '__main__':
import sys
if len(sys.argv) != 2:
print(f"Usage: {sys.argv[0]} <mountpoint>")
sys.exit(1)
mountpoint = sys.argv[1]
FUSE(HelloFS(), mountpoint, foreground=True, allow_other=False)
|
Test:
| # Create mount point
mkdir -p ~/hello-mount
# Run filesystem
python3 hello_fs.py ~/hello-mount
# In another terminal:
ls ~/hello-mount
# Shows: hello.txt
cat ~/hello-mount/hello.txt
# Shows: Hello, FUSE!
# Unmount (Ctrl+C in first terminal, or:)
fusermount3 -u ~/hello-mount
|
Practical Example: JSON File as Directory
| #!/usr/bin/env python3
# json_fs.py - Mount JSON file as directory structure
from fuse import FUSE, FuseOSError, Operations
import json
import errno
import stat
import time
from pathlib import Path
class JSONFS(Operations):
def __init__(self, json_file):
self.json_file = json_file
with open(json_file, 'r') as f:
self.data = json.load(f)
self.start_time = time.time()
def _get_node(self, path):
"""Navigate JSON structure by path"""
if path == '/':
return self.data
parts = path.strip('/').split('/')
node = self.data
for part in parts:
if isinstance(node, dict) and part in node:
node = node[part]
else:
return None
return node
def getattr(self, path, fh=None):
node = self._get_node(path)
if node is None:
raise FuseOSError(errno.ENOENT)
# Directory for dict, file for primitive values
if isinstance(node, dict):
return {
'st_mode': (stat.S_IFDIR | 0o755),
'st_nlink': 2,
'st_ctime': self.start_time,
'st_mtime': self.start_time,
'st_atime': time.time(),
}
else:
content = str(node).encode()
return {
'st_mode': (stat.S_IFREG | 0o644),
'st_nlink': 1,
'st_size': len(content),
'st_ctime': self.start_time,
'st_mtime': self.start_time,
'st_atime': time.time(),
}
def readdir(self, path, fh):
node = self._get_node(path)
if not isinstance(node, dict):
raise FuseOSError(errno.ENOTDIR)
return ['.', '..'] + list(node.keys())
def read(self, path, size, offset, fh):
node = self._get_node(path)
if isinstance(node, dict):
raise FuseOSError(errno.EISDIR)
content = str(node).encode()
return content[offset:offset + size]
if __name__ == '__main__':
import sys
if len(sys.argv) != 3:
print(f"Usage: {sys.argv[0]} <json_file> <mountpoint>")
sys.exit(1)
FUSE(JSONFS(sys.argv[1]), sys.argv[2], foreground=True, allow_other=False)
|
Test:
| # Create test JSON
cat > config.json <<EOF
{
"server": {
"host": "192.168.1.100",
"port": 8080,
"ssl": true
},
"database": {
"name": "mydb",
"user": "admin"
}
}
EOF
# Mount
mkdir -p ~/config-view
python3 json_fs.py config.json ~/config-view &
# Browse as directory
ls ~/config-view
# Shows: server database
ls ~/config-view/server
# Shows: host port ssl
cat ~/config-view/server/host
# Shows: 192.168.1.100
cat ~/config-view/database/name
# Shows: mydb
|
Advanced Example: Temperature Sensor as Virtual File
| #!/usr/bin/env python3
# temp_fs.py - Raspberry Pi temperature as filesystem
from fuse import FUSE, FuseOSError, Operations
import errno
import stat
import time
class TempFS(Operations):
def __init__(self):
self.files = {
'/': {'type': 'dir'},
'/cpu_temp': {'type': 'file'},
'/gpu_temp': {'type': 'file'},
'/temp_celsius': {'type': 'file'},
'/temp_fahrenheit': {'type': 'file'},
}
def _get_cpu_temp(self):
"""Read CPU temperature"""
try:
with open('/sys/class/thermal/thermal_zone0/temp', 'r') as f:
temp = int(f.read()) / 1000.0
return temp
except:
return 0.0
def _get_gpu_temp(self):
"""Read GPU temperature using vcgencmd"""
try:
import subprocess
result = subprocess.run(
['vcgencmd', 'measure_temp'],
capture_output=True,
text=True
)
temp_str = result.stdout.strip()
temp = float(temp_str.replace("temp=", "").replace("'C", ""))
return temp
except:
return self._get_cpu_temp()
def getattr(self, path, fh=None):
if path not in self.files:
raise FuseOSError(errno.ENOENT)
file_info = self.files[path]
if file_info['type'] == 'dir':
return {
'st_mode': (stat.S_IFDIR | 0o755),
'st_nlink': 2,
'st_ctime': time.time(),
'st_mtime': time.time(),
'st_atime': time.time(),
}
else:
# File - calculate size dynamically
content = self._get_file_content(path)
return {
'st_mode': (stat.S_IFREG | 0o444), # Read-only
'st_nlink': 1,
'st_size': len(content),
'st_ctime': time.time(),
'st_mtime': time.time(),
'st_atime': time.time(),
}
def readdir(self, path, fh):
if path != '/':
raise FuseOSError(errno.ENOTDIR)
return ['.', '..', 'cpu_temp', 'gpu_temp', 'temp_celsius', 'temp_fahrenheit']
def _get_file_content(self, path):
"""Generate file content dynamically"""
if path == '/cpu_temp':
temp = self._get_cpu_temp()
return f"{temp:.1f}°C\n".encode()
elif path == '/gpu_temp':
temp = self._get_gpu_temp()
return f"{temp:.1f}°C\n".encode()
elif path == '/temp_celsius':
cpu = self._get_cpu_temp()
gpu = self._get_gpu_temp()
return f"CPU: {cpu:.1f}°C\nGPU: {gpu:.1f}°C\n".encode()
elif path == '/temp_fahrenheit':
cpu = self._get_cpu_temp() * 9/5 + 32
gpu = self._get_gpu_temp() * 9/5 + 32
return f"CPU: {cpu:.1f}°F\nGPU: {gpu:.1f}°F\n".encode()
return b''
def read(self, path, size, offset, fh):
content = self._get_file_content(path)
return content[offset:offset + size]
if __name__ == '__main__':
import sys
if len(sys.argv) != 2:
print(f"Usage: {sys.argv[0]} <mountpoint>")
sys.exit(1)
FUSE(TempFS(), sys.argv[1], foreground=True, allow_other=False)
|
Test:
| # Mount
mkdir -p ~/temp-fs
python3 temp_fs.py ~/temp-fs &
# Read temperature (always current!)
cat ~/temp-fs/cpu_temp
# Shows: 45.2°C
watch -n 1 cat ~/temp-fs/temp_celsius
# Live temperature monitoring!
# Use in scripts
TEMP=$(cat ~/temp-fs/cpu_temp | cut -d'°' -f1)
if (( $(echo "$TEMP > 70" | bc -l) )); then
echo "Warning: High temperature!"
fi
|
Systemd Integration
Auto-mount SSHFS on Boot
| # Create systemd service
sudo tee /etc/systemd/system/sshfs-remote.service <<'EOF'
[Unit]
Description=SSHFS mount to remote server
After=network-online.target
Wants=network-online.target
[Service]
Type=forking
User=pi
Group=pi
ExecStartPre=/bin/mkdir -p /home/pi/remote-server
ExecStart=/usr/bin/sshfs -o reconnect,ServerAliveInterval=15,allow_other \
username@server.com:/remote/path /home/pi/remote-server
ExecStop=/bin/fusermount3 -u /home/pi/remote-server
Restart=on-failure
RestartSec=10
[Install]
WantedBy=multi-user.target
EOF
# Enable and start
sudo systemctl enable sshfs-remote
sudo systemctl start sshfs-remote
# Check status
sudo systemctl status sshfs-remote
|
Auto-mount rclone Cloud Storage
| # Create service
sudo tee /etc/systemd/system/rclone-gdrive.service <<'EOF'
[Unit]
Description=rclone mount Google Drive
After=network-online.target
Wants=network-online.target
[Service]
Type=notify
User=pi
Group=pi
ExecStartPre=/bin/mkdir -p /home/pi/GoogleDrive
ExecStart=/usr/bin/rclone mount gdrive: /home/pi/GoogleDrive \
--vfs-cache-mode writes \
--vfs-cache-max-age 24h \
--buffer-size 256M \
--dir-cache-time 72h \
--log-file /home/pi/rclone.log \
--log-level INFO
ExecStop=/bin/fusermount3 -u /home/pi/GoogleDrive
Restart=on-failure
RestartSec=30
[Install]
WantedBy=multi-user.target
EOF
# Enable
sudo systemctl enable rclone-gdrive
sudo systemctl start rclone-gdrive
|
Auto-mount GocryptFS Encrypted Storage
| # Store passphrase securely
echo "your-passphrase" > ~/.gocryptfs-password
chmod 600 ~/.gocryptfs-password
# Create service
sudo tee /etc/systemd/system/gocryptfs-vault.service <<'EOF'
[Unit]
Description=GocryptFS encrypted vault
After=rclone-gdrive.service
Requires=rclone-gdrive.service
[Service]
Type=forking
User=pi
Group=pi
ExecStartPre=/bin/mkdir -p /home/pi/secure-files
ExecStart=/usr/bin/gocryptfs \
-passfile /home/pi/.gocryptfs-password \
/home/pi/GoogleDrive/encrypted-vault \
/home/pi/secure-files
ExecStop=/bin/fusermount3 -u /home/pi/secure-files
Restart=on-failure
[Install]
WantedBy=multi-user.target
EOF
# Enable
sudo systemctl enable gocryptfs-vault
sudo systemctl start gocryptfs-vault
|
| #!/bin/bash
# fuse-benchmark.sh - Compare FUSE performance
# Test locations
NATIVE_DIR="/tmp/native-test"
FUSE_DIR="$HOME/fuse-mount"
# Create test file (1GB)
dd if=/dev/zero of=/tmp/testfile bs=1M count=1024
echo "=== Sequential Write Test ==="
# Native
sync; echo 3 | sudo tee /proc/sys/vm/drop_caches > /dev/null
time dd if=/tmp/testfile of=$NATIVE_DIR/test bs=1M
sync
# FUSE
sync; echo 3 | sudo tee /proc/sys/vm/drop_caches > /dev/null
time dd if=/tmp/testfile of=$FUSE_DIR/test bs=1M
sync
echo "=== Sequential Read Test ==="
# Native
sync; echo 3 | sudo tee /proc/sys/vm/drop_caches > /dev/null
time dd if=$NATIVE_DIR/test of=/dev/null bs=1M
# FUSE
sync; echo 3 | sudo tee /proc/sys/vm/drop_caches > /dev/null
time dd if=$FUSE_DIR/test of=/dev/null bs=1M
echo "=== Random I/O Test ==="
# Using fio
fio --name=native-random --directory=$NATIVE_DIR \
--rw=randrw --bs=4k --size=100M --numjobs=1 \
--time_based --runtime=30 --group_reporting
fio --name=fuse-random --directory=$FUSE_DIR \
--rw=randrw --bs=4k --size=100M --numjobs=1 \
--time_based --runtime=30 --group_reporting
|
Optimization Strategies
1. Caching:
| # SSHFS with aggressive caching
sshfs user@server:/path /mount \
-o cache=yes \
-o kernel_cache \
-o cache_timeout=300 \
-o attr_timeout=300 \
-o entry_timeout=300
# rclone with VFS cache
rclone mount remote: /mount \
--vfs-cache-mode full \
--vfs-cache-max-size 20G \
--vfs-cache-max-age 72h \
--buffer-size 512M
|
2. Parallel Operations:
| # rclone parallel transfers
rclone mount remote: /mount \
--transfers 8 \
--checkers 16 \
--multi-thread-streams 4
|
3. Compression (for network filesystems):
| # SSHFS with compression
sshfs user@server:/path /mount \
-C \
-o compression=yes \
-o Ciphers=aes128-gcm@openssh.com
|
4. Large Buffer Sizes:
| # Increase read/write buffers
sshfs user@server:/path /mount \
-o max_read=131072 \
-o max_write=131072
# rclone buffer
rclone mount remote: /mount \
--buffer-size 1G
|
5. Async I/O:
| # Enable async reads (SSHFS)
sshfs user@server:/path /mount \
-o async_read
# Background writes
rclone mount remote: /mount \
--vfs-write-back 30s
|
Raspberry Pi-Specific Tuning
| # For Pi 4/5 with 4GB+ RAM:
rclone mount gdrive: ~/GoogleDrive \
--vfs-cache-mode full \
--vfs-cache-max-size 8G \
--buffer-size 512M \
--transfers 4 \
--use-mmap
# For Pi 3/Zero (limited RAM):
rclone mount gdrive: ~/GoogleDrive \
--vfs-cache-mode writes \
--buffer-size 32M \
--transfers 1 \
--low-level-retries 10
|
Monitoring and Debugging
Check Mount Status
| # List all FUSE mounts
mount | grep fuse
# Detailed mount info
findmnt --type fuse
# Check specific mount
df -h ~/GoogleDrive
|
Debug FUSE Operations
| # Enable debug output
sshfs user@server:/path /mount -o debug,sshfs_debug
# rclone verbose logging
rclone mount remote: /mount -vv --log-file rclone-debug.log
# Monitor FUSE kernel module
sudo dmesg | grep fuse
# System calls trace
strace -e trace=read,write,open cat ~/fuse-mount/file.txt
|
| # I/O statistics
iostat -x 1
# Per-process I/O
sudo iotop
# FUSE-specific stats
cat /sys/fs/fuse/connections/*/waiting
cat /sys/fs/fuse/connections/*/congestion_threshold
# Monitor rclone
rclone rc core/stats # If rclone started with --rc
|
Troubleshooting
Mount Point Already in Use
| # Error: Transport endpoint is not connected
# Force unmount
fusermount3 -uz /mount/point
# Or with root
sudo umount -l /mount/point
# Check for stale mounts
mount | grep /mount/point
# Kill FUSE process if needed
ps aux | grep fuse
kill <pid>
|
Permission Denied
| # Check user permissions
groups
# Should include 'fuse' group
# Re-add user to group
sudo usermod -a -G fuse $USER
# Log out and back in
# Check fuse.conf
cat /etc/fuse.conf
# Should have: user_allow_other
# Mount with allow_other
sshfs user@server:/path /mount -o allow_other
|
Connection Failures (SSHFS/rclone)
| # SSHFS reconnect
sshfs user@server:/path /mount \
-o reconnect \
-o ServerAliveInterval=15 \
-o ServerAliveCountMax=3 \
-o ConnectTimeout=10
# rclone retries
rclone mount remote: /mount \
--retries 10 \
--low-level-retries 20 \
--timeout 30s
|
High CPU Usage
| # Check which process
top -p $(pgrep -f fuse)
# Reduce caching for memory-limited systems
# Lower buffer sizes
# Disable async operations if unstable
|
| # Check network (for remote filesystems)
ping -c 10 server.com
iperf3 -c server.com
# Increase cache
# Enable compression
# Use parallel transfers
# Check disk I/O (for local FUSE)
sudo iotop
sudo hdparm -t /dev/sda1
|
Security Considerations
1. Encrypted Credentials
| # Use SSH key instead of password (SSHFS)
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519_server
ssh-copy-id -i ~/.ssh/id_ed25519_server.pub user@server
sshfs user@server:/path /mount \
-o IdentityFile=~/.ssh/id_ed25519_server
# Protect rclone config
chmod 600 ~/.config/rclone/rclone.conf
# Encrypt rclone config
rclone config password
|
2. Limit Access
| # Mount with specific user
sshfs user@server:/path /mount \
-o uid=$(id -u),gid=$(id -g)
# Prevent other users from accessing
sshfs user@server:/path /mount \
-o default_permissions \
-o umask=077
# Read-only mount
mount -o ro ...
|
3. Firewall Rules
| # Allow only specific IPs for SSHFS
sudo ufw allow from 192.168.1.0/24 to any port 22
# Limit connection rate
sudo ufw limit ssh
|
4. Audit Logging
| # Log SSHFS access
sshfs user@server:/path /mount \
-o LogLevel=VERBOSE \
-o SyslogFacility=AUTH
# Monitor auth logs
sudo tail -f /var/log/auth.log | grep sshfs
|
Real-World Use Cases
| #!/bin/bash
# media-center-setup.sh
# Mount Google Drive with media
rclone mount gdrive:Media ~/Media \
--vfs-cache-mode full \
--vfs-cache-max-size 20G \
--buffer-size 512M \
--dir-cache-time 24h \
--daemon
# Setup Plex/Jellyfin to use ~/Media
# Stream 4K video with local caching
|
2. Secure Cloud Backup
| #!/bin/bash
# secure-backup.sh
# 1. Encrypt data locally
gocryptfs ~/Important ~/encrypted-view
# 2. Sync encrypted to cloud
rclone sync ~/encrypted-view gdrive:Backup \
--progress \
--transfers 4
# 3. Unmount
fusermount3 -u ~/encrypted-view
# Zero-knowledge backup - cloud provider can't read files
|
3. Development Environment Sync
| #!/bin/bash
# dev-sync.sh
# Mount remote development server
sshfs dev@server:/home/dev/projects ~/remote-projects \
-C \
-o cache=yes,kernel_cache \
-o reconnect
# Develop locally, run remotely
cd ~/remote-projects/myapp
code . # Edit locally in VS Code
ssh dev@server 'cd projects/myapp && npm start' # Run remotely
|
4. IoT Data Logger
| #!/usr/bin/env python3
# sensor_fs.py - IoT sensors as filesystem
# Virtual filesystem exposing sensor data
# /sensors/temperature -> current temp
# /sensors/humidity -> current humidity
# /sensors/history/2024-11-23.csv -> historical data
# Perfect for:
# - Grafana data source
# - Monitoring scripts
# - Data analysis tools
|
Summary
This comprehensive guide covered FUSE filesystem implementation on Raspberry Pi:
✅ Core Concepts
- FUSE architecture and userspace filesystem design
- Advantages over kernel filesystems
- Performance trade-offs and optimization strategies
- SSHFS: Remote directory mounting over SSH
- rclone: Universal cloud storage (40+ providers)
- GocryptFS: Strong encryption for cloud sync
- BindFS: Permission and ownership remapping
- NTFS-3G: Windows filesystem support
- ArchiveMount: Browse ZIP/TAR without extraction
✅ Cloud Integration
- Google Drive, OneDrive, Dropbox mounting
- Amazon S3 and object storage
- Optimal caching strategies
- Bandwidth optimization
✅ Custom Development
- Python FUSE programming (fusepy)
- Real-world examples (JSON viewer, temperature monitor)
- Virtual filesystems for hardware abstraction
✅ Production Deployment
- Systemd auto-mount services
- Encrypted credential management
- Monitoring and debugging
- Performance benchmarking
✅ Security
- End-to-end encryption with GocryptFS
- SSH key authentication
- Access control and permissions
- Audit logging
- Raspberry Pi-specific optimizations
- Caching strategies (20-30% speed improvement)
- Parallel transfers and async I/O
- Memory-conscious configurations
Next Steps
Advanced Topics:
- FUSE in Docker - Container filesystem layers
- Network Protocols - WebDAV, FTP, SMB via FUSE
- Database as Filesystem - SQL queries as directory structure
- Version Control - Git commits as browsable directories
- Distributed Filesystems - GlusterFS, CephFS on Raspberry Pi cluster
Related Guides:
With FUSE, your Raspberry Pi can transparently access cloud storage, remote servers, and create custom filesystems tailored to your specific needs - all without kernel programming!