Windows Server 2019 – Building a routing table

How to configure nginx for wordpress

When you hear the term routing table, it is easy to pass that off as something the network folks need to deal with, something that is configured within the network routers and firewalls. It doesn’t apply to the server admins, right? Networking servers together has been made pretty easy for us by only requiring an IP address, subnet mask, and default gateway, and we can instantly communicate with everything inside the rest of our network. While there is indeed a lot of networking magic going on under the hood that has been provided to us by networking equipment and network administrators, it is important to understand how routing inside Windows works because there will be some cases when you need to modify or build out a routing table right on a Windows Server itself.

Multi-homed servers

Running multi-homed servers is a case where you would certainly need to understand and work with a local Windows routing table, so let’s start here. If you think this doesn’t apply to you because you’ve never heard of multi-homed before, think again. Multi-homed is just a funny-looking word meaning your server has more than one NIC. This could certainly be the case for you, even if you are a small shop that doesn’t have a lot of servers. Often, Small Business or Essentials Servers have multiple network interfaces, separating internal traffic from internet traffic. Another instance of a multi-homed server would be a remote access server that provides DirectAccess, VPN, or proxy capabilities at the edge of your network. Yet another reason to be interested and understand multi-homing is Hyper-V servers. It is very common for Hyper-V servers to have multiple NICs, because the VMs that are running on that server might need to tap into different physical networks within your organization.

Now that we have established what a multi-homed server is, you might still be wondering why we are discussing this. If I have more than one NIC, don’t I simply configure each NIC individually inside Windows, giving each one an IP address, just like I would for any NIC on any server? Yes and no. Yes, you configure an IP address on each NIC, because it needs that for the identification and transport of packets on the network. No, you do not set up all of the NICs on your server in the same way. There is one critical item that you need to keep in mind and adhere to in order to make traffic flow properly on your multihomed server.

Only one default gateway

This is the golden ticket. When you multi-home a server by having multiple NICs, you can only have one default gateway. One for your entire server. This means you will have one NIC with a default gateway, and one or many NICs that do NOT have a default gateway inside their TCP/IP settings. This is extremely important. The purpose of a default gateway is to be the path of last resort. When Windows wants to send a packet to a destination, it browses over the local routing tableyes, there is a routing table even if you haven’t configured it or ever looked at itand checks to see whether a specific, static route exists for the destination subnet where this packet needs to go. If a route exists, it shoots the packet out that route and network interface to the destination. If no static route exists in the routing table, it falls back onto using the default gateway, and sends the traffic to that default gateway address. On all single NIC servers, the default gateway is a router that is designated with all of the routing information for your network, and so the server simply hands it to the router, and the router does the rest of the work.

When we have multiple NICs on a Windows Server, we cannot give each one a default gateway because it will confuse traffic flow from your server. It will be a crapshoot as to which default gateway traffic flows toward with every network transmission. I have helped many people troubleshoot servers in the field with exactly this problem. They needed to use their server as a bridge between two networks, or to have the server plugged into multiple different networks for whatever reason, and are now struggling because sometimes the traffic seems to work, and sometimes it doesn’t. We start looking through the NIC properties only to discover that every NIC has its own default gateway address in the TCP/IP properties. Bingo, that’s our problem. The system is completely confused when it tries to send out traffic, because it doesn’t know which gateway it needs to use at what times.

If you have ever tried adding default gateways to more than one NIC on the same server, you are probably familiar with the warning prompt that is displayed when you do this. Let’s give it a try. I have added another NIC to one of my servers, and have IP settings configured on just one of the NICs. Now I will add a new IP address, subnet mask, and default gateway onto my second NIC. When I click on the OK button to save those changes, I am presented with the following popup:

This is one of those warnings that is easy to misread because of its slightly cryptic nature, but you get the essence of it: proceed at your own risk! And then what do most admins do at this point? Simply click through it and save the changes anyway. Then the routing problems start. Maybe not today, but perhaps the next time you reboot that server, or maybe three weeks down the road, but at some point your server will start to send packets to the wrong destinations and cause you trouble.

Building a route

So what is our answer to all of this? Building a static routing table. When you have multiple NICs on a server, thereby making it multi-homed, you must tell Windows which NIC to use for what traffic inside the routing table. This way, when network traffic needs to leave the server for a particular destination, the routing table is aware of the different directions and paths that the traffic will need to take in order to get there, and will send it out accordingly. You will still be relying on routers to take the traffic the rest of the way, but getting the packets to the correct router by sending them out via the proper physical NIC is key to making sure that traffic flows quickly and appropriately from your multi-homed server.

Now that we understand why the routing table is important and conceptually how we need to use it, let’s dig in and add a couple of routes on my dual-NIC server. We will add a route using the Command Prompt, and we will also add one using PowerShell, since you are able to accomplish this task from either platform, but the syntax used is different depending on which you prefer.

Adding a route with the Command Prompt

Before we can plan our new route, we need to get the lay of the land for the current networking configuration on this server. It has two NICs: one is plugged into my internal network and one is plugged into my DMZ that faces the internet. Since I can only have one default gateway address, it goes onto the DMZ NIC because there is no way that I could add routes for every subnet that might need to be contacted over the internet. By putting the default gateway on my DMZ NIC, the internal NIC does not have a default gateway, and is very limited in what it can contact at the moment. The internal subnet that I am physically plugged into is, so I can currently contact anything in this small network from through This is known as an on-link route; since I am plugged directly into this subnet, my server automatically knows how to route traffic inside this subnet. But I cannot contact anything else at the moment through my internal NIC, because the routing table knows nothing about the other subnets that I have inside my internal network. For example, I have an additional subnet,, and there are some servers running within this subnet that I need to be able to contact from this new server. If I were to try to contact one of those servers right now, the packets would shoot out from my DMZ NIC, because the routing table on my server has no idea how to deal with 192.168 traffic, and so it would send it toward the default gateway. The following is the general syntax of the route statement we need to follow in order to make this traffic flow from our server into the new subnet:


Before we can type out our unique route statement for adding the 192.168 network, we need to do a little detective work and figure out what we are going to use in these fields. The following is a breakdown of the parts and pieces that are required to build a route statement:

  • -p: This makes the command persistent. If you forget to put -p in the route add statement, this new route will disappear the next time you reboot the server. Not good.
  • SUBNET_ID: This is the subnet we are adding; in our case it is
  • SUBNET_MASK: This is the subnet mask number for the new route,
  • GATEWAY: This one is a little confusing. It is very common to think it means you need to enter the gateway address for the new subnet, but that would be incorrect. What you are actually defining here is the first hop that the server needs to hit in order to send out this traffic. Or in other words, if you had configured a default gateway address on the internal NIC, what would that address be? For our network it is
  • INTERFACE_ID: Specifying an interface ID number is not entirely necessary to create a route, but if you do not specify it, there is a chance that your route could bind itself to the wrong NIC and send traffic out in the wrong direction. I have seen it happen before, so I always specify a NIC interface ID number. This is typically a one- or two-digit number that is the Windows identifier for the internal NIC itself. We can figure out what the interface ID number is by looking at the route print command:

At the top of route print you see all of the NICs in a system listed. In our case, the internal NIC is the top one in the list; I identified it by looking at the MAC address for this NIC from the output of an ipconfig /all command. As you can see, my internal NIC’s interface ID number is 5. So in my route add statement, I am going to use IF 5 at the end of my statement to make sure my new route binds itself to that internal physical NIC.

The following is our completed route add statement:

route add -p mask if 5  

If you now run a route print command, you can see our new route listed in the Persistent Routes section of the routing table, and we can now send packets into that subnet from this new server. Whenever our server has traffic that needs to go into the 192.168.16.x subnet, it will send that traffic out via the internal NIC, toward the router running on The router then picks up the traffic from there and brings it into the 192.168 subnet:

Deleting a route

Occasionally, you may key in a route statement incorrectly. The best way to handle this is to simply delete the bad route, and then re-run your route add statement with the correct syntax. There are possibly other reasons why you might need to delete routes every now and then, so you’ll want to be familiar with this command. Deleting routes is much simpler than adding new ones. All you need to know is the subnet ID for the route that you want to remove, then simply route delete <SUBNET_ID>. For example, to get rid of our route that we created while we were working inside the Command Prompt, I would simply issue this command:

route delete  

Adding a route with PowerShell

Since PowerShell is king when it comes to most command-line-oriented tasks inside Windows Server, we should accomplish the same mission from this interface as well. You can utilize the same route add command from inside the PowerShell prompt and that will work just fine, but there is also a specialized cmdlet that we can use. Let’s utilize New-NetRoute to add yet another subnet to our routing table; this time we are going to add The following is a command we can utilize:

New-NetRoute -DestinationPrefix "" -InterfaceIndex 5 -NextHop  

You can see that the structure is similar, but a little bit friendlier. Instead of having to type the word mask and specify the whole subnet mask number, you can use the slash method to identify the subnet and mask within the same identifier. Also, where before we were specifying the gateway, which is always a little confusing, with the New-NetRoute cmdlet, we instead specify what is called the NextHop. This makes a little bit more sense to me.

Where we previously utilized route print in order to see our full routing table, the PowerShell cmdlet to display that table for us is simply Get-NetRoute:

Comments are closed.