Run a Gravity Mainnet Public Full Node With Docker
Run a Gravity Mainnet (L1) Public Full Node with Docker. Covers image preparation, mainnet artifacts, PFN identity generation, pruning, startup, sync checks, and operational cleanup.
This guide walks you through running a Gravity Mainnet Public Full Node (PFN) with the gravity_node Docker image. A PFN syncs from an upstream public-network seed and can serve EVM JSON-RPC for applications, indexers, or internal services.
A PFN does not participate in consensus, does not hold validator stake, and does not require validator invite access.
Placeholders. Commands below use
<YOUR_...>placeholders. Replace each value before running. Never commit generated identities, private keys,.envfiles, rendered node config, logs, or node databases to version control.
Prerequisites
Docker and Docker Compose v2. Production nodes should run on Linux. Docker Desktop on macOS is useful for local validation, but it handles host networking differently from Linux.
Local command-line tools. Install
just,envsubstfrom GNU gettext,jq,curl,nc, andlsof.The Gravity SDK repository. The Docker image and config templates live in
gravity-sdk.git clone https://github.com/Galxe/gravity-sdk.git cd gravity-sdkMainnet
genesis.jsonandwaypoint.txt. These artifacts pin the exact chain you are joining. Download the canonical files fromgravity-sdk/genesis/mainnet.An upstream public-network seed. The current public PFN seed is shown below.
SSD/NVMe storage. Chain data grows with uptime. Budget well above the current chain size.
1. Build or Load the Docker Image
From the gravity-sdk repository root:
TAG=$(git rev-parse --short HEAD)
DOCKER_BUILDKIT=1 docker build --network=host \
-f docker/gravity_node/Dockerfile \
-t gravity_node:${TAG} \
--build-arg CARGO_PROFILE=release \
.If your operator package provides a prebuilt image, load or pull that image instead and set IMAGE_TAG to its tag in later commands.
2. Prepare the Docker Workspace
Edit .env:
The container reads node config from ./config and stores chain data in Docker volumes.
3. Prepare Mainnet Artifacts
From docker/gravity_node:
Copy these artifacts into the Docker config directory:
4. Gather Seed Information
At the moment, public internet access is intended for the mainnet RPC/PFN fleet. Other validator and VFN hosts should be treated as private/internal unless the Gravity team explicitly shares invite-only seed information.
rpc-1
mainnet-rpc-p2p-1.gravity.xyz
6180
38013b46c21388c3fd08ab32b86b478b3109125566d63c2da8fdc941dc474077
234aee14677a3d2198208ea72ca5e95ed75520df27f01f0c36220303ff78642f
Before using the seed, verify from your node host that the public-network port is reachable:
Use the current public PFN seed when rendering PFN_SEEDS_BLOCK in the Docker config section below:
5. Generate a PFN Identity
Create a minimal cluster config file for identity generation, for example cluster/local-pfn-docker.toml:
The Docker flow uses this TOML only to generate node identity material. It does not read ports, seeds, base_dir, or data_dir from the TOML during container startup. Docker runtime storage is controlled by the volume or bind mount in the start command, and by the container paths rendered in the next section.
Generate the PFN identity:
The generated identity.yaml contains private node identity material. Keep it on the runtime host only.
6. Render Container Config
The container sees config at /gravity/config and data at /gravity/data, so the rendered files must use container paths, not host paths.
DATA_DIR, STORAGE_DIR, and LOG_DIR are intentionally separate:
To place data on a specific host disk, mount that host path to /gravity/data. To place logs on a specific host disk, mount that host path to /gravity/logs. Do not change the TOML data_dir for Docker runtime storage.
From docker/gravity_node:
If you do not want transaction-lookup pruning, do not set PRUNE_TRANSACTIONLOOKUP_DISTANCE, and render reth_config.json from the non-prune template instead:
Verify the rendered config:
Expected reth_config.json behavior:
chainpoints to/gravity/config/genesis.json;gravity_node_configpoints to/gravity/config/public_full_node.yaml;datadirpoints to/gravity/data/data/reth;log.file.directorypoints to/gravity/logs/execution_logs/;when pruning is enabled,
prune.transactionlookup.distanceis10064.
7. Pruning Mode
prune_transactionlookup_distance = 10064 starts reth with transaction-lookup pruning enabled. This keeps recent transaction-hash lookup data while allowing older lookup indexes to be pruned.
Use a value greater than or equal to 10064 for production PFN/RPC nodes. Treat smaller values as test-only and reject them during config review.
Use this pruning mode when you want lower execution database growth and do not need arbitrary old eth_getTransactionByHash lookups from this node.
If you omit prune_transactionlookup_distance, the generated PFN reth config uses archive-style transaction lookup behavior and keeps historical lookup indexes instead of pruning them. That is simpler for indexers or debugging flows that need old transaction hashes, but it uses more disk over time.
Do not set prune_transactionlookup_distance = 0 to disable pruning. A distance of 0 is still a pruning mode and can prune transaction lookup data aggressively. To run without transaction-lookup pruning, leave the field out.
8. Optional: Warm Start From a Snapshot or Existing Node
A new Docker PFN can sync from genesis, but that may take a long time on an established chain. To warm start, load the snapshot into the Docker data volume before the first node start.
If the Docker PFN has already started once, stop the container and remove the old data volume before importing a snapshot. Do not merge snapshot files into an already-initialized database.
The Docker container mounts its data volume at /gravity/data. The chain databases must live under /gravity/data/data, so extract snapshot contents into that data subdirectory.
Option A: Download the Public Mainnet Data Snapshot
Gravity publishes daily mainnet PFN data snapshots in the public bucket. Pick the latest available date and download it to your node host:
The snapshot tar contains database directories such as consensus_db/, quorumstoreDB/, and reth/ at the archive root. It does not contain an outer data/ directory.
For the Linux compose flow, load the snapshot into the compose data volume:
For the macOS docker run flow, load the snapshot into the explicit named volume used by the start command below:
After extraction, the Docker data volume should contain:
Option B: Copy From an Existing Node You Control
If you already run a trusted RPC/PFN, you can copy only the chain databases from that node:
Then load /tmp/pfn-data.tar into the Docker data volume with the same compose or docker run extraction pattern above. Mount /tmp as /snapshot and replace the extraction command with:
Do not copy rand_db or secure_storage.json from another node. Those files carry node-specific randomness or safety state and should not be reused.
9. Start the PFN
Make sure the selected host ports are free:
On Linux, use Docker Compose:
The compose file uses network_mode: host because p2p ports need predictable advertised addresses.
On Docker Desktop for macOS, host networking behaves differently. For local validation from the macOS host, use explicit port publishing:
10. Verify Sync
Query the local Docker PFN:
Compare with the public RPC:
Follow logs:
Confirm the prune config was accepted:
11. Stop, Restart, or Reset
For the Linux compose flow, stop the container but keep chain data:
Restart:
Delete the local PFN database and start from zero again:
For the macOS docker run flow, stop the container but keep chain data:
Delete the local PFN database and start from zero again:
Only remove Docker volumes when you intentionally want to delete the node database.
Files to Keep Out of Version Control
Do not commit generated runtime files:
docker/gravity_node/.env;docker/gravity_node/config/*;cluster/output/<YOUR_NODE_ID>/config/identity.yaml;Docker volumes such as
gravity-data,gravity-logs,gravity_node_local_pfn_data, andgravity_node_local_pfn_logs;node databases and logs.
The reusable materials are the public guide and SDK templates. Each operator should generate their own identity and runtime config.
Last updated
Was this helpful?

