Requirements
Hardware requirements
AegisGate is designed for Raspberry Pi-class hardware, but also runs on regular Debian/Ubuntu/RHEL servers.
Quick Install
The installer runs these steps in order:
- Packages — nftables, dnsmasq, WireGuard, Python 3, Flask, Gunicorn, Suricata, CrowdSec
- Network — disables NetworkManager, configures ifupdown static WAN/LAN, creates
aegisgate-net-setup.service - nftables — default firewall: input (drop), forward (drop), postrouting (NAT), blacklist/allowlist/CrowdSec/IPBL sets, Suricata NFQ rule
- dnsmasq — DNS/DHCP server with blocklist streaming config, per-list files, validates entries (strips CSS selectors, URL paths)
- Suricata — IPS mode (
engine-mode: ips), NFQ queue 0,ct state new, local-bridge.rules with 5 drop + 6 alert rules - WireGuard — VPN server interface with ACL system
- Dashboard — Flask + Gunicorn on
:8080 - Systemd — all services enabled and started
First Login
- Open
http://gateway-ip:8080in your browser - Log in with the credentials printed at the end of the install script
- Go to Settings → Change Password and set a strong password
- Configure WAN/LAN roles in Network → Interfaces
- Start the VPN in VPN → Start
- Enable DNS blocklists in DNS → Blocklists
Architecture
AegisGate is a Python Flask application (app.py) served by Gunicorn, managing nftables, dnsmasq, WireGuard, Suricata, CrowdSec and QoS through dedicated modules.
Boot Sequence
- networking.serviceBrings up interfaces with ifupdown static config
- aegisgate-net-setup.serviceSets interface roles (WAN/LAN/WiFi), VLANs, routes
- nftables.serviceApplies firewall rules: input, forward, postrouting chains + Suricata NFQ rule
- aegisgate-restore.serviceRestores saved state: security toggles, QoS, custom rules, IP sets, blocklists
- dnsmasq.serviceDNS/DHCP server starts with
conf-file=chain, blocklists, per-client policies - suricata.serviceIPS engine starts in NFQ mode (
-q 0 --set engine-mode=ips) - crowdsec + bouncerThreat intelligence feeds nft sets
- nft-dashboard.serviceGunicorn serves Flask dashboard on
:8080
Config Files
All persistent state is stored under /opt/nft-dashboard/data/ and restored at boot by restore-state.py:
{
"wan_interface": "eth0",
"lan_interface": "eth1",
"wan_ip": "31.172.140.234",
"lan_ip": "172.24.1.2",
"listen_addr": "172.24.1.2",
"listen_port": 8080
}{ "users": { "admin": { "password_hash": "pbkdf2:...", "role": "admin" } } }-- dns_rules (blocklist entries, groups, policies, services)
-- dns_lists (blocklist sources, update timestamps)
-- dns_queries (query log, latency, client info)
-- dns_custom_services (service bundle definitions)dnsmasq config chain:
conf-file=/etc/dnsmasq.d/aegisgate.conf
# /etc/dnsmasq.d/aegisgate.conf
conf-file=/etc/dnsmasq.d/aegisgate-blocklist.conf
conf-file=/etc/dnsmasq.d/aegisgate-local.conf
conf-file=/etc/dnsmasq.d/aegisgate-upstream.conf
conf-file=/etc/dnsmasq.d/aegisgate-dhcp.conf
conf-file=/etc/dnsmasq.d/aegisgate-clients.conf
conf-dir=/etc/dnsmasq.d/aegisgate-blocklists
# Blocklist entries use 1 line per domain (null_ip mode):
address=/ads.example.com/0.0.0.0
# Invalid entries (CSS selectors, URL paths) are automatically stripped:
# address=/domain.com##div[class ← REJECTED
# address=/domain.com/path/script.js ← REJECTED
Systemd Services
| Service | Description | Depends On |
|---|---|---|
aegisgate-net-setup | Interface roles, VLANs, routes | networking.service |
nftables | Firewall rules (input, forward, postrouting) | aegisgate-net-setup |
aegisgate-restore | Restores saved state, IP sets, blocklists | nftables |
dnsmasq | DNS/DHCP server with ad-blocking | aegisgate-net-setup |
suricata | IPS engine (NFQ queue 0, engine-mode: ips) | aegisgate-net-setup |
crowdsec | Threat intelligence agent | nftables |
nft-dashboard | Flask web dashboard (Gunicorn :8080) | aegisgate-restore |
Aegis DNS / AdBlock
Aegis DNS is a network-wide ad and malware blocker powered by dnsmasq. Every device on the network — phones, TVs, laptops, IoT — inherits the same filtering without any per-device configuration.
- 680k+ domains blocked via HaGeZi Ultimate + custom lists
- Block modes:
0.0.0.0(null_ip, default),NXDOMAIN,REFUSED, or custom IP - Per-list files: blocklists stored in
aegisgate-blocklists/directory, one file per source (streaming, no memory spikes) - Validation: CSS selectors (
##), URL paths (/path/to/script.js), and bare/prefixes are automatically rejected — no more accidental domain blocks likeukr.net##div - DNS hijack: redirect all port 53 traffic to the gateway DNS
- DoH bypass protection: block known DNS-over-HTTPS providers
- DHCP integration: per-client DNS policy assignment via dnsmasq
set:tags
dhcp-host=AA:BB:CC:DD:EE:FF,set:Kids,kids-phone,192.168.1.50
dhcp-option=tag:Kids,option:dns-server,172.24.1.2
# Block mode null_ip (1 line per domain)
address=/ads.example.com/0.0.0.0
Blocklists
AegisGate ships with HaGeZi Ultimate (~660k domains) and supports custom lists. Lists are stored per-source in aegisgate-blocklists/ and streamed from the SQLite database to avoid memory spikes.
- Add a list: DNS → Blocklists → Add URL or upload a file
- Update: Automatic daily at 04:17 via cron, or manual refresh from the UI
- Validation: Entries with
##,[,], or URL paths after TLD are automatically disabled — they would block entire domains in dnsmasq
Client Groups & Policies
Assign devices to groups with different filtering levels. Each group can have its own blocked services, blocklists, and upstream DNS.
- Kids: block YouTube, TikTok, social media, adult content, gambling
- IoT: block telemetry, ad/tracker domains
- Guest: block ads, malware; allow social media
- Work: minimal blocking, allow all work services
Service Bundles
One-click blocking of popular services. Each bundle contains domains, wildcards, and known alternate domains for the service.
DNS Hijack & DoH
DNS hijack redirects all port 53 traffic (TCP/UDP) on the LAN interface to the gateway dnsmasq. This prevents clients from bypassing filtering by manually setting a different DNS server.
DoH bypass protection blocks known DNS-over-HTTPS provider domains and IPs so clients cannot tunnel DNS queries over HTTPS.
Local Records & Rewrites
- Local records: map
myserver.lan→192.168.1.100 - Rewrites: map
app.example.com→ custom IP orNXDOMAIN/REFUSED - Wildcards:
*.example.comfor whole-domain overrides
DNS Dashboard
Pi-hole-style dashboard with real-time KPIs: total queries, blocked count, block rate, unique clients, top blocked domains, top clients, query log with period filter (5m/1h/6h/12h/24h/7d/all).
nftables Firewall
The AegisGate firewall is built on nftables with a strict default-drop policy on both input and forward chains. All traffic passes through multiple security layers.
- Input chain (policy: drop): Suricata NFQ → established/related → invalid drop → blacklist/CrowdSec/IPBL → allowlist/trusted → DNS/DHCP/SSH/HTTP/HTTPS accept
- Forward chain (policy: drop): established → invalid → blacklist/CrowdSec/IPBL → allowlist/trusted → hostname rules → accept
- Postrouting: masquerade for VPN and LAN → WAN, DNAT port forwarding
nft insert rule, not nft add rule. It uses ct state new to avoid dropping established connections.IP Sets
| Set | Type | Purpose | Source |
|---|---|---|---|
blacklist_ipv4/6 | interval, timeout | Manual blacklist | Dashboard |
crowdsec-blacklists/6 | interval, timeout | CrowdSec auto-ban | CrowdSec bouncer |
ipbl_ipv4/6 | interval, timeout, auto-merge | IP blocklists | External lists |
allowlist_ipv4/6 | interval | Trusted IPs (always pass) | Dashboard |
lan_trusted | interval | Trusted LAN nets | Config |
Hostname Firewall Rules
DNS Clients table includes a Track Hostname checkbox and a Firewall dropdown (Allow/Drop). When set to Drop, the hostname's resolved IPs are added to the forward chain as drop rules. This lets you block specific devices from accessing the internet while still allowing DNS.
firewall_action="" (empty) is the safe default meaning DNS-only, no nft rules.NAT, DNAT & Masquerade
Port forwarding (DNAT) publishes internal services to the WAN. VPN masquerade ensures VPN clients can reach the internet. All NAT rules are managed from the dashboard.
Security Rules
11 toggleable security rules with one-click enable/disable:
Suricata IPS
AegisGate runs Suricata in IPS mode using NFQ (NetFilter Queue). This means Suricata doesn't just detect — it drops malicious packets before they reach the target.
- Engine mode:
ips(set insuricata.yamland systemd override) - NFQ: queue 0,
mode: accept,fail-open: yes,queue-length: 1024 - NFQ rule:
nft insert rule inet filter input iifname "eth0" ct state new queue flags bypass to 0— first rule in input chain - ct state new: mandatory; without it Suricata drops established packets (stream_midstream errors)
- action-order:
pass, drop, reject, alert
Drop & Alert Rules
/etc/suricata/rules/local-bridge.rules:
| SID | Action | Description |
|---|---|---|
| 9000010 | DROP | SSH brute force (threshold: 5/60s) |
| 9000040 | DROP | C2 pattern (sqlmap User-Agent) |
| 9000050 | DROP | Directory traversal (../) |
| 9000051 | DROP | SQL injection (' OR) |
| 9000052 | DROP | XSS (<script) |
| 9000001 | ALERT | SYN flood (500/30s) |
| 9000002 | ALERT | ICMP flood (100/10s) |
| 9000003 | ALERT | UDP flood (500/30s) |
| 9000011 | ALERT | HTTP scan (100/30s) |
| 9000012 | ALERT | HTTPS scan (100/30s) |
| 9000020 | ALERT | DNS amplification (100/10s) |
Plus Emerging Threats rules (~49k alert rules) from the suricata-et package.
IPS Dashboard
The dashboard Suricata tab shows:
- IPS Stats: Accepted / Blocked / Alerts (from
suricatasc dump-counters) - Alerts table: period-filtered (5m/1h/6h/12h/24h/7d/all), with DROP (red) and ALERT (yellow) tags
- Local drop SIDs (9000xxx) displayed as DROP even though Suricata 7 NFQ logs
action=allowed - Real-time: auto-refresh every 60s via AJAX
WireGuard VPN
Built-in WireGuard VPN server with per-peer ACL, QR provisioning, bandwidth tracking and connection events.
- One-click start/stop from the dashboard
- Per-peer ACL: Internet, LAN, DMZ, or custom networks
- QR codes for instant mobile provisioning
- Bandwidth per peer: live TX/RX stats
- VPN NAT: masquerade rules auto-managed for internet access
- Download client: wireguard.com/install
ACL Modes
| Mode | Allowed IPs | Description |
|---|---|---|
| Internet | 0.0.0.0/0 | Full internet + LAN + DMZ |
| LAN | 172.24.1.0/24, 10.0.0.0/24 | Local network only |
| DMZ | 172.24.1.204/32 | DMZ server only |
| Custom | user-defined CIDRs | Specific networks |
QR Provisioning
Each peer has a "QR" button that generates a scannable WireGuard config QR code. Scan it with the WireGuard mobile app (Android/iOS) to import the tunnel instantly — no manual config needed.
Download Client
Download the official WireGuard client for your platform:
DHCP Server
Full dnsmasq DHCP server integrated with DNS policies. Leases, static assignments, and per-client DNS tags are all managed from the dashboard.
- Static leases: MAC → IP assignment with hostname tracking
- DNS tags: each static lease gets a
set:ClientNametag for per-client DNS policy - Duplicate protection:
seen_ipsset prevents duplicate IPs in generated config - Config order:
dhcp.confloaded beforeclients.confto ensure default options come first
dhcp-range=172.24.1.100,172.24.1.200,24h
dhcp-option=option:dns-server,172.24.1.2
# Per-client DNS override:
dhcp-host=AA:BB:CC:DD:EE:FF,set:Kids,kids-phone,172.24.1.50
dhcp-option=tag:Kids,option:dns-server,172.24.1.2
QoS / Traffic Shaping
Bandwidth management with pre-built profiles and manual rules. Supports CAKE, fq_codel, HTB and HFSC algorithms.
- Profiles: Gaming (latency priority), Streaming (bandwidth), Office (balanced), IoT (minimal), Custom
- Speed test: built-in with real-time SVG gauges
- Manual rules: per-port, per-protocol, per-IP shaping
- Auto-apply: profile applies tc/queue disciplines on the WAN interface
Network
Complete interface management with ifupdown static config, VLAN CRUD, static routes, and Multi-WAN.
- Interface roles: WAN, LAN, WiFi, VPN with live status
- VLANs: create/delete 802.1Q VLANs on any interface
- Static routes: custom routing for VPN, DMZ, or specific networks
- Conntrack: live connection tracking table with filtering
Monitoring Dashboard
Real-time dashboard with period filter (5m/1h/6h/12h/24h/7d/all):
- Drops: total dropped packets, unique sources, by rule, by port
- Blacklist: manual blacklist IPs with timeouts
- CrowdSec: auto-banned IPs from community threat intel, deduplicated
- Suricata: IPS stats (Accepted/Blocked/Alerts), alerts table with period filter, DROP/ALERT tags
- SSH attempts: failed/success logins
- Services: status and uptime for nftables, dnsmasq, WireGuard, Suricata, CrowdSec
- Auto-refresh: dashboard stats every 30s, DNS top stats every 60s
GeoIP
Geographic threat analysis using MaxMind GeoLite2 databases and CrowdSec blacklist data. Shows attack origins by country, ASN, and IP.
System Health
CPU usage, RAM, CPU temperature, conntrack table occupancy, disk usage, and per-interface bandwidth graphs with live updates.
Policy Modes
One-click security posture profiles that configure all security rules at once:
| Mode | Description | Rules Enabled |
|---|---|---|
| Balanced | Recommended default. Blocks known threats while allowing normal traffic. | SSH bruteforce, port scan, bogon, bad TCP, CrowdSec, Suricata |
| Strict | Maximum security. All 11 rules enabled plus DNS hijack. | All + DNS hijack + ICMP restricted |
| Permissive | Minimal filtering. Only critical protections. | Bogon, bad TCP |
| Paranoid | Lockdown. Everything in Strict plus aggressive SYN flood, full DNS hijack, no new inbound by default. | All + aggressive thresholds |
CrowdSec Integration
CrowdSec provides community-driven threat intelligence. When CrowdSec detects an attack pattern, it automatically adds the offending IP to the crowdsec-blacklists nft set. AegisGate then drops all packets from that IP in both input and forward chains.
- Auto-ban: decisions are deduplicated by IP — only the longest-duration decision per IP is kept
- nft sets:
crowdsec-blacklists(IPv4) andcrowdsec6-blacklists(IPv6) with interval+timeout - Dashboard: shows CrowdSec decisions, IP, scenario, duration and remaining TTL
- 33k+ IPs blocked at any given time from community threat intelligence
Log → CrowdSec parser → scenario match?
→ YES: add IP to nft set
crowdsec-blacklists→ NO: log & continue
nftables checks CrowdSec set on every new packet
IP Blocklists
External IP blocklists are loaded into nft sets ipbl_ipv4 and ipbl_ipv6 with interval, timeout, auto-merge flags. These sets are checked in both input and forward chains.
- 18k+ IPv4 entries from curated threat lists
- Automatic updates via cron (every 6 hours)
- Custom entries: add individual IPs or CIDRs from the dashboard
- Logged:
DROP_IPBL_SADDR_INPUT,DROP_IPBL_SADDR_INPUT,DROP_IPBL4_SRC,DROP_IPBL4_DST
GeoIP
Geographic threat analysis using MaxMind GeoLite2 databases (City + ASN). Shows attack origins by country and ASN. CrowdSec blacklist IPs are overlaid on the map.
- Country breakdown: attacks by country with flag emojis
- ASN breakdown: top ISPs and organizations
- IP details: click any IP to see country, city, ASN, ISP
Reports & Export
Export security reports in HTML format for auditing or compliance. Reports include:
- 11 export sections: nft drops, SSH attempts, blacklisted IPs, CrowdSec decisions, Suricata alerts (with DROP/ALERT tags and IPS stats), QoS bandwidth, DHCP leases, VPN peers, GeoIP, system health
- Period-filtered data matching the dashboard period selector
- Flag emojis for country codes
- Standalone HTML files with embedded CSS — no server needed to view
Multi-WAN
Configure multiple WAN interfaces with failover and policy routing. Each WAN can have its own gateway, metric, and routing rules.
- Failover: automatic switch to backup WAN when primary goes down
- Policy routing: route specific traffic (VPN, LAN) through specific WAN
- FRR/BGP support: optional BGP/OSPF routing protocols
- Status monitoring: real-time WAN status, latency, and packet loss
Cron Jobs
AegisGate sets up the following scheduled tasks:
| Schedule | Task | Description |
|---|---|---|
| Every 2 min | dns_log_import.py | Parse dnsmasq query log, insert into DB, cleanup old entries |
| Every 1 min | dns_apply_schedules.py | Apply time-based DNS blocking schedules |
| Every 5 min | dns_apply_service_blocks.py | Apply service-level blocking via nftables |
| Daily 04:17 | dns_update_lists.py | Download and update remote blocklists, regenerate configs |
| Every 5 min | collect_bandwidth.py | Collect per-interface bandwidth samples |
| Every 30 min | log-truncate.sh | Truncate nft-drops.log to 50k lines, restart rsyslog |
Troubleshooting
After=network-online.target to service files. Use After=networking.service and After=aegisgate-net-setup.service instead. NetworkManager is removed — use ifupdown.- DNS not resolving: Check
dnsmasq --testfor config errors. Verifyconf-file=(notconf-dir=) in/etc/dnsmasq.conf. Blocklist entries with##,[, or URL paths are auto-stripped. - Suricata not blocking: Verify
engine-mode: ipsin suricata.yaml and-q 0 --set engine-mode=ipsin systemd override. NFQ rule must be FIRST in input chain (nft insert rule, notnft add rule). Must havect state new. - DNS blocks whole domain: Caused by invalid entries like
address=/domain.com##div/0.0.0.0oraddress=/domain.com/path/0.0.0.0. AegisGate auto-strips these on config generation. Run the installer's DB cleanup to disable existing bad entries. - VPN can't reach internet: Check
POSTROUTINGmasquerade rules for wg0. Each peer ACL must allow internet (0.0.0.0/0 allowed_ips). - Hostnames not resolving: DHCP tags require
dhcp.confloaded beforeclients.conf. Theconf-file=chain ensures this order. - Dashboard shows only 2 rules: Period filter (1h default) may exclude rules with few hits. Change to "All" to see all 6+ rules. Excluded networks (LAN, bogon) are filtered from the dashboard.