Sign your PDFs with your own certificate.
Garabato is a self-hosted app for signing PDFs with your PKCS#12 digital certificates. Drop a file, place the visible signature, sign and download. Certificates and documents are stored encrypted, and every signature becomes a new version.
curl -fsSL https://raw.githubusercontent.com/Nonetss/garabato/main/scripts/bootstrap.sh | bashWhat you get
Place the signature and sign.
Pick a certificate, choose a visible or invisible signature, drag a rectangle on the page and add an optional reason and place. The signature is PAdES with the certificate chain embedded, and with a time-stamping authority configured it carries a timestamp that proves when it was made.
Every signature is a new version.
Signing never overwrites a document. The viewer shows the visible stamps, the version history, each one downloadable, and who signed with which certificate.
A library that stays tidy.
PDF thumbnails in nested folders with their own icon, colored tags and pinned documents. Search and filter across the whole library, select several at once and move them by dragging.
Your certificates, kept encrypted.
Import a PKCS#12 file once and sign with it from then on. The file and its password are sealed with their own key, and the list shows the holder, tax id, issuer and how long each one is still valid.
A trace of everything you do.
Every signature with its document, certificate, version, placement and hashes, next to every import, upload, merge, page edit, download, rename, move and deletion, filterable by type, certificate, name and dates.
And the rest of the app
- Search everywhere
- ⌘K or Ctrl+K jumps to any page, document or folder of the library.
- Light, dark and mobile
- Light, dark or system theme, a layout that works on a phone, and an installable PWA.
- Sign-in your way
- Email and password, plus any OIDC provider (Keycloak, Authentik, Google…) turned on with three variables.
- Admin panel
- Users, sessions, organizations and teams, API keys and an activity log, for the admin role only.
- A typed API
- Every procedure is also plain HTTP under /api/v1, documented at /scalar for admins. Call it from scripts with an API key.
- Your storage
- Documents go to the bundled MinIO or to any S3-compatible store you already run.
How it fits together
Three app images plus PostgreSQL and object storage, run with Docker Compose. Browsers only talk to the Caddy gateway, which sends the API to the backend and everything else to the frontend. The backend owns the database and the document store.
Request paths
- → HTTPS
- :80Caddy→ /*
- :4321Astro SSR
- → /rpc
- :80Caddy
- :3000Hono · oRPCPostgreSQL→ S3
- :9000MinIO · S3
Gateway routing
| Request | Goes to |
|---|---|
| /rpc/* /api/* /scalar* /openapi.json | backend:3000 |
| /health | ok |
| any other path | frontend:4321 |
- Everything sensitive is encrypted at rest.
- Each certificate and document gets its own random data key, wrapped by the master key in CERTIFICATE_ENCRYPTION_KEY. PKCS#12 files, their passwords and every PDF version are sealed with AES-256-GCM, bound to the record and slot they belong to.
- Signatures a validator can check.
- Garabato signs PAdES baseline (ETSI.CAdES.detached) with the signing-certificate-v2 attribute and embeds the issuer chain, so a validator can build the path to the certificate authority. Set TSA_URL and every signature also gets an RFC 3161 timestamp (B-T), or fails rather than be stored without one.
- Nothing is overwritten.
- A signature produces a new version of the document and a signature record, listed in the traces. Earlier versions stay downloadable, and another user's documents and certificates answer as not found.
Up in one command.
On a Linux host with Docker, curl and openssl, from an empty directory:
curl -fsSL https://raw.githubusercontent.com/Nonetss/garabato/main/scripts/bootstrap.sh | bashPrefer to set it up by hand? Deploy with Docker Compose
What the script does
- Asks for the port, the public URL and the first admin, and whether documents go to the bundled MinIO or to an external S3-compatible store.
- Generates every secret with openssl, including the master key that encrypts certificates and documents.
- Writes .env and downloads compose.prod.yml into the current directory.
- Starts the stack with the images from ghcr.io. The backend migrates the database and creates the admin on startup.