Skip to content

Self-hosting

You do not need to use signed-data.org as your data provider. CDS is a standard — the SDK, the spec, and the domain schemas are infrastructure-free. Run your own ingestors, sign with your own key, and serve your own events.

ComponentMinimum viableProduction
Private keyLocal PEM fileAWS Secrets Manager / KMS
IngestorPython scriptLambda / container (cron)
Event storeLocal filesS3 (append-only, versioned)
Consumer APIRead from diskAPI Gateway / ALB + Lambda / ECS
MCP serversigneddata-mcp-lotteryECS Fargate behind ALB
Terminal window
pip install signeddata-cds
# Generate keys
python3 -c "
from cds import generate_keypair
import os; os.makedirs('keys', exist_ok=True)
generate_keypair('keys/private.pem', 'keys/public.pem')
"
import asyncio
from cds import CDSSigner
from cds.sources.lottery import MegaSenaIngestor
signer = CDSSigner("keys/private.pem", issuer="https://mycompany.example.com")
ingestor = MegaSenaIngestor(signer=signer)
events = asyncio.run(ingestor.ingest())
for e in events:
print(e.context.summary)
print(f" signed_by: {e.integrity.signed_by}")
print(f" hash: {e.integrity.hash[:32]}...")

Set your issuer to the URI of your organisation:

signer = CDSSigner("keys/private.pem", issuer="https://mycompany.example.com")

Publish your public key at:

https://mycompany.example.com/.well-known/cds-public-key.pem

Consumers can then discover and verify your key automatically.

If you run your own CDS issuer, you should publish your vocabulary so consumers can dereference URIs in your events.

  1. Create your vocabulary file

    Create vocab/cds.jsonld for your organisation, listing the classes and properties you use. You can copy and adapt the reference vocabulary from https://signed-data.org/vocab/.

  2. Serve it at your domain

    Upload vocab/cds.jsonld and any domain files to your web server or CDN:

    https://mycompany.example.com/vocab/ → cds.jsonld
    https://mycompany.example.com/vocab/domains/ → domain files
    https://mycompany.example.com/sources/ → source documents
    https://mycompany.example.com/contexts/ → JSON-LD context

    Set Content-Type: application/ld+json for all .jsonld files.

  3. Publish your public key

    https://mycompany.example.com/.well-known/cds-public-key.pem
  4. Reference your vocabulary in events

    Your events should use your base URI:

    from cds.vocab import content_type_uri, source_uri
    MY_BASE = "https://mycompany.example.com"
    my_content_type = f"{MY_BASE}/vocab/custom-domain/custom-schema"
    my_source = f"{MY_BASE}/sources/my-api.v1"

When self-hosting, the envelope format, content types, signing algorithm, and domain specs are identical to signed-data.org. Your events are verifiable by any CDS consumer — they just use your public key instead of ours.

Propertysigned-data.orgYour deployment
integrity.signed_byhttps://signed-data.orghttps://mycompany.example.com
Public key URLsigned-data.org/.well-known/...mycompany.example.com/.well-known/...
InfrastructureOur AWS accountYour AWS / GCP / Azure account
Ingestor scheduleOur cronsYour crons

A consumer can hold multiple public keys and verify against the declared issuer:

KNOWN_ISSUERS = {
"signed-data.org": CDSVerifier("signed-data-org.pub.pem"),
"mycompany.example.com": CDSVerifier("mycompany.pub.pem"),
}
verifier = KNOWN_ISSUERS.get(event.integrity.signed_by)
if not verifier:
raise ValueError(f"Unknown issuer: {event.integrity.signed_by}")
verifier.verify(event)