├── postgres.Dockerfile ├── scripts ├── entrypoint.sh ├── setup-bns.sh └── nginx.sh ├── unit-files ├── log │ ├── nginx │ └── stacks-blockchain-api └── run │ ├── nginx │ ├── stacks-blockchain-api │ └── stacks-blockchain ├── configs ├── nginx-default.conf ├── nginx.conf ├── nginx-stacks.conf ├── nginx-api.conf ├── Stacks-mainnet.toml ├── Stacks-mocknet.toml └── Stacks-testnet.toml ├── nginx.Dockerfile ├── stacks-blockchain.Dockerfile ├── stacks-blockchain-api.Dockerfile ├── standalone.Dockerfile ├── render.yaml └── README.md /postgres.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM postgres:14-alpine 2 | -------------------------------------------------------------------------------- /scripts/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | runsvdir /etc/service 3 | -------------------------------------------------------------------------------- /unit-files/log/nginx: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | exec svlogd -tt /var/log/nginx 3 | -------------------------------------------------------------------------------- /unit-files/run/nginx: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | exec /usr/sbin/nginx -g "daemon off;" 2>&1 3 | -------------------------------------------------------------------------------- /unit-files/log/stacks-blockchain-api: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | exec svlogd -tt /var/log/stacks-blockchain-api 3 | -------------------------------------------------------------------------------- /configs/nginx-default.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80 default_server; 3 | listen [::]:80 default_server; 4 | access_log /dev/stdout; 5 | error_log /dev/stdout; 6 | 7 | location /status { 8 | default_type text/plain; 9 | return 200 OK; 10 | } 11 | 12 | location = /404.html { 13 | internal; 14 | } 15 | } -------------------------------------------------------------------------------- /nginx.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM nginx:alpine 2 | # COPY configs/nginx.conf /etc/nginx/templates/default.conf.template 3 | COPY configs/nginx-default.conf /etc/nginx/conf.d/default.conf 4 | COPY configs/nginx-default.conf /srv/nginx-default.conf 5 | COPY configs/nginx.conf /srv/nginx.conf 6 | COPY scripts/nginx.sh /entrypoint.sh 7 | RUN chmod 755 /entrypoint.sh 8 | CMD "/entrypoint.sh" 9 | -------------------------------------------------------------------------------- /unit-files/run/stacks-blockchain-api: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | exec 2>&1 3 | 4 | if [ ! -z "${BNS_IMPORT_DIR}" ]; then 5 | if [ ! -f "${BNS_IMPORT_DIR}/imported" ]; then 6 | /setup-bns.sh 7 | fi 8 | fi 9 | 10 | case $STACKS_NETWORK in 11 | mainnet) 12 | export STACKS_CHAIN_ID=0x00000001 13 | ;; 14 | testnet) 15 | export STACKS_CHAIN_ID=0x80000000 16 | ;; 17 | *) 18 | export STACKS_CHAIN_ID=2147483648 19 | ;; 20 | esac 21 | cd /app && exec node ./lib/index.js 2>&1 -------------------------------------------------------------------------------- /unit-files/run/stacks-blockchain: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | exec 2>&1 3 | 4 | case $STACKS_NETWORK in 5 | mainnet) 6 | CONFIG=/stacks-blockchain/Stacks-mainnet.toml 7 | ;; 8 | testnet) 9 | CONFIG=/stacks-blockchain/Stacks-testnet.toml 10 | ;; 11 | *) 12 | CONFIG=/stacks-blockchain/Stacks-mocknet.toml 13 | ;; 14 | esac 15 | sed -i -e "s|\$STACKS_BLOCKCHAIN_API_HOST|$STACKS_BLOCKCHAIN_API_HOST|g" $CONFIG 16 | sed -i -e "s|\$STACKS_CORE_EVENT_PORT|$STACKS_CORE_EVENT_PORT|g" $CONFIG 17 | exec /bin/stacks-node start --config=$CONFIG 2>&1 -------------------------------------------------------------------------------- /configs/nginx.conf: -------------------------------------------------------------------------------- 1 | 2 | map $http_upgrade $connection_upgrade { 3 | default upgrade; 4 | '' close; 5 | } 6 | upstream stacks-blockchain-api { 7 | server $STACKS_BLOCKCHAIN_API_HOST:80/; 8 | } 9 | server { 10 | listen 80; 11 | server_name localhost; 12 | location /status { 13 | default_type text/plain; 14 | return 200 ok; 15 | } 16 | location / { 17 | proxy_pass http://stacks-blockchain-api/; 18 | proxy_http_version 1.1; 19 | proxy_set_header Upgrade $http_upgrade; 20 | proxy_set_header Connection $connection_upgrade; 21 | proxy_set_header Host $host; 22 | } 23 | } -------------------------------------------------------------------------------- /configs/nginx-stacks.conf: -------------------------------------------------------------------------------- 1 | map $http_upgrade $connection_upgrade { 2 | default upgrade; 3 | '' close; 4 | } 5 | upstream stacks-blockchain { 6 | server localhost:20443; 7 | } 8 | server { 9 | listen 80 default_server; 10 | listen [::]:80 default_server; 11 | access_log /dev/stdout; 12 | error_log /dev/stdout; 13 | server_name localhost; 14 | location /status { 15 | default_type text/plain; 16 | return 200 ok; 17 | } 18 | location / { 19 | proxy_pass http://stacks-blockchain/; 20 | proxy_http_version 1.1; 21 | proxy_set_header Upgrade $http_upgrade; 22 | proxy_set_header Connection $connection_upgrade; 23 | proxy_set_header Host $host; 24 | } 25 | } -------------------------------------------------------------------------------- /configs/nginx-api.conf: -------------------------------------------------------------------------------- 1 | map $http_upgrade $connection_upgrade { 2 | default upgrade; 3 | '' close; 4 | } 5 | upstream stacks-blockchain-api { 6 | server localhost:3999; 7 | } 8 | server { 9 | listen 80 default_server; 10 | listen [::]:80 default_server; 11 | access_log /dev/stdout; 12 | error_log /dev/stdout; 13 | server_name localhost; 14 | location /status { 15 | default_type text/plain; 16 | return 200 ok; 17 | } 18 | location / { 19 | proxy_pass http://stacks-blockchain-api/; 20 | proxy_http_version 1.1; 21 | proxy_set_header Upgrade $http_upgrade; 22 | proxy_set_header Connection $connection_upgrade; 23 | proxy_set_header Host $host; 24 | } 25 | } -------------------------------------------------------------------------------- /configs/Stacks-mainnet.toml: -------------------------------------------------------------------------------- 1 | [node] 2 | working_dir = "/root/stacks-blockchain/data" 3 | rpc_bind = "0.0.0.0:20443" 4 | p2p_bind = "0.0.0.0:20444" 5 | bootstrap_node = "02da7a464ac770ae8337a343670778b93410f2f3fef6bea98dd1c3e9224459d36b@seed-0.mainnet.stacks.co:20444,02afeae522aab5f8c99a00ddf75fbcb4a641e052dd48836408d9cf437344b63516@seed-1.mainnet.stacks.co:20444,03652212ea76be0ed4cd83a25c06e57819993029a7b9999f7d63c36340b34a4e62@seed-2.mainnet.stacks.co:20444" 6 | 7 | [burnchain] 8 | chain = "bitcoin" 9 | mode = "mainnet" 10 | peer_host = "bitcoin.mainnet.stacks.org" 11 | username = "stacks" 12 | password = "foundation" 13 | rpc_port = 8332 14 | peer_port = 8333 15 | 16 | [[events_observer]] 17 | endpoint = "$STACKS_BLOCKCHAIN_API_HOST:$STACKS_CORE_EVENT_PORT" 18 | retry_count = 255 19 | events_keys = ["*"] -------------------------------------------------------------------------------- /configs/Stacks-mocknet.toml: -------------------------------------------------------------------------------- 1 | [node] 2 | rpc_bind = "0.0.0.0:20443" 3 | p2p_bind = "0.0.0.0:20444" 4 | bootstrap_node = "04ee0b1602eb18fef7986887a7e8769a30c9df981d33c8380d255edef003abdcd243a0eb74afdf6740e6c423e62aec631519a24cf5b1d62bf8a3e06ddc695dcb77@127.0.0.1:21444" 5 | wait_time_for_microblocks = 10000 6 | use_test_genesis_chainstate = true 7 | 8 | [burnchain] 9 | chain = "bitcoin" 10 | mode = "mocknet" 11 | 12 | [[events_observer]] 13 | endpoint = "$STACKS_BLOCKCHAIN_API_HOST:$STACKS_CORE_EVENT_PORT" 14 | retry_count = 255 15 | events_keys = ["*"] 16 | 17 | [[ustx_balance]] 18 | address = "ST3EQ88S02BXXD0T5ZVT3KW947CRMQ1C6DMQY8H19" 19 | amount = 100000000000000 20 | 21 | [[ustx_balance]] 22 | address = "ST3KCNDSWZSFZCC6BE4VA9AXWXC9KEB16FBTRK36T" 23 | amount = 100000000000000 24 | 25 | [[ustx_balance]] 26 | address = "STB2BWB0K5XZGS3FXVTG3TKS46CQVV66NAK3YVN8" 27 | amount = 100000000000000 28 | 29 | [[ustx_balance]] 30 | address = "STSTW15D618BSZQB85R058DS46THH86YQQY6XCB7" 31 | amount = 100000000000000 32 | -------------------------------------------------------------------------------- /configs/Stacks-testnet.toml: -------------------------------------------------------------------------------- 1 | [node] 2 | working_dir = "/root/stacks-blockchain/data" 3 | rpc_bind = "0.0.0.0:20443" 4 | p2p_bind = "0.0.0.0:20444" 5 | bootstrap_node="047435c194e9b01b3d7f7a2802d6684a3af68d05bbf4ec8f17021980d777691f1d51651f7f1d566532c804da506c117bbf79ad62eea81213ba58f8808b4d9504ad@testnet.stacks.co:20444" 6 | 7 | [burnchain] 8 | chain = "bitcoin" 9 | mode = "xenon" 10 | peer_host = "bitcoin.testnet.stacks.org" 11 | username = "stacks" 12 | password = "foundation" 13 | rpc_port = 18332 14 | peer_port = 18333 15 | 16 | [[events_observer]] 17 | endpoint = "$STACKS_BLOCKCHAIN_API_HOST:$STACKS_CORE_EVENT_PORT" 18 | retry_count = 255 19 | events_keys = ["*"] 20 | 21 | [[ustx_balance]] 22 | address = "ST2QKZ4FKHAH1NQKYKYAYZPY440FEPK7GZ1R5HBP2" 23 | amount = 10000000000000000 24 | 25 | [[ustx_balance]] 26 | address = "ST319CF5WV77KYR1H3GT0GZ7B8Q4AQPY42ETP1VPF" 27 | amount = 10000000000000000 28 | 29 | [[ustx_balance]] 30 | address = "ST221Z6TDTC5E0BYR2V624Q2ST6R0Q71T78WTAX6H" 31 | amount = 10000000000000000 32 | 33 | [[ustx_balance]] 34 | address = "ST2TFVBMRPS5SSNP98DQKQ5JNB2B6NZM91C4K3P7B" 35 | amount = 10000000000000000 -------------------------------------------------------------------------------- /stacks-blockchain.Dockerfile: -------------------------------------------------------------------------------- 1 | ARG STACKS_BLOCKCHAIN_VERSION=2.1.0.0.0 2 | 3 | 4 | FROM blockstack/stacks-blockchain:${STACKS_BLOCKCHAIN_VERSION} 5 | ARG STACKS_NETWORK=mainnet 6 | ARG LOG_DIR=/var/log/ 7 | ARG STACKS_SVC_DIR=/etc/service 8 | 9 | ENV STACKS_NETWORK=${STACKS_NETWORK} 10 | 11 | RUN apk add \ 12 | nginx \ 13 | runit \ 14 | && mkdir -p \ 15 | /root/stacks-blockchain/data \ 16 | ${STACKS_SVC_DIR}/stacks-blockchain \ 17 | ${STACKS_SVC_DIR}/nginx \ 18 | ${STACKS_SVC_DIR}/nginx/log \ 19 | ${LOG_DIR}/nginx/log 20 | 21 | 22 | COPY configs/nginx-stacks.conf /etc/nginx/http.d/default.conf 23 | COPY configs/Stacks-*.toml /stacks-blockchain/ 24 | COPY unit-files/run/stacks-blockchain ${STACKS_SVC_DIR}/stacks-blockchain/run 25 | COPY unit-files/run/nginx ${STACKS_SVC_DIR}/nginx/run 26 | COPY unit-files/log/nginx ${STACKS_SVC_DIR}/nginx/log/run 27 | COPY scripts/entrypoint.sh /docker-entrypoint.sh 28 | 29 | RUN chmod 755 \ 30 | /docker-entrypoint.sh \ 31 | ${STACKS_SVC_DIR}/stacks-blockchain/run \ 32 | ${STACKS_SVC_DIR}/nginx/run \ 33 | ${STACKS_SVC_DIR}/nginx/log/run 34 | 35 | CMD /docker-entrypoint.sh 36 | -------------------------------------------------------------------------------- /stacks-blockchain-api.Dockerfile: -------------------------------------------------------------------------------- 1 | ARG STACKS_API_VERSION=1.0.4 2 | 3 | FROM hirosystems/stacks-blockchain-api:${STACKS_API_VERSION} 4 | 5 | ARG STACKS_NETWORK=mainnet 6 | ARG LOG_DIR=/var/log/ 7 | ARG STACKS_SVC_DIR=/etc/service 8 | ARG STACKS_BLOCKCHAIN_API_PORT=3999 9 | ARG STACKS_CORE_EVENT_PORT=3700 10 | ARG V2_POX_MIN_AMOUNT_USTX=90000000260 11 | ARG STACKS_CORE_RPC_PORT=20443 12 | ARG STACKS_CORE_P2P_PORT=20444 13 | 14 | ENV STACKS_NETWORK=${STACKS_NETWORK} 15 | ENV STACKS_CORE_EVENT_PORT=${STACKS_CORE_EVENT_PORT} 16 | ENV STACKS_CORE_EVENT_HOST=127.0.0.1 17 | ENV STACKS_BLOCKCHAIN_API_PORT=${STACKS_BLOCKCHAIN_API_PORT} 18 | ENV STACKS_BLOCKCHAIN_API_HOST=0.0.0.0 19 | ENV STACKS_CORE_RPC_HOST=127.0.0.1 20 | ENV STACKS_CORE_RPC_PORT=${STACKS_CORE_RPC_PORT} 21 | ENV STACKS_CORE_P2P_PORT=${STACKS_CORE_P2P_PORT} 22 | ENV V2_POX_MIN_AMOUNT_USTX=${V2_POX_MIN_AMOUNT_USTX} 23 | 24 | RUN apk add \ 25 | nginx \ 26 | runit \ 27 | && mkdir -p \ 28 | /root/stacks-blockchain/data \ 29 | ${STACKS_SVC_DIR}/stacks-blockchain-api \ 30 | ${STACKS_SVC_DIR}/nginx \ 31 | ${STACKS_SVC_DIR}/nginx/log \ 32 | ${LOG_DIR}/nginx/log 33 | 34 | 35 | COPY configs/nginx-api.conf /etc/nginx/http.d/default.conf 36 | COPY configs/Stacks-*.toml /stacks-blockchain/ 37 | COPY unit-files/run/stacks-blockchain-api ${STACKS_SVC_DIR}/stacks-blockchain-api/run 38 | COPY unit-files/run/nginx ${STACKS_SVC_DIR}/nginx/run 39 | COPY unit-files/log/nginx ${STACKS_SVC_DIR}/nginx/log/run 40 | COPY scripts/entrypoint.sh /docker-entrypoint.sh 41 | COPY scripts/setup-bns.sh /setup-bns.sh 42 | 43 | RUN chmod 755 \ 44 | /docker-entrypoint.sh \ 45 | /setup-bns.sh \ 46 | ${STACKS_SVC_DIR}/stacks-blockchain-api/run \ 47 | ${STACKS_SVC_DIR}/nginx/run \ 48 | ${STACKS_SVC_DIR}/nginx/log/run 49 | 50 | CMD /docker-entrypoint.sh 51 | -------------------------------------------------------------------------------- /scripts/setup-bns.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | echo "" 3 | echo "*********************************" 4 | echo "Setting up BNS Data" 5 | echo "" 6 | echo " Checking for existing dir ${BNS_IMPORT_DIR}" 7 | if [ ! -d ${BNS_IMPORT_DIR} ];then 8 | mkdir -p ${BNS_IMPORT_DIR} 9 | fi 10 | echo " Checking for existing file ${BNS_IMPORT_DIR}/export-data.tar.gz" 11 | if [ ! -f ${BNS_IMPORT_DIR}/export-data.tar.gz ]; then 12 | echo " - Retrieving V1 BNS data as ${BNS_IMPORT_DIR}/export-data.tar.gz" 13 | wget https://storage.googleapis.com/blockstack-v1-migration-data/export-data.tar.gz -O ${BNS_IMPORT_DIR}/export-data.tar.gz 14 | if [ $? -ne 0 ]; then 15 | echo " - Failed to download https://storage.googleapis.com/blockstack-v1-migration-data/export-data.tar.gz -> ${BNS_IMPORT_DIR}/export-data.tar.gz" 16 | exit 1 17 | fi 18 | fi 19 | ## Try to extract BNS files individually (faster if we're only missing 1 or 2 of them) 20 | BNS_FILES=" 21 | chainstate.txt 22 | name_zonefiles.txt 23 | subdomain_zonefiles.txt 24 | subdomains.csv 25 | " 26 | for FILE in $BNS_FILES; do 27 | if [ ! -f ${BNS_IMPORT_DIR}/$FILE ]; then 28 | echo " Extracting Missing BNS text file: ${BNS_IMPORT_DIR}/$FILE" 29 | tar -xzf ${BNS_IMPORT_DIR}/export-data.tar.gz -C ${BNS_IMPORT_DIR}/ ${FILE} 30 | if [ $? -ne 0 ]; then 31 | echo " - Failed to extract ${FILE}" 32 | fi 33 | else 34 | echo " Using Existing BNS text file: ${BNS_IMPORT_DIR}/$FILE" 35 | fi 36 | if [ ! -f ${BNS_IMPORT_DIR}/${FILE}.sha256 ]; then 37 | echo " Extracting Missing BNS sha256 file: ${BNS_IMPORT_DIR}/${FILE}.sha256" 38 | tar -xzf ${BNS_IMPORT_DIR}/export-data.tar.gz -C ${BNS_IMPORT_DIR}/ ${FILE}.sha256 39 | if [ $? -ne 0 ]; then 40 | echo " - Failed to extract ${FILE}" 41 | fi 42 | else 43 | echo " Using Existing BNS sha256 file: ${BNS_IMPORT_DIR}/$FILE" 44 | fi 45 | done 46 | touch ${BNS_IMPORT_DIR}/imported 47 | echo "Exiting" 48 | exit 0 49 | 50 | -------------------------------------------------------------------------------- /scripts/nginx.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # vim:sw=4:ts=4:et 3 | 4 | set -e 5 | 6 | if [ -z "${NGINX_ENTRYPOINT_QUIET_LOGS:-}" ]; then 7 | exec 3>&1 8 | else 9 | exec 3>/dev/null 10 | fi 11 | 12 | if [ "$1" = "nginx" -o "$1" = "nginx-debug" ]; then 13 | if /usr/bin/find "/docker-entrypoint.d/" -mindepth 1 -maxdepth 1 -type f -print -quit 2>/dev/null | read v; then 14 | echo >&3 "$0: /docker-entrypoint.d/ is not empty, will attempt to perform configuration" 15 | 16 | echo >&3 "$0: Looking for shell scripts in /docker-entrypoint.d/" 17 | find "/docker-entrypoint.d/" -follow -type f -print | sort -V | while read -r f; do 18 | case "$f" in 19 | *.sh) 20 | if [ -x "$f" ]; then 21 | echo >&3 "$0: Launching $f"; 22 | "$f" 23 | else 24 | # warn on shell scripts without exec bit 25 | echo >&3 "$0: Ignoring $f, not executable"; 26 | fi 27 | ;; 28 | *) echo >&3 "$0: Ignoring $f";; 29 | esac 30 | done 31 | 32 | echo >&3 "$0: Configuration complete; ready for start up" 33 | else 34 | echo >&3 "$0: No files found in /docker-entrypoint.d/, skipping configuration" 35 | fi 36 | fi 37 | nginx & 38 | 39 | echo >&3 "$0: Waiting for the API to come up" 40 | COUNTER=0 41 | until [ $(curl --write-out "%{http_code}\n" "http://${STACKS_BLOCKCHAIN_API_HOST}/extended/v1/status" --output output.txt --silent) -eq "200" ]; do 42 | COUNTER=$((COUNTER+1)) 43 | echo "$0:$COUNTER) Waiting for 200 from: http://${STACKS_BLOCKCHAIN_API_HOST}/extended/v1/status" 44 | sleep 30 45 | done 46 | echo >&3 "$0" 47 | echo >&e "$0: API is reachable ($STACKS_BLOCKCHAIN_API_HOST:$STACKS_BLOCKCHAIN_API_PORT)" 48 | echo >&3 "$0: Running envsubst on /srv/nginx.conf > /etc/nginx/conf.d/default.conf" 49 | envsubst < /srv/nginx.conf > /etc/nginx/conf.d/default.conf 50 | cat /etc/nginx/conf.d/default.conf 51 | echo >&3 "$0 Sleep 5" 52 | echo >&3 "$0" 53 | sleep 5 54 | echo >&3 "$0: Reloading nginx" 55 | 56 | nginx -s reload & 57 | echo >&3 "$0: ###########################################" 58 | echo >&3 "$0: ###########################################" 59 | while [[ 2 -gt 1 ]]; do 60 | sleep 60 61 | done 62 | 63 | -------------------------------------------------------------------------------- /standalone.Dockerfile: -------------------------------------------------------------------------------- 1 | ARG STACKS_API_VERSION=7.0.0 2 | ARG STACKS_BLOCKCHAIN_VERSION=2.1.0.0.0 3 | 4 | 5 | FROM blockstack/stacks-blockchain:${STACKS_BLOCKCHAIN_VERSION} as stacks-blockchain-build 6 | 7 | 8 | FROM hirosystems/stacks-blockchain-api:${STACKS_API_VERSION} as stacks-blockchain-api-build 9 | 10 | 11 | FROM node:14-alpine 12 | ARG STACKS_NETWORK=mainnet 13 | ARG LOG_DIR=/var/log/ 14 | ARG STACKS_SVC_DIR=/etc/service 15 | ARG STACKS_BLOCKCHAIN_API_PORT=3999 16 | ARG STACKS_CORE_EVENT_PORT=3700 17 | ARG V2_POX_MIN_AMOUNT_USTX=90000000260 18 | ARG STACKS_CORE_RPC_PORT=20443 19 | ARG STACKS_CORE_P2P_PORT=20444 20 | 21 | ENV STACKS_NETWORK=${STACKS_NETWORK} 22 | ENV STACKS_CORE_EVENT_PORT=${STACKS_CORE_EVENT_PORT} 23 | ENV STACKS_CORE_EVENT_HOST=127.0.0.1 24 | ENV STACKS_BLOCKCHAIN_API_PORT=${STACKS_BLOCKCHAIN_API_PORT} 25 | ENV STACKS_BLOCKCHAIN_API_HOST=0.0.0.0 26 | ENV STACKS_CORE_RPC_HOST=127.0.0.1 27 | ENV STACKS_CORE_RPC_PORT=${STACKS_CORE_RPC_PORT} 28 | ENV STACKS_CORE_P2P_PORT=${STACKS_CORE_P2P_PORT} 29 | ENV V2_POX_MIN_AMOUNT_USTX=${V2_POX_MIN_AMOUNT_USTX} 30 | 31 | COPY --from=stacks-blockchain-build /bin/stacks-node /bin 32 | COPY --from=stacks-blockchain-build /bin/puppet-chain /bin 33 | COPY --from=stacks-blockchain-api-build /app /app 34 | RUN apk add \ 35 | nginx \ 36 | runit 37 | RUN mkdir -p \ 38 | /root/stacks-blockchain/data \ 39 | /tmp/event-replay \ 40 | ${STACKS_SVC_DIR}/stacks-blockchain \ 41 | ${STACKS_SVC_DIR}/stacks-blockchain-api \ 42 | ${STACKS_SVC_DIR}/stacks-blockchain-api/log \ 43 | ${STACKS_SVC_DIR}/nginx \ 44 | ${STACKS_SVC_DIR}/nginx/log \ 45 | ${LOG_DIR}/stacks-blockchain-api/log \ 46 | ${LOG_DIR}/nginx/log 47 | 48 | 49 | COPY configs/nginx.conf /etc/nginx/http.d/default.conf 50 | COPY configs/Stacks-*.toml /stacks-blockchain/ 51 | COPY unit-files/run/stacks-blockchain ${STACKS_SVC_DIR}/stacks-blockchain/run 52 | COPY unit-files/run/stacks-blockchain-api ${STACKS_SVC_DIR}/stacks-blockchain-api/run 53 | COPY unit-files/log/stacks-blockchain-api ${STACKS_SVC_DIR}/stacks-blockchain-api/log/run 54 | COPY unit-files/run/nginx ${STACKS_SVC_DIR}/nginx/run 55 | COPY unit-files/log/nginx ${STACKS_SVC_DIR}/nginx/log/run 56 | COPY scripts/entrypoint.sh /docker-entrypoint.sh 57 | 58 | RUN chmod 755 \ 59 | /docker-entrypoint.sh \ 60 | ${STACKS_SVC_DIR}/stacks-blockchain-api/run \ 61 | ${STACKS_SVC_DIR}/stacks-blockchain-api/log/run \ 62 | ${STACKS_SVC_DIR}/stacks-blockchain/run \ 63 | ${STACKS_SVC_DIR}/nginx/run \ 64 | ${STACKS_SVC_DIR}/nginx/log/run 65 | 66 | CMD /docker-entrypoint.sh 67 | -------------------------------------------------------------------------------- /render.yaml: -------------------------------------------------------------------------------- 1 | services: 2 | # stacks-blockchain-api instance 3 | - name: mainnet-stacks-blockchain-api 4 | type: pserv 5 | env: docker 6 | region: oregon 7 | plan: standard 8 | branch: master 9 | dockerfilePath: stacks-blockchain-api.Dockerfile 10 | dockerContext: . 11 | autoDeploy: false 12 | envVars: 13 | - key: PG_HOST 14 | fromDatabase: 15 | name: mainnet-postgres 16 | property: host 17 | - key: PG_PORT 18 | fromDatabase: 19 | name: mainnet-postgres 20 | property: port 21 | - key: PG_DATABASE 22 | fromDatabase: 23 | name: mainnet-postgres 24 | property: database 25 | - key: PG_USER 26 | fromDatabase: 27 | name: mainnet-postgres 28 | property: user 29 | - key: PG_PASSWORD 30 | fromDatabase: 31 | name: mainnet-postgres 32 | property: password 33 | - key: STACKS_CORE_EVENT_HOST 34 | value: 0.0.0.0 35 | - key: STACKS_BLOCKCHAIN_API_HOST 36 | value: 0.0.0.0 37 | - key: STACKS_BLOCKCHAIN_API_DB 38 | value: pg 39 | - key: STACKS_CORE_RPC_HOST 40 | fromService: 41 | name: mainnet-stacks-blockchain 42 | type: pserv 43 | property: host 44 | - key: STACKS_CORE_RPC_PORT 45 | value: 80 46 | - fromGroup: mainnet-settings 47 | disk: 48 | name: api-event-replay 49 | mountPath: /root/stacks-blockchain/data 50 | sizeGB: 25 51 | 52 | # stacks-blockchain instance 53 | - name: mainnet-stacks-blockchain 54 | type: pserv 55 | env: docker 56 | region: oregon 57 | plan: standard 58 | branch: master 59 | dockerfilePath: stacks-blockchain.Dockerfile 60 | dockerContext: . 61 | autoDeploy: false 62 | envVars: 63 | - key: STACKS_BLOCKCHAIN_API_HOST 64 | fromService: 65 | name: mainnet-stacks-blockchain-api 66 | type: pserv 67 | property: host 68 | - fromGroup: mainnet-settings 69 | disk: 70 | name: mainnet-stacks-blockchain 71 | mountPath: /root/stacks-blockchain/data 72 | sizeGB: 50 73 | 74 | # nginx proxy instance 75 | - name: mainnet-nginx 76 | type: web 77 | env: docker 78 | region: oregon 79 | plan: standard 80 | branch: master 81 | dockerfilePath: nginx.Dockerfile 82 | dockerContext: . 83 | healthCheckPath: /status 84 | autoDeploy: true 85 | envVars: 86 | - key: STACKS_BLOCKCHAIN_API_HOST 87 | fromService: 88 | name: mainnet-stacks-blockchain-api 89 | type: pserv 90 | property: host 91 | - fromGroup: mainnet-settings 92 | 93 | # Managed Postgres instance 94 | databases: 95 | - name: mainnet-postgres 96 | plan: Standard Plus 97 | 98 | envVarGroups: 99 | - name: mainnet-settings 100 | envVars: 101 | - key: NODE_ENV 102 | value: production 103 | - key: GIT_TAG 104 | value: master 105 | - key: STACKS_CHAIN_ID 106 | value: 0x00000001 107 | - key: V2_POX_MIN_AMOUNT_USTX 108 | value: 90000000260 109 | - key: STACKS_NETWORK 110 | value: mainnet 111 | - key: STACKS_EXPORT_EVENTS_FILE 112 | value: /root/stacks-blockchain/stacks-node-events.tsv 113 | - key: STACKS_CORE_EVENT_PORT 114 | value: 3700 115 | - key: STACKS_BLOCKCHAIN_API_PORT 116 | value: 3999 117 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Stacks Blockchain on Render 2 | 3 | This repo makes it possible to spin up an instance of the [stacks-blockchain](https://github.com/blockstack/stacks-blockchain) and [stacks-blockchain-api](https://github.com/hirosystems/stacks-blockchain-api) on the hosted [render.com](https://render.com) service. 4 | 5 | To get started, you should [register for a render account](https://dashboard.render.com/register) and get familiar with the [documentation for render](https://render.com/docs). 6 | 7 | Once you've registered, hit this big blue button, and select the network mode you want from the branches drop down (mainnet, testnet, mocknet) 8 | 9 | 10 | [![Deploy to Render](https://render.com/images/deploy-to-render-button.svg)](https://render.com/deploy?repo=https://github.com/wileyj/render-stacks&branch=master) 11 | 12 | ### Important considerations 13 | One thing to note is that with the free-tier plan, it's **possible** to run this with some modifications (mainly to the persistent disks and database), but it's **NOT recommended** 14 | 15 | 16 | ## Components 17 | 18 | This project is using render.com's infrastructure as code system, called blueprints. The blueprint is similar in nature to what you might see with a docker compose set up. Each service is a block of YAML. Read below to learn about each one. 19 | 20 | ### stacks-blockchain 21 | 22 | This is the stacks-blockchain container, built from the [officially released docker image](https://hub.docker.com/r/blockstack/stacks-blockchain/tags) 23 | 24 | Some additional components were added to make the startup work within render's platform (there is an nginx proxy in front of `stacks-blockchain`) 25 | 26 | Note that this instance is unreachable on the P2P port 20444 from external neighbors, but the HTTP endpoint will be available over port `80` once the port opens (on first sync, this can take a while). 27 | 28 | This container is built from [stacks-blockchain.Dockerfile](./stacks-blockchain.Dockerfile) and uses runit to start the 2 services (nginx, stacks-blockchain), with the [service script](./unit-files/run/stacks-blockchain) performing a `sed` replacement for the `event-observer` config directive before starting the service. 29 | 30 | The nginx service itself is a very [simple setup](./configs/nginx-stacks.conf) - `/status` returns a `200` for the render health check, and nginx proxies / to `localhost:20443` (it may take sometime before this port is open). 31 | 32 | --- 33 | 34 | ### stacks-blockchain-api 35 | This is the stacks-blockchain API container, built from the [officially released docker image](https://hub.docker.com/r/hirosystems/stacks-blockchain-api/tags) 36 | 37 | As with the `stacks-blockchain` container, some additional components were added to make the startup work within render's platform (there is an nginx proxy in front of stacks-blockchain-api) 38 | 39 | In render, this means that the API's event-observer is running internally on port `3700`, and the HTTP interface is on `3999`, with an nginx proxy over port `80` to the HTTP endpoint (when it's available - dependent on `/v2/info` ). 40 | 41 | The container that is built from [stacks-blockchain-api.Dockerfile](./stacks-blockchain-api.Dockerfile) uses runit to start the 2 services (nginx, stacks-blockchain-api). 42 | 43 | Nginx itself is a very [simple setup](./configs/nginx-api.conf) - `/status` returns a `200` for the render health check, and nginx proxies / to `localhost:3999`. 44 | 45 | --- 46 | 47 | ### postgres 48 | 49 | Using the [render.yaml](./render.yaml) file, this spins up a managed instance of postgres. Currently it's open to the world and the password is randomly generated. 50 | 51 | IP allowlist can be added to the `render.yaml` to restrict access further. 52 | 53 | --- 54 | 55 | ### nginx 56 | 57 | The only publicly accessible service, this container acts as a proxy for the API (both /`extended/v1` and `/v2` endpoints) 58 | 59 | During startup, it's not uncommon to see this service take a while before the root domain is available. 60 | 61 | During this time, though, `/status` will respond with `200 OK` to satisfy the health checks for render. 62 | 63 | The [default config](configs/nginx-default.conf) is generic and only exposes `/status` for the render healtcheck. The [entrypoint script](scripts/nginx.sh) is periodically checking the `/extended/v1/status` endpoint for a `200` response. \ 64 | Once the API is serving requests, an envsubst is run from the [entrypoint script](scripts/nginx.sh) on the [config](./configs/nginx.conf) and nginx is reloaded with the new config enabled. 65 | 66 | --- 67 | 68 | ## Deployment 69 | Fork this repo and update [render.yaml](./render.yaml) to your liking, or use the big blue **Deploy to Render** button above 70 | 71 | 72 | --------------------------------------------------------------------------------