Skip to main content
You have a node that starts cleanly in the foreground from Join mainnet. At the end the node runs as a dedicated user under systemd, restarts on failure, survives reboots, and logs to the journal. Pick the Cosmovisor unit if the node will follow Hub upgrades, which is most mainnet nodes. The plain unit is for containers, test machines, and nodes you upgrade by hand.

Create a service user

A system user with no login shell owns the node home and nothing else. If you initialized the node as your own user, move ~/.gaia to /var/lib/gaia/.gaia. Then run chown -R gaia:gaia on it. The two key files deserve stricter modes than the rest:
The priv_validator_key.json file is the consensus key. It cannot be rotated on the Hub today, so the service user is the only account that should be able to read it. A validator should move signing off this machine entirely with remote signing. The node_key.json file holds no on-chain state and can be regenerated if lost. However, a stable node id keeps your peers’ persistent peer lists valid. From here on the node home is /var/lib/gaia/.gaia and belongs to gaia. Later pages write node commands against ~/.gaia. On a service node, run them as the service user with the explicit home, for example sudo -u gaia gaiad comet show-validator --home /var/lib/gaia/.gaia. Without --home, a command reads the ~/.gaia of whoever runs it, which is a different key or no key at all.

Put gaiad where the units expect it

Both units run /usr/local/bin/gaiad, because systemd has no shell PATH. The release install on Install gaiad already puts it there. A source build leaves it in $(go env GOPATH)/bin, so copy it:
The version must be the tag you built. The Cosmovisor unit below also needs this copy, because cosmovisor init takes its first binary from /usr/local/bin/gaiad.

Plain gaiad unit

The ExecStart line uses absolute paths because systemd has no shell PATH. The value LimitNOFILE=50000 is what the gaia upgrade guide uses. The old 4096 default runs out under peer load, and the node crashes with too many open files. The KillSignal=SIGINT setting with a two minute stop timeout lets gaiad flush its stores instead of being killed mid write. The Restart=on-failure setting brings the node back after a crash but not after a clean stop, so a stop you asked for stays stopped.

Cosmovisor unit

Cosmovisor is the Cosmos SDK process manager that watches for an upgrade height and swaps the gaiad binary. Install it and lay out the directories once. Upgrade a node covers what happens at each upgrade.
The go install step needs Go 1.25 on the machine. Release archives for linux-amd64 and linux-arm64 are on the cosmovisor v1.7.3 release if you would rather not build it. The cosmovisor init command copies the current binary to cosmovisor/genesis/bin/gaiad, points the cosmovisor/current symlink at genesis, and writes cosmovisor/config.toml. Cosmovisor v1.7.3 prints v1.7.3 for cosmovisor version. It errors if DAEMON_NAME and DAEMON_HOME are unset, which is why the environment is passed inline.
The command is cosmovisor run start. The cosmovisor start form from older guides no longer exists. The Restart=no setting is deliberate and comes from the gaia upgrade guide. Cosmovisor itself restarts gaiad after a successful upgrade. A systemd restart loop on a failed upgrade would keep relaunching a binary that cannot apply the block. Setting DAEMON_ALLOW_DOWNLOAD_BINARIES=false means you place every upgrade binary yourself and verify it. Auto download trusts whatever URL the proposal named. Setting UNSAFE_SKIP_BACKUP=true skips the pre upgrade copy of data/, which on a Hub node would take longer than the upgrade and double the disk. Take your own backup before upgrade day instead. Confirm the environment Cosmovisor sees:
This prints every DAEMON_* value and the derived paths, including the monitored file data/upgrade-info.json.

Enable and start

Use one of the two units, never both, since they start the same node on the same ports.
The daemon-reload command makes systemd read the new unit. The enable --now command starts it and arranges a start at boot. The status command shows active (running) with the last log lines. Substitute gaiad for the plain unit.

Logs

The first follows the live log without timestamps added by the journal (gaiad prints its own). The second is the first thing to run when a node looks unhealthy. Set a journal size cap in /etc/systemd/journald.conf (SystemMaxUse=2G) so a chatty node cannot fill the root disk.

Stop and restart safely

A stop sends SIGINT and waits up to TimeoutStopSec. Let it finish. A restart on a validator costs the blocks missed while the node reconnects to peers, typically under a minute. That is why configuration changes get batched into one restart.

Verify

Expect active, enabled, a climbing height, and a current symlink pointing at genesis until the first upgrade moves it to upgrades/<name>.

Next

Upgrade a node before the next upgrade height, and Monitoring to be told when the node stops.