Barazo Docker Compose templates for self-hosting barazo.forum

feat(plugins): add plugin installation support for self-hosters (#66)

Add plugins.json mechanism for declaring plugins, install-plugins.sh
script for container startup installation, and self-hoster documentation.

authored by

Guido X Jansen and committed by
GitHub
62e4b067 2357cbd6

+193
+2
docker-compose.yml
··· 124 124 LOG_LEVEL: ${LOG_LEVEL:-info} 125 125 volumes: 126 126 - plugins:/app/plugins 127 + - ./plugins.json:/app/plugins.json:ro 128 + - ./scripts/install-plugins.sh:/app/install-plugins.sh:ro 127 129 networks: 128 130 - frontend 129 131 - backend
+112
docs/plugins.md
··· 1 + # Plugin Installation for Self-Hosters 2 + 3 + Barazo supports extending your forum with plugins. Plugins are npm packages installed into a persistent Docker volume. 4 + 5 + ## Quick Start 6 + 7 + 1. Copy the example plugin configuration: 8 + 9 + ```bash 10 + cp plugins.json.example plugins.json 11 + ``` 12 + 13 + 2. Edit `plugins.json` to declare the plugins you want: 14 + 15 + ```json 16 + { 17 + "plugins": [ 18 + { 19 + "name": "@barazo/plugin-polls", 20 + "version": "^1.0.0" 21 + } 22 + ] 23 + } 24 + ``` 25 + 26 + 3. Restart the API container to install plugins: 27 + 28 + ```bash 29 + docker compose restart barazo-api 30 + ``` 31 + 32 + The `install-plugins.sh` script runs on startup. It reads `plugins.json` and installs each declared plugin into the `plugins` volume at `/app/plugins/`. 33 + 34 + ## plugins.json Format 35 + 36 + ```json 37 + { 38 + "plugins": [ 39 + { 40 + "name": "@barazo/plugin-polls", 41 + "version": "^1.0.0" 42 + }, 43 + { 44 + "name": "community-badges", 45 + "version": "2.0.0" 46 + } 47 + ] 48 + } 49 + ``` 50 + 51 + Each entry requires: 52 + 53 + - `name` -- the npm package name (scoped or unscoped) 54 + - `version` -- a semver range (optional; defaults to `latest`) 55 + 56 + ## How It Works 57 + 58 + - `plugins.json` is bind-mounted read-only into the container at `/app/plugins.json` 59 + - On startup, `install-plugins.sh` reads the file and runs `npm install` for each plugin 60 + - Plugins are installed into the `plugins` Docker volume at `/app/plugins/` 61 + - The volume persists across container restarts -- plugins are not reinstalled unless the version changes 62 + - If `plugins.json` is missing or empty, no plugins are installed and the forum runs normally 63 + 64 + ## Enabling and Configuring Plugins 65 + 66 + After installation, enable plugins through the admin UI: 67 + 68 + 1. Go to **Admin > Plugins** 69 + 2. Find the installed plugin in the **Installed** tab 70 + 3. Toggle it on 71 + 4. Configure plugin-specific settings if available 72 + 73 + ## Adding a New Plugin 74 + 75 + 1. Add the plugin to `plugins.json` 76 + 2. Restart the API: `docker compose restart barazo-api` 77 + 3. Enable it in the admin UI 78 + 79 + ## Removing a Plugin 80 + 81 + 1. Remove the plugin entry from `plugins.json` 82 + 2. Disable it in the admin UI 83 + 3. Restart the API: `docker compose restart barazo-api` 84 + 85 + To fully remove installed files, delete the plugins volume and restart: 86 + 87 + ```bash 88 + docker compose down 89 + docker volume rm barazo_plugins 90 + docker compose up -d 91 + ``` 92 + 93 + This reinstalls only the plugins declared in `plugins.json`. 94 + 95 + ## Troubleshooting 96 + 97 + **Plugin fails to install:** 98 + 99 + Check the API container logs: 100 + 101 + ```bash 102 + docker compose logs barazo-api | grep install-plugins 103 + ``` 104 + 105 + Common causes: 106 + - Invalid package name in `plugins.json` 107 + - Network connectivity issues (the container needs access to the npm registry) 108 + - Version not found on npm 109 + 110 + **Plugin installed but not showing in admin:** 111 + 112 + Ensure `PLUGINS_ENABLED=true` is set in your `.env` file (this is the default).
+13
plugins.json.example
··· 1 + { 2 + "$schema": "https://barazo.forum/schemas/plugins.json", 3 + "plugins": [ 4 + { 5 + "name": "@barazo/plugin-polls", 6 + "version": "^1.0.0" 7 + }, 8 + { 9 + "name": "@barazo/plugin-spam-filter", 10 + "version": "^1.0.0" 11 + } 12 + ] 13 + }
+66
scripts/install-plugins.sh
··· 1 + #!/bin/sh 2 + # install-plugins.sh -- Install plugins declared in plugins.json on container startup. 3 + # 4 + # Expected to run inside the barazo-api container before the main process starts. 5 + # Reads /app/plugins.json (bind-mounted from the host) and installs each plugin 6 + # into /app/plugins/ (a named Docker volume that persists across restarts). 7 + # 8 + # If plugins.json does not exist or is empty, this script exits silently. 9 + # If a plugin is already installed at the requested version, it is skipped. 10 + 11 + set -e 12 + 13 + PLUGINS_FILE="/app/plugins.json" 14 + PLUGINS_DIR="/app/plugins" 15 + 16 + if [ ! -f "$PLUGINS_FILE" ]; then 17 + echo "[install-plugins] No plugins.json found, skipping plugin installation." 18 + exit 0 19 + fi 20 + 21 + PLUGIN_COUNT=$(node -e " 22 + const fs = require('fs'); 23 + try { 24 + const data = JSON.parse(fs.readFileSync('$PLUGINS_FILE', 'utf8')); 25 + const plugins = data.plugins || []; 26 + console.log(plugins.length); 27 + } catch { 28 + console.log('0'); 29 + } 30 + ") 31 + 32 + if [ "$PLUGIN_COUNT" = "0" ]; then 33 + echo "[install-plugins] plugins.json has no plugins declared, skipping." 34 + exit 0 35 + fi 36 + 37 + echo "[install-plugins] Installing $PLUGIN_COUNT plugin(s) from plugins.json..." 38 + 39 + # Ensure plugins directory has a package.json for npm install 40 + if [ ! -f "$PLUGINS_DIR/package.json" ]; then 41 + echo '{"name":"barazo-plugins","private":true,"dependencies":{}}' > "$PLUGINS_DIR/package.json" 42 + fi 43 + 44 + # Parse plugins.json and install each plugin 45 + node -e " 46 + const fs = require('fs'); 47 + const { execSync } = require('child_process'); 48 + const data = JSON.parse(fs.readFileSync('$PLUGINS_FILE', 'utf8')); 49 + const plugins = data.plugins || []; 50 + 51 + for (const plugin of plugins) { 52 + const spec = plugin.version ? plugin.name + '@' + plugin.version : plugin.name; 53 + console.log('[install-plugins] Installing ' + spec + '...'); 54 + try { 55 + execSync('npm install --prefix $PLUGINS_DIR ' + spec, { 56 + stdio: 'inherit', 57 + timeout: 120000, 58 + }); 59 + console.log('[install-plugins] Installed ' + spec); 60 + } catch (err) { 61 + console.error('[install-plugins] Failed to install ' + spec + ': ' + err.message); 62 + process.exit(1); 63 + } 64 + } 65 + console.log('[install-plugins] All plugins installed successfully.'); 66 + "