0xhardman

0xhardman

twitter
medium
jike
github

Guide to Deploying a Custom Blockscout Blockchain Explorer

Introduction#

It is well known that Blockscout is an open-source blockchain explorer for the Ethereum ecosystem. If you are only developing Blockscout in a local development environment, it is quite simple; you can seamlessly start it by just modifying the RPC configuration file. However, due to the frequent updates of Blockscout, it can be a bit troublesome for developers to deploy a Blockscout for their operational chain, as the configuration changes can be somewhat complex and there are many pitfalls. Therefore, I provide a detailed deployment guide for reference.

Overall Approach#

Overall, the files we need to pay attention to are located in the docker-compose directory, and the basic operations are also completed there. Additionally, we need to focus on the service configuration files in the services directory, the environment variable files in the envs directory, and the Nginx configuration files in the proxy directory. The general steps are:

  1. Generate SSL certificates
  2. Configure the docker-compose startup file
  3. Modify the envs environment configuration
  4. Modify the proxy Nginx configuration

Server Configuration#

CPU: 4core / 8core

RAM: 8GB / 16GB / 32GB

DISK: 120gb or 500GB NVME SSD or Standard SSD

OS: Linux (Ubuntu preferred), MacOS

Prerequisites#

  • Docker (V20+) and Docker Compose (V2+) are installed
  • Domain name is configured (e.g., testnetexplorer.karpak.paratrix.xyz)
  • SSL certificate has been obtained (for HTTPS support)
  • Blockchain RPC node is set up (HTTP+WS); note that if you need to enable HTTPS on the RPC node, otherwise Blockscout cannot connect
  • Ports 80/443/8080/8081 are open

Deployment Steps#

1. Prepare SSL Certificates#

It is recommended to use Certbot to generate SSL certificates. Here are the detailed steps:

1.1 Install Certbot#

# Install Certbot
apt-get update
apt-get install -y certbot

1.2 Generate Certificates (when Docker occupies port 80)#

After Blockscout starts, it will occupy port 80, so use Certbot's standalone mode:

Method 1: Temporarily Stop Docker Services

# Stop the Docker container occupying port 80
docker-compose -f custom-rpc.yml down

# Generate certificates using Certbot
certbot certonly --standalone -d your-domain.com --email [email protected] --agree-tos --no-eff-email

# Restart Docker services after generation
docker-compose -f custom-rpc.yml up -d

1.3 Set Up Automatic Renewal#

# Create an automatic renewal script
cat > /root/renew-cert.sh << 'EOF'
#!/bin/bash
# Certificate automatic renewal script

# Set log file
LOG_FILE="/var/log/cert-renewal.log"

# Record start time
echo "$(date): Starting certificate renewal process" >> $LOG_FILE

# Check domain name
DOMAIN="your-domain.com"

# Check certificate expiration time
EXPIRY=$(openssl x509 -in /etc/letsencrypt/live/$DOMAIN/fullchain.pem -text -noout | grep "Not After" | cut -d: -f2-)
EXPIRY_DATE=$(date -d "$EXPIRY" +%s)
CURRENT_DATE=$(date +%s)
DAYS_LEFT=$(( ($EXPIRY_DATE - $CURRENT_DATE) / 86400 ))

echo "$(date): Certificate expires in $DAYS_LEFT days" >> $LOG_FILE

# If the certificate will expire within 30 days, attempt to renew
if [ $DAYS_LEFT -lt 30 ]; then
    echo "$(date): Certificate will expire within 30 days, attempting to renew" >> $LOG_FILE
    
    # Stop Docker services
    docker-compose -f custom-rpc.yml down >> $LOG_FILE 2>&1
    
    # Attempt to renew using Certbot
    certbot renew >> $LOG_FILE 2>&1
    
    # Restart Docker services
    docker-compose -f custom-rpc.yml up -d >> $LOG_FILE 2>&1
    
    echo "$(date): Certificate renewal process completed" >> $LOG_FILE
else
    echo "$(date): Certificate is valid, no renewal needed" >> $LOG_FILE
fi
EOF

# Add execute permissions
chmod +x /root/renew-cert.sh

# Add to crontab, execute every Sunday at midnight
echo "0 0 * * 0 /root/renew-cert.sh" | crontab -

1.4 Certificate Location#

The generated certificates are usually located at the following paths:

  • Certificate path: /etc/letsencrypt/live/your-domain.com/fullchain.pem
  • Private key path: /etc/letsencrypt/live/your-domain.com/privkey.pem

Configure these paths in your Nginx or other services.

2. Custom Network Configuration#

2.1 Docker-Compose Configuration File#

Refer to the docker-compose/anvil.yml file to create the docker-compose/custom-rpc.yml file. Do not configure NFT-related services yet; configure your blockchain network parameters:
Note: The environment variables in the docker-compose configuration file will actually override the environment variables under services (i.e., the environment variables in the envs directory), so you only need to configure the environment variables you need to modify.

version: '3.9'

services:
  # Basic service configuration
  redis-db:
    extends:
      file: ./services/redis.yml
      service: redis-db

  # Database initialization service
  db-init:
    extends:
      file: ./services/db.yml
      service: db-init

  db:
    depends_on:
      db-init:
        condition: service_completed_successfully
    extends:
      file: ./services/db.yml
      service: db

  # Backend service, if it crashes, nothing will be visible
  backend:
    depends_on:
      - db
      - redis-db
    extends:
      file: ./services/backend.yml
      service: backend
    links:
      - db:database
    environment:
        # Blockchain network specific configuration
        ETHEREUM_JSONRPC_VARIANT: 'geth'  # Adjust according to your node type
        ETHEREUM_JSONRPC_HTTP_URL: 'https://your-rpc-endpoint'
        ETHEREUM_JSONRPC_TRACE_URL: 'https://your-rpc-endpoint'
        ETHEREUM_JSONRPC_WS_URL: 'wss://your-ws-endpoint'
        ETHEREUM_JSONRPC_FALLBACK_HTTP_URL: 'https://your-rpc-endpoint'
        ETHEREUM_JSONRPC_FALLBACK_TRACE_URL: 'https://your-rpc-endpoint'
        CHAIN_ID: 'Your Chain ID'
        INDEXER_DISABLE_INTERNAL_TRANSACTIONS_FETCHER: 'true'  # Adjust as needed, recommended to enable first, open if necessary
        INDEXER_DISABLE_PENDING_TRANSACTIONS_FETCHER: 'true'  # Adjust as needed, recommended to enable first, open if necessary

  # Other service configurations
  visualizer:
    extends:
      file: ./services/visualizer.yml
      service: visualizer

  sig-provider:
    extends:
      file: ./services/sig-provider.yml
      service: sig-provider

  frontend:
    depends_on:
      - backend
    extends:
      file: ./services/frontend.yml
      service: frontend
    environment:
      NEXT_PUBLIC_NETWORK_ID: 'Your Chain ID'  # For example: '262144'
      NEXT_PUBLIC_NETWORK_RPC_URL: https://your-rpc-endpoint
      NEXT_PUBLIC_API_HOST: 'your-domain'  # For example: 'testnetexplorer.karpak.paratrix.xyz'
      NEXT_PUBLIC_API_PROTOCOL: https
      NEXT_PUBLIC_STATS_API_HOST: https://your-domain:8080
      NEXT_PUBLIC_NETWORK_NAME: Your Network Name
      NEXT_PUBLIC_NETWORK_SHORT_NAME: Your Network Short Name
      NEXT_PUBLIC_NETWORK_ID: Your Chain ID
      NEXT_PUBLIC_NETWORK_CURRENCY_NAME: Your Currency Name
      NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL: Your Currency Symbol
      NEXT_PUBLIC_APP_HOST: your-domain
      NEXT_PUBLIC_APP_PROTOCOL: https
      NEXT_PUBLIC_VISUALIZE_API_HOST: https://your-domain:8081
      NEXT_PUBLIC_IS_TESTNET: true  # Set according to your network type
      NEXT_PUBLIC_API_WEBSOCKET_PROTOCOL: wss
      NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID: Your WalletConnect Project ID # Must be specified for contract verification https://cloud.reown.com/
      NEXT_PUBLIC_NETWORK_LOGO: Your Network Logo URL *Recommended to use an OSS storage*
      NEXT_PUBLIC_NETWORK_ICON: Your Network Icon URL *Recommended to use an OSS storage*

  
  stats-db-init:
    extends:
      file: ./services/stats.yml
      service: stats-db-init

  stats-db:
    depends_on:
      stats-db-init:
        condition: service_completed_successfully
    extends:
      file: ./services/stats.yml
      service: stats-db

  # Statistics service configuration, if this service fails, charts will not be visible
  stats:
    depends_on:
      - stats-db
      - backend
    extends:
      file: ./services/stats.yml
      service: stats
    environment:
      STATS__BLOCKSCOUT_API_URL: https://your-domain # This is easy to overlook

  user-ops-indexer:
    depends_on:
      - db
      - backend
    extends:
      file: ./services/user-ops-indexer.yml
      service: user-ops-indexer

  # Proxy service configuration
  proxy:
    depends_on:
      - backend
      - frontend
      - stats
    extends:
      file: ./services/nginx.yml
      service: proxy
# Start services
docker-compose -f custom-rpc.yml up -d

# View logs
docker-compose -f custom-rpc.yml logs -f

# Stop services
docker-compose -f custom-rpc.yml down

Note that if you modify the configuration file, you need to restart the services and rebuild the related images:

docker-compose -f custom-rpc.yml down
docker-compose -f custom-rpc.yml up -d

2.3 Explanation#

By now, you should be able to access the corresponding frontend page by visiting the server IP. You can open the browser's developer tools to check network requests and verify whether the RPC/API is functioning properly. Some services may encounter cross-origin issues due to SSL, which we can resolve using Nginx.

3. Configure Nginx Proxy#

3.1 Update Nginx Configuration Template#

Edit the docker-compose/proxy/default.conf.template file to add HTTPS support:

map $http_upgrade $connection_upgrade {
  default upgrade;
  ''      close;
}

# HTTP Server - Redirect to HTTPS
server {
    listen       80;
    server_name  your-domain;
    
    # Redirect all HTTP requests to HTTPS
    location / {
        return 301 https://$host$request_uri;
    }
}

# HTTPS Server
server {
    listen       443 ssl;
    server_name  your-domain;
    
    # SSL Certificate Configuration
    ssl_certificate     /etc/nginx/ssl/fullchain.pem;
    ssl_certificate_key /etc/nginx/ssl/privkey.pem;
    ssl_protocols       TLSv1.2 TLSv1.3;
    ssl_ciphers         HIGH:!aNULL:!MD5;
    
    proxy_http_version 1.1;

    location ~ ^/(api(?!-docs$)|socket|sitemap.xml|auth/auth0|auth/auth0/callback|auth/logout) {
        proxy_pass            ${BACK_PROXY_PASS};
        proxy_http_version    1.1;
        proxy_set_header      Host $host;
        proxy_set_header      X-Real-IP $remote_addr;
        proxy_set_header      X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header      X-Forwarded-Proto $scheme;
        proxy_set_header      Upgrade $http_upgrade;
        proxy_set_header      Connection $connection_upgrade;
        proxy_cache_bypass    $http_upgrade;
    }
    
    location / {
        proxy_pass            ${FRONT_PROXY_PASS};
        proxy_http_version    1.1;
        proxy_set_header      Host $host;
        proxy_set_header      X-Real-IP $remote_addr;
        proxy_set_header      X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header      X-Forwarded-Proto $scheme;
        proxy_set_header      Upgrade $http_upgrade;
        proxy_set_header      Connection $connection_upgrade;
        proxy_cache_bypass    $http_upgrade;
    }
}

# Statistics Service HTTPS Configuration (port 8080)
server {
    listen       8080 ssl;
    server_name  your-domain;
    
    # SSL Certificate Configuration
    ssl_certificate     /etc/nginx/ssl/fullchain.pem;
    ssl_certificate_key /etc/nginx/ssl/privkey.pem;
    ssl_protocols       TLSv1.2 TLSv1.3;
    ssl_ciphers         HIGH:!aNULL:!MD5;
    
    proxy_http_version 1.1;
    proxy_hide_header Access-Control-Allow-Origin;
    proxy_hide_header Access-Control-Allow-Methods;
    add_header 'Access-Control-Allow-Origin' 'https://your-domain' always;
    add_header 'Access-Control-Allow-Credentials' 'true' always;
    add_header 'Access-Control-Allow-Methods' 'PUT, GET, POST, OPTIONS, DELETE, PATCH' always;

    # Other configurations...
}

# Visualization Service HTTPS Configuration (port 8081)
server {
    listen       8081 ssl;
    server_name  your-domain;
    
    # SSL Certificate Configuration
    ssl_certificate     /etc/nginx/ssl/fullchain.pem;
    ssl_certificate_key /etc/nginx/ssl/privkey.pem;
    ssl_protocols       TLSv1.2 TLSv1.3;
    ssl_ciphers         HIGH:!aNULL:!MD5;
    
    # Other configurations...
}

3.2 Update Nginx Service Configuration#

Edit the docker-compose/services/nginx.yml file to add SSL certificate mounts and HTTPS ports:

services:
  proxy:
    image: nginx:1.25.1-alpine
    restart: always
    extra_hosts:
      - 'host.docker.internal:host-gateway'
    volumes:
      - "../proxy:/etc/nginx/templates"
      - "/root/certs/live/your-domain/fullchain.pem:/etc/nginx/ssl/fullchain.pem:ro"
      - "/root/certs/live/your-domain/privkey.pem:/etc/nginx/ssl/privkey.pem:ro"
    environment:
      BACK_PROXY_PASS: ${BACK_PROXY_PASS:-http://backend:4000}
      FRONT_PROXY_PASS: ${FRONT_PROXY_PASS:-http://frontend:3000}
    ports:
      - target: 80
        published: 80
      - target: 443
        published: 443
      - target: 8080
        published: 8080
      - target: 8081
        published: 8081

4. Start Services#

Use the following command to start your custom Blockscout blockchain explorer:

cd blockscout/docker-compose
docker-compose -f docker-compose/custom-rpc.yml up -d

5. Verify Deployment#

Visit https://your-domain to verify that your Blockscout blockchain explorer has been successfully deployed.

Common Troubleshooting#

  1. Unable to connect to blockchain node

    • Check if the RPC endpoint is correctly configured
    • Confirm that the network connection is smooth
    • Verify that firewall settings allow the relevant ports
  2. HTTPS certificate issues

    • Ensure the certificate paths are correct
    • Check if the certificate is valid
    • Verify that the Nginx configuration correctly references the certificate files
  3. Database initialization failure

    • Check the database configuration
    • View logs for detailed error information

Summary#

By following the above steps, you can successfully deploy a custom Blockscout blockchain explorer that supports HTTPS and WSS connections and can be accessed via a custom domain name. The main modifications include:

  1. Adding HTTPS/SSL support
  2. Customizing blockchain network parameters
  3. Configuring a custom domain name
  4. Setting the RPC endpoint
  5. Customizing network branding (name, icon, etc.)

Please adjust the above configurations according to your specific needs.

Reference Documents#

[1] Docker Compose Deployment Documentation https://docs.blockscout.com/setup/deployment/docker-compose-deployment
[2] Environment Variable Description https://docs.blockscout.com/setup/env-variables
[3] Frontend Environment Variables https://github.com/blockscout/frontend/blob/main/docs/ENVS.md

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.