- 1. Requirements
- 2. TL;DR
- 2.1. Clone the code and implement your model
- 2.2. Check that your model generates a valid response
- 2.3. Get a VM and open port
8091 - 2.4. Create or import a Bittensor wallet
- 2.5. Launch your miner with PM2
- 2.6. Verify the port is open
- 2.7. Track your miner performance
- 2.8. Check your prediction validation
- 2.9. More information
- 3. Getting started
- 4. Protect your predictions
- Clone the Synth subnet repository.
- Modify the implementation of this function to run your own model: simulations.py#L25
- Use all parameters from the prompt except
sigma, which you may ignore.
- Run this command to test your model locally:
python synth/miner/run.py- If your format is correct, you’ll see the output:
$ CORRECT
- Ensure port 8091 is open in your cloud provider's ingress rules.
- Configure your VM's firewall to allow inbound traffic on this port.
- Use
btclito:- Create or import a wallet.
- Add funds.
- Register your hotkey (this will purchase a UID).
- Create a new file called
miner.local.config.jsusing the config from this link: miner.config.js#L1 - Modify the wallet name and hotkey name as needed.
- Start the miner with PM2:
pm2 start miner.local.config.js- Your port will only be accessible if:
- The miner is actively running.
- Port 8091 is open on the VM and network level.
- You can verify using this tool: https://www.yougetsignal.com/tools/open-ports.
- View miner performance and stats on:
- View validation status of your last submission:
https://api.synthdata.co/validation/miner?uid=<your UID>
- Explore the full Synth API documentation: https://api.synthdata.co
To ensure a miner can successfully connect to the network, the port 8091 MUST be open.
Before the beginning, check what ports are open:
nmap localhostwhich should output:
$ nmap localhost
Starting Nmap 7.80 ( https://nmap.org ) at 2025-07-15 12:43 CEST
Nmap scan report for localhost (127.0.0.1)
Host is up (0.000079s latency).
Not shown: 998 closed ports
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
631/tcp open ipp
Nmap done: 1 IP address (1 host up) scanned in 0.04 seconds
⚠️ NOTE: You can installnmapviasudo apt install nmap.
It is RECOMMENDED that ufw (Uncomplicated Firewall) is used to handle port connections.
ufw is a minimal front-end for managing iptables rules. It allows you to easily open ports with simple commands
First, enable ufw using:
sudo ufw enableNext, allow incoming traffic on the correct port:
sudo ufw allow 8091To ensure the port is accessible and the rule is active, execute:
sudo ufw statuswhich should output:
$ sudo ufw status
Status: active
To Action From
-- ------ ----
8091 ALLOW Anywhere
8091 (v6) ALLOW Anywhere (v6)
Using nmap you can check if the port is open using:
nmap -p 8091 localhostwhich should output:
$ nmap -p 8091 localhost
Starting Nmap 7.80 ( https://nmap.org ) at 2025-07-15 12:50 CEST
Nmap scan report for localhost (127.0.0.1)
Host is up (0.000073s latency).
PORT STATE SERVICE
8091/tcp open jamlink
Nmap done: 1 IP address (1 host up) scanned in 0.03 seconds
If you have set up your miner on a remote server/VM using a cloud provider (GCP, AWS, Azure, e.t.c.), you will also need to add an ingress rule on port TCP/8091 to allow for incoming connections.
Please refer to your cloud provider's documentation on adding ingress rules to your server.
Install rust:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | shAdd the required apt repositories:
sudo add-apt-repository ppa:deadsnakes/ppa
⚠️ NOTE: The deadsnakes repository, while unofficial, it is hugely popular and used by many Python projects.
Install Python and Node/npm:
sudo apt update && \
sudo apt install nodejs npm python3.11 python3.11-venv pkg-configInstall PM2 via npm:
sudo npm install pm2 -gClone the synth subnet repository:
git clone https://github.com/synthdataco/synth-subnet.gitChange directory to the project root
cd ./synth-subnetInstall uv if you don't have it:
curl -LsSf https://astral.sh/uv/install.sh | sh
source $HOME/.local/bin/env
⚠️ NOTE: The second command putsuvon thePATHof the current shell; new shells pick it up automatically.
Create the virtual environment and install all locked dependencies:
uv syncActivate and switch to the newly created Python virtual environment:
source .venv/bin/activate
export PYTHONPATH=.
⚠️ NOTE: This should activate the.venvenvironment, and you will see the command line prefixed with(.venv).
💡 TIP: For a more extensive list of the Bittensor CLI commands see here.
You will need to create the cold and hot wallets:
btcli wallet create \
--wallet.name miner \
--wallet.hotkey default🚨 WARNING: You must ensure your wallets have enough TAO (0.25 should be enough) to be able to start mining. For testnet, check out the faucet on the Discord.
Next, register the wallets by acquiring a slot on the Bittensor subnet:
btcli subnet register \
--wallet.name miner \
--wallet.hotkey default \
--netuid 50if you want to try it on testnet first, run the following command:
btcli subnet register \
--wallet.name miner \
--wallet.hotkey default \
--network test \
--netuid 247You can verify the wallet registration by running:
btcli wallet overview \
--wallet.name miner \
--wallet.hotkey defaultAnd, you can also check the network metagraph:
btcli subnet metagraph \
--netuid 50for testnet it's:
btcli subnet metagraph \
--network test \
--netuid 247Simply start PM2 with the miner config:
pm2 start miner.config.jsfor testnet use:
pm2 start miner.test.config.jsYou can check if the miner is running by using:
pm2 listYour predictions are valuable. To stop unauthorized parties from querying your miner and copying your responses, make sure only legitimate validators can reach your miner port.
We RECOMMEND configuring your firewall with an allow-list for the ingress IPs on your miner port (8091).
Legitimate validators publish their IP on the Bittensor chain, and these IPs are visible on the metagraph:
https://taostats.io/subnets/50/metagraph?order=validator_trust%3Adesc
Your miner should only answer requests from a validator that:
- Stakes at least 65000.
- Publishes its IP on chain.
- Holds the validator permit.
Maintaining this allow-list by hand is tedious, since validator IPs may change over time. We provide a chain-sync script that keeps your ufw allow-list in sync with the eligible validators on the metagraph automatically:
It admits only validators that hold the validator permit and stake at least --blacklist.validator_min_stake (default 65000), then adds/removes per-IP rules on each cycle. Use --dry-run to preview which IPs would be allowed without touching ufw:
python synth/miner/chain_sync.py --axon_port 8091 --dry-runTo run it for real (as root, so it can edit ufw):
python synth/miner/chain_sync.py --axon_port 8091We ask all miners to run their miners with the blacklist function:
neurons/miner.py#L58 In particular, it includes a security fix that rejects unsigned requests:
if not synapse.dendrite.signature:
bt.logging.warning(
f"Blacklisting unsigned request claiming hotkey "
f"{synapse.dendrite.hotkey}"
)
return True, "Missing signature"The new blacklist function applies a minimum of 65000 stake by default. This is why you MUST update your blacklist function and restart all your miners.
--blacklist.validator_min_stake 65000— gates requests by validator stake. The blacklist enforces a minimum of65000, even if you configure a lower value. Back to top ^