File System Layout
β Validated against Unraid 7.2.3 - Directory structures and paths verified on live systems.
Understanding where files are stored and why is crucial for Unraid plugin development. Unraid runs from RAM, which creates unique challenges and opportunities.
The RAM-Based Architecture
Unraid boots from a USB flash drive into RAM. This means:
- Changes to most files are lost on reboot
- The USB flash drive is the only persistent storage during boot
- Plugins must be reinstalled on every boot
flowchart TB
subgraph USB["USB Flash Drive /boot"]
subgraph Persistent["Persistent - survives reboot"]
P1["/boot/config/plugins/myplugin/"]
P2["myplugin.cfg (user settings)"]
P3["myplugin-package.txz (cached)"]
end
end
USB -->|"Installed on boot"| RAM
subgraph RAM["RAM Disk"]
subgraph Volatile["Volatile - rebuilt each boot"]
R1["/usr/local/emhttp/plugins/myplugin/"]
R2["myplugin.page (web UI)"]
R3["scripts/ (shell scripts)"]
R4["php/ (PHP code)"]
end
end
style USB fill:#4a9eff,color:#fff
style RAM fill:#ff9800,color:#fff
style Persistent fill:#4caf50,color:#fff
style Volatile fill:#f44336,color:#fff
π· Screenshot needed: File listing of /boot/config/plugins/ directory
Key Directories
/boot/config/plugins/
Location: USB Flash Drive
Persistence: β
Survives reboot
This is where plugin files are stored on the boot device:
/boot/config/plugins/
βββ myplugin.plg # The plugin installer file
βββ myplugin/ # Plugin's persistent storage
β βββ myplugin.cfg # User configuration
β βββ myplugin-package-1.0.txz # Cached package (optional)
β βββ data/ # Plugin data files
βββ [other-plugins...]
Use for:
- User configuration files
- Cached downloads (packages, icons)
- Small data files that must persist
- State files
Avoid:
- Large data files (limited USB space)
- Frequently written files (USB wear)
- Log files
π· Screenshot needed: File listing of /boot/config/plugins/ directory
/usr/local/emhttp/plugins/
Location: RAM Disk
Persistence: β Rebuilt on boot
This is where active plugin files live:
/usr/local/emhttp/plugins/myplugin/
βββ myplugin.page # Main UI page
βββ myplugin.settings.page # Settings page
βββ default.cfg # Default configuration
βββ README.md # Shown in Plugin Manager
βββ php/
β βββ exec.php # AJAX endpoint
β βββ helpers.php # Utility functions
βββ scripts/
β βββ start.sh # Service start script
β βββ status.sh # Status check
βββ event/
β βββ started # Array started handler
β βββ stopping_docker # Pre-Docker-stop handler
βββ javascript/
β βββ custom.js # Client-side scripts
βββ styles/
βββ custom.css # Plugin styles
Contains:
- Web UI pages (
.pagefiles) - PHP scripts
- Shell scripts
- Event handlers
- Static assets (JS, CSS, images)
- Default configuration
π· Screenshot needed: File listing of /usr/local/emhttp/plugins/ structure
/var/log/plugins/
Location: RAM Disk
Persistence: β Cleared on reboot
Contains symlinks indicating which plugins are installed:
/var/log/plugins/
βββ myplugin.plg -> /boot/config/plugins/myplugin.plg
βββ [other-plugins.plg...]
The plugin manager checks this directory to know whatβs installed.
/tmp/plugins/
Location: RAM Disk
Persistence: β Temporary
Used during plugin operations:
- Downloaded plugin files for updates
- Temporary extraction location
/boot/config/plugins-*/
Special directories on the USB flash:
| Directory | Purpose |
|---|---|
/boot/config/plugins/ |
Active plugins |
/boot/config/plugins-error/ |
Plugins that failed to install |
/boot/config/plugins-removed/ |
Uninstalled plugins |
/boot/config/plugins-stale/ |
Superseded plugin versions |
Data Storage Options
For Configuration
Store user settings on the USB flash:
/boot/config/plugins/myplugin/myplugin.cfg
Format:
SETTING_ONE="value"
SETTING_TWO="another value"
ENABLED="true"
Reading in PHP:
$cfg = parse_plugin_cfg('myplugin');
echo $cfg['SETTING_ONE'];
For Application Data
For larger data that needs to persist:
Option 1: User Share (Recommended)
/mnt/user/appdata/myplugin/
Option 2: Cache Drive
/mnt/cache/appdata/myplugin/
Option 3: Array Share
/mnt/user/myplugin-data/
For Logs
Use the system logger (writes to RAM, available in syslog):
logger "myplugin: Your log message"
logger -t myplugin "Tagged message"
Or write to a temporary file:
echo "Log message" >> /tmp/myplugin.log
For Runtime State
For PID files, state tracking:
# PID file
/var/run/myplugin.pid
# Lock files
/var/lock/myplugin.lock
# Temporary state
/tmp/myplugin/
File Permissions
Package Files
When building your package:
# Make scripts executable
chmod +x scripts/*.sh
chmod +x event/*
# Standard file permissions
chmod 644 *.page
chmod 644 *.cfg
chmod 644 php/*.php
# Make PHP exec scripts executable
chmod +x php/exec.php
Configuration Files
User config files on flash:
# Secure user config
chmod 600 /boot/config/plugins/myplugin/myplugin.cfg
Package Directory Structure
Your .txz package should extract to mirror the emhttp structure:
[package root]/
βββ usr/
βββ local/
βββ emhttp/
βββ plugins/
βββ myplugin/
βββ myplugin.page
βββ default.cfg
βββ [other files]
Additional files can go elsewhere:
[package root]/
βββ usr/
β βββ local/
β β βββ emhttp/
β β β βββ plugins/
β β β βββ myplugin/
β β βββ bin/
β β βββ mytool # CLI utility
β βββ lib/
β βββ docker/
β βββ cli-plugins/
β βββ docker-myplugin # Docker CLI plugin
βββ install/
βββ slack-desc # Package description
Best Practices
1. Minimize USB Writes
The USB flash has limited write cycles:
# Bad - writes on every call
echo "$value" > /boot/config/plugins/myplugin/counter.txt
# Good - write to RAM, sync occasionally
echo "$value" > /tmp/myplugin/counter.txt
# Only sync to flash on shutdown or periodically
2. Use Symlinks Wisely
Link from flash to RAM for frequently accessed data:
# During install script
if [ ! -L /boot/config/plugins/myplugin/logs ]; then
mkdir -p /tmp/myplugin/logs
ln -s /tmp/myplugin/logs /boot/config/plugins/myplugin/logs
fi
3. Handle Missing Directories
Files on flash may not exist on first install:
#!/bin/bash
# Create directories if needed
mkdir -p /boot/config/plugins/myplugin
# Source config with fallback
if [ -f /boot/config/plugins/myplugin/myplugin.cfg ]; then
source /boot/config/plugins/myplugin/myplugin.cfg
fi
4. Clean Up on Remove
In your remove script:
# Remove plugin files
rm -rf /boot/config/plugins/myplugin
# Remove runtime files
rm -rf /tmp/myplugin
rm -f /var/run/myplugin.pid
# Remove the package
removepkg myplugin-package
5. Document Data Locations
In your README, tell users where data is stored:
## Data Locations
- **Configuration**: `/boot/config/plugins/myplugin/myplugin.cfg`
- **Application Data**: `/mnt/user/appdata/myplugin/`
- **Logs**: Check syslog with `grep myplugin /var/log/syslog`
Troubleshooting
Files Missing After Reboot
Problem: Custom files in /usr/local/emhttp/plugins/ disappear after reboot.
Solution: Files must be in your .txz package or created by an install script.
Config Not Saving
Problem: Settings donβt persist.
Solution: Verify the form writes to /boot/config/plugins/yourplugin/:
<input type="hidden" name="#file" value="myplugin/myplugin.cfg">
Out of Space on Flash
Problem: USB flash drive is full.
Solution:
- Clean
/boot/config/plugins-removed/ - Clean
/boot/config/plugins-stale/ - Move large data to array shares
- Remove cached packages you donβt need
Next Steps
- Learn about PLG File Structure for installation
- See Packaging for creating
.txzpackages - Check Configuration Files for settings management

