Deploying a Gotenberg App
Introduction
Gotenberg is a powerful, Docker-powered stateless API for converting HTML, Markdown, and Office documents to PDF. Built with Go and designed for microservices architectures, Gotenberg provides a simple HTTP API that makes PDF generation effortless for any application. Whether you need to generate invoices, reports, contracts, or any other document type, Gotenberg handles the heavy lifting of document conversion with excellent performance and reliability.
Gotenberg excels at:
- HTML to PDF Conversion: Convert HTML, CSS, and JavaScript-powered web pages to beautiful PDFs
- Markdown to PDF: Transform Markdown documents into professional-looking PDFs
- Office Document Conversion: Convert Microsoft Office documents (Word, Excel, PowerPoint) and LibreOffice documents to PDF
- URL to PDF: Generate PDFs directly from URLs with full JavaScript rendering support
- Merge PDFs: Combine multiple PDF files into a single document
- Screenshot Capture: Generate screenshots and images from web pages
- Stateless Architecture: No database required, perfect for horizontal scaling
- Webhook Support: Async processing with webhook callbacks for long-running conversions
- Custom Headers and Footers: Add dynamic headers, footers, and page numbers
- Chromium-Based Rendering: Accurate rendering using headless Chrome
- LibreOffice Integration: Native Office document support
This comprehensive guide walks you through deploying Gotenberg on Klutch.sh using a Dockerfile, including detailed installation steps, configuration options, API usage examples, persistent storage setup, and production-ready best practices for reliable document conversion services.
Prerequisites
Before you begin, ensure you have the following:
- A Klutch.sh account
- A GitHub account with a repository for your Gotenberg project
- Docker installed locally for testing (optional but recommended)
- Basic understanding of Docker, HTTP APIs, and document conversion concepts
Installation and Setup
Step 1: Create Your Project Directory
First, create a new directory for your Gotenberg deployment project:
mkdir gotenberg-klutchcd gotenberg-klutchgit initStep 2: Create the Dockerfile
Create a Dockerfile in your project root directory. Klutch.sh will automatically detect and use this Dockerfile for deployment:
FROM gotenberg/gotenberg:8
# Gotenberg runs on port 3000 by defaultEXPOSE 3000
# Start Gotenberg with default configurationCMD ["gotenberg"]Note: This Dockerfile uses the official Gotenberg image. The image includes Chromium for HTML/URL conversions and LibreOffice for Office document conversions.
Step 3: Advanced Dockerfile with Custom Configuration
For a production-ready setup with custom timeouts, security settings, and optimization:
FROM gotenberg/gotenberg:8
# Set working directoryWORKDIR /app
# Expose Gotenberg portEXPOSE 3000
# Start Gotenberg with production settings# These can also be configured via environment variables in Klutch.shCMD ["gotenberg", \ "--api-timeout=30s", \ "--api-timeout-error-http-status-code=408", \ "--chromium-allow-list=.*", \ "--chromium-max-queue-size=100", \ "--chromium-auto-start=true", \ "--libreoffice-auto-start=true", \ "--libreoffice-max-queue-size=50"]Configuration Options:
--api-timeout: Maximum duration for API requests (default: 30s)--chromium-allow-list: Regex pattern for allowed URLs in conversions--chromium-max-queue-size: Maximum number of queued Chromium conversions--chromium-auto-start: Automatically start Chromium on container startup--libreoffice-auto-start: Automatically start LibreOffice on container startup--libreoffice-max-queue-size: Maximum number of queued LibreOffice conversions
Step 4: Create a .dockerignore File
Create a .dockerignore file to exclude unnecessary files from your Docker build:
.git.gitignoreREADME.mdnode_modules.env*.log.DS_StoreStep 5: Push to GitHub
Initialize your Git repository and push to GitHub:
git add .git commit -m "Initial Gotenberg setup with Dockerfile"git remote add origin https://github.com/yourusername/gotenberg-klutch.gitgit branch -M maingit push -u origin mainDeploying on Klutch.sh
Step 1: Create a New Project
- Log in to your Klutch.sh dashboard
- Click “New Project” to create a new project for your Gotenberg application
- Give your project a descriptive name like “Gotenberg PDF Service”
Step 2: Create a New App
- Inside your project, click “New App”
- Connect your GitHub repository containing the Gotenberg Dockerfile
- Klutch.sh will automatically detect the Dockerfile in your repository
- Configure the following settings:
- Traffic Type: Select HTTP (Gotenberg is an HTTP API service)
- Internal Port: Set to 3000 (Gotenberg’s default port)
Note: Klutch.sh automatically detects and uses the Dockerfile present in your repository root directory. No manual Docker configuration is needed in the dashboard.
Step 3: Configure Environment Variables (Optional)
Gotenberg can be configured through command-line flags in the Dockerfile or via environment variables. For runtime configuration flexibility, add these in the Klutch.sh dashboard:
GOTENBERG_API_TIMEOUT=30sGOTENBERG_CHROMIUM_MAX_QUEUE_SIZE=100GOTENBERG_LIBREOFFICE_MAX_QUEUE_SIZE=50GOTENBERG_LOG_LEVEL=infoNote: Environment variables use the GOTENBERG_ prefix. Most command-line flags have equivalent environment variable counterparts.
Step 4: Deploy Your Application
- Click “Create” or “Deploy” to start the deployment process
- Klutch.sh will:
- Build your Docker image from the Dockerfile
- Deploy the container
- Assign a URL like
example-app.klutch.sh
- Wait for the build and deployment to complete
- Your Gotenberg API will be available at the assigned URL
Persistent Storage and Volumes
Gotenberg is stateless by design and doesn’t require persistent storage for its core functionality. However, you may want to add persistent volumes for:
- Temporary File Storage: Store intermediate conversion files
- Custom Fonts: Add custom fonts for PDF generation
- Templates: Store HTML templates for reuse
- Logs: Persist application logs for debugging
Attaching a Persistent Volume
To attach persistent storage in Klutch.sh:
- Navigate to your Gotenberg app in the Klutch.sh dashboard
- Go to the “Volumes” section
- Click “Add Volume”
- Configure the volume:
- Mount Path:
/app/storage(or your preferred path) - Size: Choose appropriate size (e.g., 5GB)
- Mount Path:
- Save the configuration and redeploy your app
Example Use Cases:
/app/fonts <- Custom fonts directory/app/templates <- HTML templates directory/app/storage <- Temporary files and cache/var/log/gotenberg <- Application logsNote: For custom fonts, mount the volume to /usr/share/fonts/custom or specify the font directory via --chromium-custom-fonts-path flag.
API Usage and Getting Started
Basic HTML to PDF Conversion
Convert HTML content to PDF using a simple POST request:
curl --request POST \ --url https://example-app.klutch.sh/forms/chromium/convert/html \ --header 'Content-Type: multipart/form-data' \ --form 'files=@index.html' \ --output result.pdfConvert URL to PDF
Generate a PDF from a live URL:
curl --request POST \ --url https://example-app.klutch.sh/forms/chromium/convert/url \ --header 'Content-Type: multipart/form-data' \ --form 'url=https://example.com' \ --output webpage.pdfHTML with Custom CSS and JavaScript
Convert HTML with external assets:
curl --request POST \ --url https://example-app.klutch.sh/forms/chromium/convert/html \ --header 'Content-Type: multipart/form-data' \ --form 'files=@index.html' \ --form 'files=@style.css' \ --form 'files=@script.js' \ --output styled.pdfConvert Markdown to PDF
Transform Markdown documents to PDF:
curl --request POST \ --url https://example-app.klutch.sh/forms/chromium/convert/markdown \ --header 'Content-Type: multipart/form-data' \ --form 'files=@document.md' \ --output document.pdfConvert Office Documents to PDF
Convert Word, Excel, or PowerPoint files:
curl --request POST \ --url https://example-app.klutch.sh/forms/libreoffice/convert \ --header 'Content-Type: multipart/form-data' \ --form 'files=@document.docx' \ --output converted.pdfMerge Multiple PDFs
Combine multiple PDF files into one:
curl --request POST \ --url https://example-app.klutch.sh/forms/pdfengines/merge \ --header 'Content-Type: multipart/form-data' \ --form 'files=@file1.pdf' \ --form 'files=@file2.pdf' \ --form 'files=@file3.pdf' \ --output merged.pdfAdvanced: Custom Headers and Footers
Generate PDFs with custom headers and footers:
curl --request POST \ --url https://example-app.klutch.sh/forms/chromium/convert/html \ --header 'Content-Type: multipart/form-data' \ --form 'files=@index.html' \ --form 'files=@header.html' \ --form 'files=@footer.html' \ --output custom-pdf.pdfAdvanced: Page Margins and Settings
Customize page layout and margins:
curl --request POST \ --url https://example-app.klutch.sh/forms/chromium/convert/html \ --header 'Content-Type: multipart/form-data' \ --form 'files=@index.html' \ --form 'marginTop=0.5' \ --form 'marginBottom=0.5' \ --form 'marginLeft=0.5' \ --form 'marginRight=0.5' \ --form 'paperWidth=8.5' \ --form 'paperHeight=11' \ --form 'landscape=false' \ --output custom-layout.pdfSample Node.js Integration
Here’s a complete Node.js example for integrating Gotenberg into your application:
const FormData = require('form-data');const fs = require('fs');const axios = require('axios');
async function convertHtmlToPdf(htmlContent, outputPath) { try { // Create form data const form = new FormData();
// Add HTML content as a file form.append('files', Buffer.from(htmlContent), { filename: 'index.html', contentType: 'text/html' });
// Add optional parameters form.append('marginTop', '0.5'); form.append('marginBottom', '0.5');
// Make request to Gotenberg const response = await axios.post( 'https://example-app.klutch.sh/forms/chromium/convert/html', form, { headers: form.getHeaders(), responseType: 'stream' } );
// Save PDF to file const writer = fs.createWriteStream(outputPath); response.data.pipe(writer);
return new Promise((resolve, reject) => { writer.on('finish', resolve); writer.on('error', reject); }); } catch (error) { console.error('Error converting HTML to PDF:', error.message); throw error; }}
// Usageconst htmlContent = `<!DOCTYPE html><html><head> <style> body { font-family: Arial, sans-serif; padding: 40px; } h1 { color: #333; } </style></head><body> <h1>Invoice</h1> <p>Invoice #12345</p> <p>Total: $100.00</p></body></html>`;
convertHtmlToPdf(htmlContent, 'invoice.pdf') .then(() => console.log('PDF generated successfully')) .catch(err => console.error('Failed to generate PDF:', err));Sample Python Integration
Here’s a Python example using the requests library:
import requests
def convert_html_to_pdf(html_content, output_path): """Convert HTML content to PDF using Gotenberg"""
url = 'https://example-app.klutch.sh/forms/chromium/convert/html'
files = { 'files': ('index.html', html_content, 'text/html') }
data = { 'marginTop': '0.5', 'marginBottom': '0.5', 'marginLeft': '0.5', 'marginRight': '0.5' }
response = requests.post(url, files=files, data=data)
if response.status_code == 200: with open(output_path, 'wb') as f: f.write(response.content) print(f'PDF saved to {output_path}') else: raise Exception(f'Failed to generate PDF: {response.status_code}')
# Usagehtml_content = """<!DOCTYPE html><html><head> <style> body { font-family: Arial, sans-serif; padding: 40px; } h1 { color: #333; } </style></head><body> <h1>Report</h1> <p>Generated on: 2024-01-15</p> <p>Status: Completed</p></body></html>"""
convert_html_to_pdf(html_content, 'report.pdf')Environment Variables and Configuration
Gotenberg supports extensive configuration through environment variables. Here are the most commonly used options:
API Configuration
GOTENBERG_API_TIMEOUT=30sGOTENBERG_API_PORT=3000GOTENBERG_API_TIMEOUT_ERROR_HTTP_STATUS_CODE=408GOTENBERG_API_ROOT_PATH=/GOTENBERG_API_TRACE_HEADER=Gotenberg-TraceChromium Configuration
GOTENBERG_CHROMIUM_AUTO_START=trueGOTENBERG_CHROMIUM_MAX_QUEUE_SIZE=100GOTENBERG_CHROMIUM_ALLOW_LIST=.*GOTENBERG_CHROMIUM_DENY_LIST=GOTENBERG_CHROMIUM_IGNORE_CERTIFICATE_ERRORS=falseGOTENBERG_CHROMIUM_DISABLE_WEB_SECURITY=falseLibreOffice Configuration
GOTENBERG_LIBREOFFICE_AUTO_START=trueGOTENBERG_LIBREOFFICE_MAX_QUEUE_SIZE=50GOTENBERG_LIBREOFFICE_RESTART_AFTER=10Logging Configuration
GOTENBERG_LOG_LEVEL=infoGOTENBERG_LOG_FORMAT=jsonGOTENBERG_LOG_FIELDS_PREFIX=Webhook Configuration
For async processing with webhook callbacks:
GOTENBERG_WEBHOOK_ALLOW_LIST=.*GOTENBERG_WEBHOOK_DENY_LIST=GOTENBERG_WEBHOOK_ERROR_ALLOW_LIST=.*GOTENBERG_WEBHOOK_ERROR_DENY_LIST=GOTENBERG_WEBHOOK_MAX_RETRY=4GOTENBERG_WEBHOOK_RETRY_MIN_WAIT=1sGOTENBERG_WEBHOOK_RETRY_MAX_WAIT=30sHealth Checks and Monitoring
Gotenberg provides built-in health check endpoints for monitoring:
Health Check Endpoint
curl https://example-app.klutch.sh/healthResponse:
{ "status": "up"}Prometheus Metrics
Gotenberg exposes Prometheus-compatible metrics at:
curl https://example-app.klutch.sh/prometheus/metricsAvailable Metrics:
- Request counts and durations
- Queue sizes and wait times
- Chromium and LibreOffice instance statistics
- Memory and CPU usage
- Error rates
Local Development with Docker Compose
For local testing before deploying to Klutch.sh, create a docker-compose.yml file:
version: '3.8'
services: gotenberg: image: gotenberg/gotenberg:8 ports: - "3000:3000" environment: - GOTENBERG_API_TIMEOUT=30s - GOTENBERG_LOG_LEVEL=debug command: - "gotenberg" - "--api-timeout=30s" - "--chromium-auto-start=true" - "--libreoffice-auto-start=true" volumes: - ./storage:/app/storage - ./fonts:/usr/share/fonts/custom restart: unless-stoppedStart locally:
docker-compose up -dTest locally:
curl --request POST \ --url http://localhost:3000/forms/chromium/convert/url \ --form 'url=https://example.com' \ --output test.pdfNote: Docker Compose is only for local development. Klutch.sh doesn’t support Docker Compose for deployments but will automatically build and run containers from your Dockerfile.
Production Best Practices
1. Security Considerations
- URL Allowlist: Configure
--chromium-allow-listto restrict which URLs can be converted - Deny Dangerous URLs: Use
--chromium-deny-listto block internal networks or sensitive endpoints - Disable Web Security Carefully: Only use
--chromium-disable-web-securityin trusted environments - Certificate Validation: Keep
--chromium-ignore-certificate-errorsset tofalsein production
2. Performance Optimization
- Pre-start Services: Enable
--chromium-auto-startand--libreoffice-auto-startfor faster first requests - Queue Sizing: Adjust
--chromium-max-queue-sizeand--libreoffice-max-queue-sizebased on your load - Timeout Configuration: Set appropriate
--api-timeoutvalues for your use case - Resource Limits: Monitor memory usage and set container limits appropriately
3. Scaling Strategies
- Horizontal Scaling: Deploy multiple Gotenberg instances behind a load balancer
- Stateless Design: Gotenberg is stateless, making it perfect for horizontal scaling
- Queue Management: Monitor queue sizes and scale when queues are consistently full
- Webhook Processing: Use webhooks for async processing of large documents
4. Monitoring and Logging
- Enable Metrics: Integrate with Prometheus for monitoring
- Structured Logging: Use
--log-format=jsonfor better log aggregation - Health Checks: Implement regular health check monitoring
- Error Tracking: Monitor error rates and timeout occurrences
5. Custom Fonts
For documents requiring specific fonts:
- Create a fonts directory in your project
- Add your custom font files (.ttf, .otf)
- Mount the directory as a persistent volume to
/usr/share/fonts/custom - Or include fonts in your Dockerfile:
FROM gotenberg/gotenberg:8
# Copy custom fontsCOPY ./fonts /usr/share/fonts/custom
# Update font cacheRUN fc-cache -f -v
EXPOSE 3000CMD ["gotenberg"]6. Error Handling
Implement proper error handling in your application:
async function convertWithRetry(htmlContent, maxRetries = 3) { for (let i = 0; i < maxRetries; i++) { try { return await convertHtmlToPdf(htmlContent); } catch (error) { if (i === maxRetries - 1) throw error; await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1))); } }}7. Rate Limiting
Implement rate limiting in your application layer to prevent overwhelming the Gotenberg service:
const rateLimit = require('express-rate-limit');
const limiter = rateLimit({ windowMs: 15 * 60 * 1000, // 15 minutes max: 100 // limit each IP to 100 requests per windowMs});
app.use('/api/convert', limiter);Troubleshooting Common Issues
Issue: Timeout Errors
Solution: Increase the API timeout value:
CMD ["gotenberg", "--api-timeout=60s"]Or via environment variable:
GOTENBERG_API_TIMEOUT=60sIssue: Queue Full Errors
Solution: Increase queue sizes:
GOTENBERG_CHROMIUM_MAX_QUEUE_SIZE=200GOTENBERG_LIBREOFFICE_MAX_QUEUE_SIZE=100Issue: Memory Issues
Solution:
- Monitor container memory usage in Klutch.sh dashboard
- Consider scaling horizontally with multiple instances
- Adjust LibreOffice restart settings:
--libreoffice-restart-after=5
Issue: Font Rendering Issues
Solution:
- Ensure custom fonts are properly mounted
- Verify font permissions in the container
- Use web-safe fonts or include fonts in your HTML with base64 encoding
Issue: JavaScript Not Executing
Solution:
- Ensure sufficient wait time for JavaScript execution
- Add
waitDelayparameter to your requests - Check browser console errors using
--chromium-enable-devtools
Advanced Use Cases
1. Dynamic Invoice Generation
function generateInvoice(invoiceData) { const html = ` <!DOCTYPE html> <html> <head> <style> body { font-family: Arial; padding: 40px; } .header { border-bottom: 2px solid #333; padding-bottom: 20px; } .item { margin: 10px 0; } .total { font-weight: bold; font-size: 18px; } </style> </head> <body> <div class="header"> <h1>Invoice #${invoiceData.id}</h1> <p>Date: ${invoiceData.date}</p> </div> <div class="items"> ${invoiceData.items.map(item => ` <div class="item"> ${item.name}: $${item.price} </div> `).join('')} </div> <div class="total"> Total: $${invoiceData.total} </div> </body> </html> `;
return convertHtmlToPdf(html, `invoice-${invoiceData.id}.pdf`);}2. Batch Processing Multiple Documents
async function batchConvert(documents) { const promises = documents.map(doc => convertHtmlToPdf(doc.html, doc.outputPath) );
return Promise.all(promises);}3. Template-Based Report Generation
const Handlebars = require('handlebars');const fs = require('fs');
function generateReport(templatePath, data) { const template = fs.readFileSync(templatePath, 'utf8'); const compiledTemplate = Handlebars.compile(template); const html = compiledTemplate(data);
return convertHtmlToPdf(html, 'report.pdf');}Resources
- Gotenberg Official Documentation
- Gotenberg GitHub Repository
- Gotenberg Docker Hub
- Klutch.sh Quick Start Guide
- Klutch.sh Volumes Guide
- Klutch.sh Builds Guide
- Klutch.sh Deployments Guide
Conclusion
Deploying Gotenberg on Klutch.sh provides a robust, scalable solution for document conversion and PDF generation. With its stateless architecture, comprehensive API, and excellent performance characteristics, Gotenberg is ideal for modern microservices architectures. The combination of Gotenberg’s powerful conversion capabilities and Klutch.sh’s managed infrastructure gives you a production-ready document processing service that can scale with your needs.
Whether you’re generating invoices, creating reports, converting Office documents, or capturing web pages as PDFs, Gotenberg on Klutch.sh delivers the reliability and performance your applications demand. Start with the basic Dockerfile deployment, test your conversions locally, and then leverage Klutch.sh’s features like persistent volumes, environment variables, and monitoring to build a world-class document conversion service.