لماذا استضافة واجهة API لتوليد PDF ذاتيًا؟
خدمات PDF كـ SaaS تُحاسب لكل مستند أو صفحة أو استدعاء API. بمجرد أن يُولّد تطبيقك فواتير أو تقارير أو عقودًا بكميات كبيرة، تنمو التكلفة خطيًا مع استخدامك. Gotenberg تستبدلها بتكلفة VPS شهرية ثابتة بصرف النظر عن عدد PDF التي تُولّدها. كما تبقي مستنداتك خاصة: لا شيء يغادر بنيتك التحتية أثناء التحويل.
Gotenberg أم WeasyPrint أم Stirling-PDF أم Puppeteer؟
مرّر الجدول أفقيًا
| الأداة | صيغ المصدر | الحد الأدنى من RAM | واجهة REST | الرخصة |
|---|---|---|---|---|
| Gotenberg 8.x | HTML، URL، DOCX/ODT/XLSX، Markdown، صور | 2 GB (Chromium) | نعم — multipart/form-data | MIT |
| WeasyPrint | HTML + CSS (بدون JS) | 256 MB | لا — مكتبة Python/CLI | BSD |
| Stirling-PDF | PDF (تحرير، OCR، دمج) | 512 MB | نعم — JSON/multipart | MIT (AGPLv3 للنسخة Pro) |
| Puppeteer منفردًا | HTML + URL عبر Chrome headless | 1.5 GB | لا — مكتبة Node.js | Apache 2.0 |
ما يمكن لـ Gotenberg تحويله
- HTML إلى PDF عبر نسخة Chromium كاملة — CSS وخطوط الويب وJavaScript واستفسارات وسائط الطباعة مُكرَّمة جميعها.
- أي رابط إلى PDF — أرشف مشاهدات لوحة التحكم وأنشئ تقارير أسبوعية أو التقط إيصالات الدفع.
- مستندات LibreOffice (DOCX وXLSX وPPTX وODT وODS وODP وأكثر من 20 صيغة) إلى PDF بدون تثبيت Microsoft Office.
- Markdown إلى PDF عبر مسار Chromium مع CSS قابل للتهيئة.
- دمج عدة ملفات PDF في ملف واحد باستدعاء API واحد.
- الصور (PNG وJPEG وWebP وTIFF) محوَّلة إلى PDF.
المتطلبات
خادم VPS بـ 1 vCPU على الأقل و2 GB RAM (يستهلك Chromium وحده من 1.2 إلى 1.5 GB أثناء التصيير؛ 1 GB RAM غير كافٍ أثناء التحويل). Ubuntu 22.04 أو 24.04 مع Docker وDocker Compose v2 مثبَّتَين. يستمع Gotenberg على المنفذ 3000 افتراضيًا. لا يلزم نطاق إذا استدعيت الواجهة API من نفس الخادم — http://127.0.0.1:3000 يكفي. لكشفه لخدمات أخرى يُوصى بوكيل nginx العكسي (انظر أدناه).
نشر Gotenberg خطوة بخطوة
إنشاء ملف compose
اتصل بـ VPS عبر SSH وأنشئ مجلدًا:
mkdir gotenberg && cd gotenbergأنشئ
docker-compose.yml:services: gotenberg: image: gotenberg/gotenberg:8 restart: unless-stopped ports: - "127.0.0.1:3000:3000" command: - gotenberg - --chromium-disable-javascript=false - --api-timeout=30s - --chromium-max-queue-size=10الربط بـ
127.0.0.1يمنع الوصول المباشر من الإنترنت. في عام 2026 الإصدار المستقر هو 8.x (8.9.1 فما فوق) — الصورة:8تتبع أحدث 8.x.تشغيل الحاوية
شغّل
docker compose up -d. يسحب Gotenberg الصورة (~1.5 GB، تشمل Chromium وLibreOffice) ويشغّل خادم HTTP. تحقق من نقطة نهاية الصحة:curl http://127.0.0.1:3000/healthaستجابة
{"status":"up"}تؤكد أن الخدمة جاهزة.توليد أول PDF من HTML
أنشئ ملف HTML بسيطًا (
invoice.html) وحوّله:curl -s --request POST http://127.0.0.1:3000/forms/chromium/convert/html \ --form '[email protected]' \ -o invoice.pdfالاستجابة هي PDF كتدفق ثنائي.
تحويل مستند Word إلى PDF
ارفع ملف DOCX إلى مسار LibreOffice:
curl -s --request POST http://127.0.0.1:3000/forms/libreoffice/convert \ --form '[email protected]' \ -o contract.pdfيستخدم Gotenberg محرك LibreOffice المدمج للتحويل — لا يلزم ترخيص Microsoft Office.
إضافة المصادقة (مستحسن)
ليس لدى Gotenberg مصادقة مدمجة. النهج المستحسن: ثبّت nginx، أنشئ وكيلًا عكسيًا من
https://gotenberg.your-domain.comإلىhttp://127.0.0.1:3000، وأضف مصادقة HTTP basic. لا تكشف الخدمة أبدًا دون مصادقة على الإنترنت العام.
مسارات API وصيغها
يكشف Gotenberg عائلتين من مسارات REST، جميعها POST multipart/form-data.
مسارات Chromium — التصيير عبر متصفح headless:
- POST /forms/chromium/convert/html — التحويل من ملف HTML محلي (حقل index.html).
- POST /forms/chromium/convert/url — التحويل من رابط عام (حقل url)؛ يحمّل Chromium الصفحة كاملة بما فيها JavaScript.
- POST /forms/chromium/convert/markdown — تحويل Markdown مع ورقة أنماط اختيارية.
مسارات LibreOffice — تحويل مستندات المكتب:
- POST /forms/libreoffice/convert — يقبل DOCX وXLSX وPPTX وODT وODS وODP وأكثر من 20 صيغة؛ يدمج عدة ملفات في PDF واحد إذا أرسلت merge=true.
مسارات PDF — معالجة PDF الموجودة:
- POST /forms/pdfengines/merge — يدمج عدة ملفات PDF في ملف واحد.
- POST /forms/pdfengines/convert — يحوّل إلى PDF/A (أرشفة طويلة المدى).
Webhook: بدلًا من تلقي PDF ردًا متزامنًا، مرّر ترويسة Gotenberg-Webhook-Url — سيُرسل Gotenberg PDF إلى عنوانك URL بمجرد انتهاء التحويل.
وكيل nginx العكسي
لكشف Gotenberg لخدمات أخرى أو استدعائه من نطاق مخصص، أضف كتلة location في إعداد nginx:
server {
listen 443 ssl;
server_name gotenberg.your-domain.com;
ssl_certificate /etc/letsencrypt/live/gotenberg.your-domain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/gotenberg.your-domain.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_read_timeout 60s;
client_max_body_size 50M;
auth_basic "Gotenberg API";
auth_basic_user_file /etc/nginx/.htpasswd;
}
}إذا كان Gotenberg يعمل على نفس الخادم مع تطبيقك الخلفي، فضّل الاستدعاء المباشر على http://127.0.0.1:3000 — يتجنب حركة الشبكة الخارجية ولا يتطلب كشف الخدمة على نطاق.
التكامل المتقدم: PHP وPython وNode.js
Gotenberg محايد للغة — أي عميل HTTP قادر على إرسال multipart/form-data يعمل.
PHP / Laravel — استخدم حزمة gotenberg-php الرسمية:
use Gotenberg\Gotenberg;
use Gotenberg\Stream;
$request = Gotenberg::chromium('http://127.0.0.1:3000')
->pdf()
->html(Stream::path('/path/to/invoice.html'));
$response = $client->sendRequest($request);
file_put_contents('invoice.pdf', $response->getBody());Python — مع مكتبة gotenberg-client:
from gotenberg_client import GotenbergClient
with GotenbergClient('http://127.0.0.1:3000') as client:
with client.chromium.html_to_pdf() as route:
route.index(Path('invoice.html'))
response = route.run()
Path('invoice.pdf').write_bytes(response.content)Node.js — مع fetch الأصلي (Node 18+):
const form = new FormData();
form.append('index.html', new Blob([htmlContent], { type: 'text/html' }), 'index.html');
const res = await fetch('http://127.0.0.1:3000/forms/chromium/convert/html', {
method: 'POST',
body: form,
});
const pdf = Buffer.from(await res.arrayBuffer());
fs.writeFileSync('invoice.pdf', pdf);الإعداد المتقدم
تُمرَّر المعاملات كوسائط لأمر gotenberg في docker-compose.yml (أو عبر متغيرات بيئة بالبادئة GOTENBERG_).
المهلة: --api-timeout=30s — المدة القصوى لتحويل. زدها (مثلًا 60s) لمستندات DOCX الطويلة أو الصفحات ذات JavaScript الثقيل.
التزامن: --chromium-max-queue-size=10 — الحد الأقصى للتحويلات في قائمة الانتظار. عند تجاوزه يرد Gotenberg بـ 503 بدلًا من التراكم في الذاكرة.
تسجيل الأحداث: يسجّل Gotenberg بصيغة JSON على stdout — docker compose logs gotenberg يمنحك تفاصيل كل تحويل.
تعطيل LibreOffice (إذا احتجت Chromium فقط، توفيرًا في RAM):
command:
- gotenberg
- --libreoffice-disable-listener=trueللبنى عالية الحجم، شغّل عدة نسخ من Gotenberg خلف موازن حمل nginx (upstream): تحتفظ كل نسخة بعمالها من Chromium، وتتوسع أفقيًا دون حالة مشتركة.
تشخيص الأخطاء الشائعة
مهلة Chromium — context deadline exceeded: يتجاوز تحويل HTML المهلة المضبوطة. الأسباب الشائعة: JavaScript بطيء، موارد خارجية (CDN، خطوط Google Fonts) غير متاحة من الخادم، أو DOM ضخم جدًا. الحل: زد --api-timeout، استضف أصولك محليًا وألحقها كحقول multipart.
المنفذ 3000 مشغول: تطبيق آخر يستمع على 3000. عدّل التعيين في docker-compose.yml: "127.0.0.1:3001:3000" وحدّث الرابط URL في استدعاءاتك.
الملف كبير جدًا — 413 Request Entity Too Large: يقطع nginx الطلب قبل Gotenberg. زد client_max_body_size في كتلة nginx (مثلًا 100M لملفات XLSX الكبيرة).
نفاد الذاكرة — OOMKilled: يقتل Docker الحاوية عندما يتجاوز Chromium RAM المتاحة. تحقق بـ docker inspect gotenberg | grep OOMKilled. الحلول: أضف RAM لـ VPS، قلّل التزامن (--chromium-max-queue-size=3), أو عطّل JavaScript إذا لم يحتجه HTML.
خطأ LibreOffice — ملف تالف أو صيغة غير معترف بها: بعض ملفات DOCX من أدوات طرف ثالث غير متوافقة مع معيار OOXML. تحقق أولًا أن الملف يفتح بدون أخطاء في LibreOffice Desktop. يعطيك ترويسة سجل Gotenberg رسالة LibreOffice الدقيقة (docker compose logs gotenberg --tail 50).
التكامل مع تطبيقك
Gotenberg محايد للغة — أي عميل HTTP يعمل. توجد مكتبات لـ PHP وNode.js وPython وGo وغيرها. لـ Laravel توجد حزمة رسمية تُغلّف الواجهة API. في Node.js يمكنك استدعاؤها بـ axios أو fetch الأصلية بإرسال كائن FormData مع محتوى HTML أو الملف. راجع قسم التكامل المتقدم أعلاه لأمثلة كود جاهزة بكل لغة.