feat: Add VitePress docs, EPUB to PDF tool, Phosphor icons, and licensing updates
- Set up VitePress documentation site (docs:dev, docs:build, docs:preview) - Added Getting Started, Tools Reference, Contributing, and Commercial License pages - Created self-hosting guides for Docker, Vercel, Netlify, Cloudflare, AWS, Hostinger, Nginx, Apache - Updated README with documentation link, sponsors section, and docs contribution guide - Added EPUB to PDF converter using LibreOffice WASM - Migrated to Phosphor Icons for consistent iconography - Added donation ribbon banner on landing page - Removed 'Like My Work?' section (replaced by ribbon) - Updated licensing.html with delivery model, AGPL notice, invoicing, and no-refund policy - Added Commercial License documentation page - Updated translations table (Chinese added, marked non-English as In Progress) - Added sponsors.yml workflow for auto-generating sponsor avatars
This commit is contained in:
158
docs/self-hosting/apache.md
Normal file
158
docs/self-hosting/apache.md
Normal file
@@ -0,0 +1,158 @@
|
||||
# Deploy with Apache
|
||||
|
||||
Host BentoPDF using Apache HTTP Server.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Apache 2.4+
|
||||
- mod_rewrite enabled
|
||||
- SSL certificate (recommended)
|
||||
|
||||
## Step 1: Build the Project
|
||||
|
||||
```bash
|
||||
git clone https://github.com/bentopdf/bentopdf.git
|
||||
cd bentopdf
|
||||
npm install
|
||||
npm run build
|
||||
```
|
||||
|
||||
## Step 2: Copy Files
|
||||
|
||||
```bash
|
||||
sudo mkdir -p /var/www/bentopdf
|
||||
sudo cp -r dist/* /var/www/bentopdf/
|
||||
sudo chown -R www-data:www-data /var/www/bentopdf
|
||||
```
|
||||
|
||||
## Step 3: Apache Configuration
|
||||
|
||||
Create `/etc/apache2/sites-available/bentopdf.conf`:
|
||||
|
||||
```apache
|
||||
<VirtualHost *:80>
|
||||
ServerName your-domain.com
|
||||
Redirect permanent / https://your-domain.com/
|
||||
</VirtualHost>
|
||||
|
||||
<VirtualHost *:443>
|
||||
ServerName your-domain.com
|
||||
DocumentRoot /var/www/bentopdf
|
||||
|
||||
SSLEngine on
|
||||
SSLCertificateFile /etc/letsencrypt/live/your-domain.com/fullchain.pem
|
||||
SSLCertificateKeyFile /etc/letsencrypt/live/your-domain.com/privkey.pem
|
||||
|
||||
<Directory /var/www/bentopdf>
|
||||
Options -Indexes +FollowSymLinks
|
||||
AllowOverride All
|
||||
Require all granted
|
||||
</Directory>
|
||||
|
||||
# WASM MIME type
|
||||
AddType application/wasm .wasm
|
||||
|
||||
# Compression
|
||||
<IfModule mod_deflate.c>
|
||||
AddOutputFilterByType DEFLATE text/html text/plain text/css application/javascript application/json application/wasm
|
||||
</IfModule>
|
||||
|
||||
# Cache headers
|
||||
<IfModule mod_expires.c>
|
||||
ExpiresActive On
|
||||
ExpiresByType application/javascript "access plus 1 year"
|
||||
ExpiresByType text/css "access plus 1 year"
|
||||
ExpiresByType application/wasm "access plus 1 year"
|
||||
ExpiresByType image/png "access plus 1 year"
|
||||
ExpiresByType image/svg+xml "access plus 1 year"
|
||||
</IfModule>
|
||||
|
||||
# Security headers
|
||||
Header always set X-Frame-Options "SAMEORIGIN"
|
||||
Header always set X-Content-Type-Options "nosniff"
|
||||
</VirtualHost>
|
||||
```
|
||||
|
||||
## Step 4: .htaccess for SPA Routing
|
||||
|
||||
Create `/var/www/bentopdf/.htaccess`:
|
||||
|
||||
```apache
|
||||
<IfModule mod_rewrite.c>
|
||||
RewriteEngine On
|
||||
RewriteBase /
|
||||
|
||||
# Don't rewrite files or directories
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteCond %{REQUEST_FILENAME} !-d
|
||||
|
||||
# Rewrite everything else to index.html
|
||||
RewriteRule ^ index.html [L]
|
||||
</IfModule>
|
||||
```
|
||||
|
||||
## Step 5: Enable Required Modules
|
||||
|
||||
```bash
|
||||
sudo a2enmod rewrite
|
||||
sudo a2enmod ssl
|
||||
sudo a2enmod headers
|
||||
sudo a2enmod expires
|
||||
sudo a2enmod deflate
|
||||
```
|
||||
|
||||
## Step 6: Enable the Site
|
||||
|
||||
```bash
|
||||
sudo a2ensite bentopdf.conf
|
||||
sudo apache2ctl configtest
|
||||
sudo systemctl reload apache2
|
||||
```
|
||||
|
||||
## Subdirectory Deployment
|
||||
|
||||
To host at `/pdf/`:
|
||||
|
||||
1. Build with base URL:
|
||||
|
||||
```bash
|
||||
BASE_URL=/pdf/ npm run build
|
||||
```
|
||||
|
||||
2. Update `.htaccess`:
|
||||
|
||||
```apache
|
||||
<IfModule mod_rewrite.c>
|
||||
RewriteEngine On
|
||||
RewriteBase /pdf/
|
||||
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteCond %{REQUEST_FILENAME} !-d
|
||||
RewriteRule ^ index.html [L]
|
||||
</IfModule>
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### WASM 404 Errors
|
||||
|
||||
Ensure MIME type is configured:
|
||||
|
||||
```apache
|
||||
AddType application/wasm .wasm
|
||||
```
|
||||
|
||||
### Rewrite Not Working
|
||||
|
||||
Check that mod_rewrite is enabled:
|
||||
|
||||
```bash
|
||||
sudo a2enmod rewrite
|
||||
```
|
||||
|
||||
### Permission Denied
|
||||
|
||||
```bash
|
||||
sudo chown -R www-data:www-data /var/www/bentopdf
|
||||
sudo chmod -R 755 /var/www/bentopdf
|
||||
```
|
||||
132
docs/self-hosting/aws.md
Normal file
132
docs/self-hosting/aws.md
Normal file
@@ -0,0 +1,132 @@
|
||||
# Deploy to AWS S3 + CloudFront
|
||||
|
||||
Host BentoPDF on AWS for maximum control and scalability.
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
User → CloudFront (CDN) → S3 (Static Files)
|
||||
```
|
||||
|
||||
## Step 1: Create S3 Bucket
|
||||
|
||||
```bash
|
||||
# Create bucket
|
||||
aws s3 mb s3://your-bentopdf-bucket --region us-east-1
|
||||
|
||||
# Enable static website hosting
|
||||
aws s3 website s3://your-bentopdf-bucket \
|
||||
--index-document index.html \
|
||||
--error-document index.html
|
||||
```
|
||||
|
||||
## Step 2: Build and Upload
|
||||
|
||||
```bash
|
||||
# Build the project
|
||||
npm run build
|
||||
|
||||
# Sync to S3
|
||||
aws s3 sync dist/ s3://your-bentopdf-bucket \
|
||||
--delete \
|
||||
--cache-control "max-age=31536000"
|
||||
|
||||
# Set correct MIME types for WASM
|
||||
aws s3 cp s3://your-bentopdf-bucket/ s3://your-bentopdf-bucket/ \
|
||||
--recursive \
|
||||
--exclude "*" \
|
||||
--include "*.wasm" \
|
||||
--content-type "application/wasm" \
|
||||
--metadata-directive REPLACE
|
||||
```
|
||||
|
||||
## Step 3: Create CloudFront Distribution
|
||||
|
||||
```bash
|
||||
aws cloudfront create-distribution \
|
||||
--origin-domain-name your-bentopdf-bucket.s3.amazonaws.com \
|
||||
--default-root-object index.html
|
||||
```
|
||||
|
||||
Or use the AWS Console:
|
||||
|
||||
1. Go to CloudFront → Create distribution
|
||||
2. Origin domain: Select your S3 bucket
|
||||
3. Enable "Origin Access Control"
|
||||
4. Default root object: `index.html`
|
||||
5. Create distribution
|
||||
|
||||
## Step 4: S3 Bucket Policy
|
||||
|
||||
Allow CloudFront to access the bucket:
|
||||
|
||||
```json
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Sid": "AllowCloudFrontAccess",
|
||||
"Effect": "Allow",
|
||||
"Principal": {
|
||||
"Service": "cloudfront.amazonaws.com"
|
||||
},
|
||||
"Action": "s3:GetObject",
|
||||
"Resource": "arn:aws:s3:::your-bentopdf-bucket/*",
|
||||
"Condition": {
|
||||
"StringEquals": {
|
||||
"AWS:SourceArn": "arn:aws:cloudfront::ACCOUNT_ID:distribution/DISTRIBUTION_ID"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Step 5: Custom Error Pages
|
||||
|
||||
Configure 404 to return `index.html` for SPA routing:
|
||||
|
||||
1. CloudFront → Error pages
|
||||
2. Create custom error response:
|
||||
- HTTP error code: 404
|
||||
- Response page path: `/index.html`
|
||||
- HTTP response code: 200
|
||||
|
||||
## Cost Estimation
|
||||
|
||||
| Resource | Estimated Cost |
|
||||
|----------|----------------|
|
||||
| S3 Storage (~500MB) | ~$0.01/month |
|
||||
| CloudFront (1TB transfer) | ~$85/month |
|
||||
| CloudFront (10GB transfer) | ~$0.85/month |
|
||||
|
||||
::: tip
|
||||
Use S3 Intelligent Tiering for cost optimization on infrequently accessed files.
|
||||
:::
|
||||
|
||||
## Automation with Terraform
|
||||
|
||||
```hcl
|
||||
# main.tf
|
||||
resource "aws_s3_bucket" "bentopdf" {
|
||||
bucket = "your-bentopdf-bucket"
|
||||
}
|
||||
|
||||
resource "aws_cloudfront_distribution" "bentopdf" {
|
||||
origin {
|
||||
domain_name = aws_s3_bucket.bentopdf.bucket_regional_domain_name
|
||||
origin_id = "S3Origin"
|
||||
}
|
||||
|
||||
enabled = true
|
||||
default_root_object = "index.html"
|
||||
|
||||
default_cache_behavior {
|
||||
allowed_methods = ["GET", "HEAD"]
|
||||
cached_methods = ["GET", "HEAD"]
|
||||
target_origin_id = "S3Origin"
|
||||
|
||||
viewer_protocol_policy = "redirect-to-https"
|
||||
}
|
||||
}
|
||||
```
|
||||
78
docs/self-hosting/cloudflare.md
Normal file
78
docs/self-hosting/cloudflare.md
Normal file
@@ -0,0 +1,78 @@
|
||||
# Deploy to Cloudflare Pages
|
||||
|
||||
[Cloudflare Pages](https://pages.cloudflare.com) offers fast, global static site hosting with unlimited bandwidth.
|
||||
|
||||
## Quick Deploy
|
||||
|
||||
1. Go to [Cloudflare Pages](https://dash.cloudflare.com/?to=/:account/pages)
|
||||
2. Click "Create a project"
|
||||
3. Connect your GitHub repository
|
||||
|
||||
## Build Configuration
|
||||
|
||||
| Setting | Value |
|
||||
|---------|-------|
|
||||
| Framework preset | None |
|
||||
| Build command | `npm run build` |
|
||||
| Build output directory | `dist` |
|
||||
| Root directory | `/` |
|
||||
|
||||
## Environment Variables
|
||||
|
||||
Add these in Settings → Environment variables:
|
||||
|
||||
| Variable | Value |
|
||||
|----------|-------|
|
||||
| `NODE_VERSION` | `18` |
|
||||
| `SIMPLE_MODE` | `false` (optional) |
|
||||
|
||||
## Configuration File
|
||||
|
||||
Create `_headers` in your `public` folder:
|
||||
|
||||
```
|
||||
# Cache WASM files aggressively
|
||||
/*.wasm
|
||||
Cache-Control: public, max-age=31536000, immutable
|
||||
Content-Type: application/wasm
|
||||
|
||||
# Service worker
|
||||
/sw.js
|
||||
Cache-Control: no-cache
|
||||
```
|
||||
|
||||
Create `_redirects` for SPA routing:
|
||||
|
||||
```
|
||||
/* /index.html 200
|
||||
```
|
||||
|
||||
## Custom Domain
|
||||
|
||||
1. Go to your Pages project
|
||||
2. Click "Custom domains"
|
||||
3. Add your domain
|
||||
4. Cloudflare will auto-configure DNS if the domain is on Cloudflare
|
||||
|
||||
## Advantages
|
||||
|
||||
- **Free unlimited bandwidth**
|
||||
- **Global CDN** with 300+ edge locations
|
||||
- **Automatic HTTPS**
|
||||
- **Preview deployments** for pull requests
|
||||
- **Fast builds**
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Large File Uploads
|
||||
|
||||
Cloudflare Pages supports files up to 25 MB. WASM modules should be fine, but if you hit limits, consider:
|
||||
|
||||
```bash
|
||||
# Split large files during build
|
||||
npm run build
|
||||
```
|
||||
|
||||
### Worker Size Limits
|
||||
|
||||
If using Cloudflare Workers for advanced routing, note the 1 MB limit for free plans.
|
||||
170
docs/self-hosting/docker.md
Normal file
170
docs/self-hosting/docker.md
Normal file
@@ -0,0 +1,170 @@
|
||||
# Deploy with Docker
|
||||
|
||||
The easiest way to self-host BentoPDF in a production environment.
|
||||
|
||||
## Quick Start
|
||||
|
||||
```bash
|
||||
docker run -d \
|
||||
--name bentopdf \
|
||||
-p 3000:80 \
|
||||
--restart unless-stopped \
|
||||
ghcr.io/bentopdf/bentopdf:latest
|
||||
```
|
||||
|
||||
## Docker Compose
|
||||
|
||||
Create `docker-compose.yml`:
|
||||
|
||||
```yaml
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
bentopdf:
|
||||
image: ghcr.io/bentopdf/bentopdf:latest
|
||||
container_name: bentopdf
|
||||
ports:
|
||||
- "3000:80"
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:80"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
```
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
## Build Your Own Image
|
||||
|
||||
```dockerfile
|
||||
# Dockerfile
|
||||
FROM node:20-alpine AS builder
|
||||
WORKDIR /app
|
||||
COPY package*.json ./
|
||||
RUN npm ci
|
||||
COPY . .
|
||||
RUN npm run build
|
||||
|
||||
FROM nginx:alpine
|
||||
COPY --from=builder /app/dist /usr/share/nginx/html
|
||||
COPY nginx.conf /etc/nginx/nginx.conf
|
||||
EXPOSE 80
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
```
|
||||
|
||||
Build and run:
|
||||
|
||||
```bash
|
||||
docker build -t bentopdf:custom .
|
||||
docker run -d -p 3000:80 bentopdf:custom
|
||||
```
|
||||
|
||||
## Environment Variables
|
||||
|
||||
| Variable | Description | Default |
|
||||
|----------|-------------|---------|
|
||||
| `SIMPLE_MODE` | Build without LibreOffice tools | `false` |
|
||||
| `BASE_URL` | Deploy to subdirectory | `/` |
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
docker run -d \
|
||||
-e SIMPLE_MODE=true \
|
||||
-p 3000:80 \
|
||||
ghcr.io/bentopdf/bentopdf:latest
|
||||
```
|
||||
|
||||
## With Traefik (Reverse Proxy)
|
||||
|
||||
```yaml
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
traefik:
|
||||
image: traefik:v2.10
|
||||
command:
|
||||
- "--providers.docker=true"
|
||||
- "--entrypoints.web.address=:80"
|
||||
- "--entrypoints.websecure.address=:443"
|
||||
- "--certificatesresolvers.letsencrypt.acme.email=you@example.com"
|
||||
- "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json"
|
||||
- "--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web"
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
- ./letsencrypt:/letsencrypt
|
||||
|
||||
bentopdf:
|
||||
image: ghcr.io/bentopdf/bentopdf:latest
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.bentopdf.rule=Host(`pdf.example.com`)"
|
||||
- "traefik.http.routers.bentopdf.entrypoints=websecure"
|
||||
- "traefik.http.routers.bentopdf.tls.certresolver=letsencrypt"
|
||||
restart: unless-stopped
|
||||
```
|
||||
|
||||
## With Caddy (Reverse Proxy)
|
||||
|
||||
```yaml
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
caddy:
|
||||
image: caddy:2
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
volumes:
|
||||
- ./Caddyfile:/etc/caddy/Caddyfile
|
||||
- caddy_data:/data
|
||||
|
||||
bentopdf:
|
||||
image: ghcr.io/bentopdf/bentopdf:latest
|
||||
restart: unless-stopped
|
||||
|
||||
volumes:
|
||||
caddy_data:
|
||||
```
|
||||
|
||||
Caddyfile:
|
||||
|
||||
```
|
||||
pdf.example.com {
|
||||
reverse_proxy bentopdf:80
|
||||
}
|
||||
```
|
||||
|
||||
## Resource Limits
|
||||
|
||||
```yaml
|
||||
services:
|
||||
bentopdf:
|
||||
image: ghcr.io/bentopdf/bentopdf:latest
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
cpus: '1'
|
||||
memory: 512M
|
||||
reservations:
|
||||
cpus: '0.25'
|
||||
memory: 128M
|
||||
```
|
||||
|
||||
## Updating
|
||||
|
||||
```bash
|
||||
# Pull latest image
|
||||
docker compose pull
|
||||
|
||||
# Recreate container
|
||||
docker compose up -d
|
||||
```
|
||||
223
docs/self-hosting/hostinger.md
Normal file
223
docs/self-hosting/hostinger.md
Normal file
@@ -0,0 +1,223 @@
|
||||
# Deploy to Hostinger
|
||||
|
||||
[Hostinger](https://hostinger.com) is a popular shared hosting provider. This guide covers deploying BentoPDF to Hostinger's shared hosting.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Hostinger hosting plan with file manager access
|
||||
- Node.js installed locally for building
|
||||
|
||||
## Step 1: Build the Project
|
||||
|
||||
```bash
|
||||
git clone https://github.com/alam00000/bentopdf.git
|
||||
cd bentopdf
|
||||
npm install
|
||||
npm run build
|
||||
```
|
||||
|
||||
The built files will be in the `dist` folder.
|
||||
|
||||
## Step 2: Upload to Hostinger
|
||||
|
||||
### Root Domain Deployment
|
||||
|
||||
1. Log in to your Hostinger account
|
||||
2. Go to **File Manager** → **public_html**
|
||||
3. **Delete** any existing files (backup if needed)
|
||||
4. **Upload** all contents of your local `dist` folder to `public_html`
|
||||
|
||||
### Subdirectory Deployment
|
||||
|
||||
If deploying to a subdirectory (e.g., `yourdomain.com/pdf-tools/`):
|
||||
|
||||
1. Build with the correct base URL:
|
||||
|
||||
```bash
|
||||
BASE_URL=/pdf-tools/ npm run build
|
||||
```
|
||||
|
||||
2. Create the folder in Hostinger:
|
||||
- Go to **File Manager** → **public_html**
|
||||
- Create a new folder: `pdf-tools`
|
||||
|
||||
3. Upload all contents of `dist` to `public_html/pdf-tools/`
|
||||
|
||||
## Step 3: Create .htaccess File
|
||||
|
||||
Create a `.htaccess` file in the root of your deployment folder (`public_html` or `public_html/pdf-tools/`):
|
||||
|
||||
::: warning Important
|
||||
For subdirectory deployment, change `RewriteBase /` to `RewriteBase /pdf-tools/` (or your folder name).
|
||||
:::
|
||||
|
||||
```apache
|
||||
RewriteEngine On
|
||||
RewriteBase /
|
||||
|
||||
# ============================================
|
||||
# 1. SECURITY HEADERS (CRITICAL FOR WASM)
|
||||
# ============================================
|
||||
<IfModule mod_headers.c>
|
||||
Header always set X-Frame-Options "SAMEORIGIN"
|
||||
Header always set X-Content-Type-Options "nosniff"
|
||||
Header always set X-XSS-Protection "1; mode=block"
|
||||
Header always set Referrer-Policy "strict-origin-when-cross-origin"
|
||||
Header always set Permissions-Policy "geolocation=(), microphone=(), camera=()"
|
||||
|
||||
# REQUIRED for soffice.js (SharedArrayBuffer)
|
||||
Header always set Cross-Origin-Opener-Policy "same-origin"
|
||||
Header always set Cross-Origin-Embedder-Policy "require-corp"
|
||||
</IfModule>
|
||||
|
||||
# ============================================
|
||||
# 2. BROWSER CACHING
|
||||
# ============================================
|
||||
<IfModule mod_expires.c>
|
||||
ExpiresActive On
|
||||
ExpiresByType image/jpeg "access plus 1 year"
|
||||
ExpiresByType image/png "access plus 1 year"
|
||||
ExpiresByType image/gif "access plus 1 year"
|
||||
ExpiresByType image/webp "access plus 1 year"
|
||||
ExpiresByType image/svg+xml "access plus 1 year"
|
||||
ExpiresByType image/x-icon "access plus 1 year"
|
||||
ExpiresByType font/woff2 "access plus 1 year"
|
||||
ExpiresByType font/woff "access plus 1 year"
|
||||
ExpiresByType font/ttf "access plus 1 year"
|
||||
ExpiresByType text/css "access plus 1 month"
|
||||
ExpiresByType application/javascript "access plus 1 month"
|
||||
ExpiresByType application/wasm "access plus 1 year"
|
||||
ExpiresByType application/gzip "access plus 1 year"
|
||||
ExpiresByType text/html "access plus 0 seconds"
|
||||
</IfModule>
|
||||
|
||||
# ============================================
|
||||
# 3. COMPRESSION (STANDARD)
|
||||
# ============================================
|
||||
# Prevent server from double-compressing files
|
||||
SetEnvIfNoCase Request_URI "\.gz$" no-gzip
|
||||
SetEnvIfNoCase Request_URI "\.br$" no-gzip
|
||||
SetEnvIfNoCase Request_URI "\.wasm$" no-gzip
|
||||
|
||||
<IfModule mod_deflate.c>
|
||||
AddOutputFilterByType DEFLATE text/plain
|
||||
AddOutputFilterByType DEFLATE text/html
|
||||
AddOutputFilterByType DEFLATE text/xml
|
||||
AddOutputFilterByType DEFLATE text/css
|
||||
AddOutputFilterByType DEFLATE application/xml
|
||||
AddOutputFilterByType DEFLATE application/xhtml+xml
|
||||
AddOutputFilterByType DEFLATE application/rss+xml
|
||||
AddOutputFilterByType DEFLATE application/javascript
|
||||
AddOutputFilterByType DEFLATE application/x-javascript
|
||||
AddOutputFilterByType DEFLATE application/json
|
||||
AddOutputFilterByType DEFLATE image/svg+xml
|
||||
AddOutputFilterByType DEFLATE font/woff
|
||||
AddOutputFilterByType DEFLATE font/ttf
|
||||
</IfModule>
|
||||
|
||||
# ============================================
|
||||
# 4. MIME TYPES & SPECIAL FILE HANDLING
|
||||
# ============================================
|
||||
AddType application/javascript .js .mjs
|
||||
AddType application/wasm .wasm
|
||||
AddType font/woff2 .woff2
|
||||
AddType font/woff .woff
|
||||
AddType image/webp .webp
|
||||
|
||||
# Handle soffice.wasm.gz correctly
|
||||
<FilesMatch "soffice\.wasm\.gz$">
|
||||
ForceType application/wasm
|
||||
Header set Content-Encoding "gzip"
|
||||
Header set Cross-Origin-Resource-Policy "cross-origin"
|
||||
Header append Vary Accept-Encoding
|
||||
</FilesMatch>
|
||||
|
||||
# Handle data.gz
|
||||
<FilesMatch "soffice\.data\.gz$">
|
||||
ForceType application/octet-stream
|
||||
Header set Content-Encoding "gzip"
|
||||
Header append Vary Accept-Encoding
|
||||
</FilesMatch>
|
||||
|
||||
# ============================================
|
||||
# 5. REDIRECTS & ROUTING
|
||||
# ============================================
|
||||
# Canonical WWW (update domain name)
|
||||
RewriteCond %{HTTP_HOST} ^yourdomain\.com [NC]
|
||||
RewriteRule ^(.*)$ https://www.yourdomain.com/$1 [L,R=301]
|
||||
|
||||
# Force HTTPS
|
||||
RewriteCond %{HTTPS} off
|
||||
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
|
||||
|
||||
# Remove trailing slash
|
||||
RewriteCond %{REQUEST_FILENAME} !-d
|
||||
RewriteCond %{REQUEST_URI} (.+)/$
|
||||
RewriteRule ^ %1 [R=301,L]
|
||||
|
||||
# Existing files/dirs
|
||||
RewriteCond %{REQUEST_FILENAME} -f [OR]
|
||||
RewriteCond %{REQUEST_FILENAME} -d
|
||||
RewriteRule ^ - [L]
|
||||
|
||||
# Language routes
|
||||
RewriteRule ^(de|en)$ /$1/ [R=301,L]
|
||||
RewriteRule ^(de|en|zh|vi)/(.*)$ /$2 [L]
|
||||
|
||||
# SPA Fallback
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteCond %{REQUEST_FILENAME} !-d
|
||||
RewriteRule ^ /index.html [L]
|
||||
|
||||
ErrorDocument 404 /index.html
|
||||
```
|
||||
|
||||
## Subdirectory .htaccess Example
|
||||
|
||||
For `yourdomain.com/pdf-tools/`, update these lines:
|
||||
|
||||
```apache
|
||||
RewriteBase /pdf-tools/
|
||||
|
||||
# ... (same content) ...
|
||||
|
||||
# SPA Fallback - update path
|
||||
RewriteRule ^ /pdf-tools/index.html [L]
|
||||
|
||||
ErrorDocument 404 /pdf-tools/index.html
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### WASM Files Not Loading
|
||||
|
||||
Ensure the MIME types are correctly set in `.htaccess`:
|
||||
|
||||
```apache
|
||||
AddType application/wasm .wasm
|
||||
```
|
||||
|
||||
### LibreOffice Tools Not Working
|
||||
|
||||
The security headers are critical for SharedArrayBuffer:
|
||||
|
||||
```apache
|
||||
Header always set Cross-Origin-Opener-Policy "same-origin"
|
||||
Header always set Cross-Origin-Embedder-Policy "require-corp"
|
||||
```
|
||||
|
||||
If headers aren't being applied, contact Hostinger support to enable `mod_headers`.
|
||||
|
||||
### 404 Errors on Page Refresh
|
||||
|
||||
Make sure the SPA fallback rule is at the end of your `.htaccess`:
|
||||
|
||||
```apache
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteCond %{REQUEST_FILENAME} !-d
|
||||
RewriteRule ^ /index.html [L]
|
||||
```
|
||||
|
||||
### File Upload Limits
|
||||
|
||||
Hostinger may have file size limits. Upload WASM files separately if bulk upload fails.
|
||||
96
docs/self-hosting/index.md
Normal file
96
docs/self-hosting/index.md
Normal file
@@ -0,0 +1,96 @@
|
||||
# Self-Hosting Guide
|
||||
|
||||
BentoPDF can be self-hosted on your own infrastructure. This guide covers various deployment options.
|
||||
|
||||
## Quick Start with Docker
|
||||
|
||||
The fastest way to self-host BentoPDF:
|
||||
|
||||
```bash
|
||||
docker run -d -p 3000:80 ghcr.io/bentopdf/bentopdf:latest
|
||||
```
|
||||
|
||||
Or with Docker Compose:
|
||||
|
||||
```yaml
|
||||
# docker-compose.yml
|
||||
version: '3.8'
|
||||
services:
|
||||
bentopdf:
|
||||
image: ghcr.io/bentopdf/bentopdf:latest
|
||||
ports:
|
||||
- "3000:80"
|
||||
restart: unless-stopped
|
||||
```
|
||||
|
||||
```bash
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
## Building from Source
|
||||
|
||||
```bash
|
||||
# Clone and build
|
||||
git clone https://github.com/bentopdf/bentopdf.git
|
||||
cd bentopdf
|
||||
npm install
|
||||
npm run build
|
||||
|
||||
# The built files are in the `dist` folder
|
||||
```
|
||||
|
||||
## Configuration Options
|
||||
|
||||
### Simple Mode
|
||||
|
||||
Simple Mode is designed for internal organizational use where you want to hide all branding and marketing content, showing only the essential PDF tools.
|
||||
|
||||
**What Simple Mode hides:**
|
||||
- Navigation bar
|
||||
- Hero section with marketing content
|
||||
- Features, FAQ, testimonials sections
|
||||
- Footer
|
||||
- Updates page title to "PDF Tools"
|
||||
|
||||
```bash
|
||||
# Build with Simple Mode
|
||||
SIMPLE_MODE=true npm run build
|
||||
|
||||
# Or use the pre-built Docker image
|
||||
docker run -p 3000:8080 bentopdf/bentopdf-simple:latest
|
||||
```
|
||||
|
||||
See [SIMPLE_MODE.md](https://github.com/bentopdf/bentopdf/blob/main/SIMPLE_MODE.md) for full details.
|
||||
|
||||
### Base URL
|
||||
|
||||
Deploy to a subdirectory:
|
||||
|
||||
```bash
|
||||
BASE_URL=/pdf-tools/ npm run build
|
||||
```
|
||||
|
||||
## Deployment Guides
|
||||
|
||||
Choose your platform:
|
||||
|
||||
- [Vercel](/self-hosting/vercel)
|
||||
- [Netlify](/self-hosting/netlify)
|
||||
- [Cloudflare Pages](/self-hosting/cloudflare)
|
||||
- [AWS S3 + CloudFront](/self-hosting/aws)
|
||||
- [Hostinger](/self-hosting/hostinger)
|
||||
- [Nginx](/self-hosting/nginx)
|
||||
- [Apache](/self-hosting/apache)
|
||||
- [Docker](/self-hosting/docker)
|
||||
|
||||
## System Requirements
|
||||
|
||||
| Requirement | Minimum |
|
||||
|-------------|---------|
|
||||
| Storage | ~500 MB (with all WASM modules) |
|
||||
| RAM | 512 MB |
|
||||
| CPU | Any modern processor |
|
||||
|
||||
::: tip
|
||||
BentoPDF is a static site—there's no database or backend server required!
|
||||
:::
|
||||
92
docs/self-hosting/netlify.md
Normal file
92
docs/self-hosting/netlify.md
Normal file
@@ -0,0 +1,92 @@
|
||||
# Deploy to Netlify
|
||||
|
||||
[Netlify](https://netlify.com) provides excellent static site hosting with a generous free tier.
|
||||
|
||||
## One-Click Deploy
|
||||
|
||||
[](https://app.netlify.com/start/deploy?repository=https://github.com/bentopdf/bentopdf)
|
||||
|
||||
## Manual Deployment
|
||||
|
||||
### Step 1: Connect Repository
|
||||
|
||||
1. Log in to [Netlify](https://app.netlify.com)
|
||||
2. Click "Add new site" → "Import an existing project"
|
||||
3. Connect your GitHub account
|
||||
4. Select your BentoPDF fork
|
||||
|
||||
### Step 2: Configure Build Settings
|
||||
|
||||
| Setting | Value |
|
||||
|---------|-------|
|
||||
| Build command | `npm run build` |
|
||||
| Publish directory | `dist` |
|
||||
| Node version | 18+ |
|
||||
|
||||
### Step 3: Deploy
|
||||
|
||||
Click "Deploy site" and wait for the build.
|
||||
|
||||
## Configuration File
|
||||
|
||||
Create `netlify.toml` in your project root:
|
||||
|
||||
```toml
|
||||
[build]
|
||||
command = "npm run build"
|
||||
publish = "dist"
|
||||
|
||||
[build.environment]
|
||||
NODE_VERSION = "18"
|
||||
|
||||
# SPA routing
|
||||
[[redirects]]
|
||||
from = "/*"
|
||||
to = "/index.html"
|
||||
status = 200
|
||||
|
||||
# Cache WASM files
|
||||
[[headers]]
|
||||
for = "*.wasm"
|
||||
[headers.values]
|
||||
Cache-Control = "public, max-age=31536000, immutable"
|
||||
Content-Type = "application/wasm"
|
||||
```
|
||||
|
||||
## Environment Variables
|
||||
|
||||
Set these in Site settings → Environment variables:
|
||||
|
||||
| Variable | Description |
|
||||
|----------|-------------|
|
||||
| `SIMPLE_MODE` | Set to `true` for minimal build |
|
||||
|
||||
## Custom Domain
|
||||
|
||||
1. Go to Site settings → Domain management
|
||||
2. Click "Add custom domain"
|
||||
3. Follow DNS configuration instructions
|
||||
|
||||
## Large Media
|
||||
|
||||
For large WASM files, consider enabling [Netlify Large Media](https://docs.netlify.com/large-media/overview/):
|
||||
|
||||
```bash
|
||||
netlify lm:setup
|
||||
git lfs track "*.wasm"
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Build Fails
|
||||
|
||||
Check Node version compatibility:
|
||||
|
||||
```toml
|
||||
[build.environment]
|
||||
NODE_VERSION = "20"
|
||||
```
|
||||
|
||||
### Slow Initial Load
|
||||
|
||||
Enable asset optimization in Site settings → Build & deploy → Asset optimization.
|
||||
147
docs/self-hosting/nginx.md
Normal file
147
docs/self-hosting/nginx.md
Normal file
@@ -0,0 +1,147 @@
|
||||
# Deploy with Nginx
|
||||
|
||||
Host BentoPDF on your own server using Nginx.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Ubuntu/Debian server
|
||||
- Nginx installed
|
||||
- SSL certificate (recommended: Let's Encrypt)
|
||||
|
||||
## Step 1: Build the Project
|
||||
|
||||
```bash
|
||||
git clone https://github.com/bentopdf/bentopdf.git
|
||||
cd bentopdf
|
||||
npm install
|
||||
npm run build
|
||||
```
|
||||
|
||||
## Step 2: Copy Files
|
||||
|
||||
```bash
|
||||
sudo mkdir -p /var/www/bentopdf
|
||||
sudo cp -r dist/* /var/www/bentopdf/
|
||||
sudo chown -R www-data:www-data /var/www/bentopdf
|
||||
```
|
||||
|
||||
## Step 3: Nginx Configuration
|
||||
|
||||
Create `/etc/nginx/sites-available/bentopdf`:
|
||||
|
||||
```nginx
|
||||
server {
|
||||
listen 80;
|
||||
server_name your-domain.com;
|
||||
return 301 https://$server_name$request_uri;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 443 ssl http2;
|
||||
server_name your-domain.com;
|
||||
|
||||
# SSL Configuration
|
||||
ssl_certificate /etc/letsencrypt/live/your-domain.com/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/your-domain.com/privkey.pem;
|
||||
|
||||
root /var/www/bentopdf;
|
||||
index index.html;
|
||||
|
||||
# Gzip compression
|
||||
gzip on;
|
||||
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/wasm;
|
||||
gzip_min_length 1000;
|
||||
|
||||
# WASM MIME type
|
||||
types {
|
||||
application/wasm wasm;
|
||||
}
|
||||
|
||||
# Cache static assets
|
||||
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|wasm)$ {
|
||||
expires 1y;
|
||||
add_header Cache-Control "public, immutable";
|
||||
}
|
||||
|
||||
# SPA routing - serve index.html for all routes
|
||||
location / {
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
|
||||
# Security headers
|
||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
add_header X-XSS-Protection "1; mode=block" always;
|
||||
}
|
||||
```
|
||||
|
||||
## Step 4: Enable the Site
|
||||
|
||||
```bash
|
||||
sudo ln -s /etc/nginx/sites-available/bentopdf /etc/nginx/sites-enabled/
|
||||
sudo nginx -t
|
||||
sudo systemctl reload nginx
|
||||
```
|
||||
|
||||
## Step 5: SSL with Let's Encrypt
|
||||
|
||||
```bash
|
||||
sudo apt install certbot python3-certbot-nginx
|
||||
sudo certbot --nginx -d your-domain.com
|
||||
```
|
||||
|
||||
## Subdirectory Deployment
|
||||
|
||||
To host at `/pdf/`:
|
||||
|
||||
```nginx
|
||||
location /pdf/ {
|
||||
alias /var/www/bentopdf/;
|
||||
try_files $uri $uri/ /pdf/index.html;
|
||||
}
|
||||
```
|
||||
|
||||
Build with:
|
||||
|
||||
```bash
|
||||
BASE_URL=/pdf/ npm run build
|
||||
```
|
||||
|
||||
## Performance Tuning
|
||||
|
||||
Add to `nginx.conf`:
|
||||
|
||||
```nginx
|
||||
http {
|
||||
# Enable sendfile
|
||||
sendfile on;
|
||||
tcp_nopush on;
|
||||
tcp_nodelay on;
|
||||
|
||||
# Increase buffer sizes
|
||||
client_max_body_size 100M;
|
||||
|
||||
# Worker connections
|
||||
worker_connections 2048;
|
||||
}
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### WASM Not Loading
|
||||
|
||||
Ensure MIME type is set:
|
||||
|
||||
```nginx
|
||||
types {
|
||||
application/wasm wasm;
|
||||
}
|
||||
```
|
||||
|
||||
### 502 Bad Gateway
|
||||
|
||||
Check Nginx error logs:
|
||||
|
||||
```bash
|
||||
sudo tail -f /var/log/nginx/error.log
|
||||
```
|
||||
75
docs/self-hosting/vercel.md
Normal file
75
docs/self-hosting/vercel.md
Normal file
@@ -0,0 +1,75 @@
|
||||
# Deploy to Vercel
|
||||
|
||||
[Vercel](https://vercel.com) offers the easiest deployment experience for static sites.
|
||||
|
||||
## One-Click Deploy
|
||||
|
||||
[](https://vercel.com/new/clone?repository-url=https://github.com/bentopdf/bentopdf)
|
||||
|
||||
## Manual Deployment
|
||||
|
||||
### Step 1: Fork the Repository
|
||||
|
||||
Fork [bentopdf/bentopdf](https://github.com/bentopdf/bentopdf) to your GitHub account.
|
||||
|
||||
### Step 2: Import to Vercel
|
||||
|
||||
1. Go to [vercel.com/new](https://vercel.com/new)
|
||||
2. Select your forked repository
|
||||
3. Configure the project:
|
||||
|
||||
| Setting | Value |
|
||||
|---------|-------|
|
||||
| Framework Preset | Vite |
|
||||
| Build Command | `npm run build` |
|
||||
| Output Directory | `dist` |
|
||||
| Install Command | `npm install` |
|
||||
|
||||
### Step 3: Environment Variables (Optional)
|
||||
|
||||
Add these if needed:
|
||||
|
||||
```
|
||||
SIMPLE_MODE=false
|
||||
```
|
||||
|
||||
### Step 4: Deploy
|
||||
|
||||
Click "Deploy" and wait for the build to complete.
|
||||
|
||||
## Custom Domain
|
||||
|
||||
1. Go to your project settings
|
||||
2. Navigate to "Domains"
|
||||
3. Add your custom domain
|
||||
4. Configure DNS as instructed
|
||||
|
||||
## Limitations
|
||||
|
||||
::: warning Large Files
|
||||
Vercel's serverless functions have a 50MB limit. Since BentoPDF is a static site, this shouldn't affect you, but WASM modules are large (~100MB total). Ensure they're served from the `/public` folder.
|
||||
:::
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Build Timeout
|
||||
|
||||
If builds timeout, try:
|
||||
|
||||
```json
|
||||
// vercel.json
|
||||
{
|
||||
"buildCommand": "npm run build",
|
||||
"outputDirectory": "dist"
|
||||
}
|
||||
```
|
||||
|
||||
### 404 on Refresh
|
||||
|
||||
Add a `vercel.json` for SPA routing:
|
||||
|
||||
```json
|
||||
{
|
||||
"rewrites": [{ "source": "/(.*)", "destination": "/index.html" }]
|
||||
}
|
||||
```
|
||||
Reference in New Issue
Block a user