A local, OpenAI-compatible client that verifies the Nexus Gateway before any prompt is sent.
The SDK runs on your computer or server. At startup it checks a fresh attestation from the Nexus Gateway running in a trusted execution environment against a policy published by Dappnode. It accepts requests only after that verification succeeds, then protects prompt and response bodies between the local SDK and the verified Gateway.
You do not need a Dappnode to use it.
Go 1.26.8 or newer is required.
go install github.com/dappnode/dappnode-nexus-sdk/cmd/nexus-proxy@latestAlternatively, build it from source:
git clone https://github.com/dappnode/dappnode-nexus-sdk.git
cd dappnode-nexus-sdk
make buildThe maintained policy in this repository identifies the Nexus Gateway releases the SDK is allowed to trust. Download it through the Dappnode GitHub organization rather than from the Gateway being verified:
curl -fsSLo nexus-gateway-policy.json \
https://raw.githubusercontent.com/dappnode/dappnode-nexus-sdk/main/nexus-gateway-policy.jsonKeep this file updated when Dappnode publishes support for a new Gateway
release, or let the SDK track releases for you with --trust-policy-updates
described below.
--trust-policy-updates derives measurements from the most recent Gateway
releases instead of a pinned file, so the client is never stranded when the
Gateway moves on:
nexus-proxy \
--gateway-url https://nexus-api-tee.dappnode.com \
--trust-policy-updates \
--trust-policy-cache /var/lib/nexus-proxy/releases.jsonEach release is signed during the Gateway release workflow with a Sigstore certificate issued to that workflow's GitHub identity, and only that exact identity is accepted — GitHub is a CDN here, so a swapped release is rejected rather than believed. This changes only where measurements come from; they are still compared against the live attestation, and the body-encryption contract stays compiled into the SDK.
A new Gateway is picked up on first contact, not on a timer: a release the
policy has never seen is what a new deployment looks like, so the SDK
re-derives and verifies within the same request. Nothing has to be pushed to
the client, which matters behind NAT. Only an unrecognised release triggers
that — a pinned release whose measurements disagree is never retried, and
triggered refreshes are rate-limited. --trust-policy-refresh is an hourly
backstop; a failed refresh leaves the policy in force untouched.
--trust-policy-cache keeps the signed material so an offline start rebuilds
the same policy, re-verifying every signature on load.
--trust-policy-updates and --trust-policy are mutually exclusive. If
neither the network nor the cache produces a verified policy, the SDK refuses
to start.
nexus-proxy \
--gateway-url https://nexus-api-tee.dappnode.com \
--trust-policy ./nexus-gateway-policy.jsonThe SDK verifies the Gateway before opening its local listener. If verification fails, it exits without accepting prompts.
Create an API key at nexus.dappnode.com, then configure any OpenAI-compatible application with:
Base URL: http://127.0.0.1:3301/v1
API key: your Nexus API key
API: OpenAI Chat Completions
For example:
export NEXUS_API_KEY="your-api-key"
export NEXUS_BASE_URL="http://127.0.0.1:3301/v1"
curl "$NEXUS_BASE_URL/chat/completions" \
-H "Authorization: Bearer $NEXUS_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"MODEL_ID","messages":[{"role":"user","content":"Hello"}]}'Use GET /v1/models to list available model IDs. Regular and streaming chat
responses are supported.
Open the local verification page after starting the SDK:
http://127.0.0.1:3301/verification
It shows whether the Gateway passed verification and which verified connection handled each recent request. The page contains verification evidence and request metadata, never prompts or responses.
Go applications can use the same verification and encrypted transport without starting a separate process or opening a local port. For example, with the official OpenAI Go client:
verifyCtx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
sdk, err := nexus.New(verifyCtx, nexus.Config{
GatewayURL: "https://nexus-api-tee.dappnode.com",
TrustPolicyFile: "./nexus-gateway-policy.json",
})
cancel()
if err != nil {
log.Fatal(err)
}
defer sdk.Close()
client := openai.NewClient(
option.WithAPIKey(os.Getenv("NEXUS_API_KEY")),
option.WithBaseURL(nexus.InProcessBaseURL),
option.WithHTTPClient(sdk.HTTPClient()),
)
completion, err := client.Chat.Completions.New(context.Background(), openai.ChatCompletionNewParams{
Messages: []openai.ChatCompletionMessageParamUnion{
openai.UserMessage("Hello"),
},
Model: "MODEL_ID",
})
if err != nil {
log.Fatal(err)
}
fmt.Println(completion.Choices[0].Message.Content)New returns only after the Gateway passes verification. Developers can then:
- Mount
Handler()in an existing Go HTTP server. - Give
HTTPClient()andnexus.InProcessBaseURLto another Go SDK without opening a local port. - Call
ChatCompletions()orModels()directly. - Call
Verify(),Verification(), andEvidence()to build their own verification experience or independently inspect the signed evidence. - Call
Close()before exit when using a persistentStateFile.
TrustPolicyJSON can be used with Go's embed package when the application
should carry its pinned policy inside the binary.
See the complete embedding example and the package documentation.
Dappnode users can install Nexus Local Proxy instead of running the binary manually. Applications on the same Dappnode then use:
http://nexus-local-proxy.dappnode.private:3301/v1
- The SDK verifies the Gateway before accepting prompts.
- Prompt and response bodies are encrypted between the SDK and the verified Gateway.
- With a model whose id starts with
private/, that continues past the Gateway: those are served over an attested, encrypted transport that fails closed, so the prompt is protected end to end. - Prompt and response content is not written to verification history or logs.
The machine running the SDK remains trusted. Request metadata, including headers, sizes, and timing, is outside the body-encryption boundary. Protection also does not extend beyond Nexus to a downstream model provider. Keep the local listener private to your machine or trusted network.
See CONTRIBUTING.md for development instructions. Report security issues as described in SECURITY.md.
Licensed under the Apache License 2.0. Dependency notices are in THIRD_PARTY_NOTICES.md.