Skip to content

Node Plugins

The Node Plugins module configures three built-in Remnawave Node plugins for every node of the panel at once:

Torrent Blocker

Detects user torrent traffic and bans the IP at the nftables level: one caught packet is enough.

Bantemporary, configurable durationReportsstats and TelegramExceptionsIP whitelist

Ingress Filter

Cuts inbound connections by whole subnets: scanners knock on the node port and get no answer.

PresetsRU, classic, FOFA scannersOwn listsIPv4 and /8…/32 subnetsTrafficinbound, whole node server

Egress Filter

Blocks outbound traffic by destination address and port: a hijacked account reaches neither private networks nor spam sending.

Presetsprivate ranges, mail portsOwn listsIPv4/IPv6 and ports 1-65535Trafficoutbound, whole node server

All three features live in a single Reverse Node Plugins plugin record, are configured through the panel API from the server the panel runs on, and apply on the nodes without restarts.

panel serverremnawave_reverse · APIconfig save · syncplugin · Reverse Node Pluginsone record · activePluginUuidTorrent BlockertorrentBlockerIngress FilteringressFilterEgress FilteregressFilterplugin activationnode · de-fra-01nftablesnode · nl-ams-02nftablesTorrent Blocker reportsstatsone record for all three features · every change applies on all nodes at once

Every Remnawave node has exactly one active plugin (activePluginUuid), so the three features cannot be three separate records: only one of them would ever be active. The script keeps one shared record with three config sections: torrentBlocker, ingressFilter and egressFilter.

Every settings change follows the same path:

config PATCH→sync→bind to every node

Offline nodes get the binding in the panel database and pick the config up on reconnect.

The top of the module menu always shows one line of truth: Nodes running the plugin: 2 of 2. A plugin no node points at is dead weight no matter what the per-feature statuses say.

Torrent Blocker requires Node v2.7.0 or newer with Xray 26.3.27+.

Run on the panel server:

root@server: ~
remnawave_reverse
  1. In the main menu select 4:

    root@server: ~
    REMNAWAVE REVERSE-PROXY by eGames
    Version: 3.7.2
    Wiki: https://wiki.egam.es/
    
    1.Install Remnawave Components
    2.Reinstall Panel and Components
    3.Manage Panel and Components
    
    4.Node extensions (templates, plugins, core)
    
    5.Xray Checker — subscription monitoring
    6.Custom extensions by legiz
    7.WARP Native
    8.Backup and Restore
    
    9.Manage IPv6
    10.Manage certificates domain
    
    11.NetBird: overlay network for nodes and panel
    12.Check for updates script
    13.Remove script
    
    0.Exit
    - Quick start: remnawave_reverse
    
    Select action (0-13):
  2. In the extensions menu select Node Plugins:

    root@server: ~
    Node Extensions
    
    1.Install template for selfsteal node
    2.Node Plugins
    3.Xray core
    4.SSH access to a remote machine
    5.Server routing
    
    0.Exit
    
    Select action (0-5):
  3. The module menu opens with the statuses of all three features and the binding count:

    root@server: ~
    Node Plugins
     Details in the wiki: https://wiki.egam.es/configuration/node-plugins
    
    Nodes running the plugin: 2 of 2
    1.Torrent Blocker: ENABLED
    2.Ingress Filter: disabled
    3.Egress Filter: not configured
    
    0.Exit
    
    Select plugin (0-3):

Each feature’s status comes in four flavors:

ENABLED: the feature works on the nodes
disabled: the section exists in the config but is off
not configured: the section is not in the plugin config yet
unknown: the panel API did not answer

When no node points at the plugin, the counter is replaced by the warning The plugin is not bound to any node — the features are inactive on nodes. Any settings change binds it.

On entry the module checks for old plugin records left by earlier script versions (they were named Torrent Blocker, Ingress Filter, Egress Filter separately). Such records are offered to be merged into one: settings are combined, the extra records deleted, the plugin bound to every node. Declining changes nothing; the question repeats on the next entry.

The plugin detects torrent traffic on the Xray side and bans the offending IP on the node itself through nftables. The ban expires on its own after the configured time; the panel sends block notifications to Telegram when a bot is configured there.

The feature menu:

root@server: ~
Torrent Blocker

 Torrent Blocker: ENABLED

1.Disable Torrent Blocker
2.Settings (ban duration, whitelist IPs)
3.Stats and recent reports
4.Unblock IP
5.Recreate nftables tables
6.Configure Telegram notifications (panel)

7.Delete the shared plugin (all three features)

0.Exit

Select action (0-7):
  1. Select Enable Torrent Blocker (or Disable when it is enabled):

    root@server: ~
    Torrent Blocker
    
     Torrent Blocker: disabled
    
    1.Enable Torrent Blocker
    2.Settings (ban duration, whitelist IPs)
    3.Stats and recent reports
    4.Unblock IP
    5.Recreate nftables tables
    6.Configure Telegram notifications (panel)
    
    7.Delete the shared plugin (all three features)
    
    0.Exit
    
    Select action (0-7): 1
    
    [ * ] Enabling Torrent Blocker...
    [ ✓ ] Torrent Blocker enabled, the plugin is bound to every enabled node. Block notifications arrive in Telegram only if notifications are configured in the panel (Telegram bot).
    Requires Node v2.7.0+ with Xray 26.3.27+. Xray sees only part of torrent traffic — one detected packet is enough to ban the IP.

Disabling works the same way, but node blocks are not lifted by it: active bans live out their duration.

The Settings entry shows current values: Enter keeps them as is, - on the whitelist clears it.

  1. Select 2 and enter the new values:

    root@server: ~
    [ * ] Torrent Blocker settings
    Ban duration in seconds [current: 3600]: 7200
    Whitelist IPs, comma-separated [current: none] (Enter — keep, '-' — clear): 203.0.113.7, 198.51.100.4
    [ ✓ ] Settings saved and synced to nodes.

The whitelist helps when an honest user has a static address and complains about blocks: add the IP and Torrent Blocker stops reacting to it.

The Stats and recent reports entry shows counters, top offenders and fresh blocks across all nodes:

root@server: ~
[ * ] Torrent Blocker stats
 Total: 1284   24h: 17   Users: 96   Nodes: 2

 Top users:
   megauser - 204
   ivanpro - 118

 Top nodes:
   de-fra-01 - 731
   nl-ams-02 - 553

 Recent reports (up to 15):
       Date              User             IP                                        Node
    2026-10-03T11:52  megauser         45.151.100.214                            de-fra-01
    2026-10-03T09:14  ivanpro          178.62.95.10                              nl-ams-02
    2026-10-02T23:41  megauser         185.220.101.5                             de-fra-01

When a ban lands on an address you did not want to touch (for example a user behind CGNAT, where the whole provider subnet went under the ban), the IP can be unblocked on all nodes at once:

  1. Select Unblock IP and enter the address:

    root@server: ~
    IP to unblock on all nodes: 185.220.101.5
    [ * ] Unblocking 185.220.101.5...
    [ ✓ ] Unblock request for 185.220.101.5 accepted by the nodes.

A banned address lands back in the blocklist on the next trigger. To never ban it at all, add the IP to the whitelist in Settings.

This entry rebuilds the plugin nftables table on every node: it drops active bans and clears debris after failures. The Ingress Filter and Egress Filter lists live in the same table, so when those are on, the script warns: after the reset the nodes may keep them empty until the plugin config changes next time or the node restarts.

  1. Confirm the reset:

    root@server: ~
    Recreate nftables tables on all connected nodes? Existing blocks will be dropped (y/n): y
    [ * ] Recreating nftables tables...
    [ ✓ ] Recreate request accepted by the nodes.

The Configure Telegram notifications (panel) entry writes settings into the panel’s /opt/remnawave/.env: the panel’s Telegram bot starts mirroring Torrent Blocker reports into the given chat.

  1. Enter the bot token (from @BotFather) and the chat for reports. For a supergroup topic use chat_id:thread_id. Before saving, the module sends a test message:

    root@server: ~
     Panel Telegram notifications: disabled, TB chat: —
    Telegram bot token [current: —]: 7481203945:AAH3k2QvLpR9tXmZwYb5C1dE
    Chat for TB reports, chat_id or chat_id:thread_id [current: —]: -1002345678901
    Sending a test message...
    
    Write to the panel .env and restart the panel and its components? Short downtime, ~30 seconds (y/n): y
    [ * ] Saving settings to /opt/remnawave/.env...
    [ * ] Restarting the panel and its components (docker compose down/up)...
    [ ✓ ] Done: the panel now sends Torrent Blocker reports to Telegram.

When api.telegram.org is unreachable from the server (common for RU-hosted machines), the module offers to send messages through a proxy, for example a socks inbound of xray on a foreign node:

root@server: ~
Sending a test message...
api.telegram.org is unreachable from this server (possibly blocked in Russia).
Messages can be sent through a SOCKS5/HTTP proxy, for example an xray socks inbound on a foreign VPS/node.
Send Telegram through a proxy? (y/n): y
Proxy address (socks5h://host:port or socks5h://user:pass@host:port, the password can be typed as is): socks5h://45.151.100.214:1080
Sending a test message...

The proxy login and password can be typed as is: the module percent-encodes special characters itself, and the credentials never show up in the process list because curl receives them through a file descriptor.

When notifications are already configured, the entry offers Reconfigure or Disable Torrent Blocker notifications. Disabling clears only the Torrent Blocker chat: if other notification categories of the panel are still alive, the global Telegram switch stays on.

The filter blocks inbound connections at the nftables level by a subnet list: internet scanners knock on the node port and get no answer. There is one list for all nodes, and each feature has its own status.

The feature menu:

root@server: ~
Ingress Filter

 Ingress Filter: disabled
 blocklist entries: 0

1.Enable Ingress Filter
2.Blocklist presets
3.Add IP/subnet manually
4.Remove entries manually

5.Delete Ingress Filter settings

0.Exit

Select action (0-5):
  1. Select Enable Ingress Filter:

    root@server: ~
    [ * ] Enabling Ingress Filter...
    [ ✓ ] Ingress Filter enabled and synced to nodes.
    Inbound traffic is blocked at the nftables level for the whole server. Presets block entire subnets, so hosting neighbours of those subnets may be cut off too.

The filter can be enabled with an empty list too, but it starts working only once the blocklist has entries.

The Blocklist presets entry opens three ready lists. An applied preset carries an [applied: N] mark, and when the upstream list updates, the mark turns red and shows how many entries are available:

root@server: ~
Ingress blocklist presets

 Checking applied presets for updates...
1.RU scanners (Skipa) [applied: 145]
    Known RU-based internet scanners, ~145 subnets
2.Classic scanners [applied: 270, available: 271 — update it]
    Censys, Shodan, Palo Alto, Shadowserver, Driftnet, ONYPHE, ZoomEye, LeakIX, Rapid7 — ~270 subnets
3.FOFA + Quake
    Chinese scan platforms FOFA and Quake — ~950 entries, a large list

0.Exit

Select action (0-3):

The lists are downloaded from GitHub; when it is unreachable directly, the module tries mirrors on its own. Re-applying a preset replaces only that preset’s previous entries: entries of other presets and manual ones stay in place.

  1. Select a preset, for example RU scanners (Skipa):

    root@server: ~
    [ * ] Downloading preset lists...
     Source: github.com/tread-lightly/CyberOK_Skipa_ips
    Write 145 entries into the blocklist? This preset's previous entries are replaced, manual entries stay (y/n): y
    [ ✓ ] Preset applied: 145 entries in the blocklist.
    Ingress Filter is currently disabled — enable it via option 1, otherwise the lists do nothing.

When the filter is off at apply time, the module reminds with a yellow line: the lists themselves are already saved in the panel, and enabling works at any moment.

The Add IP/subnet manually entry accepts IPv4 and prefixed subnets, comma-separated:

root@server: ~
IP or CIDR, comma-separated (e.g. 1.2.3.4, 10.0.0.0/24): 185.220.101.5, 45.155.205.233
[ ✓ ] Blocklist updated, 2 entries in total. Synced to nodes.

The Remove entries manually entry shows the first 20 entries and asks what to cross out. An empty Enter with confirmation clears the whole list, 0 cancels:

root@server: ~
 Current entries (first 20):
   185.220.101.5
   45.155.205.233
Entries to remove, comma-separated (Enter — clear the whole list, 0 — cancel): 45.155.205.233
[ ✓ ] Blocklist updated, 1 entries in total. Synced to nodes.

The Delete Ingress Filter settings entry removes only the ingressFilter section from the shared plugin: the blocklist and preset marks are erased, Torrent Blocker and Egress Filter stay untouched.

root@server: ~
Delete the Ingress Filter settings from the shared plugin (blocklist and preset marks)? Torrent Blocker and Egress Filter stay untouched (y/n): y
[ * ] Deleting Ingress Filter settings...
[ ✓ ] Ingress Filter settings removed from the shared plugin.

The filter blocks the server’s outbound traffic by destination address and port. The main scenario: the server got compromised through a stolen account, the malware wants to reach private networks or send spam, and the doors are already closed.

The feature menu:

root@server: ~
Egress Filter

 Egress Filter: not configured

1.Enable Egress Filter
2.List presets
3.Add IP/subnet manually
4.Add ports manually
5.Remove entries manually

6.Delete Egress Filter settings

0.Exit

Select action (0-6):

When the lists already exist, their size shows under the status: IP entries: 5 | ports: 3.

Enabling mirrors Ingress:

root@server: ~
[ * ] Enabling Egress Filter...
[ ✓ ] Egress Filter enabled and synced to nodes.

The List presets entry computes presets right on this server, downloading nothing:

root@server: ~
Egress presets

1.Private ranges [applied: 5]
    Internal networks (RFC1918, CGNAT, link-local); ranges in use on this host are skipped automatically
2.Mail ports
    Close outbound mail from the server: 25, 465, 587

0.Exit

Select action (0-2):
  1. The Private ranges preset closes internal networks: 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 100.64.0.0/10, 169.254.0.0/16 and the IPv6 range fc00::/7. Ranges the host itself uses (routes, interface addresses, DNS resolvers, Docker bridges, meshes) are skipped automatically:

    root@server: ~
     Will be blocked (5):
       10.0.0.0/8
       192.168.0.0/16
       100.64.0.0/10
       169.254.0.0/16
       fc00::/7
     Skipped — already used on this host (1):
       172.16.0.0/12 ← 172.17.0.0/16
    
    Write these subnets into the outbound blocklist? (y/n): y
    [ ✓ ] Preset applied: 5 subnets.
    Egress Filter is currently disabled — enable it via option 1, otherwise the lists do nothing.

    When the host’s subnet composition changes (a new Docker bridge or a mesh address), the preset gets a red applied: 5, current: 4 — re-apply mark and is recomputed on the next apply.

  2. The Mail ports preset closes outbound 25, 465 and 587: the server stops being a spam source, normal traffic is untouched:

    root@server: ~
    Block outbound ports 25, 465, 587? (y/n): y
    [ ✓ ] Preset applied: ports blocked (25, 465, 587).

Addresses accept IPv4 and IPv6, with or without a prefix; ports go from 1 to 65535:

root@server: ~
IP or CIDR, comma-separated (IPv4/IPv6): 185.220.101.5
[ ✓ ] Lists updated: IPs — 1, ports — 0. Synced to nodes.
root@server: ~
Ports, comma-separated (1-65535): 6667, 6697
[ ✓ ] Lists updated: IPs — 1, ports — 2. Synced to nodes.

The Remove entries manually entry shows both lists and accepts IPs and ports for removal in one input. Deleting the settings works like Ingress: only the egressFilter section leaves the shared plugin.

A few details worth knowing about how the module handles plugin records in the panel:

  • One record for everything. The plugin is named Reverse Node Plugins; its uuid is stored on the panel server, so renaming the record in the panel UI does not lose it.

  • Binding on every save. A saved config means nothing until the plugin is active on a node. After every change the module re-binds it to all enabled nodes and syncs the config.

  • Another plugin on the nodes. When some nodes keep a different plugin active (your own custom one), the module asks whether to re-bind them too. A decline is remembered for the session: such nodes stay on their plugin, and the record is not deleted from the panel.

    root@server: ~
    These nodes run another plugin: us-nyc-03. Bind them to the shared plugin as well? Their current plugin stops working on them (its record stays in the panel) (y/n): n
    Left on their own plugin: us-nyc-03 — the shared plugin is not active there.
  • Merging old records. Records left from earlier script versions are offered to be merged into one on entry: configs are deep-merged, address lists are unioned without losses, extra records are deleted.

    root@server: ~
    Plugin records to merge: Torrent Blocker, Egress Filter. Their settings are merged into "Reverse Node Plugins", the other records are deleted and the plugin is bound to every enabled node. Merge now? (y/n): y
    [ * ] Merging node plugins into one record: Torrent Blocker, Egress Filter...
    [ ✓ ] Done: one shared plugin, bound to every enabled node.

The Delete the shared plugin (all three features) entry in the Torrent Blocker menu removes the record entirely: the plugin is first unbound from the nodes (so no dangling references stay), then deleted from the panel.

root@server: ~
Delete the shared plugin from the panel? Torrent Blocker, Ingress Filter and Egress Filter settings will be removed and the plugin unbound from nodes (y/n): y
[ * ] Deleting the shared plugin...
[ ✓ ] Plugin deleted and unbound from nodes. Active bans expire on their own, or reset them via the recreate tables option.

To keep some of the features, delete the sections one by one: the Delete Ingress Filter settings and Delete Egress Filter settings entries in their menus touch only their own sections.