Note: the below applies to those only with direct hardware access, which dockerized solutions don't provide. We currently cannot commit to offering long-term assistance or guarantee results, as managing each miner's setup on an individual basis is not feasible for us. Once we introduce a universal solution that is more standardized, we will be able to offer more comprehensive support.
There have been ddos attacks on the bittensor network, and to protect your miners or your validator, you can set up ufw firewalls using this script on the server running your miners. It will make the miners only accept requests from validator IP addresses.
Do notice that in rare cases, the DDoS can come from a validator IP address, in which case that would need to be blocked independently.
You should run it using pm2 since you want it to be permanent:
import copy
import time
import argparse
import bittensor as bt
import subprocess
import numpy as np
def resync_metagraph(metagraph, subtensor):
print("Resyncing metagraph")
previous_metagraph = copy.deepcopy(metagraph)
# Sync the metagraph
metagraph.sync(subtensor=subtensor)
# Check if axon info has changed
if previous_metagraph.axons != metagraph.axons:
print("Metagraph updated, re-syncing hotkeys")
print("Metagraph synced")
def get_top_ips_from_metagraph(metagraph, top_n=25):
print("Fetching top IPs from metagraph")
top_stake_indices = np.argsort(metagraph.stake)[-top_n:][::-1]
top_uids = metagraph.uids[top_stake_indices].tolist()
axons = [metagraph.axons[uid] for uid in top_uids]
ips = [axon.ip for axon in axons]
# Ensure unique IP-to-UID mapping
unique_ip_to_uid = {ip: uid for ip, uid in zip(ips, top_uids)}
unique_ips = list(unique_ip_to_uid.keys())
print(f"Top {top_n} UIDs: {top_uids}")
return unique_ips
def update_ufw_with_ips(ips):
print("Updating UFW with new IPs")
# Disable UFW and reset rules
subprocess.run("sudo ufw disable", shell=True)
subprocess.run("echo y | sudo ufw reset", shell=True)
# Allow SSH through UFW for all IPs
subprocess.run("sudo ufw allow ssh", shell=True)
# Whitelist the provided IPs
for ip in ips:
if ip != "0.0.0.0":
cmd = f"sudo ufw allow proto tcp from {ip}/32"
subprocess.run(cmd, shell=True)
print(f"Whitelisted IP {ip} for Bittensor")
# Ensure port 22 is open for all IPs
subprocess.run("sudo ufw allow 22", shell=True)
print("Ensured port 22 (SSH) is open for all IPs")
# Re-enable UFW
subprocess.run("echo y | sudo ufw enable", shell=True)
def parse_arguments():
parser = argparse.ArgumentParser(description="Run firewall script for Bittensor")
parser.add_argument('--netuid', help='Netuid of the subnet', type=int, default=23)
return parser.parse_args()
if __name__ == "__main__":
args = parse_arguments()
# Initialize Bittensor subtensor and metagraph
subtensor = bt.subtensor(network="finney")
metagraph = subtensor.metagraph(netuid=args.netuid)
while True:
# Resync the metagraph
resync_metagraph(metagraph, subtensor)
# Get the IPs of the top validators
top_ips = get_top_ips_from_metagraph(metagraph)
# Whitelist the IPs in UFW
update_ufw_with_ips(top_ips)
# Wait for 100 blocks (~1200 seconds or 20 minutes)
print("Waiting for 100 blocks (20 minutes)")
time.sleep(1200)
To use it, create a file called ufw.py by running this command:
cat > ufw.py
And then copy paste the code above into the file.
Then start the process by running:
pm2 start ufw.py --name ufw