feat: add support for default UI language configuration and non-root Dockerfile
This commit is contained in:
@@ -11,3 +11,7 @@ VITE_CORS_PROXY_SECRET=
|
||||
VITE_WASM_PYMUPDF_URL=https://cdn.jsdelivr.net/npm/@bentopdf/pymupdf-wasm@0.11.14/
|
||||
VITE_WASM_GS_URL=https://cdn.jsdelivr.net/npm/@bentopdf/gs-wasm/assets/
|
||||
VITE_WASM_CPDF_URL=https://cdn.jsdelivr.net/npm/coherentpdf/dist/
|
||||
|
||||
# Default UI language (build-time)
|
||||
# Supported: en, ar, be, fr, de, es, zh, zh-TW, vi, tr, id, it, pt, nl, da
|
||||
VITE_DEFAULT_LANGUAGE=
|
||||
|
||||
@@ -35,6 +35,10 @@ ENV VITE_WASM_PYMUPDF_URL=$VITE_WASM_PYMUPDF_URL
|
||||
ENV VITE_WASM_GS_URL=$VITE_WASM_GS_URL
|
||||
ENV VITE_WASM_CPDF_URL=$VITE_WASM_CPDF_URL
|
||||
|
||||
# Default UI language (e.g. en, fr, de, es, zh, ar)
|
||||
ARG VITE_DEFAULT_LANGUAGE
|
||||
ENV VITE_DEFAULT_LANGUAGE=$VITE_DEFAULT_LANGUAGE
|
||||
|
||||
ENV NODE_OPTIONS="--max-old-space-size=3072"
|
||||
|
||||
RUN npm run build:with-docs
|
||||
|
||||
70
Dockerfile.nonroot
Normal file
70
Dockerfile.nonroot
Normal file
@@ -0,0 +1,70 @@
|
||||
# Non-root Dockerfile — supports PUID/PGID environment variables (LSIO-style)
|
||||
# Usage: docker build -f Dockerfile.nonroot -t bentopdf .
|
||||
# docker run -d -p 3000:8080 -e PUID=1000 -e PGID=1000 bentopdf
|
||||
|
||||
ARG BASE_URL=
|
||||
|
||||
# Build stage (identical to main Dockerfile)
|
||||
FROM public.ecr.aws/docker/library/node:20-alpine AS builder
|
||||
WORKDIR /app
|
||||
COPY package*.json ./
|
||||
COPY vendor ./vendor
|
||||
ENV HUSKY=0
|
||||
RUN npm config set fetch-retries 5 && \
|
||||
npm config set fetch-retry-mintimeout 60000 && \
|
||||
npm config set fetch-retry-maxtimeout 300000 && \
|
||||
npm config set fetch-timeout 600000 && \
|
||||
npm ci
|
||||
COPY . .
|
||||
|
||||
ARG SIMPLE_MODE=false
|
||||
ENV SIMPLE_MODE=$SIMPLE_MODE
|
||||
ARG COMPRESSION_MODE=all
|
||||
ENV COMPRESSION_MODE=$COMPRESSION_MODE
|
||||
|
||||
ARG BASE_URL
|
||||
ENV BASE_URL=$BASE_URL
|
||||
|
||||
ARG VITE_WASM_PYMUPDF_URL
|
||||
ARG VITE_WASM_GS_URL
|
||||
ARG VITE_WASM_CPDF_URL
|
||||
ENV VITE_WASM_PYMUPDF_URL=$VITE_WASM_PYMUPDF_URL
|
||||
ENV VITE_WASM_GS_URL=$VITE_WASM_GS_URL
|
||||
ENV VITE_WASM_CPDF_URL=$VITE_WASM_CPDF_URL
|
||||
|
||||
# Default UI language (e.g. en, fr, de, es, zh, ar)
|
||||
ARG VITE_DEFAULT_LANGUAGE
|
||||
ENV VITE_DEFAULT_LANGUAGE=$VITE_DEFAULT_LANGUAGE
|
||||
|
||||
ENV NODE_OPTIONS="--max-old-space-size=3072"
|
||||
|
||||
RUN npm run build:with-docs
|
||||
|
||||
# Production stage — uses standard nginx (starts as root, drops to PUID/PGID)
|
||||
FROM nginx:stable-alpine-slim
|
||||
|
||||
LABEL org.opencontainers.image.source="https://github.com/alam00000/bentopdf"
|
||||
LABEL org.opencontainers.image.url="https://github.com/alam00000/bentopdf"
|
||||
|
||||
ARG BASE_URL
|
||||
|
||||
ENV PUID=1000
|
||||
ENV PGID=1000
|
||||
ENV DISABLE_IPV6=false
|
||||
|
||||
RUN apk add --no-cache su-exec
|
||||
|
||||
COPY --from=builder /app/dist /usr/share/nginx/html${BASE_URL%/}
|
||||
COPY nginx.conf /etc/nginx/nginx.conf
|
||||
COPY --chmod=755 entrypoint.sh /entrypoint.sh
|
||||
|
||||
RUN mkdir -p /etc/nginx/tmp \
|
||||
/var/cache/nginx/client_temp \
|
||||
/var/cache/nginx/proxy_temp \
|
||||
/var/cache/nginx/fastcgi_temp \
|
||||
/var/cache/nginx/uwsgi_temp \
|
||||
/var/cache/nginx/scgi_temp
|
||||
|
||||
EXPOSE 8080
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
28
README.md
28
README.md
@@ -584,6 +584,14 @@ docker run -p 3000:8080 bentopdf
|
||||
# The app will be accessible at http://localhost:3000/bentopdf/
|
||||
```
|
||||
|
||||
**Default Language:**
|
||||
|
||||
Set the default UI language at build time. Users can still switch languages — this only changes the initial default. Supported: `en`, `ar`, `be`, `fr`, `de`, `es`, `zh`, `zh-TW`, `vi`, `tr`, `id`, `it`, `pt`, `nl`, `da`.
|
||||
|
||||
```bash
|
||||
docker build --build-arg VITE_DEFAULT_LANGUAGE=fr -t bentopdf .
|
||||
```
|
||||
|
||||
**Combined with Simple Mode:**
|
||||
|
||||
```bash
|
||||
@@ -691,6 +699,26 @@ docker build -t bentopdf .
|
||||
docker run -p 8080:8080 bentopdf
|
||||
```
|
||||
|
||||
#### Custom User ID (PUID/PGID)
|
||||
|
||||
For environments that require running as a specific non-root user (e.g., NAS devices, Kubernetes with security contexts), use the non-root Dockerfile:
|
||||
|
||||
```bash
|
||||
# Build the non-root image
|
||||
docker build -f Dockerfile.nonroot -t bentopdf-nonroot .
|
||||
|
||||
# Run with custom UID/GID
|
||||
docker run -d -p 3000:8080 -e PUID=1000 -e PGID=1000 bentopdf-nonroot
|
||||
```
|
||||
|
||||
| Variable | Description | Default |
|
||||
| -------- | ------------------ | ------- |
|
||||
| `PUID` | User ID to run as | `1000` |
|
||||
| `PGID` | Group ID to run as | `1000` |
|
||||
|
||||
> [!NOTE]
|
||||
> The standard `Dockerfile` uses `nginx-unprivileged` (UID 101) and is recommended for most deployments. Use `Dockerfile.nonroot` only when you need a specific UID/GID.
|
||||
|
||||
For detailed security configuration, see [SECURITY.md](SECURITY.md).
|
||||
|
||||
### Digital Signature CORS Proxy (Required)
|
||||
|
||||
@@ -95,16 +95,18 @@ docker run -d -p 3000:8080 bentopdf:custom
|
||||
| `VITE_WASM_PYMUPDF_URL` | PyMuPDF WASM module URL | `https://cdn.jsdelivr.net/npm/@bentopdf/pymupdf-wasm@0.11.14/` |
|
||||
| `VITE_WASM_GS_URL` | Ghostscript WASM module URL | `https://cdn.jsdelivr.net/npm/@bentopdf/gs-wasm/assets/` |
|
||||
| `VITE_WASM_CPDF_URL` | CoherentPDF WASM module URL | `https://cdn.jsdelivr.net/npm/coherentpdf/dist/` |
|
||||
| `VITE_DEFAULT_LANGUAGE` | Default UI language | `en` |
|
||||
|
||||
WASM module URLs are pre-configured with CDN defaults — all advanced features work out of the box. Override these for air-gapped or self-hosted deployments.
|
||||
|
||||
`VITE_DEFAULT_LANGUAGE` sets the UI language for first-time visitors. Supported values: `en`, `ar`, `be`, `fr`, `de`, `es`, `zh`, `zh-TW`, `vi`, `tr`, `id`, `it`, `pt`, `nl`, `da`. Users can still switch languages — this only changes the default.
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
docker run -d \
|
||||
-e SIMPLE_MODE=true \
|
||||
-p 3000:8080 \
|
||||
ghcr.io/alam00000/bentopdf:latest
|
||||
# Build with French as the default language
|
||||
docker build --build-arg VITE_DEFAULT_LANGUAGE=fr -t bentopdf .
|
||||
docker run -d -p 3000:8080 bentopdf
|
||||
```
|
||||
|
||||
### Custom WASM URLs (Air-Gapped / Self-Hosted)
|
||||
@@ -147,6 +149,61 @@ docker run -d -p 3000:8080 --restart unless-stopped bentopdf
|
||||
|
||||
Set a variable to empty string to disable that module (users must configure manually via Advanced Settings).
|
||||
|
||||
## Custom User ID (PUID/PGID)
|
||||
|
||||
For environments that require running as a specific non-root user (NAS devices, Kubernetes with security contexts, organizational policies), BentoPDF provides a separate Dockerfile with LSIO-style PUID/PGID support.
|
||||
|
||||
### Build and Run
|
||||
|
||||
```bash
|
||||
# Build the non-root image
|
||||
docker build -f Dockerfile.nonroot -t bentopdf-nonroot .
|
||||
|
||||
# Run with custom UID/GID
|
||||
docker run -d \
|
||||
--name bentopdf \
|
||||
-p 3000:8080 \
|
||||
-e PUID=1000 \
|
||||
-e PGID=1000 \
|
||||
--restart unless-stopped \
|
||||
bentopdf-nonroot
|
||||
```
|
||||
|
||||
### Environment Variables
|
||||
|
||||
| Variable | Description | Default |
|
||||
| -------------- | --------------------- | ------- |
|
||||
| `PUID` | User ID to run as | `1000` |
|
||||
| `PGID` | Group ID to run as | `1000` |
|
||||
| `DISABLE_IPV6` | Disable IPv6 listener | `false` |
|
||||
|
||||
### Docker Compose
|
||||
|
||||
```yaml
|
||||
services:
|
||||
bentopdf:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile.nonroot
|
||||
container_name: bentopdf
|
||||
ports:
|
||||
- '3000:8080'
|
||||
environment:
|
||||
- PUID=1000
|
||||
- PGID=1000
|
||||
restart: unless-stopped
|
||||
```
|
||||
|
||||
### How It Works
|
||||
|
||||
The container starts as root, creates a user with the specified PUID/PGID, adjusts ownership on all writable directories, then drops privileges using `su-exec`. The nginx process runs entirely as your specified user.
|
||||
|
||||
> [!NOTE]
|
||||
> The standard `Dockerfile` uses `nginx-unprivileged` (UID 101) and is recommended for most deployments. Use `Dockerfile.nonroot` only when you need a specific UID/GID.
|
||||
|
||||
> [!WARNING]
|
||||
> PUID/PGID cannot be `0` (root). The entrypoint validates inputs and will exit with an error for invalid values.
|
||||
|
||||
## With Traefik (Reverse Proxy)
|
||||
|
||||
```yaml
|
||||
|
||||
42
entrypoint.sh
Normal file
42
entrypoint.sh
Normal file
@@ -0,0 +1,42 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
PUID=${PUID:-1000}
|
||||
PGID=${PGID:-1000}
|
||||
|
||||
# Validate PUID/PGID
|
||||
case "$PUID" in
|
||||
''|*[!0-9]*) echo "ERROR: PUID must be a number, got '$PUID'" >&2; exit 1 ;;
|
||||
esac
|
||||
case "$PGID" in
|
||||
''|*[!0-9]*) echo "ERROR: PGID must be a number, got '$PGID'" >&2; exit 1 ;;
|
||||
esac
|
||||
if [ "$PUID" -eq 0 ] || [ "$PGID" -eq 0 ]; then
|
||||
echo "ERROR: PUID/PGID cannot be 0 (root). Use the standard Dockerfile instead." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Starting BentoPDF with PUID=$PUID PGID=$PGID"
|
||||
|
||||
addgroup -g "$PGID" bentopdf 2>/dev/null || true
|
||||
adduser -u "$PUID" -G bentopdf -D -H -s /sbin/nologin bentopdf 2>/dev/null || true
|
||||
|
||||
rm -f /var/log/nginx/error.log /var/log/nginx/access.log
|
||||
touch /var/log/nginx/error.log /var/log/nginx/access.log
|
||||
chown "$PUID:$PGID" /var/log/nginx /var/log/nginx/error.log /var/log/nginx/access.log
|
||||
|
||||
sed -i '1i error_log stderr warn;' /etc/nginx/nginx.conf
|
||||
sed -i '/^http {/a\ access_log /var/log/nginx/access.log;' /etc/nginx/nginx.conf
|
||||
|
||||
chown -R "$PUID:$PGID" \
|
||||
/etc/nginx/tmp \
|
||||
/var/cache/nginx \
|
||||
/usr/share/nginx/html \
|
||||
/etc/nginx/nginx.conf
|
||||
|
||||
if [ "$DISABLE_IPV6" = "true" ]; then
|
||||
echo "Disabling Nginx IPv6 listener"
|
||||
sed -i '/^[[:space:]]*listen[[:space:]]*\[::\]:[0-9]*/s/^/#/' /etc/nginx/nginx.conf
|
||||
fi
|
||||
|
||||
exec su-exec "$PUID:$PGID" "$@"
|
||||
@@ -69,6 +69,11 @@ export const getLanguageFromUrl = (): SupportedLanguage => {
|
||||
return storedLang as SupportedLanguage;
|
||||
}
|
||||
|
||||
const envLang = import.meta.env.VITE_DEFAULT_LANGUAGE;
|
||||
if (envLang && supportedLanguages.includes(envLang as SupportedLanguage)) {
|
||||
return envLang as SupportedLanguage;
|
||||
}
|
||||
|
||||
return 'en';
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user