WireGuard NFTables Firewall Integration Guide
Complete guide to Wiretastix's nftables firewall integration: two-layer architecture, group-based access control rules, CLI/API management, and troubleshooting.
Wiretastix integrates deeply with Linux nftables to provide dynamic, group-based firewall rules for VPN peers. This guide explains the architecture, how rules are applied, and how to manage both the base firewall configuration and group-specific rules.
Architecture Overview
Two-Layer Firewall Approach
Wiretastix uses a two-layer firewall architecture that separates general network security from VPN-specific access control:
Layer 1: Base NFTables Configuration (Manual Management)
- General firewall rules for the server
- Input/output chains for server protection
- NAT rules for masquerading
- ICMP, connection tracking, basic security
- Managed by you through standard nftables configuration files
Layer 2: Group-Based Rules (Automatic Management)
- VPN peer access control based on OIDC groups
- Dynamic chains and IP sets per group
- Automatically updated when peers connect/disconnect
- Managed by Wiretastix through CLI/API
This separation ensures:
- Your base security policies remain stable
- VPN rules update automatically without manual intervention
- Clear separation of concerns (server security vs. user access control)
How It Works
┌────────────────────────────────────────────────────────┐
│ User Authenticates via OIDC │
│ → Gets Group Membership (e.g., "engineering") │
└────────────────┬───────────────────────────────────────┘
│
▼
┌────────────────────────────────────────────────────────┐
│ Wiretastix Creates Peer │
│ → Assigns IP: 10.0.100.5/32 │
│ → Associates with Group: "engineering" │
└────────────────┬───────────────────────────────────────┘
│
▼
┌────────────────────────────────────────────────────────┐
│ Wiretastix Updates NFTables Automatically: │
│ 1. Adds 10.0.100.5 to set_peers4_group_engineering │
│ 2. Ensures group_engineering_handler chain exists │
│ 3. Populates chain with group rules from database │
│ 4. Updates wghandlers to jump to group chain │
└────────────────┬───────────────────────────────────────┘
│
▼
┌────────────────────────────────────────────────────────┐
│ Traffic Forwarding: │
│ Packet from 10.0.100.5 → forward chain → wghandlers │
│ → Matches IP in set → Jump to group_engineering │
│ → Apply group rules → accept/drop │
└────────────────────────────────────────────────────────┘
Base NFTables Configuration
Initial Setup
Wiretastix requires a base nftables configuration that defines the fundamental firewall structure. This configuration is managed by you and typically located at /etc/nftables.conf.
Minimal Working Example
#!/usr/sbin/nft -f
flush ruleset
define wiretastix_ext_if = eth0 # External interface
define wiretastix_tunnel_if = wg0 # WireGuard interface
define wiretastix_tunnel_port = 51820 # WireGuard port
define wiretastix_gui_port = 443 # HTTPS port
table inet wiretastix {
# Connection tracking and ICMP
chain keeptrack {
# Allow ICMP
ip protocol icmp accept
ip6 nexthdr icmpv6 accept
# Allow established connections
ct state {established,related} accept
# Drop invalid connections
ct state invalid drop
}
# Input chain (traffic TO the server)
chain input {
type filter hook input priority 0; policy drop;
jump keeptrack
# Allow WireGuard
udp dport $wiretastix_tunnel_port accept
# Allow HTTPS (Web UI)
tcp dport $wiretastix_gui_port accept
# Allow HTTP (for Let's Encrypt)
tcp dport 80 accept
# Allow SSH
tcp dport 22 accept
# Allow from loopback
meta iif lo accept
reject
}
# Output chain (traffic FROM the server)
chain output {
type filter hook output priority 0; policy drop;
jump keeptrack
# Allow WireGuard
udp sport $wiretastix_tunnel_port accept
# Allow DNS queries
udp dport 53 accept
# Allow HTTPS (for OIDC, updates)
tcp dport 443 accept
# Allow HTTP (for system updates)
tcp dport 80 accept
# Allow to loopback
meta oif lo accept
reject
}
# Forward chain (traffic THROUGH the server - VPN traffic)
chain forward {
type filter hook forward priority 0; policy drop;
jump keeptrack
jump wghandlers # ← Wiretastix manages this!
# Allow outgoing via external interface
oifname $wiretastix_ext_if accept
reject
}
# This chain is managed by Wiretastix - DO NOT EDIT
chain wghandlers {
}
}
# NAT table for masquerading
table ip nat {
chain postrouting {
type nat hook postrouting priority -100; policy accept;
# Masquerade outgoing traffic
oifname $wiretastix_ext_if counter masquerade
}
}
Complete Production Example
A full production configuration is available in the Wiretastix repository:
# View the example configuration
sudo cat /etc/wiretastix/nftables.conf.example
# Or download from repository
curl -O https://raw.githubusercontent.com/wiretastix/wiretastix-vpn/main/nftables.conf
This includes:
- Advanced ICMP handling (ICMPv6 neighbor discovery)
- Port forwarding examples
- Additional security features
- Prometheus metrics interface rules
- DNS server rules
- Multiple interface handling
Key Requirements
The wghandlers chain is essential:
chain forward {
type filter hook forward priority 0; policy drop;
jump keeptrack
jump wghandlers # Must jump to wghandlers!
oifname $wiretastix_ext_if accept
}
chain wghandlers {
# Leave empty - Wiretastix populates this
}
Why this matters:
- Wiretastix creates group-specific chains
wghandlersacts as the entry point- Traffic is routed to appropriate group chains based on source/destination IP
- Without this jump, group rules won’t apply
Table Name Configuration
By default, Wiretastix uses the table name wiretastix. If you need a different name:
# wiretastix.yaml
wireguard:
nftables-table: "custom_table_name"
Then adjust your nftables.conf:
table inet custom_table_name {
# ... your chains ...
}
Applying Base Configuration
# Load nftables configuration
sudo nft -f /etc/nftables.conf
# Enable nftables at boot
sudo systemctl enable nftables
sudo systemctl start nftables
# Verify
sudo nft list ruleset
Group-Based Rules
How Wiretastix Manages Groups
When you create rules for groups through the CLI, Wiretastix automatically:
- Creates IP sets for each group (IPv4 and IPv6)
- Populates sets with peer IPs belonging to that group
- Creates group chains with the rules you defined
- Updates
wghandlersto jump to group chains
All this happens automatically whenever:
- A peer is added or removed
- A user’s group membership changes (via OIDC refresh)
- A rule is added, modified, or deleted
- You run
rule apply
NFTables Structure
After Wiretastix processes groups, the nftables structure looks like:
table inet wiretastix {
# IP sets for each group
set set_peers4_group_engineering {
type ipv4_addr
elements = { 10.0.100.5, 10.0.100.12, 10.0.100.19 }
}
set set_peers6_group_engineering {
type ipv6_addr
elements = { fd00::5, fd00::12, fd00::19 }
}
set set_peers4_group_sales {
type ipv4_addr
elements = { 10.0.100.50, 10.0.100.51 }
}
# Group-specific chains
chain group_engineering_handler {
# Rules for engineering group
ip saddr 10.0.0.0/8 tcp dport 22 accept
ip daddr 192.168.10.0/24 accept
drop
}
chain group_sales_handler {
# Rules for sales group
ip daddr 192.168.20.0/24 tcp dport 443 accept
drop
}
# Entry point (managed by Wiretastix)
chain wghandlers {
ip saddr @set_peers4_group_engineering jump group_engineering_handler
ip6 saddr @set_peers6_group_engineering jump group_engineering_handler
ip daddr @set_peers4_group_engineering jump group_engineering_handler
ip6 daddr @set_peers6_group_engineering jump group_engineering_handler
ip saddr @set_peers4_group_sales jump group_sales_handler
ip daddr @set_peers4_group_sales jump group_sales_handler
}
}
Viewing Active Rules
# View entire wiretastix table
sudo nft list table inet wiretastix
# View only wghandlers chain
sudo nft list chain inet wiretastix wghandlers
# View specific group chain
sudo nft list chain inet wiretastix group_engineering_handler
# View IP sets
sudo nft list set inet wiretastix set_peers4_group_engineering
Managing Rules via CLI
Rule Structure
Each rule has these properties:
| Property | Description | Required | Example |
|---|---|---|---|
group | OIDC group name | Yes | engineering |
nfproto | IP version | Yes | ip4 or ip6 |
l4proto | Layer 4 protocol | No | tcp, udp, icmp |
src | Source CIDR | No | 10.0.0.0/8 |
sport | Source port | No | 1024 |
dst | Destination CIDR | No | 192.168.10.0/24 |
dport | Destination port | No | 443 |
action | Action to take | Yes | accept or drop |
Creating Rules
Example 1: Allow SSH to Internal Network
wiretastix-cli
# In the CLI
rule add group engineering nfproto ip4 l4proto tcp dst 10.0.0.0/8 dport 22 action accept
This allows the engineering group to SSH (port 22) to any server in 10.0.0.0/8.
Example 2: Allow HTTPS to Specific Server
rule add group sales nfproto ip4 l4proto tcp dst 192.168.20.50/32 dport 443 action accept
Example 3: Allow All Traffic to Subnet
rule add group admin nfproto ip4 dst 192.168.0.0/16 action accept
No protocol specified = any protocol.
Example 4: Block Outgoing SMTP
rule add group users nfproto ip4 l4proto tcp dport 25 action drop
Example 5: Allow ICMP (Ping)
rule add group monitoring nfproto ip4 l4proto icmp action accept
Example 6: IPv6 Rules
rule add group engineering nfproto ip6 l4proto tcp dst 2001:db8::/32 dport 443 action accept
Rule Application Order
Rules are evaluated in the order they were created (by rule ID) within the group chain. To implement default-deny by hand:
# Specific allows first
rule add group engineering nfproto ip4 dst 192.168.10.0/24 action accept
rule add group engineering nfproto ip4 dst 192.168.20.0/24 action accept
# Default deny last
rule add group engineering nfproto ip4 action drop
Important: Without an explicit drop rule, traffic not matching any rule will continue to subsequent chains and may be allowed by the base forward chain. This manual pattern also has a footgun: if you add another rule to the group later, it’s appended after the existing rules by creation order – meaning after your manual “default deny” rule, where it will never be reached. Prefer Group.Policy (below) over this pattern; it doesn’t have that ordering problem.
Group Policy Enforcement
Separately from individual rules, every group has a policy field (accept, drop, or none) that acts as the group’s catch-all. Unlike a manually added last-rule, it’s always applied after every one of the group’s own rules regardless of when those rules were created – there’s no ordering footgun.
accept: after the group’s specific rules, an unconditional accept catches anything they didn’t match.drop: same, but an unconditional drop – this is how you implement default-deny for a group without manually maintaining a last rule.none: no catch-all is added. Unmatched traffic falls through past the group’s chain entirely (the group makes no policy statement).
policy is a required field when creating a group – group create rejects an empty or missing value.
Because the catch-all is enforced per network family, it’s added twice internally (once for IPv4, once for IPv6) whenever policy is accept or drop.
This matters even for a brand-new group with zero rules. A group created with policy drop and no rules yet enforces that drop immediately – its chain is built specifically to carry the catch-all, not skipped just because there are no individual rules. Don’t assume an empty group is a no-op; a drop-policy group blocks all traffic for its members from the moment it’s created, and an accept-policy group allows all of it, in both cases before you’ve written a single rule.
# A deny-by-default group: peers in it get nothing until rules explicitly allow it
group create oidc contractors name "Contractors" policy drop
# An allow-by-default group: peers get everything except what rules explicitly block
group create oidc admins name "Admins" policy accept
Multiple Group Membership and Priority Order
A user’s OIDC claims can match more than one group at once, so a peer can belong to several groups simultaneously – each with its own rules and its own policy. When that happens, priority (the prio key on group create/group update) decides which group’s chain runs first for that peer’s traffic: groups are evaluated in ascending priority order, lowest number first.
This matters because policy accept/drop is a terminal verdict: whichever group’s chain the peer hits first with a non-none policy wins, and evaluation stops there – later, lower-priority groups never get a say for that traffic. policy none is the tool for a group that shouldn’t be the one to decide: it makes no catch-all statement, so evaluation continues on to the next group in priority order.
Two groups left at the same priority have no defined tie-break – this is by design, not a bug. Priority is exactly the mechanism an admin has to control ordering, so if you have overlapping groups and the outcome between them matters, give them distinct priorities and/or set policy none on whichever one shouldn’t force a decision.
# A peer might be a member of both. Contractors (prio 10) is evaluated
# first and its "drop" wins for anything its own rules don't allow --
# the broader "employees" group below never gets a chance to accept it.
group create oidc contractors name "Contractors" prio 10 policy drop
group create oidc employees name "Employees" prio 20 policy accept
Listing Rules
wiretastix-cli
# List all rules
rule list
Output:
┌────┬──────────────┬─────────┬─────────┬──────────────────┬───────┬──────────────────┬───────┬────────┐
│ # │ GROUP │ NFPROTO │ L4PROTO │ SRC │ SPORT │ DST │ DPORT │ ACTION │
├────┼──────────────┼─────────┼─────────┼──────────────────┼───────┼──────────────────┼───────┼────────┤
│ 1 │ engineering │ IPv4 │ tcp │ - │ │ 10.0.0.0/8 │ 22 │ accept │
│ 2 │ engineering │ IPv4 │ tcp │ - │ │ 192.168.10.0/24 │ 443 │ accept │
│ 3 │ engineering │ IPv4 │ - │ - │ │ - │ │ drop │
│ 4 │ sales │ IPv4 │ tcp │ - │ │ 192.168.20.0/24 │ 443 │ accept │
│ 5 │ sales │ IPv4 │ - │ - │ │ - │ │ drop │
└────┴──────────────┴─────────┴─────────┴──────────────────┴───────┴──────────────────┴───────┴────────┘
Deleting Rules
# Delete by rule ID
rule del 3
# Delete multiple rules
rule del 3 5 7
Applying Rules
After adding, modifying, or deleting rules, apply them:
rule apply
This triggers Wiretastix to:
- Flush existing group chains
- Recreate chains with updated rules
- Update IP sets with current peer IPs
- Rebuild
wghandlersjumps
Changes take effect immediately for all active connections.
rule apply is atomic. Every group’s chain rebuild is staged in memory and sent to the kernel as a single netlink batch at the end, rather than one commit per group. Either the whole batch lands, or – on any error – none of it does and the previously-active ruleset is left completely untouched; a failure partway through can’t leave some groups re-applied and others still running stale rules.
Common Use Cases
1. Developer Access to Internal Services
Scenario: Engineering team needs SSH and HTTPS to development servers (192.168.10.0/24).
# Allow SSH
rule add group engineering nfproto ip4 l4proto tcp dst 192.168.10.0/24 dport 22 action accept
# Allow HTTPS
rule add group engineering nfproto ip4 l4proto tcp dst 192.168.10.0/24 dport 443 action accept
# Allow ICMP for troubleshooting
rule add group engineering nfproto ip4 l4proto icmp dst 192.168.10.0/24 action accept
# Default deny
rule add group engineering nfproto ip4 action drop
# Apply
rule apply
2. Sales CRM Access Only
Scenario: Sales team only needs HTTPS access to CRM server (192.168.20.50).
# Allow HTTPS to CRM only
rule add group sales nfproto ip4 l4proto tcp dst 192.168.20.50/32 dport 443 action accept
# Deny everything else
rule add group sales nfproto ip4 action drop
rule apply
3. Administrator Full Access
Scenario: Admins need unrestricted access to internal networks.
# Allow all protocols to all internal networks
rule add group admin nfproto ip4 dst 10.0.0.0/8 action accept
rule add group admin nfproto ip4 dst 192.168.0.0/16 action accept
rule add group admin nfproto ip4 dst 172.16.0.0/12 action accept
# IPv6 access
rule add group admin nfproto ip6 dst fd00::/8 action accept
rule apply
4. Contractor Limited Access
Scenario: Contractors can only access specific services during business hours (implement via external firewall or time-based rules).
# Limited access to specific ports
rule add group contractors nfproto ip4 l4proto tcp dst 192.168.30.0/24 dport 80 action accept
rule add group contractors nfproto ip4 l4proto tcp dst 192.168.30.0/24 dport 443 action accept
# No SSH
# No ping
# Default deny
rule add group contractors nfproto ip4 action drop
rule apply
5. Monitoring and Metrics
Scenario: Monitoring group needs to ping all servers and access Prometheus exporters.
# Allow ICMP
rule add group monitoring nfproto ip4 l4proto icmp action accept
# Allow Prometheus node_exporter (port 9100)
rule add group monitoring nfproto ip4 l4proto tcp dst 10.0.0.0/8 dport 9100 action accept
# Allow Prometheus (port 9090)
rule add group monitoring nfproto ip4 l4proto tcp dst 10.0.0.0/8 dport 9090 action accept
# Default deny
rule add group monitoring nfproto ip4 action drop
rule apply
6. Inter-Peer Communication
Scenario: Allow peers in the same group to communicate with each other.
# Assuming VPN network is 10.0.100.0/24
rule add group engineering nfproto ip4 src 10.0.100.0/24 dst 10.0.100.0/24 action accept
# This allows peer-to-peer within the group
rule apply
7. Deny Specific Protocols
Scenario: Block SMTP to prevent spam/malware from VPN.
# Add allow rules first (see other examples)
# Block SMTP/SMTPS before default allow
rule add group users nfproto ip4 l4proto tcp dport 25 action drop
rule add group users nfproto ip4 l4proto tcp dport 587 action drop
rule add group users nfproto ip4 l4proto tcp dport 465 action drop
# Then allow other traffic
rule add group users nfproto ip4 action accept
rule apply
Automatic Rule Updates
When Rules Are Applied
Wiretastix automatically updates nftables in these scenarios:
- Peer Added: New peer IPs added to appropriate group sets
- Peer Removed: IPs removed from sets
- Peer Activated/Deactivated: Sets updated to reflect active status
- Group Membership Changes: When OIDC token refreshes with new groups
- Rule Changes: Via
rule add,rule del,rule apply - Group Enable/Disable: Group chains created/removed
- Service Restart: Full refresh on startup
Manual Refresh
To force a complete refresh:
# Via CLI
rule apply
# Or via API
curl -X POST -H "Authorization: Bearer ${TOKEN}" \
https://vpn.example.com/api/v1/rules/apply
This rebuilds all chains and sets from the database.
Monitoring Rule Changes
Check logs for rule application events:
# System journal
sudo journalctl -u wiretastix -f | grep -i "rule\|nftable"
# Look for entries like:
# "Applying nftables rules"
# "Created chain group_engineering_handler"
# "Updated set set_peers4_group_engineering with 5 IPs"
Troubleshooting
Rules Not Applied
Symptom: Created rules via CLI but traffic isn’t filtered.
Diagnosis:
# 1. Verify rule in database
rule list
# 2. Check if rule applied to nftables
sudo nft list chain inet wiretastix group_<groupname>_handler
# 3. Check wghandlers has jump
sudo nft list chain inet wiretastix wghandlers
Solutions:
# Apply rules manually
rule apply
# Check for errors
sudo journalctl -u wiretastix -n 50
Peers Not in IP Sets
Symptom: Peer connected but not in group IP set.
Diagnosis:
# Check peer group membership
wiretastix-cli
peer list
# Check IP set
sudo nft list set inet wiretastix set_peers4_group_<groupname>
Possible causes:
- Peer is inactive (
active: false) - Group is disabled (
enabled: false) - OIDC group name mismatch
Solutions:
# Activate peer
peer enable <peer-id>
# Check group
group list
# Reapply rules
rule apply
wghandlers Chain Empty
Symptom: wghandlers chain exists but has no jump rules.
Diagnosis:
sudo nft list chain inet wiretastix wghandlers
# If empty or only has comment:
Possible causes:
- No groups have rules defined
- All groups are disabled
- No active peers in any group
Solutions:
# Check groups
group list
# Check rules
rule list
# Ensure groups enabled
group enable <group-name>
# Add at least one rule per group
rule add group <groupname> nfproto ip4 action accept
# Apply
rule apply
Traffic Blocked Unexpectedly
Symptom: Traffic should be allowed by rules but is blocked.
Diagnosis:
# 1. Verify rule exists and order
rule list
# 2. Check nftables rule
sudo nft list chain inet wiretastix group_<groupname>_handler
# 3. Check if peer IP in set
sudo nft list set inet wiretastix set_peers4_group_<groupname>
# 4. Test with nftables tracing
sudo nft add rule inet wiretastix wghandlers meta nftrace set 1
sudo nft monitor trace
# Generate traffic, observe trace
# Then remove trace rule:
sudo nft delete rule inet wiretastix wghandlers handle <handle-id>
Common issues:
- Rule order (drop before accept)
- Wrong CIDR notation
- Protocol mismatch (tcp vs udp)
- Base forward chain blocking before wghandlers
Group Chain Not Created
Symptom: Group exists but no chain in nftables.
Possible causes:
- Group has no active peers
- Group is disabled
- Group has no rules
Wiretastix only creates chains for groups that have:
- At least one active peer
- At least one rule
enabled: true
Solution: Ensure all three conditions are met.
Base Configuration Conflicts
Symptom: Base nftables rules interfere with Wiretastix rules.
Example conflict:
chain forward {
type filter hook forward priority 0; policy drop;
# This drop happens BEFORE wghandlers!
ip daddr 192.168.0.0/16 drop
jump wghandlers # Never reached for 192.168.0.0/16
oifname eth0 accept
}
Solution: Order matters. jump wghandlers should be early:
chain forward {
type filter hook forward priority 0; policy drop;
jump keeptrack
jump wghandlers # Early in chain
# Base rules after
oifname eth0 accept
}
Performance Issues
Symptom: High CPU usage, slow connections with many rules.
Optimization:
Consolidate rules: Use broader CIDRs instead of many single IPs
# Instead of: # rule add ... dst 192.168.1.1/32 ... # rule add ... dst 192.168.1.2/32 ... # ... # Use: rule add group eng nfproto ip4 dst 192.168.1.0/24 action acceptUse IP sets for large lists: Nftables sets are efficient for large IP lists (Wiretastix does this automatically for peer IPs)
Remove unused groups: Disable or delete groups with no active users
Minimize rule count: Combine similar rules
Integration with External Firewall
Upstream Firewall
If Wiretastix is behind a firewall appliance:
Firewall requirements:
- Allow UDP port 51820 (WireGuard) to Wiretastix
- Allow TCP port 443 (HTTPS) to Wiretastix
- Optionally forward other ports (SSH, Prometheus)
Wiretastix handles:
- VPN peer access control
- Group-based filtering
- NAT for VPN traffic
Port Forwarding for Internal Services
You can add port forwarding in the base nftables.conf:
table ip nat {
chain prerouting {
type nat hook prerouting priority dstnat; policy accept;
# Forward external port 8080 to internal 192.168.10.50:80
iifname eth0 tcp dport 8080 counter dnat 192.168.10.50:80
}
chain postrouting {
type nat hook postrouting priority -100; policy accept;
oifname eth0 counter masquerade
}
}
# Allow forwarded traffic in filter table
table inet wiretastix {
chain forward {
type filter hook forward priority 0; policy drop;
jump keeptrack
jump wghandlers
# Allow forwarded port
iifname eth0 oifname eth1 ip daddr 192.168.10.50 tcp dport 80 accept
oifname eth0 accept
}
}
API Management
Rules can also be managed via API (useful for automation):
List Rules
curl -H "Authorization: Bearer ${TOKEN}" \
https://vpn.example.com/api/v1/rules
Create Rule
curl -X PUT \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"group-id": "engineering",
"nf-proto": 4,
"l4-proto": "tcp",
"dst": "192.168.10.0/24",
"dst-port": 443,
"action": "accept"
}' \
https://vpn.example.com/api/v1/rules
Delete Rule
curl -X DELETE \
-H "Authorization: Bearer ${TOKEN}" \
https://vpn.example.com/api/v1/rules/5
Apply Rules
curl -X POST \
-H "Authorization: Bearer ${TOKEN}" \
https://vpn.example.com/api/v1/rules/apply
Best Practices
1. Default Deny Policy
Always end group rules with an explicit drop:
# Allow specific traffic
rule add group users nfproto ip4 dst 192.168.0.0/16 action accept
# Default deny
rule add group users nfproto ip4 action drop
2. Least Privilege
Grant only necessary access:
# Bad: Too permissive
rule add group contractors nfproto ip4 action accept
# Good: Specific access
rule add group contractors nfproto ip4 l4proto tcp dst 192.168.30.10/32 dport 443 action accept
rule add group contractors nfproto ip4 action drop
3. Document Rules
Use descriptive group names and maintain documentation:
# Create groups for different environments
group create oidc prod-dev name "prod-developers" policy drop
group create oidc staging-dev name "staging-developers" policy drop
# Different rules per environment
rule add group prod-dev nfproto ip4 dst 10.10.0.0/16 action accept
rule add group staging-dev nfproto ip4 dst 10.20.0.0/16 action accept
4. Test Before Production
Test rules in a staging environment:
# Test group
rule add group test-group nfproto ip4 dst 192.168.99.0/24 action accept
rule apply
# Verify connectivity
# Then replicate to production groups
5. Monitor Rule Effectiveness
# Add counters to important rules (manual nftables)
sudo nft add rule inet wiretastix group_engineering_handler ip daddr 192.168.10.0/24 counter accept
# Check counters
sudo nft list chain inet wiretastix group_engineering_handler -a
6. Regular Audits
Periodically review rules:
# List all rules
rule list
# Check for:
# - Unused rules (old projects)
# - Overly permissive rules
# - Missing default deny
# - Duplicate rules
7. Backup Rules
Rules are stored in the database and backed up automatically, but export for reference:
# Export current rules
wiretastix-cli rule list > rules-$(date +%Y%m%d).txt
# Or via API
curl -H "Authorization: Bearer ${TOKEN}" \
https://vpn.example.com/api/v1/rules > rules.json
Limitations and Considerations
1. No Time-Based Rules
Wiretastix doesn’t support time-based rules directly. For time-based access:
- Use OIDC IdP to control group membership by time
- Or add time-based rules in base nftables.conf
2. Rule Complexity
Very complex rules (many conditions) should be split:
# Instead of one complex rule, use multiple simpler rules
rule add group eng nfproto ip4 l4proto tcp dst 192.168.10.0/24 dport 22 action accept
rule add group eng nfproto ip4 l4proto tcp dst 192.168.10.0/24 dport 443 action accept
3. Port Ranges
Nftables supports port ranges, but CLI currently accepts single ports. For ranges, add manually:
# Add via API or directly to nftables
sudo nft add rule inet wiretastix group_engineering_handler tcp dport 8000-8999 accept
(This will be overwritten on next rule apply)
4. Stateful vs Stateless
Wiretastix rules are stateless within group chains. Connection tracking happens in keeptrack:
- Return traffic allowed by
ct state {established,related} accept - You only need to allow NEW connections in group rules
- This is why you don’t need to create “allow return SSH traffic” rules
Summary
Wiretastix’s nftables integration provides a powerful, flexible, and automatic firewall management system:
You manage:
- Base nftables configuration (server security)
- NAT rules
- Port forwarding
- General firewall policies
Wiretastix manages:
- Group-based chains and rules
- IP sets for group members
- Dynamic updates on peer/group changes
- Integration between groups and chains
Key takeaways:
- Base configuration must have
wghandlerschain and jump inforwardchain - Rules are created via CLI/API and automatically applied to nftables
- Rules are group-based and automatically associated with peers
- Changes take effect immediately after
rule apply - Always use default deny for security
For more information, see:
- Security Best Practices - Security guidelines
- FAQ & Troubleshooting - Common issues
- Configuration Reference - NFTables settings
- Initial Setup Tutorial - Setting up groups