> ## Documentation Index
> Fetch the complete documentation index at: https://docs.monad.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# Direct UDP Migration

<Warning>
  Please do not proceed until Monad Foundation provides notice.
</Warning>

## Overview

Direct UDP enables a dedicated transport channel for transaction forwarding between Monad nodes. This feature is currently **opt-in** and will become required in a future release.

**Benefits:**

* **Reduced Amplification**: Transaction traffic is sent without 2.5x amplification when both peers have direct UDP enabled
* **Dedicated Transport**: Separates transaction forwarding from consensus traffic
* **Performance**: More efficient peer-to-peer transaction delivery

**Prerequisite:** [Authenticated UDP](/node-ops/upgrade-instructions/auth-udp) must be enabled before enabling Direct UDP.

***

## Prerequisites

* **Monad Version**: `v0.14.6` or later
* **Access**: Root/sudo privileges on your node
* **Authenticated UDP**: Already enabled (port 8001 open and configured)
* **Keystore**: Existing `/home/monad/monad-bft/config/id-secp` file
* **Network**: Ability to open UDP port 8002 on your firewall

***

## Instructions for node operators

### 1. Verify the Monad version

Verify the installation:

```bash theme={null}
monad-rpc -V
# Expected output v0.14.6+
```

If not, please refer to the official documentation to upgrade to the latest recommended version: [https://docs.monad.xyz/node-ops/upgrade-instructions/](https://docs.monad.xyz/node-ops/upgrade-instructions/).

***

### 2. Configure Firewall

Open UDP port 8002 for direct UDP traffic:

```bash theme={null}
sudo ufw allow 8002/udp comment 'monad direct udp'
```

Verify the rule was added:

```bash theme={null}
sudo ufw status | grep 8002
```

**Expected output:**

```
8002/udp                   ALLOW       Anywhere                   # monad direct udp
```

Note: if the node is behind a Network Firewall, make sure to also open port 8002.

***

### 3. Generate Updated Name Record Signature

Generate your node's name record signature with the new direct UDP port:

```bash theme={null}
source /home/monad/.env
monad-sign-name-record \
  --ip $(curl -4 -s ifconfig.me) \
  --tcp-port 8000 \
  --udp-port 8000 \
  --authenticated-udp-port 8001 \
  --direct-udp-port 8002 \
  --self-record-seq-num <CURRENT_SEQ_NUM + 1> \
  --keystore-path /home/monad/monad-bft/config/id-secp \
  --password "$KEYSTORE_PASSWORD"
```

> **Important**: The `--self-record-seq-num` value must be **greater** than your current `self_record_seq_num` in `node.toml`.
>
> * Check your current value: `grep self_record_seq_num /home/monad/monad-bft/config/node.toml`
> * Increment by 1

**Example Output:**

```
self_address = "188.214.131.5:8000"
self_record_seq_num = 3
authenticated_udp_port = 8001
direct_udp_port = 8002
self_name_record_sig = "a1b2c3d4..."
```

**Save this output** - you'll need it in the next step.

***

### 4. Update Configuration

Edit your Monad configuration:

```bash theme={null}
sudo vim /home/monad/monad-bft/config/node.toml
```

#### 4.1 Update Network Section

Add the `direct_udp_bind_address_port` parameter to `[network]`:

```toml theme={null}
[network]
bind_address_host = "0.0.0.0"
bind_address_port = 8000
authenticated_bind_address_port = 8001
direct_udp_bind_address_port = 8002        # Add this line
max_rtt_ms = 300
max_mbps = 1000
```

#### 4.2 Update Peer Discovery Section

In the `[peer_discovery]` section, add `self_direct_udp_auth_port` and update the signature:

```toml theme={null}
[peer_discovery]
self_address = "YOUR_IP:8000"
self_auth_port = 8001
self_direct_udp_auth_port = 8002           # Add this line
self_record_seq_num = 3                    # Updated from Step 3
self_name_record_sig = "YOUR_NEW_SIGNATURE_FROM_STEP_3"
```

#### 4.3 Update Peer Records (Validators Only)

If you operate a **validator** with downstream full nodes, update peer configurations as they enable direct UDP.

**For peers that have enabled direct UDP**:

```toml theme={null}
[[bootstrap.peers]]
address = "188.214.131.5:8000"
record_seq_num = 3
secp256k1_pubkey = "0x0342f3..."
name_record_sig = "0xa1b2c3..."
auth_port = 8001
direct_udp_port = 8002                     # Add this for upgraded peers
```

**For peers not yet enabled**, nothing needs to be updated — omit the `direct_udp_port` line:

```toml theme={null}
[[bootstrap.peers]]
address = "188.214.131.6:8000"
record_seq_num = 2
secp256k1_pubkey = "0x..."
name_record_sig = "0x..."
auth_port = 8001
# No direct_udp_port - this peer hasn't upgraded yet
```

Save and exit the file.

***

### 5. Restart and Verify

Restart the Monad service:

```bash theme={null}
sudo systemctl restart monad-bft
```

Monitor the logs for successful startup:

```bash theme={null}
journalctl -u monad-bft -f -n 50 --no-pager
```

***

## Verification

### Check Service Status

```bash theme={null}
systemctl status monad-bft --no-pager
```

Expected: `active (running)`

### Verify Port Binding

```bash theme={null}
sudo ss -ulpn | grep 8002
```

**Expected output:**

```
udp   UNCONN 0   0   0.0.0.0:8002   0.0.0.0:*   users:(("monad-node",pid=12345,fd=25))
```

### Verify All Three UDP Ports

```bash theme={null}
sudo ss -ulpn | grep -E '8000|8001|8002'
```

**Expected output:**

```
udp   UNCONN 0   0   0.0.0.0:8000   0.0.0.0:*   users:(("monad-node",...))
udp   UNCONN 0   0   0.0.0.0:8001   0.0.0.0:*   users:(("monad-node",...))
udp   UNCONN 0   0   0.0.0.0:8002   0.0.0.0:*   users:(("monad-node",...))
```

***

## Troubleshooting

***

### Issue: "invalid name record signature in config file"

**Cause:** The signature in `node.toml` doesn't match the parameters. This often happens when the `--direct-udp-port` flag was not included when generating the signature.

**Solution:**

1. Verify you included `--direct-udp-port 8002` in the `monad-sign-name-record` command
2. Verify you incremented `self_record_seq_num` correctly
3. Re-run `monad-sign-name-record` with all three ports (address, auth, direct)
4. Copy the new signature to `node.toml`
5. Restart the service

***

### Issue: Port 8002 Not Listening

**Solution:**

```bash theme={null}
# Verify config
grep -A10 "\[network\]" /home/monad/monad-bft/config/node.toml | grep direct

# Check for startup errors
journalctl -u monad-bft -n 100 --no-pager | grep -i error

# Restart service
sudo systemctl restart monad-bft
```

***

### Issue: Name Record Not Propagating

**Cause:** The `self_record_seq_num` was not bumped, so peers don't see the updated name record with the direct UDP port.

**Solution:**

1. Check current seq\_num: `grep self_record_seq_num /home/monad/monad-bft/config/node.toml`
2. Re-run `monad-sign-name-record` with a higher seq\_num
3. Update `node.toml` with the new seq\_num and signature
4. Restart the service

***

### Issue: Firewall Blocking Connections

**Solution:**

```bash theme={null}
# Check current UFW rules
sudo ufw status numbered

# Add rule if missing
sudo ufw allow 8002/udp comment 'monad direct udp'

# Reload firewall
sudo ufw reload
```

***

## Rollback Instructions

To disable direct UDP if needed:

### 1. Generate New Signature Without Direct UDP Port

```bash theme={null}
source /home/monad/.env
monad-sign-name-record \
  --ip $(curl -4 -s ifconfig.me) \
  --tcp-port 8000 \
  --udp-port 8000 \
  --authenticated-udp-port 8001 \
  --self-record-seq-num <CURRENT_SEQ_NUM + 1> \
  --keystore-path /home/monad/monad-bft/config/id-secp \
  --password "$KEYSTORE_PASSWORD"
```

Note: Increment the seq\_num from your current value. Omit `--direct-udp-port`.

### 2. Update Configuration

Edit `/home/monad/monad-bft/config/node.toml`:

* Update `self_record_seq_num` and `self_name_record_sig` in `[peer_discovery]`
* Remove `self_direct_udp_auth_port` from `[peer_discovery]`
* Remove `direct_udp_bind_address_port` from `[network]`
* Remove all `direct_udp_port` entries from peer configurations

### 3. Restart Service

```bash theme={null}
sudo systemctl restart monad-bft
```

***

## Quick Health Check Script

Save this as `check_direct_udp.sh` for quick verification:

```bash theme={null}
#!/bin/bash
echo "=== Monad Direct UDP Health Check ==="
echo ""
echo "Checking Monad version..."
monad-rpc -V 2>/dev/null || echo "monad-rpc not found"
echo ""
echo "Checking firewall rules..."
sudo ufw status | grep -E '8001|8002' || echo "No UFW rules for 8001/8002"
echo ""
echo "Checking port bindings..."
sudo ss -ulpn | grep -E '8000|8001|8002' || echo "Ports not bound"
echo ""
echo "Checking service status..."
systemctl is-active monad-bft || echo "Service not active"
echo ""
echo "Checking configuration..."
grep -q "direct_udp_bind_address_port" /home/monad/monad-bft/config/node.toml && \
  echo "direct_udp_bind_address_port configured" || \
  echo "direct_udp_bind_address_port not found"
grep -q "self_direct_udp_auth_port" /home/monad/monad-bft/config/node.toml && \
  echo "self_direct_udp_auth_port configured" || \
  echo "self_direct_udp_auth_port not found"
echo ""
echo "Complete!"
```

Make it executable:

```bash theme={null}
chmod +x check_direct_udp.sh
./check_direct_udp.sh
```

***

## Additional Notes

* **Backward Compatibility**: Nodes can communicate with both direct-UDP-enabled and non-enabled peers
* **Gradual Rollout**: You can enable direct UDP at your own pace during the opt-in period
* **Prerequisite**: Authenticated UDP (port 8001) must be configured first
* **Sequence Numbers**: Always increment `self_record_seq_num` when regenerating signatures — if not bumped, the updated name record won't propagate
* **Key Reuse**: Direct UDP uses your existing validator keys (secp256k1) — same as authenticated UDP
* **Port Summary**: 8000 (standard UDP), 8001 (authenticated UDP), 8002 (direct UDP)

***

## Support

If you encounter issues not covered in this guide:

1. Check logs: `journalctl -u monad-bft -n 500 --no-pager`
2. Verify all configuration parameters match the examples
3. Ensure your firewall and network policies allow UDP/8002
4. Contact Monad support with your logs and configuration (sanitized of sensitive data)
