Deploy a node
End-to-end deployment for any TRON node — regular Fullnode, block-producing SR Fullnode, or Lite Fullnode. Hardware requirements, getting the client, starting it, configuration toggles, and day-to-day operation.
This page is the operational home for deploying any TRON node — Fullnode (the standard), SR Fullnode (block-producing), or Lite Fullnode (snapshot-based). The same FullNode.jar and the same procedure apply; you choose between them with a configuration option or a command-line flag.
For the conceptual comparison between node types and how to decide which to run, see Nodes overview.
Supported platforms
| OS | Architecture | JDK |
|---|---|---|
| Linux | x86_64 / amd64 | JDK 8 (Oracle JDK 8 recommended for production) |
| Linux | ARM64 / aarch64 | JDK 17 |
| macOS | x86_64 / ARM64 | JDK 8 (x86_64) or JDK 17 (ARM64) |
The CPU architecture determines the JDK versionThe JDK versions above are not alternatives:
x86_64/amd64supports only JDK 8, whileARM64/aarch64supports only JDK 17. The node checks the architecture and JDK major version at startup and exits if they do not match. ARM64 support starts with java-tron 4.8.1.
Hardware requirements
Minimum
The bare minimum to run a java-tron node without immediately running into resource limits:
- CPU: 8 cores
- Memory: 16 GB
- SSD: 4 TB or more is recommended; size the storage for the database and allow room for future growth.
- Network bandwidth: 100 Mbps
This is enough to keep up with the chain and serve light query loads. For production, prefer the recommended profile below.
Recommended
| Role | CPU | RAM | SSD | Bandwidth |
|---|---|---|---|---|
| Fullnode | 16 cores | 32 GB | 4 TB+ | 100 Mbps |
| Fullnode running as SR | 32 cores | 64 GB | 4 TB+ | 100 Mbps |
| Lite Fullnode | 16 cores | 32 GB | Few % of Fullnode, growing | 100 Mbps |
SR Fullnodes carry the consensus path on top of the standard workload, so additional CPU and RAM headroom matters. When importing a full database from a snapshot, allow space for the extracted database and subsequent growth. If you download the complete archive before extracting it, allow additional space for the archive as well. Lite Fullnodes start small but accumulate data at the same rate as a Fullnode — re-prune periodically to keep disk usage bounded (see Lite Fullnode deployment).
1. Obtain FullNode.jar
You can either compile from source or download a published release.
Option A: Compile from source
git clone https://github.com/tronprotocol/java-tron.git
cd java-tron
git checkout -t origin/master
./gradlew clean build -x testOn a successful build, FullNode.jar is at ./build/libs/FullNode.jar. If the build fails with DependencyVerificationException, retry with ./gradlew clean build -x test --refresh-dependencies; do not regenerate gradle/verification-metadata.xml merely to bypass the check.
Option B: Download a release
Download the target release's JAR from java-tron releases. Each JAR has a matching .sig signature file; before using it in production, download both from the same release and verify the GPG signature according to the official integrity check instructions to confirm the file's origin and integrity.
Toolkit ships with the release.Every published java-tron release provides a Toolkit JAR that matches
FullNode.jar. The Toolkit is a bundle of database-maintenance utilities — generate a Lite Fullnode snapshot from a Fullnode database, fast-copy a database between volumes, convert LevelDB data to RocksDB, move selected logical databases to other volumes, and apply LevelDB startup optimizations. Download the Toolkit JAR for your platform separately from the same release page and place it next toFullNode.jar. See Node maintenance toolkit for what each utility does.
2. Pick a configuration file
Each network has a default configuration:
| Network | Configuration | Source |
|---|---|---|
| Mainnet | config.conf | provided in framework/src/main/resources/ |
| Nile testnet | config-nile.conf | Download from the Nile network guide; source is tron-nile-testnet/nile-testnet |
| Shasta testnet | NA | Does not accept public nodes as P2P peers; use TronGrid endpoints instead. |
| Private chain | Custom — see TRON private chain | self-authored |
Nile may enable features before Mainnet, so use the source and config-nile.conf from the Nile repository that match the current Nile release rather than reusing the Mainnet configuration.
Save the selected configuration as config.conf next to FullNode.jar.
When -c points to an external configuration file, settings omitted from that file fall back only to the reference.conf packaged in FullNode.jar; java-tron does not also merge the Mainnet config.conf from the source tree. Do not use a sparse override file as the Mainnet configuration. Start with a complete configuration that matches the target network and java-tron release, then merge your custom settings into that file.
For settings supported by both the command line and config.conf, an explicitly supplied command-line value overrides the value in the file.
3. Start a standard Fullnode
Before startup: optimize memory allocation with tcmalloc (optional)
tcmalloc reduces fragmentation and tail latency for the JVM's native allocations. This optimization applies to Linux only; no tcmalloc configuration is required when running java-tron directly on macOS. The official java-tron Docker images for version 4.8.1 and later already include tcmalloc.
Install the package that provides libtcmalloc.so.4 for your distribution:
- Ubuntu 22.04:
sudo apt update && sudo apt install libgoogle-perftools4 - Ubuntu 24.04 / 26.04, Debian 13:
sudo apt update && sudo apt install libgoogle-perftools4t64 - Other distributions: use the system package manager to install the package that provides
libtcmalloc.so.4.
The installation path varies by distribution and CPU architecture. After installation, run ldconfig -p | awk '$1 == "libtcmalloc.so.4" {print $NF; exit}' to print the path on the host, then use that path in LD_PRELOAD. If the command prints nothing, verify that the package is installed correctly.
Before starting the node, set these environment variables in the current shell:
# Replace this path with the path printed by the command above
export LD_PRELOAD="/usr/lib/x86_64-linux-gnu/libtcmalloc.so.4"
export TCMALLOC_RELEASE_RATE=10Then run the basic startup command below, or the full command for the host architecture under recommended JVM parameters, in the same shell.
After starting the node, verify that tcmalloc is loaded:
FULLNODE_PID=$(pgrep -f 'FullNode.jar' | head -n 1)
grep tcmalloc "/proc/$FULLNODE_PID/maps"If tcmalloc is active, the command prints the path of the loaded libtcmalloc library.
Basic startup
Select the JDK and startup command for the host CPU architecture. The following examples use a host with 16 GB of RAM:
# x86_64 / amd64: JDK 8
java -Xms9G -Xmx12G -XX:+UseConcMarkSweepGC -jar FullNode.jar -c config.conf
# ARM64 / aarch64: JDK 17
java -Xmx9G -XX:+UseZGC -jar FullNode.jar -c config.confThese commands are suitable for an initial startup and basic verification. For a long-running Mainnet node, use the complete JVM parameters below.
Recommended JVM parameters
The complete commands below are for a host with 16 GB of RAM:
# x86_64 / amd64: JDK 8
java -Xms9G -Xmx12G \
-XX:ReservedCodeCacheSize=256m \
-XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m \
-XX:MaxDirectMemorySize=1G \
-XX:+PrintGCDetails \
-XX:+PrintGCDateStamps -Xloggc:gc.log \
-XX:+UseConcMarkSweepGC -XX:NewRatio=3 \
-XX:+CMSScavengeBeforeRemark -XX:+ParallelRefProcEnabled \
-XX:+HeapDumpOnOutOfMemoryError \
-XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=70 \
-jar FullNode.jar -c config.conf
# ARM64 / aarch64: JDK 17
java -Xmx9G -XX:+UseZGC \
-Xlog:gc,gc+heap:file=gc.log:time,tags,level:filecount=10,filesize=100M \
-XX:ReservedCodeCacheSize=256m \
-XX:+UseCodeCacheFlushing \
-XX:MetaspaceSize=256m \
-XX:MaxMetaspaceSize=512m \
-XX:MaxDirectMemorySize=1g \
-XX:+HeapDumpOnOutOfMemoryError \
-jar FullNode.jar -c config.conf-Xms/-Xmxset the initial and maximum JVM heap. On a 16 GB host, use-Xms9G -Xmx12Gfor x86_64 / JDK 8 and-Xmx9Gfor ARM64 / JDK 17. On hosts with at least 32 GB of RAM, set-Xmxto about 40% of physical RAM and start-Xmsat 9G, then tune it against node load and monitoring data.ReservedCodeCacheSizesets the maximum JIT code-cache capacity;MetaspaceSizesets the initial threshold that triggers metaspace garbage collection;MaxMetaspaceSizecaps metaspace capacity; andMaxDirectMemorySizecaps NIO direct memory.- These recommended configurations use CMS GC and its legacy logging flags with JDK 8 on x86_64, and ZGC with unified logging on JDK 17 on ARM64. GC logs are written to a separate file, and a heap dump is generated on an out-of-memory error.
- Every JVM option must appear before
-jar;-c config.confselects the node configuration file.
Initial sync from genesis can take weeks to months on Mainnet (the chain holds multiple TB of data and grows continuously). To skip cold sync, download a database snapshot and place it in the output-directory next to FullNode.jar before starting.
Checking startup logs
With the default logging configuration, the main node log is written to ./logs/tron.log and gRPC logs to ./logs/grpc/grpc.log. These paths are relative to the directory from which you start the node. After startup, check the logs for errors and verify that block synchronization and the services you use are working correctly.
To use a custom Logback configuration, pass --log-config /path/to/logback.xml when starting the node. Verify that the file exists, is readable by the node process, and contains a valid configuration. If the specified file cannot be loaded, node startup fails. When using a custom configuration, log paths are determined by that file.
Block-producing Fullnode (Super Representative)
Adding the --witness flag turns a Fullnode into a block producer. This is what an SR runs to participate in consensus and earn the block reward. You must also provide the SR's signing key, either as a raw private key in the config or as a keystore file.
Provide the signing key
Option A: raw private key in config.conf — quick to set up, but the key is stored in plain text on disk. This is not recommended for production; use Option B instead.
localwitness = [
650950B1...295BD812 // hex-encoded private key, 64 chars
]Option B: encrypted keystore file — production setup; requires interactive password entry at startup.
localwitness = []
localwitnesskeystore = [
"subdir/localwitnesskeystore.json"
]The path is relative to the directory you run the start-up command from. Use the Toolkit distributed with the release to manage the keystore. An existing SR should use keystore import to import the private key currently authorized for block production. Do not use keystore new merely to migrate an existing SR: it generates a random key that cannot produce blocks unless its address is first authorized as the SR's witness permission. Use keystore new only for a new SR identity or a planned witness-permission rotation.
# Existing SR: import the key currently authorized for block production
java -jar Toolkit.jar keystore import
# New SR identity or planned witness-permission rotation: generate a new key
java -jar Toolkit.jar keystore newUse --keystore-dir to specify the output directory. See Node maintenance toolkit for the complete commands and security guidance.
Note:If the SR has delegated
witness_permissionto a separate Account, use the delegated key here, not the SR account's owner key. See SR best practices for the witness-permission separation pattern.
Start with the --witness flag
--witness flagjava -Xms9G -Xmx24G -XX:+UseConcMarkSweepGC -jar FullNode.jar --witness -c config.conf
Note:This command targets the recommended 64 GB x86_64 / amd64 SR host. ARM64 / aarch64 requires JDK 17; when adapting the simplified command above, keep
-Xms9G -Xmx24Gand replace-XX:+UseConcMarkSweepGCwith-XX:+UseZGC. For production, retain--witness, and add the remaining options for the host architecture under recommended JVM parameters.
When a keystore is configured and no password is supplied by another mechanism, the process waits for a password on standard input. Do not start it directly with a non-interactive background command such as nohup. For an interactive start, use screen or tmux, enter the password, and then detach. An unattended systemd service requires a separately configured, protected password-delivery mechanism. java-tron does not send a READY=1 notification, so use Type=simple by default and use Type=notify only when a wrapper explicitly sends the readiness notification. Do not place the password directly in the unit file or command line.
Lite Fullnode deployment
A Lite Fullnode runs the same FullNode.jar as a regular Fullnode but boots from a state-data snapshot instead of syncing from genesis. The snapshot contains the complete current state plus the most recent 65,536 blocks; everything older is not on disk. See Nodes overview for the conceptual comparison.
Obtain the snapshot
Two options:
-
Download a public snapshot from Public Backup Data. Fastest.
-
Prune an existing Fullnode database with the Toolkit:
Stop the Fullnode with
SIGTERMand confirm that the process has exited before using its database. Back up the data, run Toolkit against the stopped data directory or a verified copy, and restart the node only after pruning completes successfully.java -jar Toolkit.jar db lite -o split -t snapshot -fn /path/to/fullnode/output-directory -ds /path/to/snapshotUse this if you already operate a Fullnode and want to bootstrap a Lite Fullnode from it. See Node maintenance toolkit.
Place the extracted snapshot in the output-directory next to FullNode.jar.
Start the node
A Lite Fullnode starts in the same way as a Fullnode and requires no additional Lite Fullnode startup flags. Select the JDK and startup command for the host CPU architecture. The following examples use a host with 16 GB of RAM:
# x86_64 / amd64: JDK 8
java -Xms9G -Xmx12G -XX:+UseConcMarkSweepGC -jar FullNode.jar -c config.conf
# ARM64 / aarch64: JDK 17
java -Xmx9G -XX:+UseZGC -jar FullNode.jar -c config.confFor long-running deployments, use the complete command for the host architecture under recommended JVM parameters.
FullNode.jar detects the Lite Fullnode snapshot structure at startup and runs in Lite Fullnode mode.
Default API restrictions
By default, a Lite Fullnode disables the historical-query APIs on the filter lists for /wallet/, /walletsolidity/, and /walletpbft/. Examples include APIs that retrieve blocks by ID or height and transactions or transaction information by transaction ID. This restriction applies to those API methods even when the requested block or transaction was produced after the Lite Fullnode started. Filtered requests receive this API is closed because this node is a lite fullnode. Other read APIs are not disabled solely because the node is a Lite Fullnode. See the complete lists in LiteFnQueryHttpFilter and LiteFnQueryGrpcInterceptor.
To enable the filtered API methods, add to config.conf:
node.openHistoryQueryWhenLiteFN = trueAfter enabling the setting, the node can return only data that is still present in its local database. History removed when the Lite Fullnode snapshot was created is not restored and remains unavailable.
Periodic re-pruning
A Lite Fullnode accumulates data at the same rate as a Fullnode after startup. To keep disk usage bounded, periodically stop the node, confirm that it has exited, back up the data, and re-prune the stopped database or a verified copy with the same Toolkit.jar db lite command. Restart the node after the operation completes successfully. Monthly is a common cadence.
Other run modes
These modes are not primary deployment roles; use them when you need solidified queries or offline read-only access.
Run as a SolidityNode
A SolidityNode synchronizes only solidified blocks from a trusted FullNode, does not produce blocks, and does not start the P2P network. Pass --solidity to FullNode.jar to run a SolidityNode.
The node running as a SolidityNode acts as a client: it reads solidified blocks from the trusted FullNode specified by trustNode over gRPC. node.trustNode in config.conf specifies that FullNode (default 127.0.0.1:50051):
node {
trustNode = "127.0.0.1:50051"
}trustNode must point to a FullNode you trust. If it is missing or empty, the node exits with Trust node is not set. Do not expose this gRPC port directly to the public internet.
Start the node with the command for the host architecture:
# x86_64 / amd64: JDK 8
java -Xmx24G -XX:+UseConcMarkSweepGC \
-jar FullNode.jar --solidity \
-c config.conf
# ARM64 / aarch64: JDK 17
java -Xmx9G -XX:+UseZGC \
-Xlog:gc,gc+heap:file=gc.log:time,tags,level:filecount=10,filesize=100M \
-jar FullNode.jar --solidity \
-c config.confThese commands follow the heap sizes in the official examples; adjust -Xmx to the host's memory. When started with --solidity, the HTTP query interface uses node.http.solidityPort (default 8091) and the gRPC query interface uses node.rpc.port (default 50051). This differs from a regular FullNode, whose solidified-query gRPC port is node.rpc.solidityPort (default 50061). In production, add the GC logging and heap-dump options from recommended JVM parameters.
Run as a read-only query node
A node can serve queries without joining the P2P network — useful for indexers and analytics services that ingest data via another channel.
The only mechanism to disable P2P is the CLI flag --p2p-disable (verified in CommonParameter.java; there is no corresponding node.p2p.enable config key). Pass it at start-up:
java -jar FullNode.jar -c config.conf --p2p-disable trueFor defense-in-depth, also disable discovery and clear the peer lists in config.conf so no outbound P2P connections are attempted:
node.discovery.enable = false
node.active = []
node.passive = []A node started this way still serves HTTP and gRPC queries from its local database; it just does not initiate or accept block-sync traffic.
Day-to-day operation
Shutting down cleanly
Send SIGTERM to allow the node to flush state and close the database cleanly:
kill -15 <pid>
Avoid SIGKILL (kill -9).A forced shutdown can corrupt the LevelDB / RocksDB store, requiring a re-sync from snapshot.
Keeping the node online
A node does not need to be online non-stop, but the longer it stays up the less time it spends catching up after restarts. Two operational notes:
- A clean shutdown preserves the database; a forced shutdown can corrupt it.
- On restart, the node resumes sync from its last known head. If it has been offline for a while, expect a catch-up period before it serves the latest block.
Updating the client
Keep the client up to date — especially before hard-forking proposals take effect. An out-of-date client may fail to apply blocks after a fork-activating boundary and require a forced upgrade.
The simplest update procedure:
- Review the target release notes and download the corresponding
FullNode.jarandToolkit.jarpackages. - Back up the current configuration. Compare it with the configuration for the target network and java-tron release, and merge custom settings that are still supported into the new configuration.
- Stop the node cleanly with
kill -15and confirm that the process has exited. - Replace the old JAR files and use the configuration prepared in step 2.
- Restart, check startup logs and block synchronization, and verify the APIs, event subscriptions, and other services you use.
For SRs, drain block production to a standby node before upgrading the primary — never upgrade the active producer in place. See SR best practices for the full upgrade procedure.
Default ports
The Mainnet config.conf ships these defaults. If you run multiple nodes on one host, override the ones that would collide.
| Service | Config key | Default |
|---|---|---|
| HTTP API (latest chain head) | node.http.fullNodePort | 8090 |
| HTTP API (solidified blocks) | node.http.solidityPort | 8091 |
| HTTP API (PBFT-confirmed state) | node.http.PBFTPort | 8092 |
| gRPC API (latest chain head) | node.rpc.port | 50051 |
| gRPC API (solidified blocks) | node.rpc.solidityPort | 50061 |
| gRPC API (PBFT-confirmed state) | node.rpc.PBFTPort | 50071 |
| P2P listen | node.listen.port | 18888 |
| ZeroMQ event publisher | event.subscribe.native.bindport | 5555 |
| SR master-slave coordination (UDP) | node.backup.port | 10001 |
FullNode APIs read the latest chain head, solidified APIs read only solidified blocks, and PBFT APIs read PBFT-confirmed state.
Port access controlExcept for required P2P connectivity, expose HTTP, gRPC, ZeroMQ, and SR master-slave coordination ports only to trusted private networks or explicitly authorized clients. Restrict source addresses with a firewall or security group. If a public API is required, place the node behind a trusted gateway that provides TLS, authentication, and rate limiting instead of exposing node ports directly.
Related resources
- Nodes overview — Node types and how to choose
- Database snapshots — Skip cold sync from genesis
- Node maintenance toolkit — Database utilities shipped with the release
- TRON private chain — Run an isolated network
- Becoming a Super Representative — Apply, register, and operate an SR
- SR node configuration — Witness permission delegation
- Accounts and keys — TRON's account and key model
Updated about 13 hours ago