Default Values: Most variables have defaults that suit a typical
gateway. Set a variable only to change its behavior.
Set these in the .env file next to docker-compose.yaml. The Default column is what you get under the shipped docker-compose.yaml. Where Docker Compose sets a different default from the gateway's own code, the cell gives both, and the code's value applies only when you run the gateway outside Docker.
A few variables have a different name in .env from the one the service reads, because Docker Compose renames them (for example CORE_LOG_LEVEL becomes the core service's LOG_LEVEL). The tables use the .env name.
This page covers the variables most operators need. The full list, with every default, is in the gateway repository's docs/envs.md.
Configure response signing to provide cryptographic proof that your gateway produced a given response.
If OBSERVER_KEYPAIR_PATH or OBSERVER_PRIVATE_KEY is set, the observer's Ed25519 Solana key signs responses directly. The key's Solana address is already in the on-chain Gateway Registry, so verifiers can confirm the signer with a single GAR lookup. If neither is set, the gateway auto-generates a standalone Ed25519 key at HTTPSIG_KEY_FILE; responses are still signed but can't be tied back to the registry. Setting both at once is rejected at startup as ambiguous.
Variable
Type
Default
Description
HTTPSIG_ENABLED
boolean
true
Enable RFC 9421 response signing
HTTPSIG_KEY_FILE
string
data/keys/httpsig.pem
Path to standalone Ed25519 private key PEM. Auto-generated on first startup if missing. Ignored when OBSERVER_KEYPAIR_PATH or OBSERVER_PRIVATE_KEY is set
HTTPSIG_BIND_REQUEST
boolean
true
Include request method and path in signature (prevents replay)
OBSERVER_KEYPAIR_PATH
string
-
Path to a 64-byte Solana keypair JSON file (e.g. solana-keygen new output). When set, used as the HTTPSIG signing key. The observer reads it too
OBSERVER_PRIVATE_KEY
string
-
Alternative to OBSERVER_KEYPAIR_PATH: base58-encoded 64-byte Solana secret key (the format Phantom and other browser wallets export)
Most Arweave peers tried, one after another, to fetch a chunk before giving up. Each attempt is capped at 500 ms. Release 85 raised it from 5
PREFERRED_CHUNK_GET_NODE_URLS
string
data-1 to data-17 and tip-1 to tip-4.arweave.xyz:1984
Comma-separated Arweave node URLs tried first for chunk GETs. From Release 85, each gateway orders them by how well each serves it, so set this only to pin specific nodes
PREFERRED_CHUNK_POST_NODE_URLS
string
tip-1 to tip-4.arweave.xyz:1984
Comma-separated Arweave node URLs chunks are broadcast to first (POST /chunk)
Release 85 removed tip-5.arweave.xyz from both default lists. If you set either list yourself, remove it there too.
The CDB64 index looks up which root Arweave transaction holds a data item, in one read. The gateway ships three pre-built indexes by default. See CDB64 Root TX Index for what they cover and how to use them.
Comma-separated root TX lookup sources: db, peers, gateways, graphql, hyperbeam, cdb, cdb-remote (Release 85), turbo. With cdb-remote in the order, cdb asks only CDB64 indexes on local disk and cdb-remote the ones read over the network; without it, cdb asks all of them. See Root Transaction Lookup
CDB64_ROOT_TX_INDEX_SOURCES
string
Release 85: data/indexes/installed/root-tx-index, then the three shipped resources/ indexes; Release 84: the three shipped indexes
Comma-separated CDB64 sources: local files, directories (including a directory of bands), HTTP URLs, Arweave TX IDs, or bundle data items. When you add a source, list the shipped ones too if you want to keep them
CDB64_ROOT_TX_INDEX_DATA_PATH
string
./data/cdb64-root-tx-index
Host directory mounted at data/cdb64-root-tx-index in the core container, for your own index files
CDB64_ROOT_TX_INDEX_WATCH
boolean
true
Watch every local CDB64 directory source, so new files load without a restart
CDB64_REMOTE_RETRIEVAL_ORDER
string
chunks
Data sources for fetching remote CDB64 files: gateways, chunks, tx-data
CDB64_REMOTE_CACHE_MAX_REGIONS
number
100
Maximum byte-range regions to cache per remote source
CDB64_REMOTE_CACHE_TTL_MS
number
300000
TTL for cached byte-range regions (5 minutes)
CDB64_REMOTE_REQUEST_TIMEOUT_MS
number
30000
Request timeout for remote CDB64 sources
CDB64_REMOTE_MAX_CONCURRENT_REQUESTS
number
4
One limit on concurrent HTTP requests, shared by all remote CDB64 sources
Settings for the index-swarm sidecar, which subscribes to other gateways' indexes and publishes your own. Available from Release 84, and on by default from Release 85 (On by Default). See Index Sharing for how each one is used.
[] opts out. Publishers to subscribe to, by gateway wallet: [{"publisher":"<wallet>","name":"root-tx-index"}]. name may be one index or a list. Without name, you take every index the publisher offers except opt-in kinds; from Release 85, parquet-l1 and every parquet-l2 index are opt-in and must be named. An optional url fetches from another address, such as a fleet's signing node; the signature is still checked against the registered key. See Take L1 Bands
INDEX_SWARM_PUBLISH
JSON
unset
Indexes this gateway publishes: [{"name":"root-tx-index","kind":"cdb64-root-tx"}]
INDEX_SWARM_MAX_DISK_BYTES
number
Release 85: 64 GiB with the default subscription, no ceiling with one you set; Release 84: unset (no ceiling; the setup script writes 50 GiB)
Ceiling on the disk the sidecar takes for bands. A band that would go over it is skipped. See Disk
INDEX_SWARM_OBSERVER_KEYPAIR_FILE
string
unset
Publishers only: host path of the observer keypair file. Set this or OBSERVER_PRIVATE_KEY, not both
INDEX_SWARM_TRUSTED_PUBLISHERS
string
unset
Comma-separated wallets. When set, only these publishers are accepted
INDEX_SWARM_ALLOWED_FILE_ORIGINS
string
unset
Other servers (http(s)://host[:port]) a publisher may send band files from, such as its CDN. Anything else is refused
INDEX_SWARM_POLL_INTERVAL_SECONDS
number
300
How often each publisher is checked for new bands
INDEX_SWARM_DOWNLOAD_RATE_LIMIT_BYTES_PER_SEC
number
unset
Cap on download speed, shared across all files of a band
INDEX_SWARM_DOWNLOAD_STALL_TIMEOUT_SECONDS
number
60
Give up on a download that receives nothing for this long; it resumes next poll
INDEX_SWARM_DOWNLOAD_CONCURRENCY
number
4
Parallel file downloads within one band
INDEX_SWARM_DATA_PATH
string
./data/indexes
Host directory for published, downloading and installed bands. The gateway mounts the same directory
INDEXES_PUBLISHED_DIR
string
data/indexes/published
Where the gateway's /ar-io/indexes routes serve from, inside the core container
INDEXES_PUBLIC_URL
string
https://<ARNS_ROOT_HOST>
Release 85. This gateway's public origin, such as https://gateway.example: the start of the URLs in its index feeds (/ar-io/indexes/feed/<index>.xml) and of the WebSeed each served .torrent names. An origin only (scheme, host and optional port, no path); any other value stops the gateway at startup. Never taken from a request's Host header. With neither this nor ARNS_ROOT_HOST, feeds answer 404 and .torrent files are served without a WebSeed
INDEXES_TORRENT_WEBSEED
boolean
true
Release 85. Whether each served .torrent names this gateway as its WebSeed (<INDEXES_PUBLIC_URL>/ar-io/indexes/webseed/), so a stock BitTorrent client following a feed can finish a band no peer is delivering. Such a client pulls a good share of every band from it even while seeders could serve it, through the byte routes' rate limits when they are metered. false serves torrents as the publisher wrote them, for peers only. Subscribing gateways drop the WebSeed either way
Settings for the torrent engine. From Release 85 it runs by default and generates its password on first start. On Release 84 it sits in the compose profile index-swarm-torrent, and setting INDEX_SWARM_ENGINE_AUTH turns it on; ./tools/index-swarm-setup --torrent generates it. See Tuning the Torrent Engine.
Variable
Type
Default
Description
INDEX_SWARM_ENGINE_AUTH
string
Release 85: generated on first start into data/indexes/engine-auth; Release 84: unset
user:password for the engine's Web API, for example swarm:<generated>. The password must be at least 16 characters. A value you set is used instead of the generated one. On Release 84, setting it turns the engine on
INDEX_SWARM_ENGINE_URL
string
http://index-swarm-engine:8080 when there is an engine password, else unset
The engine's Web API. Set it only for an engine run outside the compose profile
INDEX_SWARM_ENGINE_PORT
number
6881
Peer port, published on the host over TCP and UDP. Keep it below Linux's ephemeral range (32768–60999)
INDEX_SWARM_ENGINE_PUBLIC_HOST
string
host of the first INDEX_SWARM_TRACKERS URL
The host or IP peers reach this node's engine on. Set it when the tracker is served through a CDN or load balancer that does not forward the peer port
INDEX_SWARM_UPLOAD_LIMIT_BYTES_PER_SEC
number
10000000
Cap on upload to peers (10 MB/s). 0 is unlimited. See Bounding Upload
INDEX_SWARM_UPLOAD_DAILY_LIMIT_BYTES
number
100000000000
Most the engine may upload in a UTC day (100 GB). 0 is no budget. See Bounding Upload
INDEX_SWARM_TORRENT_TIMEOUT_SECONDS
number
3600
How long a torrent may go without progress before the band is fetched over HTTP instead
INDEX_SWARM_WEBSEED_AFTER_SECONDS
number
120
How long a torrent may stall before the publisher's WebSeed is added
INDEX_SWARM_TRACKERS
string
unset
Comma-separated announce URLs written into every torrent this node publishes; normally its own tracker through the gateway, https://<gateway>/ar-io/indexes/announce (Release 85; on Release 84, http://<public host>:6969/announce)
INDEX_SWARM_TRACKER_PORT
number
6969
Port the tracker listens on for direct announces, published on the host by the sidecar. Only a node that publishes torrents listens on it. Open it only when peers announce to it directly rather than through the gateway
INDEX_SWARM_TRACKER_HOST_IP
string
127.0.0.1
Release 85. Host address the tracker port is published on. Set 0.0.0.0 when peers announce to the tracker port directly
INDEX_SWARM_TRACKER_PROXY_PORT
number
6970
Release 85. Port of the tracker's second listener, which Envoy forwards /ar-io/indexes/announce to. Never published. Compose passes it to both the sidecar and Envoy. Needs the Envoy image from Release 85 or later
INDEX_SWARM_TRACKER_PROXY_HOST
string
index-swarm
Release 85. Host Envoy forwards /ar-io/indexes/announce to: the sidecar's service name. Change it only when the sidecar runs elsewhere
INDEX_SWARM_TRACKER_PROXY_TRUSTED_PROXIES
string
every private range
Release 85. IPs or CIDRs whose X-Forwarded-For hop the tracker's gateway listener believes. Like core's TRUSTED_PROXIES, the default needs no setting behind NGINX and Envoy, but also believes a client that reaches Envoy from a private address (LAN, tailnet, another container), which can then list any address as a peer. Where such clients exist, list only the proxies, such as 172.16.0.0/12,<nginx host>
INDEX_SWARM_TRACKER_TRUSTED_PROXIES
string
unset
Comma-separated IPs or CIDRs of proxies in front of the tracker whose X-Forwarded-For it believes, on both listeners. List any proxy that reaches the gateway from a public address. The direct port believes only this list. See Publishing from a Fleet
INDEX_SWARM_ALLOWED_TRACKERS
string
unset
Tracker URLs, exactly as written, that a subscriber hands its engine even though their host is private. Only useful with INDEX_SWARM_ENGINE_BLOCK_PRIVATE=false
INDEX_SWARM_ENGINE_BLOCK_PRIVATE
boolean
true
Have the engine refuse peers, trackers and WebSeeds on private, loopback, link-local and carrier-grade NAT addresses. See Sharing Between Your Own Gateways
INDEX_SWARM_ENGINE_NETWORK_NAME
string
ar-io-index-swarm-engine
Docker network the engine runs on, shared only with the sidecar
INDEX_SWARM_ENGINE_UID / INDEX_SWARM_ENGINE_GID
number
1000
User and group the engine runs as. Set the same values for the sidecar and the engine
INDEX_SWARM_ENGINE_CONFIG_PATH
string
./data/index-swarm-engine
Host directory for the engine's configuration and resume data
INDEX_SWARM_ENGINE_CONFIG_DIR
string
/config
Where index-swarm-engine-init writes the engine's configuration, inside its container. Set it only when running the init outside compose
Release Requirement: The index-export service and these settings
require gateway Release 85 or later.
Settings for the index-export service (compose profile index-export), which builds your gateway's bands for the sidecar to publish. It logs by LOG_LEVEL and LOG_FORMAT. See What the Daily Run Does.
The lowest height to build. Root-TX bands need it before the first run; ./tools/index-swarm-setup --publish --start-height <n> sets it
INDEX_EXPORT_HEADER_CHECK_URL
string
unset
Required for root-TX and L2 bands: the gateway a sample of each band's entries is checked against before publishing. ./tools/index-swarm-setup --publish writes https://turbo-gateway.com
INDEX_EXPORT_HEADER_CHECK_TIMEOUT_MS
number
30000
Timeout for each read of that check
INDEX_EXPORT_SOURCES
JSON
unset (this gateway's ClickHouse when CLICKHOUSE_URL is set, else its SQLite)
Where root-TX records come from
INDEX_EXPORT_SECRETS_DIR
string
unset
Host directory of password files for the ClickHouse sources INDEX_EXPORT_SOURCES names
INDEX_EXPORT_CORE_DB
string
data/sqlite/core.db
The core.db L1 bands are built from, opened read-only
INDEX_EXPORT_RUN_AT_UTC
string
04:00
Time of the daily run, HH:MM UTC
INDEX_EXPORT_RECENT_MAX_BLOCKS
number
100000
Span at which a recent root-TX band is frozen and a new one starts
INDEX_EXPORT_L1_RUN_BUDGET_MINUTES
number
240
How long a run keeps starting whole L1 bands. Raise it for a bootstrap
INDEX_EXPORT_L1_WITNESS_DIR
string
unset
Release 87. Where index-export takes L1 witnesses (layout l1-4) from, as the container sees it (under data/indexes, say): v1 data roots in roots-*.jsonl files, Arweave's 2.0 checkpoint as fork_2_0_checkpoint, and optionally Arweave's hash_list_1_0. Untrusted: only what the chain confirms is kept
INDEX_EXPORT_L1_WITNESS_NODES
string
unset
Release 87. Comma-separated Arweave nodes (http://host:1984) index-export asks for what the witness directory lacks. Without this or INDEX_EXPORT_L1_WITNESS_DIR, only bands needing no input (no format-1 data, no height below the 2.0 fork) get witnesses; the rest stay l1-3
INDEX_EXPORT_L2_INDEXES
JSON
unset (required for parquet-l2)
The L2 indexes to build, each {"name":…,"selection":{"kind":"ans104-data-items","tag":{"name":…,"valuePrefix":…,"excludeValuePrefix":…}},"keyTags":[…],"statTags":[…]}. An item is in an index when one of its tags is named name exactly and its value starts with valuePrefix and not with excludeValuePrefix (optional; it must extend valuePrefix), compared as UTF-8 bytes. Names match [a-z0-9-]{1,64}, are unique, and are not root-tx-index, parquet-l1 or blobs. A selection never changes: a new one is a new name. Each is listed in INDEX_SWARM_PUBLISH as {"name":<name>,"kind":"parquet-l2"}. Release 86: keyTags and statTags (optional, at most 16 tag names each, none unless given) name the tags each band's lookup_key.parquet and stats.parquet are derived for; a change is applied to every published band in place. See Publish an L2 Index
INDEX_EXPORT_L2_SOURCE
JSON
this gateway's ClickHouse
The ClickHouse L2 bands are read from: {"type":"clickhouse"} (this gateway's; CLICKHOUSE_USER must be set) or a peer's with url, user and passwordFile under INDEX_EXPORT_SECRETS_DIR
INDEX_EXPORT_L2_SETTLE_BLOCKS
number
INDEX_EXPORT_ROOT_TX_SETTLE_BLOCKS (5040)
Blocks a 5,000-height range waits below the source's stable top before its L2 band is frozen; above, a tip band per sub-range is rebuilt daily
INDEX_EXPORT_L2_WALLETS_DB
string
data/sqlite/bundles.db
The bundles.db whose wallets table gives owners' keys ClickHouse doesn't hold, read-only; skipped when absent
INDEX_EXPORT_L2_MAX_READS
number
200000
The most reads through INDEX_EXPORT_HEADER_CHECK_URL one L2 band may make to settle ambiguous locations and read owners' keys. A band needing more is rejected
INDEX_EXPORT_L2_RUN_BUDGET_MINUTES
number
240
How long a run keeps starting frozen L2 bands; the rest, and the tip, wait for the next run. Raise it for a bootstrap
INDEX_EXPORT_L2_DUCKDB_MEMORY
string
2GB
DuckDB's memory limit while an L2 band is built. Keep it, with the 4 GB heap, under the container's mem_limit
INDEX_EXPORT_L2_DUCKDB_THREADS
number
2
DuckDB's threads while an L2 band is built, 1 to 64
INDEX_EXPORT_L2_DUCKDB_SPILL_MAX_GB
number
256
The most DuckDB may spill to disk while an L2 band is built; a build past it fails rather than fill the disk
INDEX_EXPORT_L2_WINDOW_ITEMS
number
50000
The most items one window of the source holds in memory; a larger window is read again in halves. At least 1,000
INDEX_EXPORT_L2_RECHECK_UNREADABLE_EVERY
number
4
A frozen L2 band built while some roots answered 404 is rebuilt on every this many re-settles, so roots served again get in
INDEX_EXPORT_METRICS_PORT
number
9102
Port for index-export's /metrics and /healthz, inside its container
INDEX_EXPORT_IMAGE_TAG
string
the value of CORE_IMAGE_TAG
Core image tag for index-export, when it should run a newer image than the gateway
LOG_LEVEL
string
info
index-export log level
LOG_FORMAT
string
simple
index-export log format (simple or json)
INDEXES_ADVERTISE_FROM_URL
string
unset
On a fleet node that serves your indexes but does not sign them: the signing node's base URL (for example http://10.0.0.1:4000), so /ar-io/info advertises the same publication on every node. Leave it unset on the signing node. See Giving the Other Nodes the Index
Starting block height for indexing. With L1_BAND_IMPORT_ENABLED=true and an empty core.db, leaving it unset starts at the chain tip instead, and the history beneath comes from L1 bands
STOP_HEIGHT
number
Infinity
Stopping block height for indexing
L1_BAND_IMPORT_ENABLED
boolean
false
Release 85. Fill this gateway's L1 history (core.db) from installed parquet-l1 bands while it runs. Writes only heights core.db lacks beneath what the block importer writes itself, in short transactions, so the gateway keeps indexing and serving. Needs the index-swarm sidecar subscribed to parquet-l1; ./tools/index-swarm-setup --subscribe <publisher> --l1 sets both. Release 86: every range is verified before a row of it is written: the band checked whole, as index-l1-verify --bands-dir checks it, and bound to the chain by the block the gateway holds above it; a band that fails is refused and nothing of it is left. Release 87: an l1-4 band's witness files bind every block, including those below the 2.0 fork and those holding a format-1 transaction with data, so a whole chain of l1-4 bands fills with no further setting. See Bootstrap from L1 Bands
L1_BAND_IMPORT_BANDS_DIR
string
data/indexes/installed/parquet-l1
Release 85. Where the sidecar installs parquet-l1 bands, as core sees it
L1_BAND_IMPORT_INTERVAL_SECONDS
number
600
Release 85. Seconds between fill runs, counted from the end of the last. A run with nothing to fill writes nothing
L1_BAND_IMPORT_CACHE_MIB
number
512
Release 85. SQLite page cache for a fill run, in MiB. The run is a child process of core, so this is memory beside the gateway's own
L1_BAND_IMPORT_ALLOW_UNVERIFIED
boolean
false
Release 86. Legacy, for bands without witnesses (l1-3 and older) only: lets the fill write their pre-2.0 blocks and their blocks holding a format-1 transaction with data, which nothing binds without witnesses (passes --allow-unbound --allow-unverified-format1 to index-l1-import --fill). l1-4 bands don't need it. It never accepts blocks the bands hold only part of (--allow-incomplete), nor an l1-4 band's unbound blocks. Every other check still runs
L1_BAND_IMPORT_SAMPLE_FROM
string
TRUSTED_NODE_URL and the TRUSTED_GATEWAYS_URLS gateways not marked trusted: false
Release 86. Comma-separated sources the L1 band import anchors the bands' top at and draws its sample of headers and transactions from (--anchor-from). Two distinct machines must agree before a source's word refutes a band or attests a field; the worker warns when these resolve to fewer, and the import refuses to run on them
L1_BAND_IMPORT_ALLOW_UNSAMPLED
boolean
false
Release 86. Let the L1 band import fill without a sample (--allow-unsampled): with no sources, or a sample that leaves transactions undrawn; transaction ids and fields are then checked against nothing on the chain. A sample whose sources are only unreachable is never waived by this: that fill waits and is tried again
The ar.io protocol runs on five Solana programs (see protocol architecture), and the gateway talks to four of them: ario-core, ario-gar, ario-arns, and ario-ant. The fifth, ario-ant-escrow, has no gateway-side program ID below because a gateway never calls it; it is a wallet-to-wallet escrow, not something a gateway needs to resolve. Each program ID below is configured independently, so the same image can run against mainnet, staging-devnet, or a local devnet. The defaults are the mainnet IDs, listed in the Token docs. To confirm which set a running gateway is using, GET /ar-io/info returns the resolved programIds object.
Variable
Type
Default
Description
AR_IO_WALLET
string
-
Operator Solana public key (base58). Display label surfaced on /ar-io/info
SOLANA_RPC_URL
string
https://api.mainnet-beta.solana.com
Solana JSON-RPC endpoint, for the gateway and the observer
SOLANA_KEYPAIR_PATH
string
-
Path to the operator's 64-byte Solana keypair JSON file. Signs join_network, update_gateway_settings, and cranker instructions. Inside the container the path must start with /app/wallets/
SOLANA_PRIVATE_KEY
string
-
Alternative to SOLANA_KEYPAIR_PATH: base58-encoded 64-byte secret (Phantom export format). Mutually exclusive with the file form
ENABLE_EPOCH_CRANKING
boolean
false
When true, the observer runs permissionless epoch instructions (close_observation, tick_epoch, etc.)
ARIO_CORE_PROGRAM_ID
string
73YoECm6NKXpVRoe5f1Q9BcP5DJGPFUjnFy6AxBE5Nvh
ario-core program ID (token, staking, epoch state)
ARIO_GAR_PROGRAM_ID
string
89fNiiwgpFSPHKuqfNUkgYTYjtAJAhyqHjXmgXeppGpf
ario-gar program ID (Gateway Registry; joins, observations, distributions)
ARIO_ARNS_PROGRAM_ID
string
2yCUx5edFvUrkibYaUa2ZXWyx9kuJkS8CwyzsgHPWdZZ
ario-arns program ID (ArNS name registry)
ARIO_ANT_PROGRAM_ID
string
2MWexMHfMhGJwMHv9Qm9YAVCqjUFUJwDJAysW4oCUGk5
ario-ant program ID (ANT records — Metaplex Core NFTs that route names to data)
AR_IO_NODE_RELEASE
string
the release of the image
The release the gateway and observer report. Leave it unset
The default public Solana RPC is rate-limited and may block getProgramAccounts queries needed for full registry enumeration. For production gateways, use a dedicated RPC provider such as Helius, Triton, or QuickNode.
Release 85 (was 0, off). Largest item a range request that misses the cache fetches whole in the background, so the next request is a cache hit. This fills the data cache with items read only by range, such as video, SQLite or Parquet. 0 turns it off
BACKGROUND_CACHE_RANGE_CONCURRENCY
number
4
Release 85 (was 1). Background whole-item fetches at once. A miss beyond the limit is served without starting one
Comma-separated IP/CIDR allowlist, exempt from rate limits and x402. Matched against the client address only
TRUSTED_PROXIES
string
loopback, private, CGNAT and link-local ranges
Proxies (IPs/CIDRs) whose X-Forwarded-For and X-Real-IP are believed when working out the client address. Add a CDN's or public load balancer's ranges when one is in front; none trusts no proxy, only for a core that clients reach directly, with no Envoy in front. See x402 setup
The observer's offset (chunk-proof) checks, on the observer image from Release 85 (c5e98ddc). By default every gateway is checked each epoch; at a lower sample rate every observer picks the same share. A checked gateway must serve /chunk/<offset> with a Merkle proof that validates against the chain. See Failed Offset Checks.
Variable
Type
Default
Description
OFFSET_OBSERVATION_ENABLED
boolean
true
Run offset checks. false samples no gateway, and reports carry no offsetAssessments
OFFSET_OBSERVATION_ENFORCEMENT_ENABLED
boolean
true
A sampled gateway that fails its offset check fails the observation. false records failures in the report without failing gateways
OFFSET_OBSERVATION_SAMPLE_RATE
number
1.0
Share (0.0 to 1.0) of gateways sampled each epoch; 1.0 checks every gateway. At least one is sampled when it is above 0
OFFSET_SAMPLE_COUNT
number
4
Offsets tried per sampled gateway. The gateway passes on the first offset whose proof validates
The observer uploads report bundles to Turbo. The upload signer is resolved from the first matching env in the precedence chain. Setting envs from more than one chain group at once is rejected at startup.
If your observer logs warn that TurboReportSink is not configured, explicitly set a Solana upload signer. Most operators can use the same base58 secret for both OBSERVER_PRIVATE_KEY and SOLANA_UPLOAD_PRIVATE_KEY.
Variable
Type
Default
Description
ARWEAVE_UPLOAD_KEY_FILE
string
-
Path to an Arweave JWK file. Highest priority for upload signing
ARWEAVE_UPLOAD_JWK
string
-
Inline Arweave JWK JSON. Lower priority than the file form
ETHEREUM_UPLOAD_PRIVATE_KEY_FILE
string
-
Path to a 32-byte hex private key (with or without 0x prefix)
ETHEREUM_UPLOAD_PRIVATE_KEY
string
-
Inline hex private key. Lower priority than the file form
SOLANA_UPLOAD_KEYPAIR_PATH
string
-
Path to a separate Solana keypair JSON for uploads. Ignored when any ARWEAVE_UPLOAD_* or ETHEREUM_UPLOAD_* is set
SOLANA_UPLOAD_PRIVATE_KEY
string
-
Alternative to above: base58 secret. Mutually exclusive with the file form
When none of the above are set, uploads fall back to the observer key, then the operator key. For production observers, prefer setting SOLANA_UPLOAD_KEYPAIR_PATH or SOLANA_UPLOAD_PRIVATE_KEY explicitly so report uploads do not depend on fallback behavior.
Each service's image tag can be overridden. The defaults change with each release, so they are not listed here: they are in docker-compose.yaml on main.
Variable
Type
Default
Description
CORE_IMAGE_TAG
string
see docker-compose.yaml
Core image tag, also used by the index-swarm sidecar
ENVOY_IMAGE_TAG
string
see docker-compose.yaml
Envoy image tag
OBSERVER_IMAGE_TAG
string
see docker-compose.yaml
Observer image tag. Release 85 moves the default to c5e98ddc, which checks every gateway's offsets each epoch. A tag you set in .env overrides the compose default, so update it there when you upgrade
REDIS_IMAGE_TAG
string
see docker-compose.yaml
Redis image tag
CLICKHOUSE_IMAGE_TAG
string
see docker-compose.yaml
ClickHouse image tag
CLICKHOUSE_AUTO_IMPORT_IMAGE_TAG
string
see docker-compose.yaml
ClickHouse auto-import image tag
LITESTREAM_IMAGE_TAG
string
see docker-compose.yaml
Litestream image tag
INDEX_EXPORT_IMAGE_TAG (Release 85) is under Building Bands.