*Please :star: this repo if you find it useful*
# Gotenberg UI [](https://hub.docker.com/r/techblog/gotenbergui) [](https://hub.docker.com/r/techblog/gotenbergui) [](License) Gotenberg UI (branded **PDF Utils** in the page title) is a [FastAPI](https://fastapi.tiangolo.com/) based web application that lets you convert web pages (URLs), HTML files and office documents to PDF, and merge multiple PDF files into a single PDF. It is a UI wrapper for [Gotenberg](https://gotenberg.dev/), a "Docker-powered stateless API for PDF files" written in Go. Gotenberg UI does not convert anything itself: it serves a simple web page whose forms post your input straight to your own Gotenberg server. ## Table of Contents - [Features](#features) - [How it works](#how-it-works) - [Requirements](#requirements) - [Installation](#installation) - [Configuration](#configuration) - [Usage](#usage) - [HTTP routes](#http-routes) - [Security notes](#security-notes) - [Troubleshooting](#troubleshooting) - [Development](#development) - [Contributing](#contributing) - [Credits](#credits) - [License](#license) ## Features Four tabs, each backed by a Gotenberg route: | Tab | What it does | Gotenberg route | |-----|--------------|-----------------| | Convert Web Page | Converts a URL to PDF with Chromium | `POST /forms/chromium/convert/url` | | Convert HTML file | Converts an uploaded `index.html` (plus optional images, fonts, stylesheets, …) to PDF with Chromium | `POST /forms/chromium/convert/html` | | Convert Documents | Converts one or more office documents (`.docx`, `.xlsx`, `.pptx`, `.odt`, `.rtf`, `.txt`, `.csv`, images and many more) to PDF with LibreOffice | `POST /forms/libreoffice/convert` | | Merge PDF Documents | Merges several PDF files into one PDF | `POST /forms/pdfengines/merge` | - Shows the number, names and sizes of the selected files before upload. - Warns you when the HTML tab's selection does not include an `index.html` file. - Multi-arch Docker image: `linux/amd64`, `linux/arm64`, `linux/arm/v7`. ### Convert URL to PDF file [](https://github.com/t0mer/gotenberg-ui/blob/main/screenshots/gotenberg%20-%20convert%20web%20page.png?raw=true "Convert URL") ### Convert HTML file to PDF file [](https://github.com/t0mer/gotenberg-ui/blob/main/screenshots/gotenberg%20-%20convert%20html%20file.png?raw=true "Convert HTML file") ### Convert documents to PDF file [](https://github.com/t0mer/gotenberg-ui/blob/main/screenshots/gotenberg%20-%20convert%20documents.png?raw=true "Convert Documents") ### Merge multiple PDF documents into a single file [](https://github.com/t0mer/gotenberg-ui/blob/main/screenshots/gotenberg%20-%20merge%20pdf%20files.png?raw=true "Merge Documents") ## How it works ```mermaid flowchart LR B[Browser] -- "GET /" --> UI["Gotenberg UI
`).
- **Convert Documents**: select one or more documents. The supported extensions are listed on the page.
- **Merge PDF Documents**: select the PDF files to merge.
3. The browser receives the PDF from Gotenberg.
## HTTP routes
Routes served by Gotenberg UI itself:
| Method | Path | Purpose |
|--------|------|---------|
| `GET` | `/` | The web UI |
| `GET` | `/dist/*`, `/js/*`, `/css/*`, `/images/*` | Static assets |
| `GET` | `/docs`, `/redoc`, `/openapi.json` | FastAPI's automatic API docs (they only list `/`) |
All PDF work is done by Gotenberg's own API; see the [Gotenberg routes documentation](https://gotenberg.dev/docs/getting-started/routes) if you want to call it directly.
## Security notes
- **No authentication.** Neither the UI nor a default Gotenberg install requires a login. Don't expose them to the internet without a reverse proxy that adds authentication.
- **Gotenberg must be reachable from the browser**, so its port is exposed to every client that uses the UI.
- **Server-side request forgery (SSRF).** The URL tab makes Gotenberg's Chromium load any URL a user types, including hosts on your internal network, and return them as PDF. If untrusted users can reach Gotenberg, restrict Chromium with Gotenberg's `--chromium-deny-private-ips`, `--chromium-allow-list` or `--chromium-deny-list` flags.
- **CORS** on the UI is open to all origins (`*`).
- **Third-party requests.** The page includes a Google Analytics (gtag.js) snippet and Open Graph tags for the author's public instance (`pdfutils.techblog.co.il`), so browsers of self-hosted users also load the analytics script.
## Troubleshooting
- **Clicking Convert opens `/forms/...` on the UI itself and returns 404, or opens `None/forms/...`**: `GOTENBERG_API_ADDRESS` is empty or unset. Set it to your Gotenberg base URL.
- **The browser can't connect after clicking Convert**: the address is not reachable from the browser (for example a Docker service name like `http://gotenberg:3000`). Use the host IP or DNS name and the published Gotenberg port.
- **404 from Gotenberg**: you are probably running Gotenberg 6 or older (`thecodingmachine/gotenberg:6`). Use Gotenberg 7 or 8. Also check that the address has no trailing slash.
- **"index.html file must be included"**: the HTML route requires a file named exactly `index.html`.
## Development
Project layout:
```
gotenbergui/
gotenberg.py # FastAPI app (serves the page and static files)
templates/index.html # The UI (forms post to Gotenberg)
dist/ # CSS, JS (jQuery, SweetAlert2, easyResponsiveTabs), images
w3layouts-License.txt # Template license
screenshots/ # README screenshots
Dockerfile # Based on techblog/fastapi:latest, exposes 8080
VERSION # Image version tag used by the Docker Hub workflow
```
Run from source (the app must be started from inside `gotenbergui/`, because template and static paths are relative):
```bash
pip install "fastapi<0.116" uvicorn jinja2 loguru aiofiles requests
cd gotenbergui
GOTENBERG_API_ADDRESS=http://localhost:3000 python3 gotenberg.py
```
The pin matters: `gotenberg.py` calls `TemplateResponse('index.html', context=...)` with the old signature, which newer Starlette releases no longer accept (`GET /` returns 500). It works with FastAPI 0.115.x (which installs Starlette 0.46); it breaks with Starlette 1.x. There is no `requirements.txt` in the repository.
Build the image locally:
```bash
docker build -t gotenbergui .
```
CI:
- `.github/workflows/main.yml` builds and pushes `techblog/gotenbergui:latest` and `techblog/gotenbergui: