Skip to main content

Run a Stacks Blockchain API instance with Docker

NOTE:

For a faster way to deploy the Stacks Blockchain and Stacks Blockchain API with Docker, see the Stacks Blockchain Docker repository.

On this page, you will learn how to run a stacks-blockchain-api instance. There are several components involved here to have a working setup, and descriptions will be given for each of these components.

This page will also focus on the easy path to get the services running, which is currently Docker.

Please note that the following guide is meant for a Unix-like OS (Linux/MacOS). The commands may work on Windows but will likely need some adjustments.

Requirements

  1. Docker
  2. bash or some other Unix-like shell (i.e. zsh)
  3. curl binary

Note: The order of operations here is important.

Essentially, to start the API successfully you will want to perform the following steps in order:

  1. start postgres
  2. start stacks-blockchain-api
  3. start stacks-blockchain

Conversely, to bring down the API and NOT lose any data, perform the same steps in Reverse:

  1. stop stacks-blockchain
  2. stop stacks-blockchain-api
  3. stop postgres

Firewalling

In order for the services to work correctly, the host will need some ports open.

Default Ingress Ports:

  • postgres (open to localhost only):
    • 5432 TCP
  • stacks-blockchain (open to 0.0.0.0/0):
    • 20443 TCP
    • 20444 TCP
  • stacks-blockchain-api (open to where you want to access the api from):
    • 3999 TCP

Default Egress Ports:

The only egress ports you will need (outside of what you need normally to install/update packages) are:

  • 8332
  • 8333
  • 20443-20444

These are the ports used to sync the stacks-blockchain and the bitcoin headers. If they are not open, the sync will fail.

Initial Setup

Since you will need to create some files/dirs for persistent data, you must first create a base directory structure and download the docker images.

You should use the following command:

$ mkdir -p ./stacks-node/{persistent-data/postgres,persistent-data/stacks-blockchain,config}
$ docker pull blockstack/stacks-blockchain-api \
&& docker pull blockstack/stacks-blockchain \
&& docker pull postgres:alpine
$ docker network create stacks-blockchain > /dev/null 2>&1
$ cd ./stacks-node

Postgres

The postgres:alpine image can be run with default settings, the only requirement is that a password Environment Variable is set for the postgres user: POSTGRES_PASSWORD=postgres

Starting postgres

docker run -d --rm \
--name postgres \
--net=stacks-blockchain \
-e POSTGRES_PASSWORD=postgres \
-v $(pwd)/persistent-data/postgres:/var/lib/postgresql/data \
-p 5432:5432 \
postgres:alpine

There should now be a running postgres instance running on port 5432:

$ docker ps --filter name=postgres
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f835f3a8cfd4 postgres:alpine "docker-entrypoint.s…" 1 minute ago Up 1 minute 0.0.0.0:5432->5432/tcp, :::5432->5432/tcp postgres

Stopping Postgres

To stop the postgres service (this will also remove the container, but not the data), run the following command:

$ docker stop postgres

Stacks Blockchain API

The Stacks Blockchain API requires you to set several environment variables in order to run properly.
To reduce complexity, create a .env file that you will use for these environment variables.

Create a new file: ./.env with the following content:

NODE_ENV=production
GIT_TAG=master
PG_HOST=postgres
PG_PORT=5432
PG_USER=postgres
PG_PASSWORD=postgres
PG_DATABASE=postgres
STACKS_CHAIN_ID=0x00000001
V2_POX_MIN_AMOUNT_USTX=90000000260
STACKS_CORE_EVENT_PORT=3700
STACKS_CORE_EVENT_HOST=0.0.0.0
STACKS_BLOCKCHAIN_API_PORT=3999
STACKS_BLOCKCHAIN_API_HOST=0.0.0.0
STACKS_CORE_RPC_HOST=stacks-blockchain
STACKS_CORE_RPC_PORT=20443
API_DOCS_URL=https://docs.hiro.so/api

The other environment variables to pay attention to are:

  • PG_HOST: Set this to your postgres instance. In this guide, we'll be using a container named postgres.
  • STACKS_CORE_RPC_HOST: Set this to your stacks blockchain node. In this guide, we'll be using a container named stacks-blockchain.
  • API_DOCS_URL: Set this to enable your docs API http://localhost:3999/doc.

Starting stacks-blockchain-api

Run the following command to run Stacks Blockchain API:

docker run -d --rm \
--name stacks-blockchain-api \
--net=stacks-blockchain \
--env-file $(pwd)/.env \
-p 3700:3700 \
-p 3999:3999 \
blockstack/stacks-blockchain-api

You shoudl now have a running stacks-blockchain-api instance running on ports 3999 and 3700:

e$ docker ps --filter name=stacks-blockchain-api
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a86a26da6c5a blockstack/stacks-blockchain-api "docker-entrypoint.s…" 1 minute ago Up 1 minute 0.0.0.0:3700->3700/tcp, :::3700->3700/tcp, 0.0.0.0:3999->3999/tcp, :::3999->3999/tcp stacks-blockchain-api

NOTE:

On initial sync, it will take several minutes for port 3999 to become available.

Stopping stacks-blockchain-api

To stop the stacks-blockchain-api service (this will also remove the container), run the following command:

$ docker stop stacks-blockchain-api

Stacks Blockchain

In order to have a usable API instance, you need to have data from a running stacks-blockchain instance.

Because the focus is on running the API with Docker, it also makes things easier if you also run the stacks-blockchain instance the same way.

With that in mind, you will need to have the following configuration in your Config.toml. This configuration block will send blockchain events to the API instance that was previously started:

[[events_observer]]
endpoint = "<fqdn>:3700"
retry_count = 255
events_keys = ["*"]

Here is an example Config.toml that you can use - create this file as ./config/mainnet/Config.toml:

[node]
working_dir = "/root/stacks-node/data"
rpc_bind = "0.0.0.0:20443"
p2p_bind = "0.0.0.0:20444"
bootstrap_node = "02196f005965cebe6ddc3901b7b1cc1aa7a88f305bb8c5893456b8f9a605923893@seed.mainnet.hiro.so:20444"
wait_time_for_microblocks = 10000

[[events_observer]]
endpoint = "stacks-blockchain-api:3700"
retry_count = 255
events_keys = ["*"]

[burnchain]
chain = "bitcoin"
mode = "mainnet"
peer_host = "bitcoin.blockstack.com"
username = "blockstack"
password = "blockstacksystem"
rpc_port = 8332
peer_port = 8333

[connection_options]
read_only_call_limit_write_length = 0
read_only_call_limit_read_length = 100000
read_only_call_limit_write_count = 0
read_only_call_limit_read_count = 30
read_only_call_limit_runtime = 1000000000

Starting stacks-blockchain

docker run -d --rm \
--name stacks-blockchain \
--net=stacks-blockchain \
-v $(pwd)/persistent-data/stacks-blockchain:/root/stacks-node/data \
-v $(pwd)/config:/src/stacks-node \
-p 20443:20443 \
-p 20444:20444 \
blockstack/stacks-blockchain \
/bin/stacks-node start --config /src/stacks-node/Config.toml

You should now see a running stacks-blockchain instance running on ports 20443-20444:

$ docker ps --filter name=stacks-blockchain$
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
199e37a324f1 blockstack/stacks-blockchain "/bin/stacks-node st…" 1 minute ago Up 1 minute 0.0.0.0:20443-20444->20443-20444/tcp, :::20443-20444->20443-20444/tcp stacks-blockchain

Stopping stacks-blockchain

To stop the stacks-blockchain service (this will also remove the container, but not the data), run the following command:

$ docker stop stacks-blockchain

Verify Everything is running correctly

Postgres testing

To verfiy the database is ready:

  1. Connect to the DB instance: psql -h localhost -U postgres
    • this will require a locally installed postgresql client
    • use the password from the Environment Variable POSTGRES_PASSWORD
  2. List current databases: \l
  3. Disconnect from the DB : \q

stacks-blockchain testing

Verify the stacks-blockchain tip height is progressing:

$ curl -sL localhost:20443/v2/info | jq
{
"peer_version": 402653184,
"pox_consensus": "89d752034e73ed10d3b97e6bcf3cff53367b4166",
"burn_block_height": 666143,
"stable_pox_consensus": "707f26d9d0d1b4c62881a093c99f9232bc74e744",
"stable_burn_block_height": 666136,
"server_version": "stacks-node 2.0.11.1.0-rc1 (master:67dccdf, release build, linux [x86_64])",
"network_id": 1,
"parent_network_id": 3652501241,
"stacks_tip_height": 61,
"stacks_tip": "e08b2fe3dce36fd6d015c2a839c8eb0885cbe29119c1e2a581f75bc5814bce6f",
"stacks_tip_consensus_hash": "ad9f4cb6155a5b4f5dcb719d0f6bee043038bc63",
"genesis_chainstate_hash": "74237aa39aa50a83de11a4f53e9d3bb7d43461d1de9873f402e5453ae60bc59b",
"unanchored_tip": "74d172df8f8934b468c5b0af2efdefe938e9848772d69bcaeffcfe1d6c6ef041",
"unanchored_seq": 0,
"exit_at_block_height": null
}

stacks-blockchain-api testing

Verify the stacks-blockchain-api is receiving data from the stacks-blockchain:

$ curl -sL localhost:3999/v2/info | jq
{
"peer_version": 402653184,
"pox_consensus": "e472cadc17dcf3bc1afafc6aa595899e55f25b72",
"burn_block_height": 666144,
"stable_pox_consensus": "6a6fb0aa75a8acd4919f56c9c4c81ce5bc42cac1",
"stable_burn_block_height": 666137,
"server_version": "stacks-node 2.0.11.1.0-rc1 (master:67dccdf, release build, linux [x86_64])",
"network_id": 1,
"parent_network_id": 3652501241,
"stacks_tip_height": 61,
"stacks_tip": "e08b2fe3dce36fd6d015c2a839c8eb0885cbe29119c1e2a581f75bc5814bce6f",
"stacks_tip_consensus_hash": "ad9f4cb6155a5b4f5dcb719d0f6bee043038bc63",
"genesis_chainstate_hash": "74237aa39aa50a83de11a4f53e9d3bb7d43461d1de9873f402e5453ae60bc59b",
"unanchored_tip": "74d172df8f8934b468c5b0af2efdefe938e9848772d69bcaeffcfe1d6c6ef041",
"unanchored_seq": 0,
"exit_at_block_height": null
}

Now that everything is running, you can try some of these other API endpoints