Files
bentopdf/docs/zh-TW/self-hosting/apache.md
T

276 lines
7.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 使用 Apache 部署
使用 Apache HTTP Server 架設 BentoPDF。
## 事前準備
- Apache 2.4+
- 已啟用 mod_rewrite
- SSL 憑證(建議)
## 步驟 1:建置專案
```bash
git clone https://github.com/alam00000/bentopdf.git
cd bentopdf
npm install
npm run build
```
若要自訂品牌,請在建置前設定環境變數:
```bash
VITE_BRAND_NAME="AcmePDF" VITE_BRAND_LOGO="images/acme-logo.svg" npm run build
```
## 步驟 2:複製檔案
```bash
sudo mkdir -p /var/www/bentopdf
sudo cp -r dist/* /var/www/bentopdf/
sudo chown -R www-data:www-data /var/www/bentopdf
```
## 步驟 3:Apache 設定
建立 `/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
# Prevent double-compression of pre-compressed files
SetEnvIfNoCase Request_URI "\.gz$" no-gzip
# 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>
# Required headers for SharedArrayBuffer (LibreOffice WASM)
Header always set Cross-Origin-Embedder-Policy "require-corp"
Header always set Cross-Origin-Opener-Policy "same-origin"
Header always set Cross-Origin-Resource-Policy "cross-origin"
# Security headers
Header always set X-Frame-Options "SAMEORIGIN"
Header always set X-Content-Type-Options "nosniff"
# Pre-compressed LibreOffice WASM files
<FilesMatch "soffice\.wasm\.gz$">
ForceType application/wasm
Header set Content-Encoding "gzip"
</FilesMatch>
<FilesMatch "soffice\.data\.gz$">
ForceType application/octet-stream
Header set Content-Encoding "gzip"
</FilesMatch>
</VirtualHost>
```
## 步驟 4:用於路由的 .htaccess
建立 `/var/www/bentopdf/.htaccess`:
```apache
RewriteEngine On
RewriteBase /
# Existing files/dirs - serve directly
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]
# ============================================
# LANGUAGE ROUTES
# ============================================
# Supported languages: de, es, zh, zh-TW, vi, it, id, tr, fr, pt
# English has no prefix - served from root
# English prefix redirects to root
RewriteRule ^en/?$ / [R=301,L]
RewriteRule ^en/(.+)$ /$1 [R=301,L]
# Language prefix root (e.g., /de/ -> /de/index.html)
RewriteCond %{DOCUMENT_ROOT}/$1/index.html -f
RewriteRule ^(de|es|zh|zh-TW|vi|it|id|tr|fr|pt)/?$ /$1/index.html [L]
# Language prefix with path (e.g., /de/merge-pdf -> /de/merge-pdf.html)
RewriteCond %{DOCUMENT_ROOT}/$1/$2.html -f
RewriteRule ^(de|es|zh|zh-TW|vi|it|id|tr|fr|pt)/([^/]+)/?$ /$1/$2.html [L]
# ============================================
# ADD .HTML EXTENSION (ROOT LEVEL)
# ============================================
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}.html -f
RewriteRule ^([^/]+)$ $1.html [L]
ErrorDocument 404 /404.html
```
## 步驟 5:啟用必要模組
```bash
sudo a2enmod rewrite
sudo a2enmod ssl
sudo a2enmod headers
sudo a2enmod expires
sudo a2enmod deflate
```
## 步驟 6:啟用網站
```bash
sudo a2ensite bentopdf.conf
sudo apache2ctl configtest
sudo systemctl reload apache2
```
## 子目錄部署
若要架設在 `/pdf/`:
1. 以 base URL 建置:
```bash
BASE_URL=/pdf/ npm run build
```
2. 更新 `.htaccess`:
```apache
RewriteEngine On
RewriteBase /pdf/
# Existing files/dirs - serve directly
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]
# Language routes
RewriteRule ^en/?$ /pdf/ [R=301,L]
RewriteRule ^en/(.+)$ /pdf/$1 [R=301,L]
RewriteCond %{DOCUMENT_ROOT}/pdf/$1/index.html -f
RewriteRule ^(de|es|zh|zh-TW|vi|it|id|tr|fr|pt)/?$ /pdf/$1/index.html [L]
RewriteCond %{DOCUMENT_ROOT}/pdf/$1/$2.html -f
RewriteRule ^(de|es|zh|zh-TW|vi|it|id|tr|fr|pt)/([^/]+)/?$ /pdf/$1/$2.html [L]
# Root level .html extension
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}.html -f
RewriteRule ^([^/]+)$ $1.html [L]
ErrorDocument 404 /pdf/404.html
```
## 疑難排解
### WASM 404 錯誤
請確認已設定 MIME 類型:
```apache
AddType application/wasm .wasm
```
### 簽署 PDF 或表單填寫工具顯示空白檢視器(`.mjs` MIME 錯誤)
如果瀏覽器主控台顯示:
```
Failed to load module script: The server responded with a non-JavaScript
MIME type of "application/octet-stream". Strict MIME type checking is
enforced for module scripts per HTML spec.
```
…且失敗的請求以 `.mjs` 結尾,表示您的 Apache 設定缺少 `.mjs → application/javascript` 對應。內建的 PDF 檢視器以 `.mjs` 副檔名提供 ES module 檔案,而 Apache 內建的 `mime.types` 預設並未包含它。
加入您的 VirtualHost 或 `.htaccess`:
```apache
AddType application/javascript .mjs
```
然後重新載入 Apache:
```bash
sudo apache2ctl configtest && sudo systemctl reload apache2
```
確認方式:在瀏覽器 DevTools → Network 分頁中,找到失敗的 `.mjs` 請求並檢查 `Content-Type` 回應標頭。現在應為 `application/javascript`,而不是 `application/octet-stream`。
### Rewrite 無法運作
確認已啟用 mod_rewrite:
```bash
sudo a2enmod rewrite
```
### Word/ODT/Excel 轉 PDF 無法運作
LibreOffice WASM 需要 `SharedArrayBuffer`,而它需要以下標頭:
```apache
Header always set Cross-Origin-Embedder-Policy "require-corp"
Header always set Cross-Origin-Opener-Policy "same-origin"
```
它也需要安全環境(secure context)。`http://localhost` 可用於本機測試,但 `http://192.168.x.x` 或其他區域網路 IP 通常需要 HTTPS。如果標頭已存在但 `window.crossOriginIsolated` 仍為 `false`,請檢查頁面是否透過一般 HTTP 在非迴路位址的來源上開啟。
預先壓縮的 `.wasm.gz` 與 `.data.gz` 檔案也需要正確的 `Content-Encoding`:
```apache
<FilesMatch "soffice\.wasm\.gz$">
ForceType application/wasm
Header set Content-Encoding "gzip"
</FilesMatch>
<FilesMatch "soffice\.data\.gz$">
ForceType application/octet-stream
Header set Content-Encoding "gzip"
</FilesMatch>
```
請確認已啟用 `mod_headers`:`sudo a2enmod headers`
### 權限遭拒
```bash
sudo chown -R www-data:www-data /var/www/bentopdf
sudo chmod -R 755 /var/www/bentopdf
```