A beautiful, secure file manager application with authentication for managing and sharing files through a web interface. Perfect for personal use, small teams, or as a simple CDN for your website assets.
- Overview
- Key Features
- Prerequisites
- Quick Start
- Configuration
- User Guide
- API Documentation
- Production Deployment
- Troubleshooting
- Security
- License
Simple File Manager is a web-based application that allows you to upload, organize, and manage files through an intuitive interface. Once uploaded, files are instantly accessible via public URLs, making it perfect for serving website assets, sharing documents, or managing media files.
Access Pattern:
- Admin Panel:
http://yourdomain.com/admin(password protected) - API Documentation:
http://yourdomain.com/api-docs(accessible after login) - Public Files:
http://yourdomain.com/path/to/file.jpg(no authentication required) - REST API:
http://yourdomain.com/api/*(authentication required)
- Multi-User System - Support for multiple users with different roles (admin/user)
- Password Management - Users can change their passwords securely
- API Token Authentication - Generate personal API tokens for programmatic access
- Encrypted Passwords - All passwords are hashed using bcrypt
- Session-based Authentication - Secure cookie-based sessions
- Flexible API Authentication - Use Bearer tokens or URL parameters
- Role-Based Access Control - Admin-only endpoints for user management
- Secure file path validation - Protection against directory traversal attacks
- Upload Files - Single or multiple files (up to 500 files)
- Upload Folders - Complete folder structures with nested directories
- Create Folders - Organize files in hierarchical structure
- Delete - Remove files and folders
- Rename - Rename files and folders
- Download - Download files directly
- Bulk Delete - Select and delete multiple items at once
- Clean, professional design
- Mobile-responsive interface
- Real-time search functionality
- File type icons and image thumbnails
- Breadcrumb navigation
- Drag & drop file upload
- Storage statistics (size, file count, folder count)
- All uploaded files are publicly accessible via clean URLs
- No authentication required for viewing files
- Perfect for CDN usage or sharing media
- View total storage used
- Track file and folder counts
- Real-time statistics updates
- Full API access to all file operations
- Dual Authentication - Session-based or API token-based
- User Management API - Create, delete users, manage passwords (admin only)
- API Token Management - Generate and revoke personal API tokens
- List, upload, download, delete files and folders via API
- Integration with scripts and applications (Python, Node.js, Bash, cURL)
- Perfect for automation and CI/CD pipelines
- Multi-User Support - Admin can create and manage multiple users
- Auto-Generated Passwords - Secure random passwords for new users
- Role Management - Assign admin or user roles
- User Dashboard - Each user can manage their own settings
- Password Change - Users can update their passwords anytime
- API Token per User - Each user can generate their own API token
- Self-Service - Users manage their own API tokens and passwords
Before you begin, ensure you have:
- Node.js v14.0 or higher (Download here)
- npm (comes with Node.js)
- Basic command line knowledge
Check your Node.js version:
node --version
npm --versionFollow these steps to get up and running in minutes:
npm installNote: A comprehensive .env.example file is included with detailed configuration options.
Copy the example environment file:
cp .env.example .envEdit .env with your preferred settings. The .env.example file contains detailed documentation for all options:
# Server Configuration
PORT=3000
# Upload Directory - Choose ONE option:
# Option 1: Relative path (default - secure)
UPLOAD_DIR=uploads
# Option 2: Absolute path (requires ALLOW_EXTERNAL_UPLOAD_FOLDER=true)
# UPLOAD_DIR=/var/www/filemanager-uploads
# Option 3: User home directory (requires ALLOW_EXTERNAL_UPLOAD_FOLDER=true)
# UPLOAD_DIR=~/filemanager-uploads
# Security: Allow external paths (required for Options 2 & 3)
ALLOW_EXTERNAL_UPLOAD_FOLDER=false
# Set to 'true' to allow paths outside the application directory
# Authentication
ADMIN_USERNAME=admin
ADMIN_PASSWORD=your_secure_password
# Session Secret (generate with: openssl rand -base64 32)
SESSION_SECRET=your-random-secret-key-here- Change the default password before using in production!
- The
UPLOAD_DIRsetting allows you to store files outside the application directory - See
.env.examplefor detailed configuration options and examples
Optional: Use Setup Script
./setup-upload-dir.shThis interactive script helps you configure and test the upload directory.
npm startOr for development with auto-reload:
npm run devOpen your browser and navigate to:
http://localhost:3000/admin
Login with the credentials you set in .env file.
🎉 That's it! You're ready to start uploading files.
All configuration is done through the .env file:
| Variable | Description | Default | Required |
|---|---|---|---|
ADMIN_USERNAME |
Admin login username | admin |
Yes |
ADMIN_PASSWORD |
Admin login password | admin123 |
Yes |
PORT |
Server port number | 3000 |
No |
SESSION_SECRET |
Secret key for sessions | Auto-generated | Yes |
UPLOAD_DIR |
Directory for file storage (relative, absolute, or ~/home) | uploads |
No |
ALLOW_EXTERNAL_UPLOAD_FOLDER |
Allow upload dir outside app folder (security) | false |
No |
Generate a Strong Session Secret:
openssl rand -base64 32Copy the output and set it as SESSION_SECRET in your .env file.
Password Requirements:
- Use a unique password
- Minimum 12 characters recommended
- Mix of letters, numbers, and special characters
Change Upload Directory:
The UPLOAD_DIR environment variable supports three path formats:
# Option 1: Relative path (Default - Secure)
UPLOAD_DIR=uploads
ALLOW_EXTERNAL_UPLOAD_FOLDER=false
# Option 2: Absolute path (Requires explicit permission)
UPLOAD_DIR=/var/www/filemanager-uploads
ALLOW_EXTERNAL_UPLOAD_FOLDER=true
# Option 3: User home directory (Requires explicit permission)
UPLOAD_DIR=~/filemanager-uploads
ALLOW_EXTERNAL_UPLOAD_FOLDER=true🔒 Security Feature:
For security reasons, paths outside the application directory require explicit permission via ALLOW_EXTERNAL_UPLOAD_FOLDER=true. This prevents accidental or malicious configuration of external paths.
Examples:
# Secure default (inside application)
UPLOAD_DIR=uploads
# No ALLOW_EXTERNAL_UPLOAD_FOLDER needed
# Store files in user's home directory (requires permission)
UPLOAD_DIR=~/Documents/uploads
ALLOW_EXTERNAL_UPLOAD_FOLDER=true
# Store files in a separate partition (requires permission)
UPLOAD_DIR=/mnt/storage/uploads
ALLOW_EXTERNAL_UPLOAD_FOLDER=true
# Store files in /opt directory (requires permission)
UPLOAD_DIR=/opt/filemanager/uploads
ALLOW_EXTERNAL_UPLOAD_FOLDER=trueImportant Notes:
- Security Default: External access is disabled by default (
ALLOW_EXTERNAL_UPLOAD_FOLDER=false) - The directory will be created automatically if it doesn't exist
- Ensure the Node.js process has read/write permissions for the directory
- For absolute paths in production, make sure to set proper permissions:
sudo mkdir -p /var/www/filemanager-uploads sudo chown -R $USER:$USER /var/www/filemanager-uploads sudo chmod 755 /var/www/filemanager-uploads
- The server will refuse to start if you try to use an external path without setting
ALLOW_EXTERNAL_UPLOAD_FOLDER=true
File Upload Limits:
- Maximum file size: 100MB per file
- Maximum files per upload: 500 files
- No restrictions on total storage (depends on your disk space)
If port 3000 is already in use, change it:
PORT=8080- Navigate to
http://localhost:3000/admin - Enter your username and password from
.envfile - Click "Sign In"
- Session lasts 24 hours
- Click "📤 Upload Files" button
- Click the upload area or drag & drop files
- Select one or more files (up to 500)
- Click "Upload"
- Files appear in current folder
- Click "📁 Upload Folder" button
- Click the upload area
- Select a folder (complete structure will be preserved)
- Review the folder name and file count
- Click "Upload"
- Folder structure is recreated automatically
Example:
Upload: my-website/
├── css/style.css
├── js/app.js
└── images/logo.png
Result: http://yourdomain.com/my-website/css/style.css
http://yourdomain.com/my-website/js/app.js
http://yourdomain.com/my-website/images/logo.png
- Click "➕ New Folder" button
- Enter folder name
- Click "Create"
- Folder appears in current location
- Click on any folder name to open it
- Use breadcrumb navigation at the top to go back
- Click "🏠 Home" to return to root directory
- Type in the search box (top right)
- Results appear in real-time (minimum 2 characters)
- Search works across all folders
- Click the ✏️ Edit icon next to the item
- Enter new name
- Click "Rename"
- Click the ⬇️ Download icon next to any file
- File downloads to your browser's download folder
- Click the 🗑️ Delete icon next to the item
- Confirm deletion
- Item is permanently removed
- Check the boxes next to items you want to delete
- Click "Delete Selected (X)" button
- Confirm bulk deletion
- All selected items are removed
- Click "👥 Users" button (visible only to admins)
- Enter username (letters, numbers, hyphens, underscores only)
- Select role (User or Admin)
- Click "Create User"
- Save the generated password - it will only be shown once!
- Open "👥 Users" management panel
- Find the user in the list
- Click "Delete" button
- Confirm deletion
- Note: You cannot delete your own account
- Click "⚙️ Settings" button
- Enter your current password
- Enter new password (minimum 8 characters)
- Confirm new password
- Click "Change Password"
- Click "⚙️ Settings" button
- Scroll to API Token section
- To generate: Click "🔑 Generate New Token", enter password
- Save your API token securely - treat it like a password!
- To delete: Click "🗑️ Delete Token", confirm with password
API Token Usage:
# Method 1: Bearer Token (Recommended)
curl -H "Authorization: Bearer YOUR_TOKEN" http://yourdomain.com/api/files
# Method 2: URL Parameter
curl "http://yourdomain.com/api/files?apiKey=YOUR_TOKEN"Click the "📖 API Docs" button in the header to access complete API documentation in a separate page. The API docs page includes:
- Complete endpoint reference
- Authentication methods (Session & API Token)
- Request/response examples
- Code examples (Bash, Python, Node.js)
- Error handling guide
- Best practices
Direct Access: http://localhost:3000/api-docs
Once uploaded, any file can be accessed via its URL without authentication:
http://yourdomain.com/folder/subfolder/filename.ext
Examples:
- Product images:
http://yourdomain.com/products/tshirt.jpg - Documents:
http://yourdomain.com/documents/report.pdf - Website assets:
http://yourdomain.com/assets/css/style.css
This makes the file manager perfect for:
- Website CDN (images, CSS, JavaScript)
- Sharing files with clients
- Media hosting
- Document libraries
The File Manager provides a RESTful API for programmatic access to all file operations. This allows you to integrate the file manager into your applications, scripts, or automation workflows.
All API endpoints (except public file access) require authentication. The API supports two authentication methods:
Use this method for web-based interactions or when you need temporary access.
curl -c cookies.txt -X POST http://localhost:3000/api/login \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"admin123"}'Response:
{
"success": true,
"message": "Login successful"
}The session cookie is saved in cookies.txt and must be included in all subsequent requests.
Include the cookie in all API requests using -b cookies.txt flag.
Use this method for scripts, automation, CI/CD pipelines, or long-running processes.
Via Web Interface:
- Login to the admin panel
- Click "⚙️ Settings"
- Scroll to API Token section
- Click "🔑 Generate New Token"
- Enter your password
- Save the token securely!
Via API:
# First login to get session
curl -c cookies.txt -X POST http://localhost:3000/api/login \
-H "Content-Type: application/json" \
-d '{"username":"your_username","password":"your_password"}'
# Then generate API token
curl -b cookies.txt -X POST http://localhost:3000/api/user/generate-token \
-H "Content-Type: application/json" \
-d '{"password":"your_password"}'Response:
{
"success": true,
"message": "API token generated successfully",
"apiKey": "yknngagbkwqyga86qxeus5qd"
}You can use the API token in two ways:
Option A: Bearer Token (Recommended)
curl -H "Authorization: Bearer YOUR_API_TOKEN" \
http://localhost:3000/api/filesOption B: URL Parameter
curl "http://localhost:3000/api/files?apiKey=YOUR_API_TOKEN"Advantages of API Tokens:
- ✅ No need to handle sessions or cookies
- ✅ Perfect for automation scripts
- ✅ No expiration (until manually deleted)
- ✅ Can be revoked anytime without changing password
- ✅ Each user has their own token
- ✅ Works across all API endpoints
Security Best Practices:
- Never commit API tokens to version control
- Store tokens in environment variables
- Regenerate tokens if compromised
- Use separate tokens for different applications
- Delete unused tokens
POST /api/login
Content-Type: application/json
{
"username": "admin",
"password": "your_password"
}Response:
{
"success": true,
"message": "Login successful"
}POST /api/logout
Cookie: filemanager.sid=xxxResponse:
{
"success": true,
"message": "Logged out successfully"
}GET /api/auth/status
Cookie: filemanager.sid=xxxResponse:
{
"authenticated": true,
"username": "admin"
}GET /api/user/me
Cookie: filemanager.sid=xxx
OR
Authorization: Bearer YOUR_API_TOKENResponse:
{
"success": true,
"user": {
"username": "john",
"role": "user",
"hasApiKey": true,
"apiKey": "yknngagbkwqyga86qxeus5qd",
"createdAt": "2025-01-15T10:00:00.000Z",
"passwordChangedAt": "2025-01-20T15:30:00.000Z",
"apiKeyGeneratedAt": "2025-01-22T09:00:00.000Z"
}
}POST /api/user/change-password
Cookie: filemanager.sid=xxx
OR
Authorization: Bearer YOUR_API_TOKEN
Content-Type: application/json
{
"oldPassword": "current_password",
"newPassword": "new_password_min_8_chars"
}Response:
{
"success": true,
"message": "Password changed successfully"
}POST /api/user/generate-token
Cookie: filemanager.sid=xxx
Content-Type: application/json
{
"password": "your_password"
}Response:
{
"success": true,
"message": "API token generated successfully",
"apiKey": "yknngagbkwqyga86qxeus5qd"
}Important: Save this API token securely. Treat it like a password!
DELETE /api/user/delete-token
Cookie: filemanager.sid=xxx
Content-Type: application/json
{
"password": "your_password"
}Response:
{
"success": true,
"message": "API token deleted successfully"
}These endpoints require admin role.
GET /api/admin/users
Cookie: filemanager.sid=xxx (admin session required)
OR
Authorization: Bearer ADMIN_API_TOKENResponse:
{
"success": true,
"users": [
{
"username": "admin",
"role": "admin",
"hasApiKey": true,
"createdAt": "2025-01-01T00:00:00.000Z",
"passwordChangedAt": "2025-01-10T12:00:00.000Z"
},
{
"username": "john",
"role": "user",
"hasApiKey": false,
"createdAt": "2025-01-15T10:00:00.000Z"
}
]
}POST /api/admin/users
Cookie: filemanager.sid=xxx (admin session required)
OR
Authorization: Bearer ADMIN_API_TOKEN
Content-Type: application/json
{
"username": "newuser",
"role": "user"
}Response:
{
"success": true,
"message": "User created successfully",
"user": {
"username": "newuser",
"password": "randomly_generated_password_123",
"role": "user"
}
}Important: The password is only shown once. Save it securely!
DELETE /api/admin/users/{username}
Cookie: filemanager.sid=xxx (admin session required)
OR
Authorization: Bearer ADMIN_API_TOKENExample:
curl -b cookies.txt -X DELETE http://localhost:3000/api/admin/users/olduser
# Or with API token
curl -H "Authorization: Bearer YOUR_ADMIN_TOKEN" \
-X DELETE http://localhost:3000/api/admin/users/olduserResponse:
{
"success": true,
"message": "User deleted successfully"
}Note: Admins cannot delete their own account.
GET /api/files?path={folder_path}
Cookie: filemanager.sid=xxxParameters:
path(optional) - Folder path to list. Empty for root directory.
Example:
# List root directory
curl -b cookies.txt "http://localhost:3000/api/files"
# List specific folder
curl -b cookies.txt "http://localhost:3000/api/files?path=products/images"Response:
{
"currentPath": "products",
"items": [
{
"name": "tshirt.jpg",
"path": "products/tshirt.jpg",
"isDirectory": false,
"size": 245678,
"modified": "2024-10-09T10:30:00.000Z",
"created": "2024-10-08T14:20:00.000Z"
},
{
"name": "images",
"path": "products/images",
"isDirectory": true,
"size": 0,
"modified": "2024-10-09T09:15:00.000Z",
"created": "2024-10-08T14:20:00.000Z"
}
]
}POST /api/upload
Cookie: filemanager.sid=xxx
Content-Type: multipart/form-data
basePath: products
files: [file1, file2, ...]Example - Upload single file:
curl -b cookies.txt -X POST http://localhost:3000/api/upload \
-F "basePath=products" \
-F "files=@/path/to/image.jpg"Example - Upload multiple files:
curl -b cookies.txt -X POST http://localhost:3000/api/upload \
-F "basePath=products" \
-F "files=@/path/to/image1.jpg" \
-F "files=@/path/to/image2.jpg" \
-F "files=@/path/to/image3.jpg"Example - Upload to root:
curl -b cookies.txt -X POST http://localhost:3000/api/upload \
-F "basePath=" \
-F "files=@/path/to/file.pdf"Response:
{
"success": true,
"message": "3 file(s) uploaded successfully",
"files": [
{
"name": "image1.jpg",
"size": 245678,
"path": "products/image1.jpg"
},
{
"name": "image2.jpg",
"size": 189234,
"path": "products/image2.jpg"
}
]
}POST /api/folder
Cookie: filemanager.sid=xxx
Content-Type: application/json
{
"path": "products",
"name": "new-folder"
}Example:
# Create folder in root
curl -b cookies.txt -X POST http://localhost:3000/api/folder \
-H "Content-Type: application/json" \
-d '{"path":"","name":"documents"}'
# Create nested folder
curl -b cookies.txt -X POST http://localhost:3000/api/folder \
-H "Content-Type: application/json" \
-d '{"path":"products","name":"images"}'Response:
{
"success": true,
"message": "Folder created successfully"
}DELETE /api/delete
Cookie: filemanager.sid=xxx
Content-Type: application/json
{
"path": "products/image.jpg"
}Example - Delete file:
curl -b cookies.txt -X DELETE http://localhost:3000/api/delete \
-H "Content-Type: application/json" \
-d '{"path":"products/old-image.jpg"}'Example - Delete folder (recursive):
curl -b cookies.txt -X DELETE http://localhost:3000/api/delete \
-H "Content-Type: application/json" \
-d '{"path":"products/old-folder"}'Response:
{
"success": true,
"message": "Deleted successfully"
}POST /api/rename
Cookie: filemanager.sid=xxx
Content-Type: application/json
{
"path": "products/old-name.jpg",
"newName": "new-name.jpg"
}Example:
curl -b cookies.txt -X POST http://localhost:3000/api/rename \
-H "Content-Type: application/json" \
-d '{"path":"products/photo.jpg","newName":"tshirt.jpg"}'Response:
{
"success": true,
"message": "Renamed successfully"
}GET /api/download?path={file_path}
Cookie: filemanager.sid=xxxExample:
curl -b cookies.txt "http://localhost:3000/api/download?path=products/image.jpg" \
-o downloaded-image.jpgResponse: Binary file data
GET /api/search?q={query}
Cookie: filemanager.sid=xxxExample:
curl -b cookies.txt "http://localhost:3000/api/search?q=tshirt"Response:
{
"results": [
{
"name": "tshirt.jpg",
"path": "products/tshirt.jpg",
"isDirectory": false,
"size": 245678,
"modified": "2024-10-09T10:30:00.000Z"
},
{
"name": "tshirt-blue.jpg",
"path": "products/images/tshirt-blue.jpg",
"isDirectory": false,
"size": 198234,
"modified": "2024-10-09T11:45:00.000Z"
}
]
}GET /api/storage
Cookie: filemanager.sid=xxxExample:
curl -b cookies.txt "http://localhost:3000/api/storage"Response:
{
"totalSize": 15728640,
"fileCount": 42,
"folderCount": 8
}#!/bin/bash
# Step 1: Login
curl -c cookies.txt -X POST http://localhost:3000/api/login \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"admin123"}'
# Step 2: Create products folder
curl -b cookies.txt -X POST http://localhost:3000/api/folder \
-H "Content-Type: application/json" \
-d '{"path":"","name":"products"}'
# Step 3: Upload images
curl -b cookies.txt -X POST http://localhost:3000/api/upload \
-F "basePath=products" \
-F "files=@./tshirt-red.jpg" \
-F "files=@./tshirt-blue.jpg" \
-F "files=@./tshirt-green.jpg"
# Step 4: Verify upload
curl -b cookies.txt "http://localhost:3000/api/files?path=products"
echo "Files are now accessible at:"
echo "http://localhost:3000/products/tshirt-red.jpg"
echo "http://localhost:3000/products/tshirt-blue.jpg"
echo "http://localhost:3000/products/tshirt-green.jpg"#!/bin/bash
# Login
curl -c cookies.txt -X POST http://localhost:3000/api/login \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"admin123"}'
# Get list of all files
FILES=$(curl -s -b cookies.txt "http://localhost:3000/api/files" | jq -r '.items[] | select(.isDirectory==false) | .path')
# Download each file
mkdir -p backup
for file in $FILES; do
echo "Downloading: $file"
curl -b cookies.txt "http://localhost:3000/api/download?path=$file" \
-o "backup/$file" --create-dirs
done
echo "Backup complete!"#!/bin/bash
UPLOAD_DIR="./my-images"
TARGET_FOLDER="gallery"
# Login
curl -c cookies.txt -X POST http://localhost:3000/api/login \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"admin123"}'
# Create target folder
curl -b cookies.txt -X POST http://localhost:3000/api/folder \
-H "Content-Type: application/json" \
-d "{\"path\":\"\",\"name\":\"$TARGET_FOLDER\"}"
# Upload all files from directory
for file in "$UPLOAD_DIR"/*; do
if [ -f "$file" ]; then
echo "Uploading: $(basename "$file")"
curl -b cookies.txt -X POST http://localhost:3000/api/upload \
-F "basePath=$TARGET_FOLDER" \
-F "files=@$file"
fi
done
echo "Upload complete!"import requests
import json
# Configuration
BASE_URL = "http://localhost:3000"
USERNAME = "admin"
PASSWORD = "admin123"
# Create session
session = requests.Session()
# Login
response = session.post(
f"{BASE_URL}/api/login",
json={"username": USERNAME, "password": PASSWORD}
)
if response.json()["success"]:
print("✓ Logged in successfully")
# List files
files = session.get(f"{BASE_URL}/api/files").json()
print(f"\nFound {len(files['items'])} items:")
for item in files['items']:
icon = "📁" if item['isDirectory'] else "📄"
size = f"{item['size']} bytes" if not item['isDirectory'] else ""
print(f" {icon} {item['name']} {size}")
# Upload file
with open('example.txt', 'rb') as f:
files_data = {'files': f}
data = {'basePath': ''}
response = session.post(
f"{BASE_URL}/api/upload",
files=files_data,
data=data
)
print(f"\n✓ Upload: {response.json()['message']}")
# Get storage info
storage = session.get(f"{BASE_URL}/api/storage").json()
print(f"\nStorage: {storage['totalSize']} bytes")
print(f"Files: {storage['fileCount']}")
print(f"Folders: {storage['folderCount']}")
# Logout
session.post(f"{BASE_URL}/api/logout")
print("\n✓ Logged out")
else:
print("✗ Login failed")const axios = require('axios');
const FormData = require('form-data');
const fs = require('fs');
const BASE_URL = 'http://localhost:3000';
const USERNAME = 'admin';
const PASSWORD = 'admin123';
// Create axios instance with cookie jar
const api = axios.create({
baseURL: BASE_URL,
withCredentials: true,
});
async function main() {
try {
// Login
const loginResponse = await api.post('/api/login', {
username: USERNAME,
password: PASSWORD,
});
console.log('✓ Logged in:', loginResponse.data.message);
// List files
const filesResponse = await api.get('/api/files');
console.log(`\nFound ${filesResponse.data.items.length} items`);
// Create folder
await api.post('/api/folder', {
path: '',
name: 'test-folder',
});
console.log('✓ Created folder: test-folder');
// Upload file
const formData = new FormData();
formData.append('basePath', 'test-folder');
formData.append('files', fs.createReadStream('./test.txt'));
await api.post('/api/upload', formData, {
headers: formData.getHeaders(),
});
console.log('✓ Uploaded file');
// Get storage stats
const storageResponse = await api.get('/api/storage');
console.log('\nStorage Statistics:');
console.log(` Size: ${storageResponse.data.totalSize} bytes`);
console.log(` Files: ${storageResponse.data.fileCount}`);
console.log(` Folders: ${storageResponse.data.folderCount}`);
// Logout
await api.post('/api/logout');
console.log('\n✓ Logged out');
} catch (error) {
console.error('Error:', error.response?.data || error.message);
}
}
main();All API endpoints return consistent error responses:
{
"error": "Authentication required"
}{
"error": "Invalid input: folder name is required"
}{
"error": "File or folder not found"
}{
"error": "Internal server error: detailed message"
}Currently, there are no built-in rate limits. For production use, consider implementing rate limiting to prevent abuse.
-
Reuse Session Cookies
- Login once and reuse the session cookie for multiple requests
- Sessions last 24 hours
-
Handle Errors Gracefully
- Always check response status codes
- Implement retry logic for failed requests
-
Use Appropriate Timeouts
- Set longer timeouts for file uploads
- Default timeout may be too short for large files
-
Validate Before Upload
- Check file sizes before uploading
- Validate file types if needed
-
Clean Up
- Logout when done to free server resources
- Delete temporary files after operations
- Always use HTTPS in production - Never send credentials over HTTP
- Store credentials securely - Use environment variables, never hardcode
- Rotate passwords regularly - Change API credentials periodically
- Use IP whitelisting - Restrict API access to known IPs if possible
- Monitor API usage - Log and review API calls regularly
- Implement rate limiting - Prevent brute force attacks
Cause: Session cookie not being sent
Solution:
# Ensure you're using -b cookies.txt flag
curl -b cookies.txt "http://localhost:3000/api/files"
# Verify cookie was saved during login
cat cookies.txtCause: Request timeout or size limit exceeded
Solution:
# Increase timeout
curl --max-time 600 -b cookies.txt -X POST http://localhost:3000/api/upload \
-F "basePath=products" \
-F "files=@large-file.zip"
# Check file size (max 100MB per file)
ls -lh large-file.zipCause: Incorrect path format
Solution:
- Use forward slashes:
products/images✓ - No leading slash:
productsnot/products✓ - Case sensitive: match exact folder names ✓
Ubuntu/Debian:
# Update system
sudo apt update && sudo apt upgrade -y
# Install Node.js 18.x
curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -
sudo apt install -y nodejs
# Verify installation
node --version
npm --version# Create directory
sudo mkdir -p /var/www/file-manager
cd /var/www/file-manager
# Upload your files (via git, scp, or ftp)
# For example, using git:
# git clone your-repo-url .
# Install dependencies
npm install --production
# Create uploads directory
mkdir -p uploads
chmod 755 uploads
# Configure environment
nano .env# Install PM2 globally
sudo npm install -g pm2
# Start application
pm2 start server.js --name file-manager
# Auto-start on system reboot
pm2 startup
pm2 save
# Check status
pm2 status
# View logs
pm2 logs file-managerPM2 Commands:
pm2 restart file-manager # Restart app
pm2 stop file-manager # Stop app
pm2 delete file-manager # Remove from PM2
pm2 monit # Monitor resourcesInstall Nginx:
sudo apt install nginx -yCreate Nginx configuration:
sudo nano /etc/nginx/sites-available/file-managerAdd this configuration:
server {
listen 80;
server_name yourdomain.com www.yourdomain.com;
# Increase upload size limit
client_max_body_size 100M;
location / {
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
# Timeouts for large uploads
proxy_connect_timeout 600;
proxy_send_timeout 600;
proxy_read_timeout 600;
send_timeout 600;
}
}Enable the site:
sudo ln -s /etc/nginx/sites-available/file-manager /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl restart nginx# Install Certbot
sudo apt install certbot python3-certbot-nginx -y
# Obtain SSL certificate
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com
# Follow the prompts to configureSSL certificates auto-renew. Test renewal:
sudo certbot renew --dry-run# Allow SSH, HTTP, and HTTPS
sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
# Enable firewall
sudo ufw enable
# Check status
sudo ufw statusCreate Dockerfile:
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install --production
COPY . .
RUN mkdir -p uploads
EXPOSE 3000
CMD ["node", "server.js"]Create docker-compose.yml:
version: '3.8'
services:
file-manager:
build: .
ports:
- "3000:3000"
volumes:
- ./uploads:/app/uploads
- ./.env:/app/.env
restart: unless-stopped
environment:
- NODE_ENV=productionDeploy:
docker-compose up -dCreate backup script (/var/www/file-manager/backup.sh):
#!/bin/bash
BACKUP_DIR="/var/backups/file-manager"
DATE=$(date +%Y%m%d_%H%M%S)
APP_DIR="/var/www/file-manager"
# Create backup directory
mkdir -p $BACKUP_DIR
# Backup uploads folder
tar -czf $BACKUP_DIR/uploads_$DATE.tar.gz $APP_DIR/uploads
# Backup .env file
cp $APP_DIR/.env $BACKUP_DIR/env_$DATE.backup
# Keep only last 7 days of backups
find $BACKUP_DIR -name "uploads_*.tar.gz" -mtime +7 -delete
find $BACKUP_DIR -name "env_*.backup" -mtime +7 -delete
echo "Backup completed: $DATE"Make executable and schedule:
chmod +x /var/www/file-manager/backup.sh
# Add to crontab (daily at 2 AM)
crontab -e
# Add this line:
0 2 * * * /var/www/file-manager/backup.sh >> /var/log/file-manager-backup.log 2>&1Symptoms:
- Getting "Authentication required" error after login
- Can't upload files
- Session expires immediately
Solutions:
-
Hard refresh your browser:
- Windows/Linux: Press
Ctrl + Shift + R - Mac: Press
Cmd + Shift + R
- Windows/Linux: Press
-
Clear browser cookies:
- Open DevTools (F12)
- Go to Application → Storage → Clear site data
- Or manually delete cookies for your domain
-
Restart the server:
# If using PM2: pm2 restart file-manager # If running directly: # Press Ctrl+C to stop, then: npm start
-
Check browser console for errors:
- Press F12 → Console tab
- Look for red errors
-
Verify .env file exists and has correct credentials
Error: EADDRINUSE: address already in use
Solution 1 - Kill the process:
# Find and kill process on port 3000
lsof -ti:3000 | xargs kill
# Or force kill
lsof -ti:3000 | xargs kill -9Solution 2 - Change port:
Edit .env file:
PORT=8080Error: "Permission denied" or upload fails
Solution:
# Ensure uploads directory has correct permissions
chmod 755 uploads/
# If needed, change ownership
sudo chown -R $USER:$USER uploads/Checks:
- Verify file uploaded successfully in admin panel
- Check the exact path (case-sensitive)
- Ensure server is running
- Try accessing:
http://localhost:3000/filename.ext
Example:
- ❌ Wrong:
http://localhost:3000/Products/image.jpg - ✅ Correct:
http://localhost:3000/products/image.jpg
Check for errors:
# If using PM2:
pm2 logs file-manager
# If running directly, check terminal outputCommon issues:
.envfile missing or malformed- Port already in use
- Node.js version too old (need v14+)
- Missing dependencies (run
npm install)
Factors:
- Internet connection speed
- File sizes
- Server location
Tips:
- Use wired connection instead of WiFi
- Upload during off-peak hours
- Split large folders into smaller batches
- Consider uploading directly to server via SFTP for very large files
Browser Compatibility:
- ✅ Chrome/Edge/Opera: Full support
- ✅ Firefox: Use "Upload Files" and select multiple files
- ✅ Safari: Supported with webkit prefix
- ❌ Internet Explorer: Not supported
Solution:
- Use a modern browser (Chrome recommended)
- For unsupported browsers, upload files individually or use FTP
Check disk space:
df -hFree up space:
# Delete old backups
rm -rf /var/backups/file-manager/uploads_*.tar.gz
# Clean package manager cache
sudo apt clean
# Remove old logs
sudo journalctl --vacuum-time=7d- Changed default admin username
- Set strong admin password (12+ characters)
- Generated unique SESSION_SECRET
- Enabled HTTPS/SSL in production
- Configured firewall (only allow 22, 80, 443)
- Set up automated backups
- Secured .env file permissions (
chmod 600 .env) - Updated all dependencies to latest versions
- Minimum 12 characters
- Mix of uppercase and lowercase letters
- Include numbers
- Include special characters (@, #, $, %, etc.)
- Avoid dictionary words
- Don't reuse passwords from other services
Example: Xk9#mP2$qL8@nR5
Generate a cryptographically secure random string:
openssl rand -base64 32Never use default values in production!
✅ Built-in Protection:
- Session-based authentication
- Password-protected admin panel
- Directory traversal prevention
- Secure file path validation
- File size limits (100MB default)
- Secure cookie configuration
❌ Not Included (Consider Adding):
- Rate limiting for login attempts
- Two-factor authentication
- File type restrictions
- Virus scanning
- IP whitelisting
For Production Environments:
-
Add Rate Limiting: Install express-rate-limit to prevent brute force attacks on login
-
Restrict File Types: Modify server.js to allow only specific file extensions
-
Enable Fail2Ban: Automatically ban IPs with repeated failed login attempts
-
Regular Updates:
npm update pm2 restart file-manager
-
Monitor Logs:
pm2 logs file-manager --lines 100
-
Use Strong Firewall Rules: Only allow necessary ports and IPs
Recommended permissions:
# Application files
chmod 644 server.js
chmod 644 package.json
chmod 600 .env
# Uploads directory
chmod 755 uploads/
# Files inside uploads
chmod 644 uploads/*A: Yes! All uploaded files are publicly accessible via clean URLs, making it perfect for serving images, CSS, JavaScript, and other assets.
A: No built-in storage limit. Storage is limited only by your disk space.
A: Currently, there's only one admin account. All users share the same credentials.
A: Files are stored as-is on the server. They are not encrypted at rest. Use HTTPS/SSL to encrypt data in transit.
A: Yes! Deploy it on a subdomain (e.g., files.yourdomain.com) and reference files from your main website.
A: Edit the .env file on the server and change ADMIN_PASSWORD to a new password. Restart the application.
A: Yes! The uploads directory contains all your files. You can back it up manually or use the automated backup script provided in the deployment section.
A: This requires Node.js support. It works on VPS, dedicated servers, and cloud platforms. Most shared hosting doesn't support Node.js applications.
A: Yes. Edit server.js and modify the multer configuration:
limits: { fileSize: 200 * 1024 * 1024 } // 200MBA: Yes, with proper security measures. Follow the production deployment guide, use HTTPS, set strong passwords, and implement regular backups.
Minimum:
- CPU: 1 core
- RAM: 512MB
- Storage: 10GB (+ space for files)
- OS: Linux, macOS, or Windows
- Node.js: v14.0+
Recommended:
- CPU: 2+ cores
- RAM: 1GB+
- Storage: 50GB+ SSD
- OS: Ubuntu 20.04+ or Debian 11+
- Node.js: v18.0+
- Backend: Node.js + Express.js
- Frontend: Vanilla JavaScript (no framework)
- Storage: Local filesystem
- Authentication: Express Session
- File Upload: Multer
| Browser | Version | Support |
|---|---|---|
| Chrome | 90+ | ✅ Full |
| Firefox | 88+ | ✅ Full |
| Safari | 14+ | ✅ Full |
| Edge | 90+ | ✅ Full |
| Opera | 76+ | ✅ Full |
| IE | All | ❌ Not Supported |
No built-in rate limiting. Consider adding for production use.
- 👥 Multi-User System - Support for multiple users with admin/user roles
- 🔑 API Token Authentication - Generate personal API tokens for automation
- 🔐 Password Management - Users can change their passwords securely
- 🔒 Encrypted Credentials - All passwords hashed with bcrypt
- 📝 User Management UI - Admin panel for creating and managing users
- ⚙️ User Settings Panel - Self-service password and token management
- 🚀 Dual Authentication - Session-based or API token-based access
- 📊 Role-Based Access Control - Admin-only endpoints and features
- ✨ Auto-Generated Passwords - Secure random passwords for new users
- 📁 credential.json - Centralized user credential storage
- ✨ Added folder upload with complete directory structure
- 🎨 Complete UI/UX overhaul with modern design
- 📦 Support for up to 500 files per upload
- 🔧 Improved space efficiency (65% less interface chrome)
- ✅ Enhanced bulk delete functionality
- 📱 Better mobile responsiveness
- 🔐 Fixed authentication persistence issues
- 🍪 Improved session and cookie handling
- 📝 Added comprehensive troubleshooting guide
- 🧪 Added authentication test script
- 🔒 Fixed login form security (POST instead of GET)
- 📁 Fixed file upload path issues
- 🎯 Improved static file serving
- 🎉 Initial release
- 📤 File upload and download
- 📁 Folder management
- 🔍 Search functionality
- 🔐 Authentication system
- Check this README - Most questions are answered here
- Check Troubleshooting section - Common issues and solutions
- Review logs - Check terminal/PM2 logs for errors
- Verify configuration - Ensure .env file is correct
If you encounter a problem:
- Check the Troubleshooting section first
- Try restarting the application
- Check browser console for errors (F12)
- Review server logs for error messages
MIT License
Copyright (c) 2024-2025 Simple File Manager Contributors
This project is licensed under the MIT License with attribution requirements.
You are free to:
- ✅ Use commercially
- ✅ Modify and distribute
- ✅ Use privately
- ✅ Sublicense
You must:
- 📝 Include the license and copyright notice
- 🏷️ Give credit with "Powered by Simple File Manager"
⚠️ Not remove credits or attribution from source code
See the LICENSE file for complete terms.
Built with:
- Express.js - Web framework
- Multer - File upload handling
- Express-session - Session management
- Modern vanilla JavaScript and CSS
Made with ❤️ for easy file management
For the latest updates and more information, visit the project repository.