VyOS Firewall and NAT Configuration: Practical Examples - 夜莺博客

VyOS Firewall and NAT Configuration: Practical Examples

VyOS is the open-source router platform that many engineers reach for when a Linux box has outgrown iptables - it keeps the operational model of a real router (commit/rollback, show commands, hierarchical config) while running on commodity hardware. This guide configures a VyOS 1.4 edge device from blank to production: interfaces and zones, a stateful firewall policy set, source NAT for outbound traffic, destination NAT for inbound services, and the verification and rollback commands that make changes safe.

Base configuration and the commit model

configure
set system host-name edge-r1
set system name-server 1.1.1.1
set interfaces ethernet eth0 address 203.0.113.2/29
set interfaces ethernet eth1 address 10.10.0.1/24
set interfaces ethernet eth1 description LAN
set protocols static route 0.0.0.0/0 next-hop 203.0.113.1
set service ssh port 22
set service ssh listen-address 10.10.0.1
commit
save
compare        ! show uncommitted changes
rollback 1     ! go back one config revision
show configuration commands | save /config/backup-2026.conf

Nothing takes effect until commit, and commit-confirm 5 schedules an automatic rollback unless you confirm within five minutes - always use it when changing management access or routing on a remote box.

Two settings make that commit model genuinely useful in production. Keep a longer revision history so rollback can reach further back than the previous change, and archive every commit off-box so a dead router still leaves a recoverable configuration behind:

set system config-management commit-revisions 100
set system config-management commit-archive location "scp://backup@10.10.0.9/configs/edge-r1"
set system time-zone Asia/Shanghai
set service ntp server 1.1.1.1
set service ntp server 0.pool.ntp.org
commit
save

Correct time is not cosmetic. The commit log is the change history you will read at 2 a.m. during an incident, and time skew makes it unreadable; the same skew breaks certificate validation on the box. Put the timezone and NTP servers in the first commit instead of a later cleanup.

Firewall policies

set firewall ipv4 name LAN-OUT default-action drop
set firewall ipv4 name LAN-OUT rule 10 action accept
set firewall ipv4 name LAN-OUT rule 10 state established enable
set firewall ipv4 name LAN-OUT rule 10 state related enable
set firewall ipv4 name LAN-OUT rule 20 action accept
set firewall ipv4 name LAN-OUT rule 20 protocol tcp_udp
set firewall ipv4 name LAN-OUT rule 20 destination port 53
set firewall ipv4 name LAN-OUT rule 30 action accept
set firewall ipv4 name LAN-OUT rule 30 protocol icmp

set firewall ipv4 name WAN-IN default-action drop
set firewall ipv4 name WAN-IN rule 10 action accept
set firewall ipv4 name WAN-IN rule 10 state established enable
set firewall ipv4 name WAN-IN rule 10 state related enable
set firewall ipv4 name WAN-IN rule 20 action accept
set firewall ipv4 name WAN-IN rule 20 protocol icmp
set firewall ipv4 name WAN-IN rule 20 icmp type-name echo-request
set firewall ipv4 name WAN-IN rule 20 description "allow ping"

set interfaces ethernet eth1 firewall in name LAN-OUT
set interfaces ethernet eth0 firewall in name WAN-IN
commit

Write the drop default first and add explicit accepts - the opposite order produces an evaluation you will misread six months later. VyOS evaluates rules in numeric order and stops at the first match, so leave gaps of ten for later insertions.

If the same two state lines appear in every policy you write, move them into the global state policy instead. VyOS then accepts established and related traffic before any named rule is evaluated, which keeps each rule set short enough to review on one screen:

set firewall global-options state-policy established action accept
set firewall global-options state-policy related action accept
set firewall global-options state-policy invalid action drop
set system conntrack table-size 262144
commit

Watch the conntrack table on a busy edge. When it fills, new sessions are dropped while the forwarding table and interface counters still look healthy - the failure appears as random connection timeouts. show conntrack statistics and show conntrack table ipv4 show how close a router is to that ceiling, and the table size is the knob that buys headroom.

Interface groups and reusable objects

A "zone" in VyOS is only a naming convention; what makes it real is the interface group. Define each role once and reference the group from policies instead of repeating literal interface names on every rule:

set firewall group interface-group LAN interface eth1
set firewall group interface-group LAN interface eth2
set firewall group interface-group WAN interface eth0
set firewall group address-group MGMT-HOSTS address 10.10.0.0/24
set firewall group port-group WEB-PORTS port 80
set firewall group port-group WEB-PORTS port 443

set firewall ipv4 name LAN-OUT rule 40 action accept
set firewall ipv4 name LAN-OUT rule 40 protocol tcp_udp
set firewall ipv4 name LAN-OUT rule 40 destination group port-group WEB-PORTS
set firewall ipv4 name LAN-OUT rule 40 source group address-group MGMT-HOSTS
set firewall ipv4 name LAN-OUT rule 40 log enable

set system syslog global facility all level notice
commit

When a second LAN interface is added, exactly one line changes. Address and port groups do the same job for values that appear in many rules: a new management subnet is one group edit rather than a search across the whole configuration. Logging with log enable also writes matched traffic to syslog, which is the evidence you need when someone insists a flow is blocked - show log firewall names the rule number that dropped it.

Source and destination NAT

! SNAT: LAN behind the WAN address
set nat source rule 100 outbound-interface name eth0
set nat source rule 100 source address 10.10.0.0/24
set nat source rule 100 translation address masquerade

! DNAT: publish an internal web server on port 443
set nat destination rule 200 inbound-interface name eth0
set nat destination rule 200 protocol tcp
set nat destination rule 200 destination port 443
set nat destination rule 200 translation address 10.10.0.50
set nat destination rule 200 translation port 443

! hairpin: internal clients using the public name
set nat destination rule 300 inbound-interface name eth1
set nat destination rule 300 destination address 203.0.113.2
set nat destination rule 300 protocol tcp
set nat destination rule 300 destination port 443
set nat destination rule 300 translation address 10.10.0.50
commit

Prefer masquerade on dynamic WAN addresses and a specific translation address when you have a static block - it keeps traces readable. Remember that DNAT alone does not permit traffic: the WAN-IN policy must still accept the flow, which is the single most common VyOS first-deployment mistake.

Static one-to-one NAT and port ranges use the same rule syntax. Drop the port from translation to map a whole host, and use a range where a service occupies consecutive ports:

! one-to-one NAT for a mail server that owns a public address
set nat source rule 200 outbound-interface name eth0
set nat source rule 200 source address 10.10.0.25
set nat source rule 200 translation address 203.0.113.4

! forward a range of ports to the same range inside
set nat destination rule 210 inbound-interface name eth0
set nat destination rule 210 protocol tcp
set nat destination rule 210 destination port 5000-5010
set nat destination rule 210 translation address 10.10.0.60
set nat destination rule 210 translation port 5000-5010
commit

Source and destination NAT are evaluated independently, in numeric order within each type. Keep the numbering blocks aligned with your firewall rule blocks so a single number identifies the same service in both places, and an audit of "what reaches the mail server" becomes a grep rather than an investigation.

Port forwarding recipes for common services

Every DNAT rule is the same skeleton with different protocol, port and target. These four cover the majority of real edge deployments:

! HTTPS to an internal load balancer
set nat destination rule 200 description "web - nginx"
set nat destination rule 200 inbound-interface name eth0
set nat destination rule 200 protocol tcp
set nat destination rule 200 destination port 443
set nat destination rule 200 translation address 10.10.0.50
set nat destination rule 200 translation port 443

! SSH published on a non-standard port, forwarded to port 22 inside
set nat destination rule 220 inbound-interface name eth0
set nat destination rule 220 protocol tcp
set nat destination rule 220 destination port 2222
set nat destination rule 220 translation address 10.10.0.10
set nat destination rule 220 translation port 22

! UDP DNS to an internal resolver
set nat destination rule 230 inbound-interface name eth0
set nat destination rule 230 protocol udp
set nat destination rule 230 destination port 53
set nat destination rule 230 translation address 10.10.0.53
set nat destination rule 230 translation port 53
commit

Each forwarded service still needs a matching WAN-IN accept rule with the same protocol and port. A mismatch between the NAT rule and the firewall rule is by far the most common cause of a service that is "configured but unreachable", and it is invisible in show nat destination rules - only the counters tell the truth. When the service must also be reachable from inside, add the hairpin rule; without it, internal clients that resolve the public name time out because the router never sends the traffic back into the LAN.

Verification: prove the rules are matching

show interfaces
show ip route
show firewall
show nat source rules
show nat destination rules
show nat source statistics
monitor traffic interface eth0 filter "tcp port 443"
show log firewall
show configuration commands | grep 'firewall ipv4 name WAN-IN'

Confirm the rule counters are incrementing rather than assuming the configuration is live. For troubleshooting, monitor traffic provides a tcpdump view with the VyOS filter syntax, and NAT statistics show which rule translated the flow.

Three more checks belong in the same routine, because they explain failures that counters alone do not:

show conntrack statistics                 ! table pressure and drops
run show interfaces ethernet eth0 brief   ! errors, drops, CRCs
ping 203.0.113.1 count 5                  ! upstream reachability
show ip route 8.8.8.8                     ! which path is actually in use
traceroute 8.8.8.8                        ! first hop that answers

Interface error counters tell you when the problem is not policy at all. A rising drop or CRC count on the WAN interface points at a duplex or cabling fault, and no firewall rule will fix it.

Troubleshooting the four usual failures

Symptom Most likely cause What to check
No outbound access from the LAN Source NAT rule missing, or matching the wrong outbound interface show nat source statistics, then show nat source rules
Outbound request works, return traffic is dropped No established/related accept in the LAN policy Rule 10 in LAN-OUT, or the global state policy
Published service unreachable from the internet DNAT configured but no matching WAN-IN accept rule Counters on both rules; monitor traffic on the WAN
Internal clients cannot reach the public hostname Hairpin DNAT rule missing on the LAN interface DNAT rule whose inbound-interface is the LAN, not the WAN

Work through the table in order rather than in parallel. The four failures have different causes, and guessing between them is how an afternoon disappears.

Automating and reviewing policy changes

VyOS configuration is structured text, which makes it a good fit for review and generation. Two habits pay off immediately: archive every commit to Git so the router's history survives the router, and generate the policy from a template or script rather than hand-editing each box.

# capture a reviewable diff before and after a change
ssh edge-r1 "show configuration commands" > before.conf
# ... apply the change ...
ssh edge-r1 "show configuration commands" > after.conf
diff -u before.conf after.conf

# on the router: group related statements into a reviewable config script
set system config-scripts name allow-ssh
set system config-scripts name allow-ssh script "/config/scripts/allow-ssh.sh"
commit

Ansible's vyos_config module and the VyOS HTTP API reach the same configuration tree, so the choice between them is organisational rather than technical. If your team already reviews YAML pull requests, drive the router from them; if it is managed by hand, keep a scripted baseline in Git and apply deltas against it so rollback always has a known-good target.

Operations that keep an edge device boring

Keep the running configuration in Git (VyOS supports config archival), keep the firewall rule set generated from a template rather than hand-edited on each box, and set up two independent management paths before enabling a WAN-facing rule that could lock you out. If you are comparing platforms, our guides on nftables firewalls, Cisco IOS NAT and FRRouting BGP cover the same problems on other stacks; WireGuard site-to-site is the natural next project for a VyOS edge.

原文链接:https://docs.vyos.io/en/rolling/configuration/firewall/index.html