feat: add custom branding, air-gapped deployment script, and updated self-hosting docs

This commit is contained in:
alam00000
2026-02-14 21:38:58 +05:30
parent 75b1d67fbd
commit 3cf435d59d
38 changed files with 1487 additions and 123 deletions

123
README.md
View File

@@ -38,6 +38,7 @@
- [Docker Compose / Podman Compose](#-run-with-docker-compose--podman-compose-recommended)
- [Podman Quadlet](#-podman-quadlet-systemd-integration)
- [Simple Mode](#-simple-mode-for-internal-use)
- [Custom Branding](#-custom-branding)
- [WASM Configuration](#wasm-configuration)
- [Air-Gapped / Offline Deployment](#air-gapped--offline-deployment)
- [Security Features](#-security-features)
@@ -472,7 +473,69 @@ Users can also override these defaults per-browser via **Advanced Settings** in
<h3 id="air-gapped--offline-deployment">🔒 Air-Gapped / Offline Deployment</h3>
For networks with no internet access (government, healthcare, financial, etc.), you need to prepare everything on a machine **with** internet, then transfer it into the isolated network.
For networks with no internet access (government, healthcare, financial, etc.), you need to prepare everything on a machine **with** internet, then transfer the bundle into the isolated network.
#### Automated Script (Recommended)
The included `prepare-airgap.sh` script automates the entire process — downloading WASM packages, building the Docker image, exporting everything into a self-contained bundle with a setup script.
```bash
git clone https://github.com/alam00000/bentopdf.git
cd bentopdf
# Interactive mode — prompts for all options
bash scripts/prepare-airgap.sh
# Or fully automated
bash scripts/prepare-airgap.sh --wasm-base-url https://internal.example.com/wasm
```
This produces a bundle directory containing:
```
bentopdf-airgap-bundle/
bentopdf.tar # Docker image
*.tgz # WASM packages (PyMuPDF, Ghostscript, CoherentPDF)
setup.sh # Setup script for the air-gapped side
README.md # Instructions
```
**Transfer the bundle** into the air-gapped network via USB, internal artifact repo, or approved method. Then run the included setup script:
```bash
cd bentopdf-airgap-bundle
bash setup.sh
```
The setup script loads the Docker image, extracts WASM files, and optionally starts the container.
<details>
<summary><strong>Script options</strong></summary>
| Flag | Description | Default |
| ----------------------- | ------------------------------------------------ | --------------------------------- |
| `--wasm-base-url <url>` | Where WASMs will be hosted internally | _(required, prompted if missing)_ |
| `--image-name <name>` | Docker image tag | `bentopdf` |
| `--output-dir <path>` | Output bundle directory | `./bentopdf-airgap-bundle` |
| `--simple-mode` | Enable Simple Mode | off |
| `--base-url <path>` | Subdirectory base URL (e.g. `/pdf/`) | `/` |
| `--language <code>` | Default UI language (e.g. `fr`, `de`) | _(none)_ |
| `--brand-name <name>` | Custom brand name | _(none)_ |
| `--brand-logo <path>` | Logo path relative to `public/` | _(none)_ |
| `--footer-text <text>` | Custom footer text | _(none)_ |
| `--dockerfile <path>` | Dockerfile to use | `Dockerfile` |
| `--skip-docker` | Skip Docker build and export | off |
| `--skip-wasm` | Skip WASM download (reuse existing `.tgz` files) | off |
</details>
> [!IMPORTANT]
> WASM files must be served from the **same origin** as the BentoPDF app. Web Workers use `importScripts()` which cannot load scripts cross-origin. For example, if BentoPDF runs at `https://internal.example.com`, the WASM base URL should also be `https://internal.example.com/wasm`.
#### Manual Steps
<details>
<summary>If you prefer to do it manually without the script</summary>
**Step 1: Download the WASM packages** (on a machine with internet)
@@ -482,14 +545,9 @@ npm pack @bentopdf/gs-wasm
npm pack coherentpdf
```
This creates three `.tgz` files in your current directory.
**Step 2: Build the Docker image with internal URLs** (on a machine with internet)
Point the WASM URLs to where you'll host the files inside the air-gapped network:
**Step 2: Build the Docker image with internal URLs**
```bash
# Clone and build
git clone https://github.com/alam00000/bentopdf.git
cd bentopdf
@@ -522,19 +580,18 @@ Copy these files via USB drive, internal artifact repository, or approved transf
docker load -i bentopdf.tar
# Extract the WASM packages
mkdir -p /var/www/wasm/pymupdf /var/www/wasm/gs /var/www/wasm/cpdf
tar xzf bentopdf-pymupdf-wasm-0.11.14.tgz -C /var/www/wasm/pymupdf --strip-components=1
tar xzf bentopdf-gs-wasm-*.tgz -C /var/www/wasm/gs --strip-components=1
tar xzf coherentpdf-*.tgz -C /var/www/wasm/cpdf --strip-components=1
# Serve the WASM files on your internal web server (e.g., nginx, Apache)
# Make sure they're accessible at the URLs you configured in Step 2
mkdir -p ./wasm/pymupdf ./wasm/gs ./wasm/cpdf
tar xzf bentopdf-pymupdf-wasm-0.11.14.tgz -C ./wasm/pymupdf --strip-components=1
tar xzf bentopdf-gs-wasm-*.tgz -C ./wasm/gs --strip-components=1
tar xzf coherentpdf-*.tgz -C ./wasm/cpdf --strip-components=1
# Run BentoPDF
docker run -d -p 3000:8080 --restart unless-stopped bentopdf
```
Users open their browser, access BentoPDF on the internal network, and the browser fetches WASM files from the internal server. No internet required at any point.
Make sure the WASM files are accessible at the URLs you configured in Step 2.
</details>
> [!NOTE]
> If you're building from source instead of Docker, set the variables in `.env.production` before running `npm run build`:
@@ -684,6 +741,42 @@ For organizations that want a clean, distraction-free interface focused solely o
For more details, see [SIMPLE_MODE.md](SIMPLE_MODE.md).
### 🎨 Custom Branding
Replace the default BentoPDF logo, name, and footer text with your own. Branding is configured via environment variables at **build time** and works across all deployment methods (Docker, static hosting, air-gapped VMs).
| Variable | Description | Default |
| ------------------ | --------------------------------------- | --------------------------------------- |
| `VITE_BRAND_NAME` | Brand name shown in header and footer | `BentoPDF` |
| `VITE_BRAND_LOGO` | Path to logo file relative to `public/` | `images/favicon-no-bg.svg` |
| `VITE_FOOTER_TEXT` | Custom footer/copyright text | `© 2026 BentoPDF. All rights reserved.` |
**Docker:**
```bash
docker build \
--build-arg VITE_BRAND_NAME="AcmePDF" \
--build-arg VITE_BRAND_LOGO="images/acme-logo.svg" \
--build-arg VITE_FOOTER_TEXT="© 2026 Acme Corp. Internal use only." \
-t acmepdf .
```
**Building from source:**
Place your logo in the `public/` folder, then build:
```bash
VITE_BRAND_NAME="AcmePDF" \
VITE_BRAND_LOGO="images/acme-logo.svg" \
VITE_FOOTER_TEXT="© 2026 Acme Corp. Internal use only." \
npm run build
```
Or set the values in `.env.production` before building.
> [!TIP]
> Branding works in both full mode and Simple Mode. You can combine it with other build-time options like `SIMPLE_MODE`, `BASE_URL`, and `VITE_DEFAULT_LANGUAGE`.
### 🔒 Security Features
BentoPDF runs as a non-root user using nginx-unprivileged for enhanced security: