Skip to main content


Now that everything is set up let's start creating the pool. Please read the official documentation Martin of ATADA pool provides to get a better understanding of the scripts. His tutorial is much more detailed and covers a lot of options. Thank you Martin!

This tutorial on the other hand is for the basics. It contains everything necessary to get a stake pool running and some other fundamental operations. It should help to get a nice and easy workflow.

The transfer with the USB device is fully automated. It just needs to be mounted at the current working environment, which should also work automated. If not, mount it with sudo mount ~/usb_transfer. Make sure to unmount every time before removing sudo umount ~/usb_transfer.


This guide assumes, that you are always in $HOME/pool_keys when running a script on the offline machine and in $HOME/pi-pool on the core.

Prerequisits on the cold machine

Let's begin with a directory for your keys.

>_ Terminal
mkdir pool_keys
cd pool_keys

Also make sure the offline machine's time is correct, you'll have to do this everytime you use it!

>_ Terminal
timedatectl set-time xxxxx

Create a stake pool


Basically everything is created offline. Make sure that you never expose your secret keys to an online environment and back them up, multiple times best case. The only keys you need on your core are: kes-xxx.skey, vrf.skey and node-xxx.opcert.


Create and fund a wallet

First of all you'll need a wallet and with it a staking key. Create the keys and name the wallet accordingly.

>_ Terminal wallet_name cli

Now copy the addresses to your core to fund the new wallet. You'll need your fresh USB drive for that.

>_ Terminal attach wallet_name.payment.addr attach wallet_name.staking.addr

Switch the USB drive from offline to online machine. Extract the address files.

>_ Terminal extract

Retrieve the address and send some funds to your new wallet. You'll need at least 502 ADA + tx fees + your pledge.

>_ Terminal
cat wallet_name.payment.addr

Query the balance and wait until the new UTXO shows up.

>_ Terminal wallet_name.payment

When the funds arrived copy the UTXO data to your offline machine.

>_ Terminal add wallet_name.payment

Generate a transaction to register the staking address. It will be submitted later on.

>_ Terminal wallet_name.staking 

Create the pool's keys and certificates

Generate the keys for your core node.

>_ Terminal pool_name cli pool_name pool_name pool_name

Generate your stakepool certificate and metadata.json.

>_ Terminal pool_name

This creates a pool_name.pool.json file, which you can edit according to your needs and wishes. Everything is calculated in lovelaces. (Reminder: 1 ADA = 1,000,000 lovelace) So in this case we get a pool with 100k ADA pledge, 340 ADA fixed cost (minimum) and 1% margin.

Add as many of your relays as you want. Either ip or dns based.

Pool description can contain up to 255 characters.

poolMetaUrl points to the Metadata file, which you need to upload later. Github is a popular choice, if you don't want to use your own server.


poolMetaUrl can only be 64 characters long. Make sure it points to the raw file. In case you need to shorten the URL you can do it by creating an empty pool_name.metadata.json, upload it and shorten the URL. Make sure the short URL doesn't expire. Later replace it with the actual file.

You may also add an URL to an extended.metadata.json, which holds more information like the URL to your logo etc. Just create the file on your local machine, it's quite self-explanatory. The png icon is limited to 64x64 while the logo could use 400x400 pixels. jpg works aswell.

>_ Terminal
"poolName": "pool_name",
"poolOwner": [
"ownerName": "wallet_name",
"ownerWitness": "local"
"poolRewards": "wallet_name",
"poolPledge": "100000000000",
"poolCost": "340000000",
"poolMargin": "0.01"
"poolRelays": [
"relayType": "dns",
"relayEntry": "",
"relayPort": "3001"
"relayType": "ip",
"relayEntry": "x.x.x.x (ipv4 of relay)",
"relayPort": "3002"
"poolMetaName": "This is my Pool",
"poolMetaDescription": "This is the description of my Pool!",
"poolMetaTicker": "POOL",
"poolMetaHomepage": "",
"poolMetaUrl": "",
"poolExtendedMetaUrl": "",
"---": "--- DO NOT EDIT BELOW THIS LINE ---"

Now run pool_name again. This will generate the pool_name.pool.cert file and the actual pool_name.metadata.json. Later you can upload the metadata.json to the URL you specified in the previous step. Do not edit it anymore or the hash won't fit! If you want to change something, change it in the pool_name.pool.json and run pool_name again.

Delegate to your own pool as owner. (Pledge)

>_ Terminal pool_name wallet_name

Generate the stakepool registration transaction. The script also attaches the new pool_name.metadata.json to the offline transfer file.

>_ Terminal pool_name wallet_name.payment

Now attach the files needed by the core.

>_ Terminal attach pool_name.vrf.skey attach pool_name.kes-xxx.skey attach pool_name.node-xxx.opcert

You are done with the offline part. Unmount and bring your USB drive to the core again.

>_ Terminal extract

For convenience rename the core files so you don't have to change the startup script every KES rotation.

>_ Terminal
mv pool_name.kes-xxx.skey kes.skey
mv pool_name.vrf.skey vrf.skey
mv pool_name.node-xxx.opcert node.cert

Now change the startup script and add the three files.

>_ Terminal
nano $HOME/.local/bin/cardano-service
. /home/ada/.adaenv

cardano-node +RTS -N4 --disable-delayed-os-memory-return -RTS run \
--topology ${TOPOLOGY} \
--database-path ${DB_PATH} \
--socket-path ${CARDANO_NODE_SOCKET_PATH} \
--port ${NODE_PORT} \
--config ${CONFIG} \
--shelley-kes-key ${KES} \
--shelley-vrf-key ${VRF} \
--shelley-operational-certificate ${CERT}

Restart the service.

>_ Terminal
cardano-service restart

While your core is starting you can transfer the pool_name.metadata.json to your local machine and upload it to the prepared URL. Do the same with the extended metadata and your logos, if you have made them.

Check the status of the core. When it's up again you can submit the transactions. First the staking key registration, then repeat the same command for the stake pool registration.

>_ Terminal execute

Confirm successful registration is a website for pool operators to check the validity of their stake pools on chain data. You can check this site for problems and clues as to how to fix them.

You should create an account and claim your pool here at

You should also create an account and claim your pool here on

Rotate KES keys


Make sure to rotate your KES keys and node certificate before! they expire.


Before starting check timedatectl on your offline machine and adjust, if needed.

Create the new KES keypair. You will notice that the counter increments automatically.

>_ Terminal pool_name

Create a new operational certificate.

>_ Terminal pool_name

Now attach the new files.

>_ Terminal attach pool_name.vrf.skey attach pool_name.kes-xxx.skey attach pool_name.node-xxx.opcert

Unmount and bring the USB drive to the core. Stop the node and extract the files.

>_ Terminal
cardano-service stop extract

Now rename/move them to match the startup script. Then start again. That's it.

>_ Terminal
mv pool_name.kes-xxx.skey kes.skey
mv pool_name.vrf.skey vrf.skey
mv pool_name.node-xxx.opcert node.cert
cardano-service start

Update pool registration

First get up-to-date information from the core via your USB drive.

>_ Terminal add wallet_name.payment

Switch to the offline machine and edit the values you want to change in the pool_name.pool.json.

>_ Terminal
chmod 600 pool_name.pool.json
nano pool_name.pool.json
chmod 400 pool_name.pool.json

Create a new certificate pool_name.pool.cert and pool_name.metadata.json.

>_ Terminal pool_name

Create the registration transaction. If the metadata didn't change you don't need to attach it to the transfer file.

>_ Terminal pool_name wallet_name.payment

Now switch to the core. First, if you changed the metadata, extract and upload it. Otherwise skip this step and submit the transaction directly.

>_ Terminal execute

Claim rewards

First get up-to-date information from the core via your USB drive.

>_ Terminal add wallet_name.payment add wallet_name.staking

Switch over to the offline machine.

>_ Terminal wallet_name.staking wallet_name.payment

Back to the core.

>_ Terminal execute

Send a simple transaction

First get up-to-date information from the core via your USB drive. Create a other_wallet.payment.addr which contains the address (and only the address) you want to send your ADA to.

>_ Terminal add wallet_name.payment attach other_wallet.payment.addr

Bring everything over to the cold machine and create the transaction. This will send 1000 ADA from your pledge wallet to the other wallet. (Again everything in lovelaces. 1 ADA = 1000000 lovelace)

>_ Terminal extract wallet_name.payment other_wallet.payment 1000000000

Make sure to meet your pledge at any time. And some ADA for transactions fees on top aren't bad.

USB transfer and submitting at your core.

>_ Terminal execute