Skip to content

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:


Installation and Setup

Step 1: Create Your Project Directory

First, create a new directory for your Gotenberg deployment project:

Terminal window
mkdir gotenberg-klutch
cd gotenberg-klutch
git init

Step 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 default
EXPOSE 3000
# Start Gotenberg with default configuration
CMD ["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 directory
WORKDIR /app
# Expose Gotenberg port
EXPOSE 3000
# Start Gotenberg with production settings
# These can also be configured via environment variables in Klutch.sh
CMD ["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
.gitignore
README.md
node_modules
.env
*.log
.DS_Store

Step 5: Push to GitHub

Initialize your Git repository and push to GitHub:

Terminal window
git add .
git commit -m "Initial Gotenberg setup with Dockerfile"
git remote add origin https://github.com/yourusername/gotenberg-klutch.git
git branch -M main
git push -u origin main

Deploying on Klutch.sh

Step 1: Create a New Project

    1. Log in to your Klutch.sh dashboard
    2. Click “New Project” to create a new project for your Gotenberg application
    3. Give your project a descriptive name like “Gotenberg PDF Service”

Step 2: Create a New App

    1. Inside your project, click “New App”
    2. Connect your GitHub repository containing the Gotenberg Dockerfile
    3. Klutch.sh will automatically detect the Dockerfile in your repository
    4. 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=30s
GOTENBERG_CHROMIUM_MAX_QUEUE_SIZE=100
GOTENBERG_LIBREOFFICE_MAX_QUEUE_SIZE=50
GOTENBERG_LOG_LEVEL=info

Note: Environment variables use the GOTENBERG_ prefix. Most command-line flags have equivalent environment variable counterparts.

Step 4: Deploy Your Application

    1. Click “Create” or “Deploy” to start the deployment process
    2. Klutch.sh will:
      • Build your Docker image from the Dockerfile
      • Deploy the container
      • Assign a URL like example-app.klutch.sh
    3. Wait for the build and deployment to complete
    4. 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:

    1. Navigate to your Gotenberg app in the Klutch.sh dashboard
    2. Go to the “Volumes” section
    3. Click “Add Volume”
    4. Configure the volume:
      • Mount Path: /app/storage (or your preferred path)
      • Size: Choose appropriate size (e.g., 5GB)
    5. 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 logs

Note: 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:

Terminal window
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.pdf

Convert URL to PDF

Generate a PDF from a live URL:

Terminal window
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.pdf

HTML with Custom CSS and JavaScript

Convert HTML with external assets:

Terminal window
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.pdf

Convert Markdown to PDF

Transform Markdown documents to PDF:

Terminal window
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.pdf

Convert Office Documents to PDF

Convert Word, Excel, or PowerPoint files:

Terminal window
curl --request POST \
--url https://example-app.klutch.sh/forms/libreoffice/convert \
--header 'Content-Type: multipart/form-data' \
--form 'files=@document.docx' \
--output converted.pdf

Merge Multiple PDFs

Combine multiple PDF files into one:

Terminal window
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.pdf

Advanced: Custom Headers and Footers

Generate PDFs with custom headers and footers:

Terminal window
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.pdf

Advanced: Page Margins and Settings

Customize page layout and margins:

Terminal window
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.pdf

Sample 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;
}
}
// Usage
const 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}')
# Usage
html_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=30s
GOTENBERG_API_PORT=3000
GOTENBERG_API_TIMEOUT_ERROR_HTTP_STATUS_CODE=408
GOTENBERG_API_ROOT_PATH=/
GOTENBERG_API_TRACE_HEADER=Gotenberg-Trace

Chromium Configuration

GOTENBERG_CHROMIUM_AUTO_START=true
GOTENBERG_CHROMIUM_MAX_QUEUE_SIZE=100
GOTENBERG_CHROMIUM_ALLOW_LIST=.*
GOTENBERG_CHROMIUM_DENY_LIST=
GOTENBERG_CHROMIUM_IGNORE_CERTIFICATE_ERRORS=false
GOTENBERG_CHROMIUM_DISABLE_WEB_SECURITY=false

LibreOffice Configuration

GOTENBERG_LIBREOFFICE_AUTO_START=true
GOTENBERG_LIBREOFFICE_MAX_QUEUE_SIZE=50
GOTENBERG_LIBREOFFICE_RESTART_AFTER=10

Logging Configuration

GOTENBERG_LOG_LEVEL=info
GOTENBERG_LOG_FORMAT=json
GOTENBERG_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=4
GOTENBERG_WEBHOOK_RETRY_MIN_WAIT=1s
GOTENBERG_WEBHOOK_RETRY_MAX_WAIT=30s

Health Checks and Monitoring

Gotenberg provides built-in health check endpoints for monitoring:

Health Check Endpoint

Terminal window
curl https://example-app.klutch.sh/health

Response:

{
"status": "up"
}

Prometheus Metrics

Gotenberg exposes Prometheus-compatible metrics at:

Terminal window
curl https://example-app.klutch.sh/prometheus/metrics

Available 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-stopped

Start locally:

Terminal window
docker-compose up -d

Test locally:

Terminal window
curl --request POST \
--url http://localhost:3000/forms/chromium/convert/url \
--form 'url=https://example.com' \
--output test.pdf

Note: 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-list to restrict which URLs can be converted
  • Deny Dangerous URLs: Use --chromium-deny-list to block internal networks or sensitive endpoints
  • Disable Web Security Carefully: Only use --chromium-disable-web-security in trusted environments
  • Certificate Validation: Keep --chromium-ignore-certificate-errors set to false in production

2. Performance Optimization

  • Pre-start Services: Enable --chromium-auto-start and --libreoffice-auto-start for faster first requests
  • Queue Sizing: Adjust --chromium-max-queue-size and --libreoffice-max-queue-size based on your load
  • Timeout Configuration: Set appropriate --api-timeout values 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=json for 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:

    1. Create a fonts directory in your project
    2. Add your custom font files (.ttf, .otf)
    3. Mount the directory as a persistent volume to /usr/share/fonts/custom
    4. Or include fonts in your Dockerfile:
    FROM gotenberg/gotenberg:8
    # Copy custom fonts
    COPY ./fonts /usr/share/fonts/custom
    # Update font cache
    RUN fc-cache -f -v
    EXPOSE 3000
    CMD ["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=60s

Issue: Queue Full Errors

Solution: Increase queue sizes:

GOTENBERG_CHROMIUM_MAX_QUEUE_SIZE=200
GOTENBERG_LIBREOFFICE_MAX_QUEUE_SIZE=100

Issue: 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 waitDelay parameter 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


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.