Installing EdgeWarden
The complete walkthrough for bringing the platform up on a Debian 13 server (minimal install), from dependencies to a working dashboard.
- Debian 13 (Trixie)
- x86_64
- ~40 minutes
- root access
Guide contents
Before you start
flowspec prefix. To stay compatible with existing installations, the directory (/opt/flowspec-analyzer), the services (flowspec-core, flowspec-frontend and flowspec-analyzer.target), the ClickHouse database (flowspec), the package (flowspec-analyzer-stable.tar.gz) and the API keys (fsk_) keep that prefix. The commands in this guide are correct for the current release.Hardware requirements
Pick a size based on your network's flow volume. All three run the same package.
| Resource | Small: regional ISP | Medium (recommended): mid-size ISP or DC | Enterprise: Tier-1 or large DC |
|---|---|---|---|
| Volume | Up to 20k flows/s, networks up to ~5 Gbps | Up to 50k flows/s, networks up to ~20 Gbps | 100k+ flows/s, networks of 40 Gbps or more |
| CPU | 8 cores (Xeon / EPYC) | 16 cores (Xeon Scalable / EPYC) | 32+ cores (EPYC / Xeon Platinum) |
| RAM | 32 GB DDR4 | 64 GB DDR4 ECC | 128+ GB DDR4/DDR5 ECC |
| Disk | 500 GB NVMe SSD | 2 TB NVMe SSD | 4+ TB NVMe (RAID 10) |
| Network | 1 Gbps | 10 Gbps | 25 / 40 / 100 Gbps |
| OS | Debian 13 server (Trixie, minimal install), x86_64 | ||
- eBPF/XDP: Debian 13 already ships a 6.x kernel. Use a NIC with native XDP support (Mellanox or Intel).
- ClickHouse: from the Medium size up, move it to a dedicated server.
- Retention: size the disk for the retention period you want; compression is around 10:1.
- High availability: for the Enterprise size, a cluster of 2 or more nodes is recommended.
Ports used
| Port | Protocol | Service |
|---|---|---|
| 2055 | UDP | NetFlow v5/v9/IPFIX collector |
| 6343 | UDP | sFlow collector |
| 11019 | TCP | BMP station (optional) |
| 3099 | TCP | Web dashboard |
| 8123 / 9000 | TCP | ClickHouse (local only) |
| 6379 | TCP | Redis (local only) |
| 50051 | TCP | GoBGP gRPC (local only) |
| 179 | TCP | BGP (GoBGP ↔ router) |
| 8090 | TCP | Scrubber /health (distributed installs only; open it to the analyzer alone) |
| 80 / 443 | TCP | Proxy for domain access with HTTPS (optional, Step 10) |
have this ready before you start The dashboard asks for the license key on first login, before any configuration. Without it, you install everything and get stuck on the activation screen. Before you open a terminal, have ready:
- License key: sent when you subscribe. It is also available in the Customer area. Not a customer yet? See the plans.
- How the dashboard will be reached: by IP or by a domain with HTTPS. This choice goes into the configuration as early as Step 7.3, and changing it later means reconfiguring. If you go with a domain, its DNS must already point to the server.
- Two strong passwords: one for ClickHouse and one for MariaDB. Write both down, because each is used in more than one step.
sudo. Replace SUA_SENHA_CH and SUA_SENHA_MYSQL with the passwords you set aside.-
Prepare the system
Update Debian and install the base tools. EdgeWarden ships as a prebuilt binary, so no build toolchain is needed:
apt update && apt upgrade -y apt install -y curl sudo wget gnupg ca-certificates unzip \ net-tools libpcap0.8 tcpdump htop \ snmp # net-snmp: required for SNMPv3libpcap0.8is the only system library the collector uses at runtime. No compilers, no PHP, no extra packages: the smaller the install, the smaller the attack surface.The
snmppackage (net-snmp) is only used if you add devices with SNMPv3. The collector has SNMP v1/v2c built in, but for v3 it calls the system'ssnmpbulkwalk. Installing it now costs a few KB and avoids a trap: without that binary, v3 polling fails silently, no counters show up and the log doesn't point to the cause.Kernel tuning (sysctl) for the collector
The collector takes heavy UDP bursts (NetFlow/sFlow), and Debian's defaults are conservative. The core requests a 16 MB buffer per socket, but the stock
net.core.rmem_maxis only 208 KB. The request gets truncated, the kernel silently drops flow packets and traffic vanishes from the graphs with no visible error. Apply this once:cat > /etc/sysctl.d/99-flowspec-tuning.conf <<'EOF' # Network buffers — NetFlow/sFlow collector (UDP bursts) # These are CEILINGS, not allocations: the kernel only reserves what the socket # asks for. The core asks for 16 MB per socket; the ceiling is generous on purpose. net.core.rmem_default = 31457280 net.core.rmem_max = 134217728 net.core.wmem_default = 31457280 net.core.wmem_max = 134217728 net.core.netdev_max_backlog = 250000 net.core.optmem_max = 33554432 net.core.somaxconn = 65535 net.core.default_qdisc = fq # TCP — local ClickHouse + dashboard net.ipv4.tcp_rmem = 4096 87380 134217728 net.ipv4.tcp_wmem = 4096 65536 134217728 net.ipv4.tcp_max_syn_backlog = 65536 net.ipv4.tcp_mtu_probing = 1 net.ipv4.tcp_no_metrics_save = 1 net.ipv4.ip_local_port_range = 1024 65535 # File/thread limits — core + ClickHouse # SYSTEM-wide ceiling. This is NOT the per-process limit — see the note below. fs.file-max = 3263776 fs.aio-max-nr = 3263776 fs.pipe-max-size = 8388608 kernel.threads-max = 1031306 kernel.pid_max = 262144 # Memory — ClickHouse leans hard on page cache; swapping kills latency vm.swappiness = 1 vm.vfs_cache_pressure = 50 # 256 MB is the cap the kernel itself uses when deriving this value from RAM. # The old 32768 sat BELOW the default on machines with 64 GB or more. vm.min_free_kbytes = 262144 # Automatic reboot 3s after a kernel panic (unattended appliance) kernel.panic = 3 EOF # Apply and check sysctl --system 2>&1 | grep -iE "error|cannot|no such" || echo "OK sem erros" sysctl net.core.rmem_max net.core.netdev_max_backlog vm.min_free_kbytesCreating the file now is right. Just don't come back later to change values in it.
The same file ships with the package (
scripts/sysctl/99-flowspec-tuning.conf), and from the first upgrade on,update.shrewrites it on every update. A value edited directly in/etc/sysctl.d/99-flowspec-tuning.confreverts to the original on the next upgrade, with no error and no warning. It's the kind of thing you find out too late.To change a value permanently, put only what you want different in a separate file with the
zz-prefix:echo 'vm.swappiness = 10' > /etc/sysctl.d/99-zz-meus-ajustes.conf sysctl --systemThis works because
sysctl.dreads files in alphabetical order and whoever sets a key last wins:99-zz-meus-ajustescomes after99-flowspec-tuning. That file is yours, and no upgrade touches it.nothing to do now Just so you know:fs.file-maxis not the per-process limit. It's the ceiling for the whole system. Each service is still bound by systemd'sLimitNOFILE, which defaults to just 1024 descriptors. EdgeWarden's units already setLimitNOFILE=65535, so there is nothing to tune. You'll check this and the socket buffer in Step 8, once the services exist.only if you run your own firewall Stateful firewall on this machine? On a clean Debian install with no firewall rules of your own, skip this note. EdgeWarden doesn't use conntrack: its nftables chain hooks in at
hook input priority -150, ahead of connection tracking, and XDP acts before all of netfilter.If you do maintain your own stateful firewall, add an exemption for the flow ports to its ruleset:
udp dport { 2055, 6343 } notrack. This is not a shell command; it's an nftables rule fragment. On a machine that does scrubbing, exempt transit traffic as well: conntrack creates state per flow, and a spoofed-source flood fills the table in seconds. It's the classic way to take down your own scrubber. Only raisenet.nf_conntrack_maxif you really need state, and in that case keepnf_conntrack_bucketsat about ¼ of that value; otherwise the hash chains become the bottleneck.almost never applies Will this machine forward attack traffic? Only if it's an inline eBPF/XDP filter or a clean pipe scrubber. In the standard install, the server only receives NetFlow/sFlow samples and announces FlowSpec over BGP; the router is what drops the attack. If that's your setup, carry on as normal.
If it will forward traffic, the data plane tuning is in Step 11, at the end of the guide. It depends on the installed package, so it can't be done here.
Time zone and NTP
Accurate timestamps are essential for the flow graphs and for license validation:
timedatectl set-timezone America/Sao_Paulo # set to your region apt install -y systemd-timesyncd printf '[Time]\nNTP=200.160.0.8\nFallbackNTP=a.ntp.br\n' > /etc/systemd/timesyncd.conf timedatectl set-ntp true timedatectl status # "System clock synchronized: yes" -
Install Node.js 22
The web dashboard runs on Node.js, installed from the official NodeSource repository:
curl -fsSL https://deb.nodesource.com/setup_22.x | bash - apt install -y nodejs node --version # should print v22.x -
Install ClickHouse
ClickHouse is the time-series database that stores the flows. Install it from the official repository:
install -m 0755 -d /etc/apt/keyrings curl -fsSL 'https://packages.clickhouse.com/rpm/lts/repodata/repomd.xml.key' | \ gpg --dearmor -o /etc/apt/keyrings/clickhouse.gpg echo "deb [signed-by=/etc/apt/keyrings/clickhouse.gpg] https://packages.clickhouse.com/deb stable main" | \ tee /etc/apt/sources.list.d/clickhouse.list apt update apt install -y clickhouse-server clickhouse-clientDuring installation, ClickHouse asks for the password of thedefaultuser. Set a strong password and write it down: this guide refers to it asSUA_SENHA_CH.Enable the service and check that it responds:
systemctl enable --now clickhouse-server curl http://localhost:8123/ping Ok. -
Install MariaDB and Redis
MariaDB stores the dashboard's users and settings; Redis distributes alerts in real time.
apt install -y mariadb-server mariadb-client redis-server systemctl enable --now mariadb redis-server redis-cli ping PONGSet the MariaDB root password (replace
SUA_SENHA_MYSQL):mariadb -u root -e "ALTER USER 'root'@'localhost' IDENTIFIED BY 'SUA_SENHA_MYSQL'; FLUSH PRIVILEGES;" -
Install GoBGP mitigation
GoBGP is the BGP daemon that announces mitigation rules (FlowSpec/RTBH) to your router:
apt install -y gobgpdjust install it for now Installing is enough to follow the guide. Peers are configured later, with the system running, and the file is never edited by hand: the generator reads the routers you add under Settings → Devices (Configurações → Dispositivos) and builds the configuration.
When the time comes, run these in order. In
gobgp neighbor, the session must show asEstabl:python3 /opt/flowspec-analyzer/scripts/gobgp/gen_config.py > /etc/gobgpd.conf systemctl enable --now gobgpd && systemctl restart gobgpd gobgp neighborNote the
>: the generator writes to standard output. Without the redirect, it only prints to the screen and/etc/gobgpd.confstays empty. GoBGP starts with no peers and mitigation never announces anything.Not using automatic mitigation yet? You can leave this for later: collection, dashboard and detection all work without BGP.
-
Download and extract the package
Download the stable release and extract it to
/opt:cd /opt curl -fLO https://www.edgewarden.com.br/download/flowspec-analyzer-stable.tar.gz tar -xzf flowspec-analyzer-stable.tar.gz -C /opt/ cd /opt/flowspec-analyzer mkdir -p logsCreate the license directory:
mkdir -p /etc/flowspec-analyzer chown -R www-data:www-data /etc/flowspec-analyzerIf the download or extraction fails (incomplete or corrupted file), download it again or contact support before moving on. -
Configure and create the databases
7.1ClickHouse password
Edit
config.tomland enter the ClickHouse password you set in Step 3:nano /opt/flowspec-analyzer/config.toml # in the [storage.clickhouse] section: # password = "SUA_SENHA_CH"7.2Databases, schema and seed data
Create the database and load the schema and seed data (detection templates and decoders):
cd /opt/flowspec-analyzer clickhouse-client --password 'SUA_SENHA_CH' -q "CREATE DATABASE IF NOT EXISTS flowspec" clickhouse-client --password 'SUA_SENHA_CH' --database flowspec --multiquery < database/clickhouse/schema.sql clickhouse-client --password 'SUA_SENHA_CH' --database flowspec --multiquery < database/clickhouse/seed.sql # authentication database (creates the default admin user) mysql -u root -p'SUA_SENHA_MYSQL' < database/mysql/auth_schema.sql7.3Dashboard environment and AUTH_URL
Before running the command, decide which address the dashboard will be reached at. This is the choice that breaks the most installs, and it's made here:
decide now
AUTH_URLmust be exactly the URL you will type into the browser: scheme, host and port. The dashboard runs in standalone mode, where Next builds the origin from this variable and ignores theHostheader. There's no way for it to guess.If the value doesn't match the URL in use, login fails for every credential, the form looks stuck and the screen shows no useful error. Running
setup-env.shwithoutAUTH_URLwrites a placeholder value, and then login doesn't work at all.Already ran it without
AUTH_URL? No need to redo anything. Fix the line and restart the dashboard:grep AUTH_URL /opt/flowspec-analyzer/frontend/.env.production sed -i 's|^AUTH_URL=.*|AUTH_URL=https://flowspec.example.net|' /opt/flowspec-analyzer/frontend/.env.production systemctl restart flowspec-frontend7.4Public ASN data recommended
Import the public ASN data. It powers the Peering, CDN and AS Analysis (Análise de AS) screens:
CH_PASS='SUA_SENHA_CH' ./scripts/import-asn-names.sh http://127.0.0.1:8123 CH_PASS='SUA_SENHA_CH' ./scripts/import-ip2asn.sh http://127.0.0.1:8123 CH_PASS='SUA_SENHA_CH' ./scripts/seed-cdn-providers.sh http://127.0.0.1:8123 -
Enable the services (systemd)
The system runs as two supervised services: if a process dies, systemd restarts it on its own.
cd /opt/flowspec-analyzer # correct ownership BEFORE starting (the services run as www-data) chown -R www-data:www-data /opt/flowspec-analyzer cp scripts/systemd/flowspec-core.service \ scripts/systemd/flowspec-frontend.service \ scripts/systemd/flowspec-analyzer.target /etc/systemd/system/ # Reinstall the Step 1 tuning from the package so the file is identical # to what update.sh will maintain from now on (prevents drift). cp scripts/sysctl/99-flowspec-tuning.conf /etc/sysctl.d/ && sysctl --system systemctl daemon-reload systemctl enable --now flowspec-core flowspec-frontend flowspec-analyzer.target systemctl status flowspec-core flowspec-frontend ● flowspec-core.service — Active: active (running) ● flowspec-frontend.service — Active: active (running)8.1Check the tuning on the running process
With the services up, confirm that the Step 1 tuning actually reached the process. These are three read-only checks; none of them changes anything:
# 1. Core file descriptors — must read 65535, not 1024 cat /proc/$(pgrep -f flowspec-analyzer-core)/limits | grep "open files" # 2. Collector socket buffer. The core asks for 16 MB and the kernel DOUBLES # the value, so 32 MB is the right number: rb33554432. # If you see rb425984, the Step 1 sysctl was not applied. ss -ulnpme | grep -A1 -E "2055|6343" grep "Socket buffer" /opt/flowspec-analyzer/logs/core.log.* Socket buffer: solicitado 16MB, obtido 32MB # 3. UDP drops — these counters must NOT grow over time nstat -az | grep -iE "Udp.*(InErrors|RcvbufErrors)"Upgrading an older install? If item 1 still shows 1024, the unit in use is from the previous release. Copy it again fromscripts/systemd/(command above) and runsystemctl daemon-reloadfollowed bysystemctl restart flowspec-analyzer.target. Withoutdaemon-reload, the new limit doesn't take effect, even with the file in place.Everyday commands
- Restart everything
systemctl restart flowspec-analyzer.target - Restart the dashboard only
systemctl restart flowspec-frontend - Follow the logs
journalctl -u flowspec-core -f
- Restart everything
-
Firewall and first login
9.1Open the ports
Open only what's needed (example with
ufw):apt install -y ufw ufw allow ssh ufw allow 3099/tcp # dashboard ufw allow 2055/udp # NetFlow ufw allow 6343/udp # sFlow ufw enable ufw status9.2First login
Open the dashboard and log in for the first time. Use exactly the URL saved in
AUTH_URLin Step 7.3: the IP if you chose option B; the domain if you chose A (in which case Step 10 must be done first).- URL
- the same as your
AUTH_URL - User
- flowspec@managerpro.networkor admin@edgewarden.com.br
- Password
- admin123(both accounts)
On first login, change the email and password of both default admin accounts (or delete the one you don't use) under Settings → Users (Configurações → Usuários) (after changing the email, log out and back in). Then create your team's users with the right roles: admin, operator or viewer.9.3Activate the license
On the first screen, the dashboard asks for the license key you received when you subscribed. Enter the key and restart the core to complete activation:
systemctl restart flowspec-coreYour license key, subscription status and invoices are in the Customer area: license.managerpro.dev.br. Your login is created when you subscribe and sent to your email.9.4Point your routers at the collector
On your routers, configure NetFlow v9/IPFIX export (port
2055/UDP) or sFlow (port6343/UDP) to the server's IP, and add each device under Settings → Devices. Within 1 to 2 minutes, flows start showing up on the dashboard.Installation complete. The dashboard is already showing traffic in real time. Next, explore IP Zones (Zonas de IP) and Threshold Templates (Templates de Threshold) to tune DDoS detection to your network. -
Domain access and HTTPS optional
The dashboard already works at
http://IP:3099. If you want a friendly address with a certificate (for example,flowspec.example.net), put Apache in front as a reverse proxy.10.1Apache and certbot
Install Apache and certbot and enable the modules:
apt install -y apache2 certbot python3-certbot-apache a2enmod proxy proxy_http proxy_wstunnel ssl headers rewrite systemctl restart apache210.2VirtualHost
Create the VirtualHost, replacing the domain with yours. The DNS must already point to the server:
<VirtualHost *:80> ServerName flowspec.example.net ProxyPreserveHost On ProxyRequests Off # WebSocket (real-time dashboard updates) RewriteEngine On RewriteCond %{HTTP:Upgrade} =websocket [NC] RewriteRule /(.*) ws://127.0.0.1:3099/$1 [P,L] ProxyPass / http://127.0.0.1:3099/ ProxyPassReverse / http://127.0.0.1:3099/ # IMPORTANT: never set X-Forwarded-Host manually — Apache already # sends that header on its own, and duplicating it breaks login (Invalid URL). RequestHeader unset X-Forwarded-Host # Dynamic scheme (http/https) — stays correct when certbot # clones this vhost to port 443: RequestHeader set X-Forwarded-Proto expr=%{REQUEST_SCHEME} ErrorLog ${APACHE_LOG_DIR}/flowspec-error.log CustomLog ${APACHE_LOG_DIR}/flowspec-access.log combined </VirtualHost>10.3Site live and certificate
Enable the site and issue the certificate. certbot creates the HTTPS vhost and the redirect automatically:
# 1. Open 80 and 443 BEFORE certbot: it validates the domain over HTTP on # port 80, and the Step 9 ufw rules didn't open it. Out of order, it fails. ufw allow 80/tcp ufw allow 443/tcp # 2. Enable the site a2ensite flowspec apachectl configtest && systemctl reload apache2 # 3. Issue the certificate (creates the HTTPS vhost and the redirect automatically) certbot --apache -d flowspec.example.net # 4. AUTH_URL becomes the domain. Without this, login stops working # the moment you switch from the IP to the domain in the browser. sed -i 's|^AUTH_URL=.*|AUTH_URL=https://flowspec.example.net|' \ /opt/flowspec-analyzer/frontend/.env.production systemctl restart flowspec-frontend # 5. Only AFTER login through the domain works (optional): # ufw deny 3099/tcp # forces access through the domain/HTTPS onlyDon't close port 3099 too early. Until login through the domain is proven, it's your way back in if something in Apache or the certificate fails. Leave
ufw deny 3099/tcpfor last, and only run it if you really want to block direct access.If you came from option A in Step 7.3,
AUTH_URLis already the domain: item 4 changes nothing and is safe to run anyway.Validate. The response should be
307, redirecting to the login page on your domain:curl -sk -o /dev/null -w "%{http_code} -> %{redirect_url}\n" https://flowspec.example.net/ 307 -> https://flowspec.example.net/login -
Data plane: Packet Filter (XDP) and clean pipe optional
The Step 1 tuning targets the collector, which only receives flow samples. If this machine also forwards packets (inline eBPF/XDP filtering or diversion to clean pipe scrubbing), it needs a second set of keys aimed at the data plane: forwarding, softirq, qdisc and the eBPF JIT. That's what determines how many Gbps and Mpps the appliance handles on your hardware; the collector's socket buffer plays no part here.
This step sits at the end of the guide on purpose: part of it uses files that only exist after installation (
scripts/sysctl/anddeploy/scrubber/), and the scrubbing path only makes sense with the system already up.stop and decide This entire step is optional, and most installs skip it completely.
It only applies if this machine forwards attack traffic: if it's an inline eBPF/XDP filter or the scrubber in a clean pipe (the victim's traffic goes in and out through it).
In a standard EdgeWarden install, the server only receives samples of NetFlow/sFlow and announces FlowSpec over BGP; the router is what drops the attack. If that's your setup, the installation ended at Step 9 and you can close this guide.
Data plane tuning
safe on any machine This is performance only.ip_forward,rp_filterand ICMP redirects are not in this file, on purpose: they're handled byscrubber-path.sh, which validates the topology before enabling anything and knows how to roll back. This block is safe on any machine and only makes a difference where packets pass through.# The file ships ready-made in the package. Copying instead of typing ensures # it never drifts from what the product tests — and it's worth reading first: # every key has the reasoning commented next to it. cat /opt/flowspec-analyzer/scripts/sysctl/99-zz-flowspec-dataplane.conf.example # The "zz" suffix takes precedence over the Step 1 99-flowspec-tuning: # sysctl.d applies files alphabetically and the last one to set a key wins. cp /opt/flowspec-analyzer/scripts/sysctl/99-zz-flowspec-dataplane.conf.example \ /etc/sysctl.d/99-zz-flowspec-dataplane.conf sysctl --system 2>&1 | grep -iE "error|cannot|no such" || echo "OK sem erros" sysctl net.core.netdev_budget net.core.default_qdisc net.core.bpf_jit_hardenForwarding (clean pipe)
This part is not done by hand. Turning on
ip_forwardin a sysctl file makes the appliance a router without validating anything.scrubber-path.shchecks the topology first (the router must be on the same L2 segment), applies the keys with the care a hairpin requires and knows how to roll back:cd /opt/flowspec-analyzer/deploy/scrubber cp scrubber-path.conf.example scrubber-path.conf $EDITOR scrubber-path.conf # DIRTY_IF, ROUTER_IP, PROTECT_PREFIXES ./scrubber-path.sh check # validates, touches nothing ./scrubber-path.sh up # brings it up — runtime only ./scrubber-path.sh verify 203.0.113.10 # simulates the decision for one victim # Only AFTER verify passes, make it permanent: ./scrubber-path.sh up --persist ./scrubber-path.sh status # should say "Persistência ativa"Don't skip
--persist. Without it, the path lives only in memory, and the failure mode is the worst possible: the machine reboots, the core comes up, XDP loads, the router keeps diverting the victim here, and the appliance drops every packet because it's no longer forwarding. Every service showsactive (running)and the dashboard flags nothing. Your customer goes offline during the attack.--persistis also not the default on purpose: an unproven path coming up on its own at boot is worse than a path that disappears. That's why the order is prove first, persist after, andstatuswarns you while persistence is missing.NIC tuning
No sysctl makes up for a badly configured NIC. Above 100 Gbps, this is where it's decided: the commands below buy more pps than the entire previous block.
maintenance window Don't paste this whole block on a production machine. Items 1 and 2 (
ethtool -Gandethtool -L) reset the NIC: the link goes down and comes back, and anything carrying customer traffic sees a one-to-two-second outage. Item 4 disables a system service. Run it in an agreed window, one item at a time, checking between them.And change
IF=eth0to your real interface before anything else (ip -br linklists the available ones). Pointing at the wrong interface reconfigures the wrong NIC.IF=eth0 # data plane interface (the one receiving dirty traffic) # 1. Ring buffers at the MAXIMUM the NIC supports (read from the NIC itself) RXMAX=$(ethtool -g $IF | awk '/^RX:/{print $2; exit}') TXMAX=$(ethtool -g $IF | awk '/^TX:/{print $2; exit}') ethtool -G $IF rx $RXMAX tx $TXMAX # 2. RSS queues — one per core on the SAME NUMA node as the NIC (see the note) NODE=$(cat /sys/class/net/$IF/device/numa_node) NCPU=$(lscpu -p=CPU,NODE | grep -c ",$NODE$") ethtool -L $IF combined $NCPU # 3. Adaptive coalescing: fewer IRQs per packet under bursts ethtool -C $IF adaptive-rx on adaptive-tx on # 4. Pinned IRQ per queue — irqbalance reshuffles exactly when under load systemctl disable --now irqbalance # 5. Which mode did XDP come up in? ip -d link show $IF | grep -i xdp # "xdp" = native, in the driver — required at this scale # "xdpgeneric" = SKB fallback, runs AFTER GRO. In this mode the filter # sees already-coalesced packets and undercounts pps, so: ethtool -K $IF gro off lro off # 6. Check whether the NIC is dropping packets (everything should stay at zero) ethtool -S $IF | grep -iE "drop|discard|miss|nobuf|error" | grep -v ": 0$"NUMA matters more than core count. On a dual-socket machine, an RSS queue served by a core on the wrong node pays the interconnect crossing on every packet. If
cat /sys/class/net/$IF/device/numa_nodereturns0, use only node 0's cores: 16 queues on the right node outperform 64 spread across both.Also confirm the slot width: 200 Gbps requires PCIe 4.0 x16 (
lspci -vv -s $(basename $(readlink /sys/class/net/$IF/device)) | grep -i "LnkSta:"). In an x8 slot, the NIC never delivers its nominal rate, and no amount of tuning fixes that.ethtoolsettings don't survive a reboot. Pin them in apost-upin/etc/network/interfacesor in a systemdoneshotunit withAfter=network-online.target, with the same care that applies tosysctl.d.
Upgrade to new releases
Upgrading is one command. The updater checks the package's integrity, keeps your settings, swaps the release and runs a health check. Downtime is usually under 1 minute, and historical data is not touched:
cd /opt
curl -fLO https://www.edgewarden.com.br/download/flowspec-analyzer-stable.tar.gz
/opt/flowspec-analyzer/scripts/update.sh /opt/flowspec-analyzer-stable.tar.gz
Running scrubbing or clean pipe? For this upgrade only, back up the topology first. deploy/scrubber/scrubber-path.conf describes your network's topology, so it isn't in the package, and the updater replaces the whole directory. The new update.sh already preserves that file, but the swap is performed by the updater already on the server, which is still the old one. From the next upgrade on, it's automatic.
- Before:
cp /opt/flowspec-analyzer/deploy/scrubber/scrubber-path.conf /root/ - After:
cp /root/scrubber-path.conf /opt/flowspec-analyzer/deploy/scrubber/
If you forget, the file is still in /opt/flowspec-analyzer.previous/deploy/scrubber/. After restoring it, run ./scrubber-path.sh status to confirm the path came back intact.
If something doesn't go as expected, rolling back to the previous release is also one command:
/opt/flowspec-analyzer/scripts/update.sh --rollback
Troubleshooting
| Symptom | Fix |
|---|---|
| The dashboard won't open or the service won't start | journalctl -u flowspec-frontend -n 50. The most common cause is permissions: run chown -R www-data:www-data /opt/flowspec-analyzer and systemctl restart flowspec-analyzer.target. |
| Login returns error=Configuration | The dashboard couldn't connect to MariaDB. Check the user and password and run it again: MYSQL_USER=root MYSQL_PASSWORD='...' ./scripts/setup-env.sh --force |
| No flows show up | Check whether packets are arriving: tcpdump -i any -n udp port 2055. If they aren't, the problem is in the router's export config or the firewall; if they are, check journalctl -u flowspec-core -f. |
| ClickHouse doesn't respond | systemctl status clickhouse-server and curl http://localhost:8123/ping. The most common cause is a wrong password in config.toml. |
| Domain access redirects to the wrong place | Behind a reverse proxy, preserve the Host header: in Apache, use ProxyPreserveHost On and do not set X-Forwarded-Host manually; in nginx, use proxy_set_header Host $host;. |
| SNMPv3 device with no counters | net-snmp is missing: the collector has v1/v2c built in, but calls the system's snmpbulkwalk for v3. Check with command -v snmpbulkwalk and install with apt install -y snmp. For v2c, the package isn't needed. |
| Scrubbing worked, the machine rebooted and it stopped | The path was brought up without persistence. ./scrubber-path.sh status lists the keys that reverted to default and the missing nftables table; ./scrubber-path.sh up --persist fixes it and makes the path survive future reboots. |
A sysctl setting disappears after an upgrade |
Edited /etc/sysctl.d/99-flowspec-tuning.conf by hand? The updater reinstalls it on every upgrade. Put your values in a separate file with the zz- prefix, which is applied later and wins. |
Stuck on a step?
Reach support on WhatsApp or by email. During your installation window, we stay with you until the dashboard is up.
Support in Portuguese, Monday to Friday, 8 a.m. to 6 p.m. (Brasília time).
Don't have a license yet?
Compare the plans or book a demo using data from your own network.