Utilities stack¶
Three small, stateless-ish web tools that I'd otherwise reach for a random website for. They run together in one compose stack on the apps server, because none of them needs much and they share the same lifecycle.
| Tool | What it does | Port |
|---|---|---|
| IT-Tools | Developer helpers in the browser: JWT/base64/hash/UUID, cron and chmod calculators, subnet calculator, QR codes, text diff, ... | 8071 |
| BentoPDF | PDF toolkit (merge, split, compress, rotate, sign, convert). Everything runs client-side in your browser, so the files never leave your machine. | 8072 |
| ConvertX | Converts files between ~1000 formats (FFmpeg, LibreOffice, ImageMagick, Pandoc, ...). Has accounts and keeps converted files for a while. | 3002 |
Why self-host them: documents like tax PDFs, IDs or work files shouldn't be uploaded to "free online PDF merger" sites. These do the same thing on your own hardware.
Compose¶
compose.yaml
services:
### --- IT Tools --- ### https://github.com/CorentinTh/it-tools
it-tools:
image: corentinth/it-tools:2024.10.22-7ca5933
container_name: it-tools
restart: unless-stopped
ports:
- "8071:80"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:80/"]
interval: 30s
timeout: 10s
retries: 3
start_period: 15s
### --- Bento PDF --- ### https://github.com/alam00000/bentopdf
bentopdf:
image: bentopdf/bentopdf-simple:1.15.4
container_name: bentopdf
restart: unless-stopped
# bentopdf(-simple) listens on 8080 inside the container
ports:
- "8072:8080"
healthcheck:
test: ["CMD", "wget", "-q", "--spider", "http://localhost:8080/"]
interval: 60s
timeout: 5s
retries: 3
start_period: 20s
### --- ConvertX --- ### https://github.com/C4illin/ConvertX
convertx:
image: ghcr.io/c4illin/convertx:v0.19.0
container_name: convertx
restart: unless-stopped
ports:
- "3002:3000"
#environment:
#- JWT_SECRET=${JWT_SECRET} # when unset it will use the value from randomUUID()
volumes:
- /mnt/appdata/convertx/data:/app/data
# ConvertX ships a real /healthcheck route - better than a raw TCP check
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/healthcheck"]
interval: 30s
timeout: 10s
retries: 3
start_period: 30s
No .env is needed as written. If you set JWT_SECRET for ConvertX (recommended if you want logins to survive a
container recreate), add it as ${JWT_SECRET} and create the value with openssl rand -hex 32.
Notes¶
- Pinned tags. Every image is pinned and Renovate proposes updates. ConvertX is pre-1.0, where a
0.xminor bump can be a breaking release, so its updates wait for review instead of automerging. - BentoPDF listens on 8080, not 3000 as some older examples show. Mapping
8072:3000gives you a container that is "up" but serves nothing, which is why it has a real HTTP healthcheck now. - Healthchecks use what's in each image (
curlin IT-Tools and ConvertX,wgetin BentoPDF's Alpine/nginx image). Check withdocker exec <container> which curl wgetbefore copying a healthcheck to another image. - State: only ConvertX writes anything (
/app/data: its SQLite DB and the converted files, auto-deleted after 24 h by default). IT-Tools and BentoPDF are static web apps. - Access: all three are LAN-only tools. If you ever publish them, put them behind SSO first; ConvertX in particular runs real converters on uploaded files.