This guide helps you deploy a TRUF.NETWORK node on Digital Ocean and expose it to external clients. Follow these steps to configure networking, firewall rules, and optional DNS settings for your node.
- Digital Ocean Droplet running your TN node (see Node Operator Guide for initial setup)
- Node running and syncing with the network
- Basic familiarity with Digital Ocean control panel
New to Digital Ocean? Check out the Digital Ocean Getting Started Guide first.
This guide focuses on the networking configuration required to make your node accessible to external applications and the network. You'll configure:
- Cloud Firewall rules to allow necessary ports
- Public IP discovery for SDK integration
- Optional DNS setup for custom domains
- Connectivity testing to verify your setup
Before configuring your firewall, understand which ports your node needs:
| Port | Protocol | Purpose | Source |
|---|---|---|---|
| 6600 | TCP | P2P node communication | 0.0.0.0/0 (All IPv4) |
| 8484 | TCP | RPC service for queries | 0.0.0.0/0 (All IPv4) |
| Port | Protocol | Purpose | Source |
|---|---|---|---|
| 8000 | TCP | MCP Server for AI integration | Your IP or 0.0.0.0/0 |
| 22 | TCP | SSH access | Your IP (restricted) |
| Port | Protocol | Why |
|---|---|---|
| 5432 | TCP | PostgreSQL database - CRITICAL SECURITY RISK if exposed |
Important Notes:
- Port 6600: Enables two-way P2P communication. Your node can sync without this (via outbound connections), but opening it helps network health by accepting incoming peer connections.
- Port 8484: Required if you want users/applications to query data from your node.
- Port 8000: Only needed for MCP/AI integration (like Claude Code).
- Port 5432: Should ONLY bind to localhost (127.0.0.1). Never allow external access.
Digital Ocean Cloud Firewalls are network-based, stateful firewalls provided at no additional cost.
-
Navigate to Firewalls:
- Go to the Digital Ocean Control Panel
- Click Networking → Firewalls
- Click Create Firewall
-
Name your firewall:
- Enter a descriptive name (e.g.,
tn-node-firewall)
- Enter a descriptive name (e.g.,
-
Configure Inbound Rules:
Click New rule and add the following:
Rule 1: P2P Communication
- Type: Custom
- Protocol: TCP
- Port Range:
6600 - Sources: All IPv4 and All IPv6 (or use
0.0.0.0/0and::/0)
Rule 2: RPC Service
- Type: Custom
- Protocol: TCP
- Port Range:
8484 - Sources: All IPv4 and All IPv6
Rule 3: SSH Access (if not already present)
- Type: SSH (preset)
- Protocol: TCP (auto-filled)
- Port Range:
22(auto-filled) - Sources: Your IP address (recommended) or All IPv4 (less secure)
Optional Rule 4: MCP Server (only if using AI integration)
- Type: Custom
- Protocol: TCP
- Port Range:
8000 - Sources: Your IP address or All IPv4 (depending on your use case)
-
Apply to Droplets:
- In the Apply to Droplets section, select your TN node Droplet
- Click Create Firewall
If you already have a firewall attached to your Droplet:
- Navigate to Networking → Firewalls
- Select your existing firewall
- Click the Rules tab
- Under Inbound Rules, click New rule and add the rules from Option A above
- Click Save
# SSH into your Droplet
ssh root@your-droplet-ip
# Check that ports 6600 and 8484 are listening
sudo ss -tulpn | grep -E '6600|8484'
# Expected output should show kwild listening on these ports:
# tcp LISTEN 0 4096 0.0.0.0:6600 0.0.0.0:*
# tcp LISTEN 0 4096 0.0.0.0:8484 0.0.0.0:*Your node's endpoint URL requires the Droplet's public IP address.
- Go to Digital Ocean Control Panel
- Navigate to Droplets
- Locate your TN node Droplet
- The Public IPv4 address is displayed in the Droplet's information panel
# Method 1: Query external service
curl -4 ifconfig.co
# Method 2: Using Digital Ocean metadata service
curl -s http://169.254.169.254/metadata/v1/interfaces/public/0/ipv4/address
# Method 3: Using ip command
ip -4 addr show eth0 | grep -oP '(?<=inet\s)\d+(\.\d+){3}'If you have doctl installed:
# List all droplets with their IPs
doctl compute droplet list --format Name,PublicIPv4
# Get specific droplet info
doctl compute droplet get <droplet-id> --format Name,PublicIPv4Once you have your public IP address, your node endpoint follows this format:
http://YOUR_DROPLET_IP:8484
Example:
If your Droplet's public IP is 203.0.113.45, your endpoint is:
http://203.0.113.45:8484
Verify that your node is accessible from external clients.
From your local machine (not the Droplet):
# Test health check endpoint
curl http://YOUR_DROPLET_IP:8484/api/v1/health
# Expected response (if healthy):
# {
# "healthy": true,
# "services": {
# "user": {
# "syncing": false,
# "block_height": "12345"
# }
# }
# }# SSH into your Droplet
ssh root@YOUR_DROPLET_IP
# Check node sync status
kwild admin status
# Or if using Docker/systemd
# For systemd: sudo systemctl status kwild
# For Docker: docker exec <container-name> ./kwild admin status# From your local machine, test if port 6600 is accessible
nc -zv YOUR_DROPLET_IP 6600
# Expected output:
# Connection to YOUR_DROPLET_IP 6600 port [tcp/*] succeeded!If this test fails, verify your firewall rules are correctly configured.
Using a custom domain instead of an IP address makes your node endpoint more memorable and portable.
- A domain name you own
- Access to your domain registrar's settings
- Go to Digital Ocean Control Panel
- Navigate to Networking → Domains tab
- Click Add Domain (or Create → Domains/DNS)
- Enter your domain name (e.g.,
example.com) - Click Add Domain
- On the domain's DNS records page, click Create a record
- Select A as the record type
- Configure the A record:
- Type: A
- Hostname:
@(for apex domain) ornode(for subdomain likenode.example.com) - Will Direct To: Your Droplet's public IP address
- TTL: 3600 (default)
- Click Create Record
At your domain registrar (e.g., Namecheap, GoDaddy, Google Domains):
- Find the DNS/Nameserver settings
- Change nameservers to Digital Ocean's:
ns1.digitalocean.com ns2.digitalocean.com ns3.digitalocean.com - Save changes
Note: DNS propagation can take 24-72 hours, though it's usually much faster (within a few hours).
If you prefer to keep your current DNS provider:
- Log in to your DNS provider's control panel
- Navigate to DNS management for your domain
- Create an A record:
- Name/Host:
@(apex domain) ornode(subdomain) - Type: A
- Value/Points To: Your Droplet's public IP
- TTL: 3600 (or default)
- Name/Host:
- Save the record
# Wait a few minutes after creating the record, then test:
nslookup your-domain.com
# Or using dig:
dig your-domain.com A +short
# Expected output: Your Droplet's public IP addressWith DNS configured, your endpoint becomes:
http://your-domain.com:8484
Or for a subdomain:
http://node.your-domain.com:8484
Now that your node is accessible, you can use it with the TRUF.NETWORK SDKs.
import { NodeTNClient, StreamId, EthereumAddress } from '@trufnetwork/sdk-js';
import { Wallet } from 'ethers';
// Initialize client with your node endpoint
const wallet = new Wallet(process.env.PRIVATE_KEY);
const client = new NodeTNClient({
endpoint: 'http://YOUR_DROPLET_IP:8484', // or your domain
signerInfo: {
address: wallet.address,
signer: wallet,
},
chainId: 'tn-v2.1',
});
// Query stream data
const streamAction = client.loadAction();
const records = await streamAction.getRecord({
stream: {
streamId: StreamId.fromString('st...').throw(),
dataProvider: EthereumAddress.fromString('0x...').throw(),
},
});import (
"context"
"github.com/trufnetwork/kwil-db/core/crypto"
"github.com/trufnetwork/kwil-db/core/crypto/auth"
"github.com/trufnetwork/sdk-go/core/tnclient"
"github.com/trufnetwork/sdk-go/core/types"
)
ctx := context.Background()
// Set up signer
pk, _ := crypto.Secp256k1PrivateKeyFromHex("your-private-key")
signer := &auth.EthPersonalSigner{Key: *pk}
// Connect to your node
tnClient, err := tnclient.NewClient(
ctx,
"http://YOUR_DROPLET_IP:8484", // or your domain
tnclient.WithSigner(signer),
)
// Query stream data
composedActions, _ := tnClient.LoadComposedActions()
result, err := composedActions.GetRecord(ctx, types.GetRecordInput{
DataProvider: "0x...",
StreamId: "st...",
})CRITICAL: Never expose PostgreSQL port 5432 to the internet.
-
Verify PostgreSQL is bound to localhost only:
sudo ss -tulpn | grep 5432 # Should show 127.0.0.1:5432, NOT 0.0.0.0:5432
-
If using UFW (Uncomplicated Firewall) on the Droplet:
# Ensure port 5432 is blocked from external access sudo ufw deny 5432/tcp # Verify UFW status sudo ufw status
-
Docker users: Ensure PostgreSQL container uses localhost binding:
# Correct (localhost binding) docker run -p 127.0.0.1:5432:5432 ... # WRONG (exposed to internet) docker run -p 5432:5432 ...
For production deployments, consider enabling RPC private mode for enhanced security:
-
Edit your
config.toml:[rpc] # Enforce data privacy: authenticate JSON-RPC call requests private = true
-
Restart your node:
# For systemd sudo systemctl restart kwild # For Docker docker restart <your-container-name> # Or if using Docker Compose: docker compose restart
For more details, see the Kwil Private RPC documentation.
-
Use SSH keys instead of passwords:
# Generate SSH key on your local machine (if you haven't already) ssh-keygen -t ed25519 -C "your_email@example.com" # Add to Digital Ocean Droplet ssh-copy-id root@YOUR_DROPLET_IP
-
Disable password authentication:
# Edit SSH config sudo nano /etc/ssh/sshd_config # Set the following: PasswordAuthentication no # Restart SSH service sudo systemctl restart sshd
-
Restrict SSH access in firewall: Configure your firewall to only allow SSH from your IP address.
Keep your system and node software up to date:
# Update system packages
sudo apt update && sudo apt upgrade -y
# Update node binary (if building from source)
cd ~/node
git pull
task build
sudo mv .build/kwild /usr/local/bin/kwild
sudo systemctl restart kwild
# Or download latest release
# See: https://github.com/trufnetwork/node/releasesProblem: curl http://YOUR_DROPLET_IP:8484/api/v1/health times out or connection refused.
Solutions:
-
Check if kwild is running:
sudo systemctl status kwild # Or for Docker: docker ps -
Verify kwild is listening on the correct port:
sudo ss -tulpn | grep 8484 -
Check firewall rules:
- Digital Ocean Cloud Firewall: Verify port 8484 is in inbound rules
- UFW (if enabled):
sudo ufw statusand ensure 8484 is allowed
-
Check kwild configuration:
# Print current config kwild print-config # Look for rpc.listen_addr (should be 0.0.0.0:8484 for external access)
Problem: Domain doesn't resolve to your Droplet's IP.
Solutions:
-
Check if DNS propagation is complete:
dig your-domain.com @8.8.8.8 A +short
-
Verify nameservers (if using Digital Ocean DNS):
dig your-domain.com NS +short # Should show ns1.digitalocean.com, ns2.digitalocean.com, etc. -
Wait for propagation: DNS changes can take up to 72 hours, though usually much faster.
Problem: Node shows syncing: true for extended periods.
Solutions:
-
Check peer connections:
kwild admin status | grep -i peer -
Verify port 6600 is accessible:
- Check firewall allows inbound on 6600
- Test:
nc -zv YOUR_DROPLET_IP 6600from external machine
-
Check node logs:
# For systemd sudo journalctl -u kwild -f # For Docker (replace with your container name) docker logs -f <container-name>
Problem: MCP server not reachable on port 8000.
Solutions:
-
Verify MCP is enabled and running:
# For Docker deployment docker ps | grep mcp # Check logs (replace with your container name) docker logs <mcp-container-name>
-
Check firewall allows port 8000:
- Verify Digital Ocean Cloud Firewall has inbound rule for port 8000
- Test:
nc -zv YOUR_DROPLET_IP 8000
-
Verify MCP server configuration:
# MCP should be listening on 0.0.0.0:8000 for external access sudo ss -tulpn | grep 8000
- Monitor your node: Regularly check sync status with
kwild admin status - Enable extensions: Consider enabling
tn_cachefor better performance (see Node Operator Guide)
- Node Operator Guide: Complete manual setup instructions
- Deployment Options Comparison: Compare all deployment methods
- Digital Ocean Documentation: Official Digital Ocean resources
- TRUF.NETWORK SDKs: SDK repositories and examples
Need help? We're here to assist:
- GitHub Issues: Node Repository
- Documentation: Full documentation
Successfully deployed? Consider sharing your node in the Available Nodes List to help grow the network!