Protecting a non-forging node

Setting up a blockchain application behind a reverse proxy

There are times whereby it maybe desirable to run a blockchain application behind a reverse proxy for SSL termination, rate limiting, and other reasons.

We highly recommended running a reverse proxy for a public web service.

HAProxy is one such reverse proxy.

An HAProxy configuration has 4 sections, and is explained here . The relevant sections to be aware of here are the frontend and backend. Firstly, it is recommended to start with a very basic config snippet and then build up from there.

For this example to work, it is assumed that the application uses the default configuration for the WebSocket port, which is 8080.

If a different port has been configured, then replace it with 8080 as shown in the example below:

frontend f_lisk
        mode http
        bind :80 (1)
        use_backend b_lisk_ws (2)
backend b_lisk_ws
        server lisk_ws 127.0.0.1:8080 (3)
1 A new bind line is added, and creates a listener on port 80.
2 use_backend defines the backend which responds to incoming requests.
3 server sets the backend server and expects a name as first argument, and the IP and port as second argument.

This does nothing more than process proxy requests coming in at port 80 to your blockchain application WebSocket port.

SSL Termination

it is possible to add SSL termination by telling it to listen on port 443, and specifying the certificate in the frontend section:

frontend f_lisk
        mode http
        bind [::]:443 ssl crt /etc/haproxy/ssl/cert.pem alpn h2,http/1.1 (1)
        bind [::]:80 (2)
        http-response set-header Strict-Transport-Security max-age=15768000 (3)
        redirect scheme https code 301 (4)
        use_backend b_lisk_ws
1 A new bind line is added, which performs the following:
2 The bind lines were changed so that HAProxy will also listen on ipv6.
3 The Strict-Transport-Security response header is set to tell web browsers to only access this site over HTTPS.
4 A permanent redirect is created for anyone connecting over http to connect via https.

Rate Limiting

HAProxy is very configurable when it comes to rate limiting. We’ll provide a specific example here.

frontend f_lisk
        mode http
        bind [::]:443 ssl crt /etc/haproxy/ssl/cert.pem alpn h2,http/1.1
        bind [::]:80
        http-response set-header Strict-Transport-Security max-age=15768000
        redirect scheme https code 301
        rate-limit sessions 500 (1)
        stick-table type ipv6 size 200k expire 10m store gpc0 (2)
        acl repeat_abuses src_get_gpc0(f_lisk) gt 2 (3)
        tcp-request content track-sc0 src (4)
        tcp-request content reject if repeat_abuses (5)
        use_backend b_lisk_ws
backend b_lisk_ws
        stick-table type ipv6 size 200k expire 2m store conn_rate(10s) (6)
        tcp-request content track-sc1 src (7)
        acl exceeds_conn_rate sc1_conn_rate gt 50 (8)
        acl mark_repeat_abuses sc0_inc_gpc0 gt 0 (9)
        http-request deny deny_status 429 if exceeds_conn_rate mark_repeat_abuses (10)
        server lisk_ws 127.0.0.1:8080

This is somewhat of a 3-pronged approach to rate limiting. rate-limit sessions 500 limits the number of new sessions per second. New sessions are queued and accepted in line with the set value, which can be adjusted as necessary.

The rest of the changes here tell HAProxy to track the connection rate (over a rolling 10 seconds), of up 200k connecting IP addresses, the entries of which will expire after 2 minutes. If the connection rate of an IP exceeds 50 connections per 10 seconds, a 429 response gets returned and a global counter for that IP gets incremented, to track repeat abuses. If an IP exceeds this threshold more than twice in a 10 minute period, new connections from that IP will be silently dropped.

Multiple Backends

So far, the examples have been just for proxying the Lisk WebSocket RPC (Remote-Procedure-Call), endpoint. The example below will proxy both the WebSocket RPC endpoint and the HTTP API endpoint by hostname (http.lisk.example is a placeholder for whatever your domain is).

For this example to work, it is assumed that the application has the HTTP API enabled with the HTTP port set to 4000 (which is the default value).

If a different port has been configured, then replace it with 4000 as shown in the below example.

It is possible to have multiple backends that get served using all kinds of different criteria. Commonly, this is done by the Host header to serve more than one site. This can be performed as shown below:

frontend f_lisk
        mode http
        bind [::]:443 ssl crt /etc/haproxy/ssl/cert.pem alpn h2,http/1.1
        bind [::]:80
        http-response set-header Strict-Transport-Security max-age=15768000
        redirect scheme https code 301
        rate-limit sessions 500
        stick-table type ipv6 size 200k expire 10m store gpc0
        acl repeat_abuses src_get_gpc0(f_lisk) gt 2
        tcp-request content track-sc0 src
        tcp-request content reject if repeat_abuses
        acl host_http hdr(host) http.lisk.example
        use_backend b_lisk_http if host_http
    default_backend b_lisk_ws
backend b_lisk_ws
        stick-table type ipv6 size 200k expire 2m store conn_rate(10s)
        tcp-request content track-sc1 src
        acl exceeds_conn_rate sc1_conn_rate gt 50
        acl mark_repeat_abuses sc0_inc_gpc0 gt 0
        http-request deny deny_status 429 if exceeds_conn_rate mark_repeat_abuses
        server lisk_ws 127.0.0.1:8080
backend b_lisk_http
        stick-table type ipv6 size 200k expire 2m store conn_rate(10s)
        tcp-request content track-sc2 src
        acl exceeds_conn_rate sc2_conn_rate gt 50
        acl mark_repeat_abuses sc0_inc_gpc0 gt 0
        http-request deny deny_status 429 if exceeds_conn_rate mark_repeat_abuses
        server lisk_http 127.0.0.1:4000
If multiple domains are used with SSL termination, your certificate will either have to be for those multiple domains or you will need to have multiple certificates, which can be specified with crt-list instead of crt (https://www.haproxy.com/documentation/aloh