Complete Guide for Developing Plugins for Mini-B
In versions after 3.6.2, Mini Bucket supports installing and using plugins.
Template:
For example, you can download a plugin template or use it for development: https://mini-bucket.ru/project/plugin-template/
Or you can look at the finished plugin, it’s different from the template, but it also works: https://mini-bucket.ru/project/log-manager/
📋 Table of Contents
- Introduction
- Plugin Structure
- Naming Rules (CRITICAL)
- Step-by-Step Plugin Creation
- File Descriptions
- JavaScript API
- PHP API
- Database
- Complete Plugin Example
- Installation and Testing
Introduction
What is a Mini-B Plugin?
A plugin is an extension of Mini-B functionality that can:
- Run on the local host (where Mini-B is installed)
- Run on remote hosts (via API)
- Automatically install on remote servers
- Have its own SQLite database
- Use system APIs and authentication
Plugin Requirements
- PHP 7.0 or higher
- Write permissions in plugin directory
- Host must have an API key
Plugin Structure
Minimal Structure
plugin_name/ # Plugin folder (REQUIRED)
│
├── info.json # Plugin metadata (REQUIRED)
├── plugin_name.php # Main UI file (REQUIRED)
├── plugin_name_api.php # API backend file (REQUIRED)
├── init.php # Initialization file (REQUIRED)
├── plugin.js # JavaScript core (REQUIRED)
├── plugin.css # Styles (REQUIRED)
│
└── [additional files] # Optional
└── assets/ # Additional resources
├── images/
└── fonts/Naming Rules (CRITICAL)
⚠️ Golden Rule: ALL NAMES MUST MATCH!
This is the most important part. If names don’t match – the plugin WILL NOT WORK!
Where and what names must match:
| # | Where to specify | What to specify | Must match with |
|---|---|---|---|
| 1 | Plugin folder name | my_plugin | All below ↓ |
| 2 | info.json → sysname | "my_plugin" | Folder name |
| 3 | plugin_name.php | my_plugin.php | Folder name |
| 4 | plugin_name_api.php | my_plugin_api.php | Folder name |
| 5 | plugin.js | plugin.js | Always this (don’t change) |
| 6 | plugin.css | plugin.css | Always this (don’t change) |
| 7 | init.php | init.php | Always this (don’t change) |
| 8 | menu/plugin_name.php | | Folder name |
| 9 | URL in menu | plugins/my_plugin/my_plugin.php | Folder name |
| 10 | window.pluginName | 'my_plugin' | Folder name |
📝 Example of Correct Naming:
Let’s say you’re creating a plugin named log_manager:
✅ CORRECT:
Frontend
/var/www/html/admin/plugins/log_manager/ # Folder
/var/www/html/admin/plugins/log_manager/log_manager.php
/var/www/html/admin/plugins/log_manager/log_manager_api.php
/var/www/html/admin/plugins/log_manager/log_manager/init.php
/var/www/html/admin/plugins/log_manager/plugin.js
/var/www/html/admin/plugins/log_manager/plugin.css
/var/www/html/admin/plugins/menu/log_manager.php
Backend
/var/www/minib/plugins/installed/log_manager/info.json # sysname: "log_manager"
/var/www/minib/plugins/installed/log_manager/uninstall.sh
/var/www/minib/plugins/installed/log_manager/log_manager.db
❌ INCORRECT:
/var/www/html/admin/plugins/log_manager/ # Case mismatch
/var/www/html/admin/plugins/log_manager/info.json # sysname: "logmanager" (different)
/var/www/html/admin/plugins/log_manager/index.php # Wrong file name
/var/www/html/admin/plugins/log_manager/log_manager.db
/var/www/html/admin/plugins/log_manager/info.json
/var/www/html/admin/plugins/log_manager/uninstall.sh⚠️ For security reasons, do not place executable .sh scripts, downloadable files (logs, temporary files, reports), databases, or warcry files that can be run without authorization in the web directory /var/www/html/admin/plugins/plugin_name.
For such files, use the directory /var/www/minib/plugins/installed/plugin_name.
This directory is located outside the web server.

Step-by-Step Plugin Creation
Step 1: Create plugin folder backend
cd /var/www/minib/plugins/installed/
mkdir my_plugin
cd my_pluginStep 2: Create info.json
{
"name": "My Awesome Plugin",
"sysname": "my_plugin",
"version": "1.0.0",
"multinet": "Yes",
"release_date": "2026-06-07",
"author": "Your Name",
"description": "Plugin description here",
"php_version": ">=7.4",
"os": "Debian/Ubuntu",
"icon": "fas fa-rocket",
"icon_bg": "#667eea",
"group": "tools",
"group_title": "Tools"
}Create plugin folder backend frontend
cd /var/www/html/admin/plugins
mkdir my_plugin
cd my_pluginStep 3: Create init.php
<?php
$init = require_once __DIR__ . '/../plugin_template/init.php';
return $init;
OR write your own (copy from template)
Step 4: Create my_plugin.php
php
<?php
$init = require_once __DIR__ . '/init.php';
extract($init);
?>
<!DOCTYPE html>
<html>
<head>
<title>Mini-B - <?php echo $plugin_name; ?></title>
<!-- Include system libs -->
<link href="../../lib/bootstrap-5.3.8-dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="../../lib/fontawesome-free-6.7.2-web/css/all.min.css">
<link rel="stylesheet" href="../../style.css">
<link rel="stylesheet" href="../../css/loader.css">
<!-- Plugin assets -->
<link rel="stylesheet" href="plugin.css">
<script src="../../js/hosts_load.js"></script>
<script src="../../js/crt_checker.js"></script>
<!-- API Config -->
<script>
window.apiConfig = <?php echo json_encode($js_config); ?>;
window.pluginName = 'my_plugin';
</script>
</head>
<body>
<?php echo $menu; ?>
<main class="main-content">
<div id="alertContainer"></div>
<div class="widget">
<div class="widget-header">
<h3><i class="fas fa-rocket"></i> <?php echo $plugin_name; ?></h3>
</div>
<div class="widget-body">
<p>Your plugin content here</p>
<button class="btn btn-primary" onclick="testAPI()">Test API</button>
</div>
</div>
</main>
<script src="../../lib/jquery-3.6.0-master/dist/jquery.min.js"></script>
<script src="../../lib/bootstrap-5.3.8-dist/js/bootstrap.bundle.min.js"></script>
<script src="../../js/loader.js"></script>
<script src="plugin.js"></script>
<script>
function initPlugin() {
console.log('Plugin initialized');
showAlert('Plugin is ready!', 'success');
}
async function testAPI() {
const result = await apiCall('test', 'GET');
showAlert(JSON.stringify(result), 'info');
}
</script>
</body>
</html>Step 5: Create my_plugin_api.php
<?php
define('ROOT_PATH', dirname(dirname(dirname(__FILE__))));
require_once ROOT_PATH . '/config.php';
if (session_status() === PHP_SESSION_NONE) {
session_start();
}
header("Access-Control-Allow-Origin: *");
header("Content-Type: application/json");
// Validate API key
function validateApiKey() {
global $db;
if (!$db) $db = getDB();
$headers = getallheaders();
$apiKey = $headers['X-API-Key'] ?? $_GET['api_key'] ?? '';
if (empty($apiKey) && isset($_SESSION['user_id'])) {
return true;
}
if (empty($apiKey)) {
http_response_code(401);
echo json_encode(['error' => 'API key required']);
exit;
}
$stmt = $db->prepare("SELECT idHost FROM hosts WHERE hostApiKey = :key");
$stmt->bindValue(':key', $apiKey, SQLITE3_TEXT);
$result = $stmt->execute();
if (!$result->fetchArray()) {
http_response_code(403);
echo json_encode(['error' => 'Invalid API key']);
exit;
}
return true;
}
validateApiKey();
$action = $_GET['action'] ?? $_POST['action'] ?? '';
switch ($action) {
case 'get_plugin_status':
echo json_encode(['success' => true, 'available' => true]);
break;
case 'test':
echo json_encode(['success' => true, 'message' => 'API is working!']);
break;
default:
echo json_encode(['success' => false, 'error' => 'Unknown action']);
}
?>Step 6: Copy plugin.js and plugin.css
Copy from template (they are universal)
Step 7: Create my_plugin.php
<?php
return [
'enabled' => true,
'group' => 'tools',
'group_title' => 'Tools',
'title' => 'My Awesome Plugin',
'url' => '/plugins/my_plugin/my_plugin.php',
'icon' => 'fas fa-rocket',
];Step 8: Install bash script
#!/bin/bash
# Paths
MENU_DIR="/var/www/html/admin/plugins/menu"
ADMIN_DIR="/var/www/html/admin/plugins/my_plugin"
MINIB_DIR="/var/www/minib/plugins/installed/my_plugin"
# Creating folder
mkdir -p $ADMIN_DIR
mkdir -p $MINIB_DIR
# Assigning the owner and rights
chown -R www-data:www-data $ADMIN_DIR
chown -R www-data:www-data $MINIB_DIR
chmod -R 755 $ADMIN_DIR
chmod -R 755 $MINIB_DIR
chmod +x uninstall.sh
# copy file in admin
cp -p my_plugin.php $ADMIN_DIR/
cp -p my_plugin_api.php $ADMIN_DIR/
cp -p init.php $ADMIN_DIR/
cp -p plugin.css $ADMIN_DIR/
cp -p plugin.js $ADMIN_DIR/
cp -p menu/my_plugin.php $MENU_DIR/
# copy file in minib
cp -p info.json $MINIB_DIR/
cp -p uninstall.sh $MINIB_DIR/
# Delete instalation folder
rm -rf /var/www/minib/plugins/extract/my_plugin*Step 9. uninstall file
#!/bin/bash
MENU_DIR="/var/www/html/admin/plugins/menu"
ADMIN_DIR="/var/www/html/admin/plugins/my_plugin"
MINIB_DIR="/var/www/minib/plugins/installed/my_plugin"
rm -rf $ADMIN_DIR
rm -rf $MINIB_DIR
rm $MENU_DIR/my_plugin.phpFinal structure installation ZIP archive.
my_plugin_v0.0.1.zip/
│
├── info.json # Plugin metadata (REQUIRED)
├── my_plugin.php # Main UI file (REQUIRED)
├── my_plugin_api.php # API backend file (REQUIRED)
├── init.php # Initialization file (REQUIRED)
├── plugin.js # JavaScript core (REQUIRED)
├── plugin.css # Styles (REQUIRED)
├── install.sh
├── uninstall.sh
├── menu/
│ └── my_plugin.php
│
└── [additional files] # Optional
└── assets/ # Additional resources
├── images/
└── fonts/File Descriptions
📄 info.json
Purpose: Plugin metadata
Required fields:
{
"name": "Display Name", // Display name of the plugin
"sysname": "plugin_name", // System name (MUST match folder!)
"version": "1.0.0", // Version
"multinet": "Yes", // Multi-host support (Yes/No)
"release_date": "2026-06-07", // Release date
"author": "Author Name", // Author
"description": "Description", // Description (HTML supported)
"php_version": ">=7.4", // Required PHP version
"os": "Debian/Ubuntu", // Supported OS
"icon": "fas fa-code", // Font Awesome icon
"icon_bg": "linear-gradient(...)", // Icon color or gradient
"group": "tools", // Menu group (tools, system, network)
"group_title": "Tools" // Group display name
}Menu groups:
- Panel
- Storage
- Resources
- Users
- Security
- Tools
- System
📄 init.php
Purpose: Plugin initialization
What it does:
- Includes system configuration
- Verifies authentication
- Gets current host data
- Configures API URLs (local/remote)
- Creates JavaScript configuration
- Defines plugin constants
Returned variables:
return [
'db' => $db, // System DB connection
'host' => $host, // Host data
'api_key' => $api_key, // API key
'js_config' => $js_config, // JS config
'menu' => $menu, // System menu
'current_host_id' => $id, // Current host ID
'plugin_name' => 'Plugin Name' // Plugin name
];📄 plugin_name.php
Purpose: Main UI file
What it does:
- Displays plugin interface
- Includes system libraries
- Injects API configuration
- Calls JavaScript initialization
Key points:
// Required: Set plugin name for JS
<script>
window.pluginName = 'my_plugin'; // MUST match sysname!
</script>
// Required: Include plugin.js
<script src="plugin.js"></script>📄 plugin_name_api.php
Purpose: Plugin API backend
What it does:
- Handles AJAX requests
- Validates API keys
- Works with database
- Returns JSON responses
Required actions:
case 'get_plugin_status': // REQUIRED for remote installation!
echo json_encode(['success' => true, 'available' => true]);
break;📄 plugin.js
Purpose: Universal JavaScript core
Provides:
apiCall()– universal API callshowAlert()– notificationsescapeHtml()– XSS protectioncheckRemotePluginAvailability()– plugin checkshowPluginInstallModal()– remote installation
Do not modify this file! It’s universal for all plugins.
📄 plugin.css
Purpose: Plugin styles
What you can add:
- Custom CSS classes
- Animations
- Responsive styles
📄 menu_entry.php
Purpose: System menu entry
Structure:
<?php
return [
'enabled' => true, // Enabled/disabled
'group' => 'tools', // Menu group
'group_title' => 'Tools', // Group display name
'title' => 'Plugin Title', // Display name
'url' => '/plugins/my_plugin/my_plugin.php', // URL (MUST match!)
'icon' => 'fas fa-code', // Icon
];JavaScript API
Core Functions
apiCall(action, method, data)
Universal API call.
// GET request
const result = await apiCall('get_data', 'GET');
// GET with parameters
const result = await apiCall('get_item', 'GET', { id: 5 });
// POST request
const result = await apiCall('save_data', 'POST', {
name: 'test',
value: 123
});showAlert(message, type)
Show notification.
showAlert('Success!', 'success');
showAlert('Error!', 'danger');
showAlert('Warning!', 'warning');
showAlert('Info!', 'info');escapeHtml(str)
XSS protection.
const safe = escapeHtml('<script>alert("xss")</script>');Helper Functions
// Format file size
formatFileSize(1024); // "1 KB"
// Format date
formatDate(1686123456); // "2023-06-07 12:34:56"
// Highlight search term
highlightSearch('text with search term', 'search'); // 'text with <span class="search-highlight">search</span> term'
// Debounce for search
const searchHandler = debounce(() => {
// Search logic
}, 300);Plugin Lifecycle
// Called automatically after loading
function initPlugin() {
console.log('Plugin ready');
// Your initialization code
}
// Access configuration
console.log(window.apiConfig);
// {
// pluginApiUrl: '...',
// apiBaseUrl: '...',
// apiKey: '...',
// isLocalhost: true/false,
// currentHostId: 1,
// pluginName: 'my_plugin'
// }PHP API
Standard API Functions
// API key validation (REQUIRED)
function validateApiKey() { ... }
// Initialize plugin database
function initPluginDB() { ... }
// Get status (REQUIRED)
function getPluginStatus() {
return ['success' => true, 'available' => true];
}$action = $_GET['action'] ?? $_POST['action'] ?? '';
switch ($action) {
case 'get_plugin_status': // REQUIRED
echo json_encode(getPluginStatus());
break;
case 'my_action': // Your actions
// Processing
echo json_encode(['success' => true]);
break;
default:
echo json_encode(['success' => false, 'error' => 'Unknown action']);
}Database Operations
// Create/connect to database
function initPluginDB() {
$db = new SQLite3(PLUGIN_DIR . '/plugin_name.db');
// Create tables
$db->exec("
CREATE TABLE IF NOT EXISTS my_table (
id INTEGER PRIMARY KEY AUTOINCREMENT,
data TEXT NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
)
");
return $db;
}
// Example query
function getData() {
$db = initPluginDB();
$result = $db->query("SELECT * FROM my_table");
$data = [];
while ($row = $result->fetchArray(SQLITE3_ASSOC)) {
$data[] = $row;
}
$db->close();
return $data;
}Database
Where to Store DB
define('PLUGIN_DIR', dirname(__FILE__));
define('PLUGIN_DB', PLUGIN_DIR . '/plugin_name.db');File Permissions
// After creating DB
chmod($db_path, 0666);Example Database Structure
-- Settings table
CREATE TABLE IF NOT EXISTS settings (
key TEXT PRIMARY KEY,
value TEXT,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
-- Data table
CREATE TABLE IF NOT EXISTS items (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
status INTEGER DEFAULT 1,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);Complete Plugin Example
Todo List Plugin
info.json:
{
"name": "Todo List",
"sysname": "todo_list",
"version": "1.0.0",
"multinet": "Yes",
"release_date": "2026-06-07",
"author": "Mini-B Team",
"description": "Simple todo list plugin",
"php_version": ">=7.4",
"os": "Debian/Ubuntu",
"icon": "fas fa-tasks",
"group": "tools",
"group_title": "Tools"
}todo_list_api.php:
<?php
define('PLUGIN_DIR', dirname(__FILE__));
define('TODO_DB', PLUGIN_DIR . '/todo_list.db');
function initDB() {
$db = new SQLite3(TODO_DB);
$db->exec("
CREATE TABLE IF NOT EXISTS todos (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
completed INTEGER DEFAULT 0,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
)
");
return $db;
}
function getTodos() {
$db = initDB();
$result = $db->query("SELECT * FROM todos ORDER BY created_at DESC");
$todos = [];
while ($row = $result->fetchArray(SQLITE3_ASSOC)) {
$todos[] = $row;
}
$db->close();
return $todos;
}
function addTodo($title) {
$db = initDB();
$stmt = $db->prepare("INSERT INTO todos (title) VALUES (:title)");
$stmt->bindValue(':title', $title, SQLITE3_TEXT);
$stmt->execute();
$id = $db->lastInsertRowID();
$db->close();
return ['success' => true, 'id' => $id];
}
function toggleTodo($id) {
$db = initDB();
$stmt = $db->prepare("UPDATE todos SET completed = NOT completed WHERE id = :id");
$stmt->bindValue(':id', $id, SQLITE3_INTEGER);
$stmt->execute();
$db->close();
return ['success' => true];
}
function deleteTodo($id) {
$db = initDB();
$stmt = $db->prepare("DELETE FROM todos WHERE id = :id");
$stmt->bindValue(':id', $id, SQLITE3_INTEGER);
$stmt->execute();
$db->close();
return ['success' => true];
}
$action = $_GET['action'] ?? $_POST['action'] ?? '';
switch ($action) {
case 'get_plugin_status':
echo json_encode(['success' => true, 'available' => true]);
break;
case 'get_todos':
echo json_encode(['success' => true, 'data' => getTodos()]);
break;
case 'add_todo':
$title = $_POST['title'] ?? '';
echo json_encode(addTodo($title));
break;
case 'toggle_todo':
$id = $_POST['id'] ?? 0;
echo json_encode(toggleTodo($id));
break;
case 'delete_todo':
$id = $_POST['id'] ?? 0;
echo json_encode(deleteTodo($id));
break;
}
?>Installation and Testing
Local Installation
- Copy plugin folder:
cp -r my_plugin_v0.0.1.zip /var/www/minib/plugins/repositories/Login control panel > System > Plugins > Repository > Select your plugin and click Install button.
Plugin Installation Principle
A plugin is a ZIP archive that contains:
- the plugin’s files;
- an installation script (
install.sh); - other necessary files required for the plugin to function.
When you upload a plugin to mini-bucket, it is saved to the following directory:/var/www/minib/plugins/repositories
Once uploaded, the plugin becomes available for installation in the interface under:System > Plugins > Repository
To install the plugin, click the Install button. This triggers the following actions:
- The archive is extracted to
/var/www/minib/plugins/extract. - The
install.shfile is granted execution permissions. - The
install.shscript is executed.
After a successful installation, the plugin appears in the interface under:System > Plugins > Installed Plugins
Each installed plugin is equipped with a Toggle switch to enable or disable it.
You can also delete the plugin file from the repository by clicking the Delete button.
Important notes:
- Deleting a plugin from the repository does not remove the plugin from the system.
- Deleting a plugin from the system (via the Installed Plugins interface) does not delete its ZIP archive from the repository.
Back end installation process.

🎯 Pre-release Checklist
- Folder name matches
sysnameininfo.json - File names
plugin_name.phpandplugin_name_api.phpmatch folder name window.pluginNameset inplugin_name.phpget_plugin_statusaction exists inplugin_name_api.php- Correct URL in
munu file - All files have permissions 644 (755 for folders)
- Plugin tested on local host
- Plugin tested on remote host
- Automatic installation works
- Documentation updated
📞 Support
- Forum Eng: https://mini-bucket.ru/community/community/plugins/
- Forum Rus: https://mini-bucket.ru/community/community/%d0%bf%d0%bb%d0%b0%d0%b3%d0%b8%d0%bd%d1%8b/
- Other Plugins: https://mini-bucket.ru/plugins/
📄 License
MIT License – freely use, modify, and distribute!
Documentation Version: 1.0.0
Last Updated: 2026-06-07
Author: Mini-B Development