# Environmental Variables #check env.md file for examples and descriptions on each variable #----------------- REQUIRED -------------------------- #This is the only required/mandatory variable #Node will simply not run without this variable #All the other variables can remain blank (because they have defaults) or simply commented export PRIVATE_KEY=REPLACE_ME #----------------------------------------------------- ## core export RPCS= export DB_URL= export IPFS_GATEWAY=https://ipfs.io/ export ARWEAVE_GATEWAY=https://arweave.net/ export LOAD_INITIAL_DDOS= export FEE_TOKENS= export FEE_AMOUNT= export ADDRESS_FILE= export NODE_ENV= export AUTHORIZED_DECRYPTERS= export AUTHORIZED_DECRYPTERS_LIST= export OPERATOR_SERVICE_URL= export POLICY_SERVER_URL export INTERFACES= export ALLOWED_VALIDATORS= export ALLOWED_VALIDATORS_LIST= export AUTHORIZED_PUBLISHERS= export AUTHORIZED_PUBLISHERS_LIST= export INDEXER_INTERVAL= export ALLOWED_ADMINS= export ALLOWED_ADMINS_LIST= export RATE_DENY_LIST= export MAX_REQ_PER_MINUTE= export MAX_CHECKSUM_LENGTH= export LOG_LEVEL= export HTTP_API_PORT= export VALIDATE_UNSIGNED_DDO= export JWT_SECRET= ## p2p export P2P_ENABLE_IPV4= export P2P_ENABLE_IPV6= export P2P_ipV4BindAddress= export P2P_ipV4BindTcpPort= export P2P_ipV4BindWsPort= export P2P_ipV6BindAddress= export P2P_ipV6BindTcpPort= export P2P_ipV6BindWsPort= export P2P_ANNOUNCE_ADDRESSES= export P2P_ANNOUNCE_PRIVATE= export P2P_dhtMaxInboundStreams= export P2P_dhtMaxOutboundStreams= export P2P_mDNSInterval= export P2P_connectionsMaxParallelDials= export P2P_connectionsDialTimeout= export P2P_ENABLE_UPNP= export P2P_ENABLE_AUTONAT= export P2P_ENABLE_CIRCUIT_RELAY_SERVER= export P2P_ENABLE_CIRCUIT_RELAY_CLIENT= export P2P_BOOTSTRAP_NODES= export P2P_FILTER_ANNOUNCED_ADDRESSES= ## p2p keys that are mapped but were undocumented here # # Commented out with their real defaults, for the same reason as the timeout # budgets below: a bare `export KEY=` is NOT "unset". It reaches the config as an # empty string, and `z.coerce.number()` turns that into 0. Measured against # `OceanNodeP2PConfigSchema`, a blank value silently replaces the default with 0 # (or with "") for every key in this block except P2P_DHT_FILTER, # P2P_CIRCUIT_RELAYS and P2P_ENABLE_NETWORK_STATS - so a blank # P2P_MAX_CONNECTIONS would cap the node at zero connections. To keep a default, # leave the line commented out. # How long to wait before discovering bootstrap nodes, in ms. Default 10000. # export P2P_BOOTSTRAP_TIMEOUT=10000 # Tag applied to a bootstrap peer before discovering it. Default bootstrap. # export P2P_BOOTSTRAP_TAGNAME=bootstrap # Value of that bootstrap peer tag. Default 50. # export P2P_BOOTSTRAP_TAGVALUE=50 # Remove the bootstrap peer tag after this many ms. This node sets no default of # its own - left unset, libp2p's own bootstrap TTL applies. Example: 120000. # export P2P_BOOTSTRAP_TTL=120000 # Port used for IPv4 secure-websocket (wss) connections. Default 9005. # export P2P_ipV4BindWssPort=9005 # Address filtering in the DHT: filterNone (or 0) = none, filterPrivate (or 1) # = filter private addresses (default), filterPublic (or 2) = filter public # addresses. An unrecognised value falls back to the default with a warning. # export P2P_DHT_FILTER=filterPrivate # Force this node's kad-dht into server mode instead of letting it auto-switch # based on whether it currently has a public address. Only set this if the # operator already knows the node is reachable. Default false. # export P2P_DHT_FORCE_SERVER=false # Number of circuit relay servers to reserve a slot on. Default 0. # export P2P_CIRCUIT_RELAYS=0 # Connection count below which libp2p dials peers from the peer book; 0 disables # that behaviour. Default 1. # export P2P_MIN_CONNECTIONS=1 # Connection count above which libp2p starts pruning connections. Default 300. # export P2P_MAX_CONNECTIONS=300 # After a failed dial, do not auto-dial that peer again for this many ms. # Default 120000 (2 minutes). # export P2P_AUTODIALPEERRETRYTHRESHOLD=120000 # How many peers from the peer book are added to the dial queue at once. # Default 5. # export P2P_AUTODIALCONCURRENCY=5 # Maximum number of addresses tried for one peer before giving up. Default 30 - # a single bootstrap peer now has around 6 addresses (tcp/ws/wss x v4/v6), and this # budget is spent per address before the transport check runs. # export P2P_MAXPEERADDRSTODIAL=30 # Maximum number of dials that may be queued at once. Default 500 (libp2p's own default). # export P2P_MAXDIALQUEUELENGTH=500 # Time between closing a connection and opening the next auto-dialled one, in # ms. Default 5000. # export P2P_AUTODIALINTERVAL=5000 # Exposes the getP2pNetworkStats HTTP endpoint. It reports private information # such as your addresses, so it is off by default. Default false. # export P2P_ENABLE_NETWORK_STATS=false ## p2p timeout / attempt budgets # # Deliberately commented out rather than listed in the blank `export KEY=` style # used above, for two reasons: # # 1. A blank value is not a default. `export P2P_SENDTO_DIAL_MS=` was measured # reaching `OceanNodeP2PConfigSchema` as `''`, coercing to `0` and landing in # the config as a 0 ms - i.e. instantly expired - budget, while the code used # 15000. That is now fixed: `normalizeP2pBudget` (shared by the schema and the # `P2P_TIMEOUTS` getters) drops a blank, non-numeric, zero or negative value # and falls back to the default shown below. But a blank line still tells a # reader nothing, and it was wrong for long enough to be worth avoiding. # 2. Commented-out lines carry the actual default, so this file documents the # value you are overriding. # # Rules for every key here: a positive integer, milliseconds unless stated # otherwise. A malformed value (`15s`, `0`, `-1`, blank) is IGNORED with a # fallback to the default - it is an operator typo, not a reason to refuse to # boot. Values are floored to an integer. Every millisecond budget also has a # floor of 50ms: below that a budget expires before the round trip it is meant # to bound can finish, so such a value is ignored the same way. The two keys # that are counts rather than durations - P2P_SENDTO_MAX_ATTEMPTS and # P2P_COMMAND_MAX_INBOUND_STREAMS - keep a floor of 1. # How long a Kademlia findPeer walk may run. Default 20000 (20s). # export P2P_FINDPEER_TIMEOUT_MS=20000 # How long a findProviders query may run; without it kad-dht falls through to 180s. Default 20000. # export P2P_FINDPROVIDERS_TIMEOUT_MS=20000 # Per-frame idle budget when reading a response stream. Default 60000 (60s). # export P2P_STREAM_IDLE_TIMEOUT_MS=60000 # Ceiling on a WHOLE response body, measured from the first frame the caller reads. The # idle budget above rearms on every frame, so it bounds a stall, not a transfer; this one # bounds the transfer. Raise it if your peers legitimately stream for longer than an hour. # Default 3600000 (60 min). # export P2P_STREAM_BODY_TIMEOUT_MS=3600000 # sendTo stage 1 - address resolution. Default 20000 (20s). # export P2P_SENDTO_RESOLVE_MS=20000 # sendTo stage 2 - dial. Default 15000 (15s). # export P2P_SENDTO_DIAL_MS=15000 # sendTo stage 3 - stream open + command write + status read. Default 10000 (10s). # export P2P_SENDTO_STREAM_MS=10000 # Overall deadline for one sendTo SETUP phase, across all attempts; does not bound # the response body. Default 45000 (45s) = resolve + dial + stream. # export P2P_SENDTO_TOTAL_MS=45000 # Number of sendTo attempts, each with fresh per-stage signals. Default 2, hard cap 5 # (a larger value is clamped to 5, not ignored). # export P2P_SENDTO_MAX_ATTEMPTS=2 # Budget for a contentRouting.provide() (DDO / C2D capability advertise). Default 20000 (20s). # export P2P_ADVERTISE_TIMEOUT_MS=20000 # Budget for a local peerStore lookup. Default 3000 (3s). # export P2P_PEERSTORE_GET_MS=3000 # Budget for the opportunistic dial of a newly discovered peer. Default 10000 (10s). # export P2P_DISCOVERY_DIAL_MS=10000 # maxInboundStreams for the ocean command protocol handler. Not a timeout. Default 32. # export P2P_COMMAND_MAX_INBOUND_STREAMS=32 # Overall FindDDO deadline across all providers. Default 60000 (60s). # export P2P_FINDDDO_TIMEOUT_MS=60000 # Budget for asking ONE provider for a DDO. Providers are queried concurrently and the # first legitimate answer wins, so this bounds one branch rather than dividing the # deadline above. Default 10000 (10s). # export P2P_FINDDDO_PROVIDER_TIMEOUT_MS=10000 # How long FindDDO remembers that a DDO id was found nowhere, to blunt a hot re-query # loop. Consulted after the local database lookup, never before, so a DDO this node # holds is always returned. Default 30000 (30s). # export P2P_DDO_NOT_FOUND_CACHE_MS=30000 # Lifetime of the app-level "these are the peer's addresses" cache. Invalidated whenever # a dial against cached addresses fails, so a stale entry corrects itself rather than # making a peer unreachable. Default 45000 (45s). # export P2P_RESOLVE_CACHE_MS=45000 # Lifetime of the negative half of that cache - "this peer resolved to nothing". Short # on purpose: a peer that was offline comes back on its own schedule and must become # reachable again without a restart. Default 15000 (15s). # export P2P_RESOLVE_NEGATIVE_CACHE_MS=15000 # Ceiling on concurrent outbound sendTo calls, so a provider fan-out or the indexer's # decrypt loop cannot starve the dial queue. A count, not a timeout; half of # P2P_connectionsMaxParallelDials by default, hard-capped at 200. Default 25. # export P2P_SENDTO_MAX_CONCURRENCY=25 # How many peers the DHT routing table must hold before the node reports its P2P # interface as ready in the status endpoint. A count, not a timeout. Default 4 - the # number of disjoint lookup paths one DHT query is configured to run, i.e. the smallest # table at which a query can use the fan-out it is set up for. # export P2P_READY_MIN_ROUTING_PEERS=4 # Delay before kad-dht runs its first self-query, the query that populates the routing # table. Raised above kad-dht's own 1000 because at one second a fresh node has no DHT # peers yet - bootstrap peers are discovered after P2P_BOOTSTRAP_TIMEOUT and still have # to be dialled - so the query failed against an empty table and was not retried for # five minutes. Default 20000 (20s) = bootstrap timeout + discovery dial budget; raise # it in step if you raise either of those. # export P2P_INITIAL_QUERY_SELF_MS=20000 # How long the peer store keeps a peer's addresses before treating them as expired. # libp2p's own default is 3600000 (1 hour), but a DHT provider record is valid for 48 # hours, so with the library default the network kept handing us providers whose # addresses we had already dropped. Both this and the peer-record lifetime below match # the provider-record lifetime instead. Lower it only if your peers change address more # often than they re-announce. Default 172800000 (48 hours). # export P2P_PEERSTORE_MAX_ADDRESS_AGE_MS=172800000 # How long a peer record with no addresses survives before eviction (libp2p default # 21600000, 6 hours). Held to at least the address lifetime above - a lower value would # evict the record while its addresses were still valid, undoing the setting above. # Default 172800000 (48 hours). # export P2P_PEERSTORE_MAX_PEER_AGE_MS=172800000 ## compute # Resources are defined at the Docker-connection level (socketPath) and shared across all environments. # cpu, ram, and disk are auto-detected from the host — omit them to use all available capacity, # or include them to cap/reserve (e.g. limit an 8-core host to 6 cores for compute). # GPUs and other hardware go in the connection-level "resources" array with kind:"discrete". # Each environment references pool resources by id using lightweight refs {id, total?, min?, max?}. # Dual-gate tracking for fungible resources: per-env ceiling (Gate 1) + engine-wide pool (Gate 2). # Discrete resources (GPUs) are tracked globally — a GPU in use on envA shows as in-use on envB too. # export DOCKER_COMPUTE_ENVIRONMENTS='[{"socketPath":"/var/run/docker.sock","resources":[{"id":"disk","total":500},{"id":"gpu0","kind":"discrete","type":"gpu","total":1,"description":"NVIDIA A100","platform":"nvidia","driverVersion":"570.195.03","init":{"deviceRequests":{"Driver":"nvidia","DeviceIDs":["GPU-uuid-a"],"Capabilities":[["gpu"]]}}}],"serviceOnDemand":{"enabled":true,"nodeHost":"localhost","hostPortRange":[30000,32767],"minDurationSeconds":0,"maxDurationSeconds":86400,"allowImageBuild":false},"environments":[{"id":"envA","storageExpiry":604800,"maxJobDuration":3600,"minJobDuration":60,"minServiceDuration":600,"maxServiceDuration":7200,"resources":[{"id":"cpu"},{"id":"ram"},{"id":"disk","max":500},{"id":"gpu0"}],"fees":{"1":[{"feeToken":"0x123","prices":[{"id":"cpu","price":1},{"id":"ram","price":0.1},{"id":"disk","price":0.01},{"id":"gpu0","price":5}]}]}}]}]' export DOCKER_COMPUTE_ENVIRONMENTS= # Hugging Face mirror for service containers (docs/services.md, "Hugging Face mirror (DingoSpeed)") # export SERVICE_HF_MIRROR_URL=http://172.17.0.1:8092 # export SERVICE_HF_CLIENT_PATCH=true # Node-owner env vars injected into every C2D + service container (docs/env.md, "PASS_CONTAINER_ENVS"). # JSON object or array of KEY=value. SECURITY: readable inside third-party containers — no secrets. # export PASS_CONTAINER_ENVS='["HF_ENDPOINT=http://172.17.0.1:8092","LOG_LEVEL=debug"]'