Self-host Let's Seal
v0.1.0Open standard for sealing any file with cryptographic proof
- Stars
- 377
- Ports
- 8081 (Signing service (FastAPI) holding the intermediate CA key), 3000 (Web app (Next.js) dashboard, hosted API, verification portal)
- Requires
- PostgreSQL
What is Let's Seal?
Let's Seal provides an open standard for proving file authenticity — that a file is unchanged, certified by a known authority, and existed by a certain date. It handles PDFs (PAdES), media (C2PA), XML (XML-DSig), email (S/MIME), generic files (detached CAdES/CMS), and software artifacts with attestations. The stack includes a certificate authority as code, a FastAPI signing service holding the intermediate key, and a Next.js web app with dashboard, API, and verification portal. Verification is free, keyless, and works offline with standard tools. Run by Experimental Open Works as a public-benefit project. Self-hosting gives full control of your CA and keys; seals stay verifiable forever. Current release v0.1.0 (pre-1.0).
Let's Seal alternatives
DocusealOpen-source, self-hosted DocuSign alternative for creating fillable PDF forms and collecting digital signatures via a mobile-friendly web tool.CompareDocuseal with Let's Seal
OpenSignA self-hosted, open-source DocuSign alternative for e-signing PDFs: templates, sequential multi-signer flows, audit trails and a document vault.CompareOpenSign with Let's Seal
Ultimate Certificate ManagerManage your own PKI with this web-based CA: issue certificates, run ACME/SCEP/EST servers, integrate with Active Directory, and automate renewals.CompareUltimate Certificate Manager with Let's Seal
Signature PDFWeb app for digital PDF signatures, organizing (merge, rotate), metadata editing, and compression. PHP Fat-Free with Bootstrap.CompareSignature PDF with Let's Seal
signserver-ceSelf-hosted, LGPL-licensed open-source signing server that centrally signs code, documents and timestamps, deployed via Docker, Helm or a WildFly plus database install.Comparesignserver-ce with Let's Seal
CertMateCertMate is a self-hosted, open-source TLS certificate manager that issues, renews, discovers, and deploys certs across 29 DNS providers with audit trail, OIDC/SSO.CompareCertMate with Let's Seal
CertimateSelf-hosted open-source ACME tool for SSL cert workflows: DNS-01/HTTP-01 requests, deployment to 160+ cloud and Kubernetes targets, automated renewal and monitoring.CompareCertimate with Let's Seal
Pocket IDSelf-hosted, open-source OpenID Connect Certified provider for homelabs and small teams that find Keycloak or Authentik too heavy; passkey sign-in only.ComparePocket ID with Let's Seal
All self-hosted alternatives to Paid document sealing services →
Should you self-host Let's Seal?
Let's Seal scores 45/100 on selfhost.directory (how scoring works) and ranks #27 of 40 in Authentication. It has 377 GitHub stars.
It shipped 1 stable release in the past year. The latest, v0.1.0, came out on 23 July 2026.
Setup is advanced: plan for several services and some ongoing maintenance. It is Apache-2.0-licensed and written mostly in JavaScript.
Its closest alternative on selfhost.directory is keycloak (85/100, 37 600 stars). It scores higher overall, so compare the two before you pick. See Let's Seal vs keycloak side by side.
Features
- Bitcoin timestamp anchoring
- CLI (sealbot)
- Document sealing (PDF, PAdES)
- Email sealing (S/MIME)
- Generic file sealing (detached CAdES/CMS)
- GitHub Actions CI integration
- Image/video/audio sealing (C2PA)
- Offline verification
- Provider-verified email identity
- Public transparency log
- REST API
- SDKs (Python, TypeScript)
- Self-hosted certificate authority
- Software artifact sealing
- XML sealing (XML-DSig)
Let's Seal README
Seal anything.
The open standard for proving any file is real: unaltered, sealed by a known certificate, and in existence by a certain date.
Website · The SEAL standard · Free web app · Quickstart · What it seals · How it works · Use cases · Developers · Self-host · Verify a document
SEAL is the open standard for proving any file is real. One sealed artifact, one way to check it, verifiable by anyone, forever. Seal with any conforming tool, and anyone can verify it with any other.
Let's Seal created that standard, SEAL, Sealed Evidence Anchored to a Ledger, and runs the free network and reference implementation that issues and verifies it. The standard is the backbone. Everything in this repository is built on it, and given away.
It is the Let's Encrypt of document proof. Let's Encrypt made paid TLS certificates obsolete. Let's Seal does the same for paid document seals, and like Let's Encrypt it is free, open, and run as a public-benefit project of a foundation, not a startup.
Authenticity is infrastructure. It shouldn't be for rent.
Three ways to seal, all free:
- The hosted web app, app.letsseal.org. Free for anyone, in the browser, nothing to install. Seal a file, send documents out for signature (remote, in person, or with no email at all), and issue branded certificates and credentials.
- The command line and API.
sealbotfor the terminal, plus a REST API and SDKs to build sealing into your own systems. - Self-hosted. Run the whole engine yourself, under your own certificate authority.
Verifying is always free and never needs an account, at verify.letsseal.org or offline on your own machine.
- Free forever. No per-document fees, no paid seal.
- Open source (Apache-2.0). The engine, the SDKs, and the standard itself.
A SEAL proof establishes three things cryptographically, and states its boundary plainly:
- Unaltered. The file has not changed by a single byte since it was sealed. Change one byte and the signature breaks.
- Time. It existed by a certain date, anchored to Bitcoin through OpenTimestamps, with no trust in us.
- Issuer. It was sealed by a specific certificate. Where an organisation has proven control of a domain, the seal carries that domain as a machine-checkable identity.
Every seal is also written to a public, append only transparency log (RFC 6962) with a Bitcoin anchored root, so the record of what was sealed is itself tamper evident and anyone can audit it.
That is the whole guarantee, complete and permanent. A seal proves integrity, time, and the issuing certificate. It is not notarisation, and it does not assert a person's real world identity. The identity feature binds an email that a provider verified at seal time, and the honest term for it is a provider verified email, which is exactly what it delivers.
One standard, every kind of file, each in its own native format so any standard validator can check it. No bespoke tooling for the reader, and no dependency on Let's Seal to verify.
| File | Seal form | How it verifies |
|---|---|---|
| PAdES / X.509 signature embedded in the file | Any standard PAdES validator, or the reference verifier here | |
| Image, video, audio | C2PA (Content Credentials) manifest embedded in the media | Any C2PA reader |
| XML | Enveloped W3C XML-DSig signature | Any XML-DSig validator |
S/MIME multipart/signed (RFC 8551) |
openssl smime -verify |
|
| Any other file | Detached CAdES / CMS .sig over the file's SHA-256 |
openssl cms -verify; the file's bytes never leave your machine |
| Software artifact, container image | Signature plus in-toto / DSSE attestation (SBOM, SLSA provenance) | The standard open artifact-signing tools your pipeline already runs |
The seal is native to each format, so a sealed PDF is still a normal PDF that opens anywhere, a sealed image still shows everywhere, and a signed artifact still installs as usual. The proof rides along inside.
Seal and verify from the command line:
The free public verification portal, verify.letsseal.org:
A public proof page: the plain-English verdict anyone can open, with the evidence behind it. Subject and signer details stay private until you upload the file:
The hosted app at app.letsseal.org does the rest: seal files, send documents out for signature (remote, in person, or with no email at all), and issue branded certificates and credentials.
Verify any sealed document, free and in the open, at verify.letsseal.org, or run the reference verifier yourself:
python spec/verify.py sealed.pdf sealed.pdf.ots
Seal a file through the hosted API with an organisation key:
curl -X POST https://app.letsseal.org/api/v1/seal \
-H "Authorization: Bearer $LETSSEAL_KEY" \
-F file=@contract.pdfOr from the command line:
sealbot seal contract.pdf # seal a PDF or any file sealbot verify contract.sealed.pdf # verify a seal, offline
SDKs for Python and TypeScript, plus the OpenAPI schema, live in sdk/.
Open a sealed file's proof page, or run the verifier, and you get a plain verdict backed by evidence anyone can reproduce:
Authentic and unaltered
Document contract.pdf
SHA-256 9f2c1a…e7b4 (matches the sealed bytes, exactly)
Issuer Acme Solicitors LLP
Issuer verified, controls acme.example (dNSName in the cert)
Sealed 2026-07-14 11:42 UTC
Time anchor Bitcoin block #812,043 (via OpenTimestamps)
Transparency Entry #48,120 in the public log, inclusion proof checks out
Verdict rule: Authentic = valid and intact and trusted.
A valid signature that does not chain to the published root is
reported as unrecognised, never as authentic.
The verdict is deliberately strict. A cryptographically valid signature from a certificate that does not chain to the pinned root is a forgery vector, and it is reported as unrecognised, never as a pass.
The life of a seal: made once, evidenced and anchored to the public ledger, served back, and checkable by anyone, forever.
Two checks, both independent of us. A seal carries everything needed to check it, so pin the published root once and then verify offline, anywhere, forever.
- Root fingerprint (SHA-256):
02:68:6D:EE:20:67:31:C4:59:C1:7A:9F:58:36:7B:0B:0B:BA:5D:24:C6:85:D8:6D:1F:74:49:86:2D:C0:FE:BE, subjectCN=Let's Seal Root CA, O=Let's Seal, C=GB. Download it at letsseal.org/api/root-ca. - PDF: any standard PAdES validator with the root pinned, or
python spec/verify.py sealed.pdf sealed.pdf.ots. - Email and detached:
openssl smime -verify -in message.eml -CAfile letsseal-root.crt·openssl cms -verify -inform DER -in file.sig -content file -binary -CAfile letsseal-root.crt. - Software and SBOM: the standard open artifact-signing tools verify the signature and attestation against the published root, reproducible on any machine.
- Time:
ots verify sealed.pdf.otsagainst Bitcoin. - Transparency log: fetch an inclusion proof at
/api/log/proof?sha256=<hex>and check it against the signed tree head at/api/log/sth(RFC 6962). Consistency proofs at/api/log/consistencyprove the log is append only.
Every seal is written to an append only Merkle log (RFC 6962), the same structure browsers rely on for Certificate Transparency. The log's root is signed and itself anchored to Bitcoin, so:
- anyone can prove a given seal is included in the log (an inclusion proof),
- anyone can prove the log has never been rewritten (a consistency proof),
- and the whole thing can be audited without trusting the operator.
It is the impersonation audit trail: if a certificate ever sealed something under a name it shouldn't have, the evidence is public and permanent.
A seal always proves which certificate signed it. On top of that, an organisation can prove control of a domain (DNS record or a message to a controller address), and that domain is then bound into the signing certificate itself as a dNSName, so an off-platform verifier reads the identity straight from the certificate.
- Organisations that have not verified a domain are shown as self asserted, never as verified.
- A verified issuer's badge is the domain it controls, which is globally unique and cannot collide.
- Abuse can be reported publicly, and an impersonating issuer can be suspended, which stops its keys and drops its verified badge.
This is domain control as identity, the same model the web took for TLS. It proves who controls the seal, not a person's legal identity, and it says so plainly.
The practices behind every certificate are published in full: the hierarchy and key protection, how a domain is validated before it is bound into a certificate, what each certificate profile carries, how revocation works and how far back each reason reaches. See CPS.md, which follows the RFC 3647 framework and names the file in this repository that performs each practice, so every statement in it can be checked against the code.
Open to verify. Open to implement. Impossible to lock up.
SEAL is a published specification anyone can build on, see SPEC.md and letsseal.org/standard. The goal is one interoperable way to seal and verify any file, not a product to lock into. A SEAL proof is integrity, time, transparency, and optional verified-email attribution in a single self-contained artifact.
The signing service, the SDKs, and the reference verifier in this repository are the reference implementation. Anyone else is free to write their own, and a proof made by one implementation verifies under any other.
The standard fits any file and any sector. Worked guides for the common ones, each with step-by-step instructions and live proofs:
- Documents and law: Law & legal · Property & conveyancing · Compliance & audit · HR & corporate · Government & public sector
- Finance and professional services: Banking & lending · Insurance · Accounting & audit · Investment & asset management · Surveying & property reports
- Software and supply chain: Software supply chain · Procurement & supply chain · Manufacturing & trade
- Regulated and specialist: Healthcare · Pharma & life sciences · Construction & engineering · Intellectual property · Education & credentials
- Media and individuals: Media, journalism & creative · Individuals & freelancers
See them all at letsseal.org/use-cases.
The engine is fully self hostable and carries no hosted only code paths. A single-user install runs the identical code the hosted service runs.
Run the whole thing yourself, under your own certificate authority.
git clone https://github.com/letsseal/letsseal.git && cd letsseal # 1. Certificate authority (see ca/) ./ca/setup-ca.sh init # 2. Signing service (holds the intermediate key; bind to localhost) cd signing-service && python -m venv .venv && . .venv/bin/activate pip install -r requirements.txt && uvicorn main:app --port 8081 # 3. Web app: dashboard, hosted API, verification portal, site cd ../web && npm install && cp .env.example .env # fill in the values npx prisma migrate deploy && npm run dev # http://localhost:3000
You can swap in a paid AATL or eIDAS .p12 later with zero code changes, if you want a reader's automatic green check for verifiers outside your own portal. The cryptographic guarantee is identical either way. Your verification portal is the trust anchor.
REST API (hosted or self-hosted), authenticated with an organisation API key:
POST /api/v1/seal seal a PDF (PAdES)
POST /api/v1/seal/c2pa seal an image, video, or audio file (C2PA)
POST /api/v1/seal/xml seal XML (XML-DSig)
POST /api/v1/seal/smime seal an email message (S/MIME)
POST /api/v1/seal/detached seal any file by digest (detached CAdES)
POST /api/v1/seal/blob seal a software artifact
POST /api/v1/seal/identity seal with a provider-verified email
POST /api/v1/attest attach an SBOM / SLSA attestation
POST /api/v1/anchor anchor a hash to Bitcoin
POST /api/v1/verify verify a seal (public, no key)
GET /api/v1/whoami check a key's organisation
Digest-only endpoints (/seal/detached, /seal/blob) never receive the file's bytes, only its SHA-256.
CLI: sealbot seal, sealbot verify, sealbot issue, sealbot anchor, sealbot watch. Install with npm i -g sealbot (or run npx sealbot); a self-contained Rust build lives in cli-rs/.
SDKs: hand-written clients for Python (sdk/python) and TypeScript (sdk/ts), plus the OpenAPI schema (sdk/openapi.json). Generate a client for any other language with sdk/generate.sh.
CI: seal build artifacts in a pipeline with the GitHub Action in ci/.
| Path | What it is |
|---|---|
ca/ |
Certificate authority as code (root and intermediate issuance) |
signing-service/ |
FastAPI signing service (holds the intermediate key) |
web/ |
Next.js app: dashboard, hosted API, verification portal, site |
spec/ |
The SEAL specification and reference verifier |
sdk/ |
Python and TypeScript SDKs, the OpenAPI schema, and generate.sh |
cli/, cli-rs/ |
The sealbot command line tool (Node and Rust) |
ci/ |
A GitHub Action for sealing artifacts in CI |
Authenticity is infrastructure. It shouldn't be for rent. Proving a file is real is a public good, like a padlock in a browser bar, and it should be free, open, and owned by everyone who relies on it. Let's Seal is run as a public-benefit project of a foundation, not a startup, so the standard can never be pulled back behind a paywall.
Apache-2.0, see LICENSE and NOTICE. The SEAL specification is free to implement.
Created and maintained by nsokin. Let's Seal is a project of Experimental Open Works.
More in Authentication
LinOTPLinOTP is a self-hosted, open-source MFA server supporting OATH standards, LDAP/AD, and various tokens with web UI and REST API.
LLDAPlldap is a self-hosted, open-source lightweight LDAP server with web UI, supporting SQLite/MySQL/PostgreSQL, simpler than OpenLDAP.
lmgateSelf-hosted gateway adding enterprise auth, rate limits, and model ACLs to Ollama, llama.cpp, and LM Studio via Docker Compose.
logtoSelf-hosted, open-source auth server for SaaS and AI apps: OIDC, OAuth 2.1 and SAML with passwordless, social login, MFA, RBAC and multi-tenant organizations.
LoStackLoStack is a self-hosted Docker and Traefik proxy manager automating service routing, SSO via Authelia, with a 100+ package depot for one-click installs.
melody-authOpen-source OAuth auth server for Cloudflare Workers or self-hosted Node.js with Redis/PostgreSQL. Features MFA, social login, SAML SSO, RBAC, and web admin panel.
Mozilla Accounts (FxA)Monorepo for Mozilla Accounts (formerly Firefox Accounts)
my-self-hosting-servicesSelf-hosted Docker homelab with Authentik SSO, Traefik automated SSL, Cloudflare DNS automation, and Portainer. Includes n8n, OpenClaw AI, and microservices.
nforwardauthnforwardauth is a self-hosted, open-source forward auth service for Traefik, Caddy, and nginx that protects apps behind a single login using username/password credentials
nginx-ldap-authSelf-hosted reference for adding LDAP auth to NGINX via auth_request module, with Python daemon and sample config.
nhostOpen-source Firebase alternative and Backend-as-a-Service: Postgres, Hasura GraphQL APIs, auth, file storage and serverless functions, self-hosted with Docker Compose.
OIDC AuthSelf-hosted Home Assistant integration adding OpenID Connect single sign-on via providers like Authentik, Authelia, Keycloak, or Pocket ID. Installed via HACS.




0 comments