bzl

self-hosted ephemeral community engine
Log | Files | Refs | README | LICENSE

commit 172cbe10f185923bd3abc08ad7cfe64187e5a97b
parent ed26a9921559f224026c5c203dfa46282c639174
Author: Dokkae6949 <finnliry@gmail.com>
Date:   Tue, 17 Feb 2026 00:09:52 +0100

feat: docker integration

also fixes plugin installation in docker containers

Diffstat:
ADockerfile | 29+++++++++++++++++++++++++++++
MREADME.md | 11+++++++++++
Acompose.yaml | 14++++++++++++++
Mserver.js | 10+++++++++-
4 files changed, 63 insertions(+), 1 deletion(-)

diff --git a/Dockerfile b/Dockerfile @@ -0,0 +1,29 @@ +# Use a lightweight Node.js image +FROM node:20-alpine + +# Set working directory +WORKDIR /app + +# Copy package files first to leverage Docker cache +COPY package*.json ./ + +# Install dependencies +RUN npm ci --only=production + +# Copy the rest of the application code +COPY . . + +# Create the data directory so permissions can be set if needed +# (Though server.js creates it if missing, doing it here ensures the volume mount point exists) +RUN mkdir -p data + +ENV PORT=3000 + +# Expose the default port +EXPOSE ${PORT} + +# persist data +VOLUME ["/app/data"] + +# Start the server +CMD ["npm", "start"] diff --git a/README.md b/README.md @@ -27,6 +27,17 @@ Media uploads: ## Run locally +### Docker + +To run a local instance of the app, the following command can be used: +```bash +docker compose -f compose.yaml up --build --remove-orphans +``` + +Optionally the `-d` flag can be specified to let the app run as a background process. + +### Manual + 1. Install Node.js (recommended: Node 18+) 2. From this folder: - Optional first-time wizard: `npm run init` (Windows PowerShell: `npm.cmd run init`) diff --git a/compose.yaml b/compose.yaml @@ -0,0 +1,14 @@ +services: + bzl: + build: . + image: bzl:latest + container_name: bzl + restart: unless-stopped + env_file: .env + ports: + - "${PORT:-3000}:${PORT:-3000}" + volumes: + - bzl_data:/app/data + +volumes: + bzl_data: diff --git a/server.js b/server.js @@ -3224,7 +3224,15 @@ async function handlePluginInstall(req, res, url) { } // Move extracted plugin directory into place. - fs.renameSync(extractedRoot, destDir); + try { + fs.renameSync(extractedRoot, destDir); + } catch (renameErr) { + if (renameErr.code === "EXDEV") { + fs.cpSync(extractedRoot, destDir, { recursive: true }); + } else { + throw renameErr; + } + } // Ensure state entry exists and defaults to disabled. if (!pluginsStateById.has(manifest.id)) pluginsStateById.set(manifest.id, { enabled: false });