Environment Reference

The configuration variables a self-hosted Solana Developer Platform reads from .env.

The stack reads one .env file next to compose.yml. The configurator writes it, with the defaults and validation of the release you installed. This page covers how the file is organized and the variables you're most likely to set by hand.

The configurator groups the variables into sections:

SectionWhat it covers
BasicENVIRONMENT. The deployment mode is always self_hosted.
DatabaseBundled Postgres or an external database.
CacheBundled Redis or an external one.
Solana RPCThe devnet and mainnet RPC endpoints.
Authentication (Clerk)Clerk keys, issuer, dashboard URL, and webhook secret.
Signing providerWhich signers to enable, the default one, and their credentials.
Fee paymentThe Kora that sponsors each cluster's transaction fees, if any.
SecretsApp secrets, generated where you run the configurator.
AdvancedImage source, ports, public URLs, proxy trust, and optional features.

Required variables

compose.yml refuses to start without these:

VariableDescription
POSTGRES_PASSWORDPassword for the bundled Postgres. Required even with an external DATABASE_URL, because the bundled postgres service still starts.
API_KEY_PEPPERServer-side pepper for API key hashes. Generate it with openssl rand -hex 32.
CUSTODY_ENCRYPTION_KEYEncrypts custody secrets at rest. Generate it with openssl rand -base64 32.
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEYClerk publishable key for the dashboard.
CLERK_SECRET_KEYClerk secret key.

The configurator also requires these. The stack starts without them, but most leave a core flow broken:

VariableDescription
CLERK_ISSUERClerk issuer URL. Without it, dashboard sessions can't be verified, so sign-in fails.
FRONTEND_URLThe dashboard URL the browser loads. With ENVIRONMENT=production, the compose default, the API accepts only Clerk sessions issued to this origin, and won't start if it isn't an http(s) URL.
SOLANA_RPC_DEFAULT_DEVNET_API_KEY_URLThe devnet endpoint Sandbox projects read and send through. Without it, they get 503 RPC_UNAVAILABLE.
SIGNING_PROVIDERThe configurator writes local unless you pick another provider. The API reads it only at startup, where local (also its value when unset) requires SDP_DEPLOYMENT_MODE=self_hosted.
CUSTODY_PRIVATE_KEYWith local signing selected: SDP offers the local signer only while this is set.
CREDENTIAL_FINGERPRINT_PEPPERWithout it, saving or rotating provider credentials in the dashboard fails. Keep it stable.

SOLANA_RPC_DEFAULT_MAINNET_API_KEY_URL is optional: without it, SDP refuses Production projects' chain reads and sends.

The configurator generates API_KEY_PEPPER, CREDENTIAL_FINGERPRINT_PEPPER, and CUSTODY_ENCRYPTION_KEY for you, and can generate POSTGRES_PASSWORD.

Database

The configurator's database choice (DATABASE_MODE) shapes the file, but isn't written to it.

  • Bundled: set POSTGRES_DB, POSTGRES_USER, and POSTGRES_PASSWORD. The API and sdp-migrate build their connection string from them.
  • External: set DATABASE_URL to your postgresql://… string, and the API and migrations connect there. The bundled postgres container still starts, unused, so it still needs POSTGRES_PASSWORD. The configurator hides that field and generates a value for it.

Cache

The cache choice (CACHE_MODE) isn't written to the file either. For an external cache, set REDIS_URL to your redis://… or rediss://… endpoint. The bundled redis container still starts, unused.

Signing providers

The configurator offers local, fireblocks, privy, coinbase_cdp, para, turnkey, and utila. Its list of providers to enable (SIGNING_PROVIDERS) only decides which credential fields it shows, and isn't written to the file. Each provider other than local needs its own credentials, such as an API key and secret for Fireblocks. Each project picks its signer when you set up custody in the dashboard.

Privy, Coinbase CDP, Para, and Turnkey are open to every organization. The others, local included, also need a per-organization activation: First devnet deployment shows how for the local signer.

For provider co-signers that run outside the stack, see External co-signers.

Fee payment

SDP pays transaction fees through a Kora on each project's cluster, and the stack doesn't bundle one. The configurator's choice of clusters (FEE_SPONSOR_CLUSTERS) isn't written to the file: it shows each chosen cluster's fields. Without a Kora, sends SDP sponsors, such as payment transfers, answer 503 PROVIDER_UNAVAILABLE.

VariableDescription
KORA_DEVNET_URLThe Kora that pays fees for Sandbox projects.
KORA_DEVNET_RPC_URLThe Solana RPC endpoint that Kora reads. SDP prices and settles sponsored fees through it. Set it with KORA_DEVNET_URL: the API won't start with only one of the two.
KORA_DEVNET_API_KEYOptional. The API key your Kora requires, if any.
KORA_DEVNET_CLOUD_RUN_AUDIENCEOptional. For a private Kora on Cloud Run: SDP sends it a Google identity token for this audience, which needs the API on Google Cloud and the Kora URL on the audience's https origin.

The KORA_MAINNET_* variables do the same for Production projects.

Advanced

VariableDefaultDescription
SDP_IMAGE_REGISTRYghcr.io/solana-foundation/sdpRegistry the images come from.
SDP_VERSIONlatestImage tag for every SDP service. Pin it to a release tag, such as vX.Y.Z, in production.
SDP_API_PORT8787Host port for the API.
SDP_WEB_PORT3000Host port for the dashboard.
SDP_DOCS_PORT3001Host port for these docs.
TRUST_PROXY_HEADERSfalseHow to read X-Forwarded-For. true trusts the first address: use it only behind an ingress that replaces caller-supplied forwarding headers. gclb is for ingress restricted to a Google Cloud external Application Load Balancer, which appends the verified client address. With false, SDP can't see caller addresses: per-IP limits count every caller as one, and an IP allowlist refuses every request.

SDP_API_BASE_URL (default http://sdp-api:8787) is how the dashboard's server reaches the API inside the Docker network. The browser-facing NEXT_PUBLIC_* URLs default to localhost, such as http://localhost:8787 for the API and http://localhost:3000 for the dashboard. Change them, and FRONTEND_URL, when you put the services behind your own domains.

compose.yml also reads SDP_RELEASE_CHANNEL, which the configurator doesn't set. It decides which modules and providers the API and dashboard run (experimental, beta, or stable), and defaults to experimental.