8

I just created my first substrate node following the official tutorial, I'm wondering how do I make it public, so other people can also communicate with my node

Do I host it on Digital Ocean/AWS ?

Thanks,

1 Answer 1

11

you can host it with a cloud provider but you certainly don't have to. making a node public is partly about making it reachable over the internet. this is a big subject because there's a lot to think about in terms of

  • availability is your node reachable behind your routers, switches and firewalls?
  • security is the access limited to things you are comfortable with and prepared for?
  • authenticity can your node be impersonated by an imposter or mitm?

substrate nodes expose a number of services over tcp. you can make none, some or all of these ports visible to the world:

  • p2p: usually on port 30333. otherwise customised with cli arg: --port 30333. this port is used by the network to create consensus and share blockchain state. if you want other nodes to be able to learn about your node's blockchain state (a good thing), open this port first.
  • ws: usually on port 9944. otherwise customised with cli arg: --ws-port 9944. listen on the public socket with --ws-external. this port responds to websocket queries that keep subscribers informed of the changing state of your node's ledger over time. it can also be used by polkadot.js to provide rich interactions with your node
  • rpc: usually on port 9933. otherwise customised with cli arg: --rpc-port 9933. listen on the public socket with --rpc-external. this port responds to rpc queries enabling a limited set of interactions with your node. some rpc calls are not safe to expose to the world and substrate has some cli flags (like --rpc-methods safe) that help you to prevent exposure of unsafe rpc calls (like author_insertKey, amongst others)
  • metrics: usually on port 9615. otherwise customised with cli arg: --prometheus-port 9615. listen on the public socket with --prometheus-external. this port exposes metrics that help you to monitor the health of your node. it can give you information about things like slow or stopped block production and is usually monitored by a metrics monitoring suite like prometheus, alertmanager and grafana.

if you're running a parachain node, all of the above ports are duplicated (with default port numbers incremented by 1) because parachain binaries run both an embedded relay chain node and their own parachain node.

the references to cli args for listening on public sockets above, modifies the node to listen on all interfaces (eg: 0.0.0.0:9944) rather than just the loopback interface (eg: 127.0.0.1:9944).

to expose these ports to the world, you need to have:

  • an isp that does not block the port numbers you use and allows multiple, simultaneous inbound tcp connections (some german isps are known to throttle down when a substrate node instigates or receives more than a threshold number of connections)
  • a router capable of forwarding requests to those port numbers from the router that receives the request to the node system running your node
  • either a fixed ip address or dynamic dns that is synchronised to your dynamic ip address

it is good practice to put any service you expose to the world behind tls. a simple way to do this is to:

  • register a domain name (or use one provided by your dyn dns provider)
  • use let's encrypt's certbot to request a tls certificate for your domain, to request a certificate,
    • edit (or create) a default nginx configuration that listens on port 80 for letsencrypt challenges only and redirects all other requests to port 443 (the location for this file is conventionally /etc/nginx/sites-available/default). replace mynode.example.com with your node's fully qualified domain name (fqdn):
      server {
        server_name mynode.example.com;
        listen 80;
        listen [::]:80;
      
        # certbot challenges
        location ^~ /.well-known/acme-challenge/ {
          default_type "text/plain";
          root /var/www/html;
        }
      
        # tls redirect
        if ($host = mynode.example.com) {
          return 301 https://$host$request_uri;
        }
        return 404;
      }
      
    • use certbot to request a cert. replace mynode.example.com with your node's fqdn and [email protected] with your email address:
      sudo certbot certonly \
        --noninteractive \
        --cert-name mynode.example.com \
        --key-type ecdsa \
        -m [email protected] \
        --agree-tos \
        --no-eff-email \
        --preferred-challenges http \
        --webroot \
        --webroot-path /var/www/html \
        -d mynode.example.com
      
  • run an nginx reverse proxy listening on port 443 (ssl/tls) and forwarding requests to your node ports. here's an example nginx configuration that does this. you might place this file at /etc/nginx/sites-available/mynode.example.com.conf, then create a symlink at /etc/nginx/sites-enabled/mynode.example.com.conf which points to it. replace mynode.example.com with your node's fqdn:
    server {
      server_name mynode.example.com;
      listen 443 ssl;
    
      # websocket
      location / {
        proxy_pass http://127.0.0.1:9944;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      }
    
      # json rpc
      location /rpc {
        proxy_pass http://127.0.0.1:9933;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      }
    
      # health
      location /health {
        proxy_pass http://127.0.0.1:9933/health;
        access_log off;
        proxy_http_version 1.1;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        if ($request_method = 'GET') {
          add_header 'Access-Control-Allow-Origin' '*' always;
          add_header 'Access-Control-Allow-Methods' 'GET' always;
          add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range' always;
          add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range' always;
        }
      }
    
      # metrics
      location /metrics {
        proxy_pass http://127.0.0.1:9615/metrics;
        proxy_http_version 1.1;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
      }
    
      ssl_certificate /etc/letsencrypt/live/mynode.example.com/fullchain.pem;
      ssl_certificate_key /etc/letsencrypt/live/mynode.example.com/privkey.pem;
    }
    

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.