Configurez votre reverse proxy, sinon votre RPC devient injoignable

Substrate inclut des mesures anti-spam par IP. Si vous avez un reverse proxy devant votre nœud Duniter v2, alors le nœud Duniter v2 verra tout le trafic extérieur comme provenant de la même IP et bannira tout le monde.

Vous devez configurer votre reverse proxy pour qu’il écrase les en-têtes X-Real-IP et/ou X-Forwarded-For.

Il faut également lancer votre nœud Duniter avec l’option --rpc-rate-limit-trust-proxy-headers pour qu’il prenne en compte ces en-têtes. Par défaut, il ne les utilise pas, car ils peuvent être fournis arbitrairement par un spammeur.

Exemple de configuration nginx pour fournir ces en-têtes. Il faut bien fournir les deux, sinon l’un des deux peut être falsifié par un spammeur.

location / {
    proxy_pass http://127.0.0.1:9944;
    proxy_http_version 1.1;

    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $remote_addr;

    # On supprime Forwarded pour éviter de relayer une valeur client.
    proxy_set_header Forwarded "";

    # Si RPC WebSocket
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
}
5 Likes

L’image docker ne permet pas de passer l’option --rpc-rate-limit-trust-proxy-headers actuellement il faudrait merger cette MR et rebuild des images.

EDIT: en fait si, on peut passer les options dans la command: du docker-compose :slight_smile:

services:
  duniter-mirror:
    command: --rpc-rate-limit-trust-proxy-headers
7 Likes

Est-ce qu’il y a un moyen de vérifier que cela est bien configuré lorsque l’on fait le changement ?

Il faut activer les logs target rpc au niveau debug avec l’option CLI -l rpc=debug ou la variable d’environnement RUST_LOG=rpc=debug, puis grep les logs pour rechercher proxy_ip=. Si proxy_ip=None (ou toujours l’IP du reverse proxy), alors ce n’est pas bon.

1 Like

J’ai ajouté la variable d’environnement pour le debug:

    environment:
      #...
      - RUST_LOG=rpc=debug

J’ai redémarré avec l’argument supplémentaire (ajout de “command” dans le compose.yaml comme mentionné par @aya) - bien mentionné au démarrage:

duniter-g1-archive  | Starting duniter with parameters: --rpc-rate-limit-trust-proxy-headers --name Nicolas80-G1-arch...

Et j’ai normalement bien ajouté la config dans NGinx

Par contre, dans les logs de mon noeud archive (après redémarrage), j’ai bien plein de lignes de debug; mais rien contenant “proxy_ip”…

...
duniter-g1-archive  | 2026-03-09 20:26:47.605 DEBUG tokio-runtime-worker rpc_metrics: [ws] chain_getBlockHash call took 204 μs
duniter-g1-archive  | 2026-03-09 20:26:47.649 DEBUG tokio-runtime-worker rpc_metrics: [ws] chain_getHeader call took 101 μs
...

A t’on moyen de savoir lesquelles ? Histoire de savoir si un client App peut tomber dans ce cas. Par exemple Cesium v1 tombait parfois dans de limite rate sur l’api BMA de Duniter v1, le détectait via l’erreur, puis retentait plus tard ou changait de nœuds.

Voici les cas que peux rencontrer une application et la manière de gérer que je recommande, je vais ajouter ça à la doc de duniter dans docs/api:

Symptôme Exemple Action app
Timeout réseau délai dépassé Changer de nœud
Connexion refusée ou coupée ECONNREFUSED, ECONNRESET, EOF, WS closed Changer de nœud
Erreur HTTP d’infrastructure 429, 502, 503, 504 Changer de nœud
Rate limit RPC explicite JSON-RPC -32999, RPC rate limit exceeded Changer de nœud
Nœud non sain Node is not fully functional Changer de nœud
Limite atteinte sur chainHead -32800, ReachedLimits, limitReached Retry court, puis changer de nœud si ça se répète
Paramètres invalides -32602 Invalid params Ne pas changer de nœud, corriger la requête
Hash / bloc invalide InvalidBlock Ne pas changer de nœud, corriger la requête
Mauvais usage de chainHead InvalidRuntimeCall, InvalidContinue, InvalidDuplicateHashes Ne pas changer de nœud, corriger le flux client
Méthode RPC non exposée MethodNotFound, RPC call is unsafe to be called externally Ne pas changer de nœud, adapter la méthode ou la config
Transaction rejetée TooLowPriority, AlreadyImported, TemporarilyBanned, ImmediatelyDropped, RejectedFutureTransaction Ne pas changer de nœud, traiter le cas transactionnel
2 Likes

@elois est-ce que tu as une idée alternative pour pouvoir faire la vérification que c’est bien configuré ?

Ce que tu proposais ne semble pas fournir les données “proxy_ip” :thinking:

J’ai regardé de plus près : il semble que le log en question ne s’affiche que dans des conditions qui n’ont pas de sens; probablement un bug de Substrate. Pour voir le log s’afficher, il faut whitelister au moins une IP. Oui, c’est débile, je suis d’accord :

–rpc-rate-limit-whitelisted-ips 192.168.1.10/32

En plus substrate exige la notation CIDR avec un masque hôte pour les IP, utiliser /32 pour une IP v4 unique.

Le code est là: polkadot-sdk/substrate/client/rpc-servers/src/lib.rs at stable2512 · paritytech/polkadot-sdk · GitHub

On pourrais fixer ça dans notre fork si besoin

1 Like

Ca fonctionne, j’ai ces logs-ci de “proxy_ip”:

duniter-g1-mirror-bn  | 2026-03-10 18:58:45.678 DEBUG tokio-runtime-worker rpc: ip=172.21.0.7, proxy_ip=Some(138.84.41.0) is not trusted, rate-limit enabled
duniter-g1-mirror-bn  | 2026-03-10 18:58:49.641 DEBUG tokio-runtime-worker rpc: ip=172.21.0.7, proxy_ip=Some(176.145.224.62) is not trusted, rate-limit enabled
duniter-g1-mirror-bn  | 2026-03-10 18:58:52.560 DEBUG tokio-runtime-worker rpc: ip=172.21.0.7, proxy_ip=Some(139.28.91.91) is not trusted, rate-limit enabled
duniter-g1-mirror-bn  | 2026-03-10 18:58:52.896 DEBUG tokio-runtime-worker rpc: ip=172.21.0.7, proxy_ip=Some(77.205.19.127) is not trusted, rate-limit enabled
duniter-g1-mirror-bn  | 2026-03-10 18:58:53.598 DEBUG tokio-runtime-worker rpc: ip=172.21.0.7, proxy_ip=Some(147.53.149.142) is not trusted, rate-limit enabled

Je suppose que c’est correct du coup vu que je vois bien des ip différentes ?

1 Like

Oui félicitations ça fonctionne

2 Likes

@elois Question supplémentaire, comme j’ai mis mes p2p derrière un reverse proxy également; est-ce qu’il y a un risque d’avoir le même genre de soucis ?

Exemple d’url p2p pour ce noeud là

ipfs swarm connect /dns/mirror.g1-bn.brussels.ovh/tcp/443/wss/p2p/12D3KooWBYwuuBHh3co7kr4mZTbccVWNCpdA8A1e7PKNxeHvGq9D
connect 12D3KooWBYwuuBHh3co7kr4mZTbccVWNCpdA8A1e7PKNxeHvGq9D success

Non le réseau p2p ne ban pas par IP, à la place il y a un système de réputation par PeerId

1 Like