How to install:
Copy the xml file templates on your Unraid templates directory: /config/plugins/dockerMan/templates-user Both containers have to be in the same docker network.
A RESTful API service for managing files and directories on Unraid servers. Built with FastAPI and designed to run in Docker, this API provides a clean interface for Flutter mobile apps (or any HTTP client) to remotely browse, upload, download, and manage files on your Unraid server.
✨ NEW: Web UI Available! A modern, production-ready web interface is now included for visual file management. See Web UI Setup below.
- 📁 File Browsing: Navigate directories and list files with sorting options
- 📤 File Upload: Upload files with size limits and validation
- 📥 File Download: Download files directly through the API
- 📂 Directory Operations: Create and delete directories (with recursive option)
- ✏️ File Operations: Move, copy, rename, and delete files
- 🔍 Search: Search for files and directories with wildcard support
- 💾 Disk Usage: Get disk space information for any path
- 🔒 Security: API key authentication and configurable permissions
- 🌐 CORS Enabled: Ready for web and mobile apps
- 🐳 Docker Ready: Easy deployment with Docker/Docker Compose
- 🎨 Material Design 3: Modern, polished interface with smooth animations
- 🌓 Dark/Light Mode: Toggle themes with persistent preferences
- 📱 Responsive Design: Works seamlessly on desktop, tablet, and mobile
- ⚡ Real-time Updates: Instant feedback for all file operations
- 🔄 Drag & Drop: Easy file uploads with progress tracking
- 🔍 Live Search: Filter files as you type
- ✅ Production Ready: Professional UI suitable for production use
- Docker and Docker Compose installed
- Unraid server with accessible file shares
- Proper permissions to access
/mnt/userdirectory
-
Clone this repository:
git clone <repository-url> cd file_core_api
-
Create your environment file:
cp .env.example .env
-
Edit
.envand configure your settings:BASE_PATH=/mnt/user API_KEY=your_secret_key_here MAX_UPLOAD_SIZE=10737418240
-
Start the services:
With Web UI (Recommended):
docker-compose --profile ui up -d
API Only:
docker-compose up -d
-
Access the interfaces:
- Web UI: http://localhost:8764 (if enabled)
- API Docs: http://localhost:8000/docs
- ReDoc: http://localhost:8000/redoc
GET /api/v1/files/browse?path=/mnt/user/documents&sort_by=name&sort_order=ascParameters:
path(required): Directory path to browseshow_hidden(optional): Show hidden files (true/false)sort_by(optional): Sort by field (name, size, modified, type)sort_order(optional): Sort order (asc, desc)
Response:
{
"path": "/mnt/user/documents",
"parent": "/mnt/user",
"items": [
{
"name": "document.pdf",
"path": "/mnt/user/documents/document.pdf",
"type": "file",
"size": 1048576,
"modified": "2024-01-15T10:30:00",
"permissions": "rw-r--r--",
"owner": "nobody",
"group": "users",
"is_hidden": false,
"extension": "pdf",
"mime_type": "application/pdf"
}
],
"total_items": 1,
"total_size": 1048576
}GET /api/v1/files/info?path=/mnt/user/documents/file.txtResponse: Returns detailed FileInfo object
GET /api/v1/files/download?path=/mnt/user/documents/file.txtReturns the file as an octet-stream for download.
POST /api/v1/files/upload
Content-Type: multipart/form-dataForm Data:
file: The file to uploaddestination_path: Directory where file should be saved
Response:
{
"success": true,
"file_path": "/mnt/user/uploads/document.pdf",
"file_name": "document.pdf",
"file_size": 1048576,
"message": "File uploaded successfully"
}POST /api/v1/files/directory
Content-Type: application/json
{
"path": "/mnt/user/documents",
"name": "new_folder",
"create_parents": true
}DELETE /api/v1/files/directory?path=/mnt/user/old_folder&recursive=trueParameters:
path(required): Directory path to deleterecursive(optional): Delete directory and all contents (default: false)
DELETE /api/v1/files/file?path=/mnt/user/documents/old_file.txtPOST /api/v1/files/move
Content-Type: application/json
{
"source": "/mnt/user/documents/file.txt",
"destination": "/mnt/user/backup/file.txt",
"overwrite": false
}POST /api/v1/files/copy
Content-Type: application/json
{
"source": "/mnt/user/documents/file.txt",
"destination": "/mnt/user/backup/file.txt",
"overwrite": false
}PUT /api/v1/files/rename
Content-Type: application/json
{
"path": "/mnt/user/documents/old_name.txt",
"new_name": "new_name.txt"
}GET /api/v1/files/search?path=/mnt/user&query=*.pdf&recursive=trueParameters:
path(required): Directory to search inquery(required): Search pattern (supports wildcards like*.pdf,document*)recursive(optional): Search in subdirectories (default: true)case_sensitive(optional): Case sensitive search (default: false)file_type(optional): Filter by type (file/directory)
GET /api/v1/files/disk-usage?path=/mnt/userResponse:
{
"path": "/mnt/user",
"total": 1099511627776,
"used": 549755813888,
"free": 549755813888,
"percent": 50.0
}| Variable | Description | Default |
|---|---|---|
PUID |
User ID for file permissions (linuxserver.io compatible) | 99 (nobody on Unraid) |
PGID |
Group ID for file permissions (linuxserver.io compatible) | 100 (users on Unraid) |
UMASK |
File creation mask | 022 |
DEBUG |
Enable debug mode | false |
CORS_ORIGINS |
Allowed CORS origins (JSON array) | ["http://localhost","http://localhost:8080","http://localhost:3000"] |
BASE_PATH |
Base path for file operations | /mnt/user |
MAX_UPLOAD_SIZE |
Maximum file upload size in bytes | 10737418240 (10GB) |
SHOW_HIDDEN_FILES |
Show hidden files by default | false |
ALLOWED_EXTENSIONS |
Allowed file extensions (JSON array, ["*"] for all) |
["*"] |
API_KEY |
API key for authentication (optional) | - |
ENABLE_FILE_DELETION |
Enable file deletion operations | true |
ENABLE_RECURSIVE_DELETE |
Enable recursive directory deletion | true |
ENABLE_WEB_UI |
Enable the web UI (documentation only, use docker-compose profiles) | true |
UNRAID_DATA_PATH |
Host path to mount (Docker only) | /mnt/user |
When using volumes, permissions issues can arise between the host OS and the container. To avoid this issue, you can specify the user PUID and group PGID.
Ensure any volume directories on the host are owned by the same user you specify:
# Find your user ID and group ID
id your_user
# Example output: uid=1000(your_user) gid=1000(your_group) ...On Unraid, the default values (PUID=99, PGID=100) correspond to the nobody user and users group, which is the standard configuration for Unraid shares.
To secure your API, set an API key in .env:
API_KEY=your_secret_key_hereThen include it in requests:
curl -H "X-API-Key: your_secret_key_here" \
http://localhost:8000/api/v1/files/browse?path=/mnt/userBrowse directory:
curl "http://localhost:8000/api/v1/files/browse?path=/mnt/user/documents"Upload file:
curl -X POST \
-F "file=@/path/to/local/file.pdf" \
-F "destination_path=/mnt/user/uploads" \
http://localhost:8000/api/v1/files/uploadDownload file:
curl -O "http://localhost:8000/api/v1/files/download?path=/mnt/user/file.txt"Search for PDF files:
curl "http://localhost:8000/api/v1/files/search?path=/mnt/user&query=*.pdf"import 'package:http/http.dart' as http;
import 'package:http_parser/http_parser.dart';
import 'dart:convert';
import 'dart:io';
class FileManagerService {
final String baseUrl = 'http://your-server-ip:8000';
final String? apiKey = 'your_api_key'; // Optional
Map<String, String> get headers => apiKey != null
? {'X-API-Key': apiKey!}
: {};
// Browse directory
Future<Map<String, dynamic>> browseDirectory(String path) async {
final response = await http.get(
Uri.parse('$baseUrl/api/v1/files/browse?path=$path'),
headers: headers,
);
if (response.statusCode == 200) {
return json.decode(response.body);
} else {
throw Exception('Failed to browse directory');
}
}
// Upload file
Future<Map<String, dynamic>> uploadFile(
File file,
String destinationPath
) async {
var request = http.MultipartRequest(
'POST',
Uri.parse('$baseUrl/api/v1/files/upload'),
);
if (apiKey != null) {
request.headers['X-API-Key'] = apiKey!;
}
request.files.add(
await http.MultipartFile.fromPath(
'file',
file.path,
contentType: MediaType('application', 'octet-stream'),
),
);
request.fields['destination_path'] = destinationPath;
final response = await request.send();
final responseData = await response.stream.bytesToString();
if (response.statusCode == 200) {
return json.decode(responseData);
} else {
throw Exception('Failed to upload file');
}
}
// Download file
Future<void> downloadFile(String path, String savePath) async {
final response = await http.get(
Uri.parse('$baseUrl/api/v1/files/download?path=$path'),
headers: headers,
);
if (response.statusCode == 200) {
await File(savePath).writeAsBytes(response.bodyBytes);
} else {
throw Exception('Failed to download file');
}
}
// Delete file
Future<Map<String, dynamic>> deleteFile(String path) async {
final response = await http.delete(
Uri.parse('$baseUrl/api/v1/files/file?path=$path'),
headers: headers,
);
if (response.statusCode == 200) {
return json.decode(response.body);
} else {
throw Exception('Failed to delete file');
}
}
// Rename file
Future<Map<String, dynamic>> renameFile(
String path,
String newName
) async {
final response = await http.put(
Uri.parse('$baseUrl/api/v1/files/rename'),
headers: {...headers, 'Content-Type': 'application/json'},
body: json.encode({
'path': path,
'new_name': newName,
}),
);
if (response.statusCode == 200) {
return json.decode(response.body);
} else {
throw Exception('Failed to rename file');
}
}
// Search files
Future<Map<String, dynamic>> searchFiles(
String path,
String query
) async {
final response = await http.get(
Uri.parse(
'$baseUrl/api/v1/files/search?path=$path&query=$query&recursive=true'
),
headers: headers,
);
if (response.statusCode == 200) {
return json.decode(response.body);
} else {
throw Exception('Failed to search files');
}
}
}The File Manager Web UI provides a modern, visual interface for managing your files. It features:
- Material Design 3 styling with smooth animations
- Dark and light mode with persistent theme
- Drag-and-drop file uploads
- Real-time search and filtering
- Breadcrumb navigation
- File type icons
- Responsive design for all devices
Start with Web UI:
docker-compose --profile ui up -dAccess the UI: Open http://localhost:8764 in your browser
For detailed setup instructions, see FRONTEND_SETUP.md
The Web UI provides:
- Clean file browser with breadcrumb navigation
- File operations via context menus
- Upload dialog with progress tracking
- Dark/light mode toggle
- Real-time file search
The Web UI is controlled via Docker Compose profiles:
Enable UI:
docker-compose --profile ui up -dDisable UI (API only):
docker-compose up -dFor more information, see:
- Frontend README - Detailed UI documentation
- Frontend Setup Guide - Installation and configuration
With Web UI:
# Start both API and UI
docker-compose --profile ui up -d
# View logs
docker-compose --profile ui logs -f
# Stop services
docker-compose --profile ui downAPI Only:
# Start API only (no UI)
docker-compose up -d
# View logs
docker-compose logs -f
# Stop the service
docker-compose downdocker run -d \
--name file-manager-api \
-p 8000:8000 \
-v /mnt/user:/mnt/user \
-e BASE_PATH=/mnt/user \
-e API_KEY=your_secret_key \
file-manager-apiFor detailed Unraid setup instructions, including templates and troubleshooting, see:
This guide covers:
- Docker Compose deployment (recommended)
- Using Unraid Docker templates
- Fixing common issues (UI restart loops, connectivity problems)
- Network configuration for API-UI communication
Quick Unraid Setup:
# Clone and deploy with Docker Compose
cd /mnt/user/appdata
git clone https://github.com/jandrop/file_core_api.git
cd file_core_api
cp .env.example .env
nano .env # Configure your settings
docker-compose --profile ui up -dAccess at: http://your-unraid-ip:8764
-
Create a virtual environment:
python -m venv venv source venv/bin/activate # On Windows: venv\Scripts\activate
-
Install dependencies:
pip install -r requirements.txt
-
Create
.envfile with your settings -
Run the application:
python main.py
The API will be available at http://localhost:8000
docker build -t file-manager-api .- Use API Key Authentication: Always set an API_KEY in production
- Configure CORS: Limit CORS_ORIGINS to only your trusted applications
- File Permissions: Ensure proper file system permissions are set
- Disable Dangerous Operations: Set
ENABLE_FILE_DELETION=falseif needed - Reverse Proxy: Run behind a reverse proxy with HTTPS in production
- Network Isolation: Use Docker networks to isolate the container
- Monitor Access: Check logs regularly for suspicious activity
- Path Traversal Protection: The API includes built-in protection against directory traversal attacks
- File Size Limits: Configure MAX_UPLOAD_SIZE to prevent abuse
If you get permission errors when accessing files:
-
Check that the Docker container user has proper permissions:
# On Unraid, you may need to match UID/GID # Edit Dockerfile and change: useradd -m -u YOUR_UID appuser
-
Ensure volumes are mounted correctly in docker-compose.yml
- Verify BASE_PATH is set correctly
- Check that UNRAID_DATA_PATH points to the correct host directory
- Ensure the directory exists and is accessible
- Check MAX_UPLOAD_SIZE setting
- Verify destination directory exists
- Check disk space with
/api/v1/files/disk-usage
Once running, interactive API documentation is available at:
- Swagger UI: http://localhost:8000/docs