As a VyOS evangelist, maintainer, and more, I’ve been meaning to write a simple series of “how-to” guides for VyOS for a while. Sure, there are plenty of guides out there, but I think a lot of them fall short in demonstrating WHY you are entering specific commands.
VyOS is capable, but it’s much more helpful if you can fully understand what it’s doing.
This initial guide will walk through the basic setup steps in replacing something like pfSense or some other consumer router with a simple and secure system running VyOS.
This is also going to be a very very long post, so buckle in!
Who is this For
Anybody that wants to use VyOS of course!
The nice thing about running VyOS is that if you set up it, and understand WHAT it’s doing, then you’ve actually learned something about networking.
Does something like pfSense work?
Sure, but it also doesn’t teach you much about what’s actually going on. And the knowledge learned in VyOS will easily translate to almost any other vendor like Cisco, Arista, and more. At that point, the concepts are the same, you are just learning the different dialects.
VyOS really doesn’t take much in resources.
8GB of storage and 2-4GB of RAM will be overkill for most basic setups.
CPU-wise, even small Pentium Silver CPUs can handle gigabit and beyond, even over VPN . Anything like an i3/i5 or a Xeon won’t break a sweat except in all but the most demanding scenarios.
If you virtualize, it can be helpful to set up a test environment. This could consist of a simple:
- WAN Network. For testing this could be your existing LAN network.
- A new “LAN” Network. For testing this could just be a separate port group or bridge, and it wouldn’t even need an uplink.
- A simple VM with a GUI (or without), to run some testing.
If virtualization isn’t an option, VyOS can run on almost any device that is x86_64. I’ve run it on everything from:
- NUCs with single NICs and USB/USB-C NICs.
- WYSE 5070/3040 Thin Clients.
- A variety of Dells, including R710s/R620s/R630s.
- Anything Supermicro from 1U to 4U devices.
Finally, for this guide, I’ll be working with two NICs.
One is a WAN, connected to my current LAN. I’ll be creating a “network inside a network”. The second will be our new “LAN”. This is separate from my existing LAN so I can pretend like it’s a second private network. These interfaces can be anything:
- Physical NICs.
- Virtual NICs from ESXi, Proxmox, etc.
The first step is to grab yourself a copy of the installer ISO.
If you want access to the LTS version, it requires self-building (an easy process), contributing, or a subscription. I highly recommend contributing, as even writing or cleaning up some documentation will get you access to the LTS prebuilt versions.
Note that for these guides, I will be using a recent version of rolling. This is important as some configuration nodes have changed locations and format between 1.3+ and the existing LTS versions (DHCP and IPv6 RAs are two things that come to mind).
Installation is trivial:
- Burn ISO to CD/DVD/USB stick, or boot ISO via remote management (iDrac, iLo, IPMI)
- Login with
- Answer the install steps
- Reboot and remove installation media
Once installed, you’ll be staring at the login screen. Login with
vyos and the password you set up during install:
Before you go any further, you need to make a decision. You need to pick out the subnet (or later subnets) where your network will live. Or, if you are converting over your existing network, just reuse it.
These should be RFC1918 addresses. You generally want a /24, which is 254 usable addresses.
So, there are three main groups of these private addresses you can choose from:
Yare any number between 0 and 255. For the last number, 0 would be your “network” address, and 255 would be your broadcast address. You could then assign all your hosts to 1-254.
172.X.Y.1-254, in this case
Xwould be between 16 and 31, and
Ycould be 0 to 255.
Xis between 0 and 255.
Configuring the LAN and Remote access
After the subnet is chosen, the first step is to get the router on the LAN and accessible via SSH. This makes it much easier to configure, as you are no longer tethered to a keyboard/monitor, VM console, can copy/paste, etc.
- Enter configure mode
- Add address to the correct interface
- Commit and save
The first step is to enter configure mode. This allows you to make changes to the system configuration. Type
configure. VyOS also supports shortcuts and tab completion, so typing
conf<TAB> will do the same thing.
The prompt will change to include
#, and the
 line will appear to designate that you are in configure mode.
Next, you need to add your LAN IP. You can check your interfaces by typing
run show interfaces. This tells VyOS to show all the interfaces in operational mode (the mode you were in before you typed
In my case,
eth1 is attached to my LAN here. I’m going to use the subnet from above,
10.32.0.0/24. I prefer to use
.1 for my routers, but you can use any IP in that range.
There are two methods to assign it once in
conf mode. Either with the full path, or by drilling-down.
configure set interfaces ethernet eth1 address 10.32.0.1/24 set interfaces ethernet eth1 description LAN commit save
configure edit interfaces ethernet eth1 set address 10.32.0.1/24 set description LAN commit save
Committing makes the configuration active, and saving saves it to disk so it will persist on a reboot.
You can show your work with
show interfaces and
run show interfaces
Set up DHCP
Now that that router has a LAN IP, it’s time to connect your laptop/desktop/etc up to it.
You can assign it a static IP in the chosen subnet (
10.32.0.10/24 for example), but I imagine you are also going to want to assign a DHCP range for automatic configuration of clients.
- Enter configure mode
- Set up DHCP ranges
- commit and save
Let’s talk about the following config.
We are going to make two DHCP ranges, and leave some holes. This would allow us to assign the IP addresses between
.49 for static or other uses, as well as
While this is a non-standard usage, it demonstrates the capabilities. Many people would just have a single range.
set service dhcp-server shared-network-name LAN subnet 10.32.0.0/24 range 0 start 10.32.0.50 set service dhcp-server shared-network-name LAN subnet 10.32.0.0/24 range 0 stop 10.32.0.125 set service dhcp-server shared-network-name LAN subnet 10.32.0.0/24 range 1 start 10.32.0.200 set service dhcp-server shared-network-name LAN subnet 10.32.0.0/24 range 1 stop 10.32.0.250
Some other important config options follow.
You want to tell the DHCP server to hand out the router’s IP address as the default gateway and DNS. This will make it so (eventually), your LAN devices will have DNS and routing to the Internet:
set service dhcp-server shared-network-name LAN subnet 10.32.0.0/24 dns-server 10.32.0.1 set service dhcp-server shared-network-name LAN subnet 10.32.0.0/24 default-router 10.32.0.1
The final step before we can access the router over SSH is to actually enable SSH:
set service ssh port 22 commit save
At this point you ought to be able to hook up a LAN client, and verify that you have an IP, gateway, and DNS.
This is a fairly stock Debian VM I set up. As you can see, my IP is in one of my DHCP ranges, and my DNS and default route are the router’s IP.
This is on Linux, but the same thing could be confirmed on Windows or MacOS:
From there, you should be able to ssh into the router with the username
vyos and password you set up during install:
show configuration (in op mode), should show you the work done so far. VyOS also comes with a few defaults, like NTP servers configured.
NAT & DNS
The next important duty for a router and firewall is to be able to NAT. NAT allows all your private LAN devices to access the Internet.
For this setup, it’s important to identify which network interface will eventually be your WAN interface, even though it’s not configured yet.
- As before, enter configuration mode.
- Set up a source NAT rule to target our LAN or LAN subnets.
- Define the outgoing WAN interface on the rule.
- Set the translation type of the rule to
The type of NAT we will be using is called
SOURCE NAT. This type of NAT is going to have three components:
- Target all traffic from our LAN or LANs…
- … when the traffic is going out to the Internet through this outgoing interface…
- … Change the IP address from the LAN IP to the WAN IP
To do this:
set nat source rule 100 source address '10.32.0.0/24' set nat source rule 100 outbound-interface 'eth0' set nat source rule 100 translation address masquerade commit save
In the above example, the
100 is an arbitrary number (between 1-9999). The
eth0 is my eventual WAN interface.
masquerade translates the internal LAN IP to your public WAN IP.
Once we set up our WAN interface, we’ll be able to type
show nat source rules in op mode, or
run show nat source rules in conf mode to run the op mode command, it will be clear what’s happening.
The next step is to set up our VyOS instance as for DNS. This will allow you to use local DNS and caching instead of your ISP’s, but also eventually will allow you run custom DNS and hosts.
- Enter config mode
- Set the DNS Listen Address
- Set the subnets we are allowing from
- Set the cache size to 0
- commit and save
set service dns forwarding listen-address '10.32.0.1' set service dns forwarding allow-from '10.32.0.0/24' set service dns forwarding cache-size '0' commit save
As mentioned, this accomplishes three things.
- It tells VyOS to listen for DNS requests on its LAN IP,
- It limits requests from your LAN subnet.
- Finally, it sets the cache size to 0. This is good to start out with to make sure everything is working, but later you can bump it up to speed up multiple requests for the same sites.
There is one more consideration to be made. As configured, your DNS server will run in “recursor” mode. This means it will take responsibility for fully resolving DNS on its own. This may be a bad thing for a number of reasons:
- It leaks your IP to potential undesirables.
- It’s almost always slower, as you don’t get to benefit from the caches of a large service like CloudFlare or Google.
It’s quite simple to set up in forwarding mode, meaning when you make a DNS request, you end up asking an upstream resolver.
In the following example, we’ll be using CloudFlare and Google:
set service dns forwarding name-server 22.214.171.124 set service dns forwarding name-server 126.96.36.199 set service dns forwarding name-server 188.8.131.52 set service dns forwarding name-server 184.108.40.206 commit save
One final step is to set the DNS for VyOS itself. Everything we’ve done so far has just set up VyOS to be a DNS server for your clients.
This will be the DNS that is used, for example, when you do a VyOS update, ping or traceroute from VyOS, etc.
The easiest thing to do if you’ve been following this guide, is just to use the DNS server you set up above:
set system name-server 10.32.0.1 commit save
This is also another spot where if you wanted to use Google, CloudFlare, or AD-DNS, you could plug in that IP:
Alternatively, you call tell VyOS to use the DNS servers that it received from your WAN DHCP server with:
set system name-servers-dhcp eth0
If you’ve made it this far, congrats! We are almost there!
This section will cover the creation of a zone-based firewall, which is far superior to the default method of attaching firewalls to interfaces.
The reason it is superior is simple. It’s a bit more hassle to set up, but it’s far easier to manage on an ongoing basis, plus, you start thinking about firewalling as flows of information from interface to interface.
- Enter configuration mode
- Create a firewall to allow all LAN traffic.
- Create firewall to allow all LAN traffic to access VyOS itself.
- Create a firewall to protect the router itself from WAN.
- Create a firewall to protect LAN devices from WAN.
- Create LOCAL/LAN zones.
- Assign appropriate interfaces to zones.
- Commit and save
For as complex as firewalling seems, it’s actually pretty simple when you break it down.
A firewall tracks connection “states” to determine what is and is not allowed. This is where packets are originating and going to, ports involved, types of traffic like TCP/UDP/ICMP, and more.
We are going to build a very simple firewall that assumes that we want to block everything externally, and allow everything from LAN.
So let’s dig right into it.
First, create a firewall that will allow our LAN to access everything. This is a setup that would mimic what most consumer routers do:
conf set firewall name LAN-WAN default-action accept set firewall name LAN-LOCAL default-action accept commit save
LAN-WAN and the
LAN-LOCAL can be arbitrarily named anything. I use this naming scheme because as mentioned above, it’s better to think about firewalls as controlling the flow of information through the router, and these names are self-documenting.
LOCAL is a specific VyOS designation that means “this router”. When you are attaching the firewall in the zones, LOCAL will be what you use to control traffic destined to the firewall itself.
As should be obvious, we are just allowing everything. But you can set whatever rules you wanted.
LAN-WAN would generally remain pretty open as it would be uncommon to block your own access to the Internet, but
LAN-LOCAL might contain rules to maybe allow only specific devices access to manage the VyOS router.
Also note that we are just creating the firewalls here. They don’t become active until you attach them to the zones.
As mentioned, the
LOCAL zone is traffic destined for the VyOS router itself.
In most cases, it will have a similar ruleset to the LAN one above, as most people want their router to have full access to the Internet and their LAN devices:
conf set firewall name LOCAL-WAN default-action accept set firewall name LOCAL-LAN default-action accept commit save
WAN zone is where we are actually going to do most of our work.
The basic goal here will be two things. To block all access to the router itself, and to provide basic setup and template for future things like port forwarding to our LAN.
When you start moving data to and from the Internet, that’s when you need to start worrying about the state tracking I mentioned before.
For both LOCAL and LAN traffic, we’ll be setting up what’s known as a “stateful firewall”.
In stateful firewalling, there are three main states to worry about:
- New – Traffic in a
NEWstate is the first packet from a destination to a source. Allowing or denying this packet ultimately determines whether the traffic will be allowed.
- Established – Once traffic from
NEWhas been allowed, the subsequent packets are marked as
ESTABLISHED. This is essentially traffic that has already been allowed by other rules. This is another basic requirement for a working stateful firewall.
- Related – This means that this is traffic that is somehow related to already allowed traffic. Also required.
As mentioned, the
WAN-LOCAL firewall is traffic destined for the VyOS router itself. In the future, this will be where you allow traffic, say to your WireGuard port for VPN.
The first rule we want to build is to allow all
RELATED traffic. So we’ll:
- Create the WAN-LOCAL firewall.
- Set the default policy on the firewall to drop everything.
- Create a rule to accept specific traffic for rule.
- Set the match for the rule to our established and related states.
- Set a description for ease of use later.
set firewall name WAN-LOCAL default-action drop set firewall name WAN-LOCAL rule 5 action accept set firewall name WAN-LOCAL rule 5 state established enable set firewall name WAN-LOCAL rule 5 state related enable set firewall name WAN-LOCAL rule 5 description "Allow EST/Related Traffic" commit save
The next rule we want on is to allow ICMP. Many people like to block this, but not me. I’ll defer to ShouldIBlockICMP.com on this.
- Create a new rule matching ICMP
- Match the state of
NEW. This is what actually matches the unknown traffic to allow
- Allow the traffic
- Commit and save
set firewall name WAN-LOCAL rule 20 protocol icmp set firewall name WAN-LOCAL rule 20 state new enable set firewall name WAN-LOCAL rule 20 action accept commit save
And you can see that the firewall is created (but still not attached to any interfaces), by doing the
op mode command
For now, the
WAN-LAN firewall is identical to the
WAN-LOCAL. In the future, this is where you will allow your port forward rules, or other traffic you want to send to your LAN devices, so it’s helpful to break it out beforehand.
As before, we create the firewall, set it to drop by default, allowed EST/RELATED, and allow ICMP, which won’t do anything now, but could be helpful in the future:
set firewall name WAN-LAN default-action drop set firewall name WAN-LAN rule 5 action accept set firewall name WAN-LAN rule 5 state established enable set firewall name WAN-LAN rule 5 state related enable set firewall name WAN-LAN rule 5 description "Allow EST/Related Traffic" set firewall name WAN-LAN rule 20 protocol icmp set firewall name WAN-LAN rule 20 state new enable set firewall name WAN-LAN rule 20 action accept
Don’t forget you can dive down into levels as in the following example:
Finally! We have our firewalls set up and ready to deploy.
WAN and Zones
If you’ve been paying attention, we still don’t have one VERY important piece to this puzzle. We still don’t have WAN access!
Of course I did this to protect your router during the initial setup phase. Until you have firewalls ready to deploy, you probably don’t want to be kicking your brand new VyOS install out on the open Internet.
Zones are easily one of my favorite parts of VyOS, and something that in my opinion, puts it lightyears ahead of other firewall solutions.
Especially as your firewalling needs grow, zones just make it so EASY. As I sort of touched on, zones are a bit more work initially, but save you MUCH more time in the future.
The naming scheme as I’ve outlined above should be helpful here when creating our firewall zones. It basically says
So let’s run through the whole thing.
- Set the default action for the zone. This should always be drop to cover yourself in case you miss something.
- Apply the “For traffic from X zone to current zone, attach Y firewall”
- Add the interfaces that are part of this zone
- Repeat for all zones
So what does this look like for the LAN:
- In this example we are working on the LAN zone
- We drop everything by default
- We assign the
WAN-LANfirewall to traffic from any interface in the below
- Similarly for the
LOCAL-LAN. This is traffic from the VyOS instance itself to LAN hosts.
- We put
eth1in our LAN zone.
set zone-policy zone LAN default-action drop set zone-policy zone LAN from WAN firewall name WAN-LAN set zone-policy zone LAN from LOCAL firewall name LOCAL-LAN set zone-policy zone LAN interface eth1
Repeat all steps for the
LOCAL zone. The major difference here is the
local-zone designation. As I’ve mentioned a few times,
LOCAL is a special designation that means “this firewall”, so you don’t attach interfaces:
set zone-policy zone LOCAL local-zone set zone-policy zone LOCAL from LAN firewall name LAN-LOCAL set zone-policy zone LOCAL from WAN firewall name WAN-LOCAL set zone-policy zone LOCAL default-action drop
Finally, the WAN zone is basically the same as the LAN zone. The only major change you should notice is that I just changed the firewall names and interface name:
set zone-policy zone WAN from LAN firewall name LAN-WAN set zone-policy zone WAN from LOCAL firewall name LOCAL-WAN set zone-policy zone WAN interface eth0 set zone-policy zone WAN default-action drop
If you were like me, you might have tried committing between steps. Unfortunately, if you don’t set up everything at once, you’ll quickly discover that zones are interdependent on one another. This happens because I’ve created the LAN zone, but the referenced WAN and LOCAL zones don’t exist yet.
Show your work
Hopefully, if you’ve done everything correctly, you should see all your zone policies set up under the
op mode command
run show zone-policy. This view should make it obvious which traffic is flowing through what firewall:
Finally, here we are.
Setting up your WAN. If you’ve made it this far, congrats. You are basically 1 or 2 commands away from having a working router and firewall!
There are multiple ways to get a WAN address. For simplicity’s sake, I’ll just cover two of them here, static and DHCP assignment. For something like PPPoE, you’ll need a few more steps.
DHCP is when your router asks your ISP’s servers for what it should use for its IP address and routing information. This is accomplished with one simple command (well, four if you add a description to the interface, and commit and save):
set interfaces ethernet eth0 address dhcp set interfaces ethernet eth0 description WAN commit save
You can verify that the setup is complete with the
op mode commands
run show interfaces and
run show ip route. (I have some debug variables set, so ignore the extra output:
In the above output,
10.21.21.57 is the IP address I was assigned via DHCP. The
show ip route verifies that I have a default route.
Static IPs just skip the automatic configuration. It’s up to your ISP how this is configured, but usually it’s an extra step, manually applying your default route.
So to duplicate my above DHCP configuration:
set interfaces ethernet eth0 address 10.21.21.57/24 set protocols static route 0.0.0.0/0 next-hop 10.21.21.1 commit save
As you can see in the following screenshot, I forgot the exact format, so I hit my
<TAB> button to get hints:
Check your work
Assuming nothing has gone wrong, you should be able to verify everything with the
op mode command
ping. So let’s hit Google with 4 pings:
run ping www.google.com count 4
If all goes well, you should see a response:
So wow, this post turned into a bit of a novel. Hopefully if you’ve made it this far, your LAN clients now have accessible Internet. From a client, you should be able to ping google:
Obviously there are a lot of basic topics I haven’t covered yet. But I wanted to lay out and explain the basic setup first.
Future editions will feature:
- Port Forwarding.
- Hairpin NAT (this goes hand-in-hand with the first).
- VPNs, especially WireGuard
- How routing works when you have VPNs.
- Some potential hardening tactics.
- Other advanced topics like BGP/OSPF.