{"id":220,"date":"2017-09-23T17:15:57","date_gmt":"2017-09-23T22:15:57","guid":{"rendered":"https:\/\/codemonkeyden.com\/blog\/?p=220"},"modified":"2023-11-10T23:02:56","modified_gmt":"2023-11-11T05:02:56","slug":"gnu-linux-router-ubiquiti-erl","status":"publish","type":"post","link":"https:\/\/codemonkeyden.com\/?p=220","title":{"rendered":"Run a GNU\/Linux Router with Ubiquiti ERL"},"content":{"rendered":"<h2>Background<\/h2>\n<p>The Ubiquiti EdgeRouter Lite (ERL) is a bit different than your typical SOHO &#8220;router&#8221;, which is a combination of a router, a switch, and an access point. I have had some pretty bad experiences with these all-in-one products. The firmware provided with all-in-one routers tends to be very buggy. The idea behind the ERL is that it focuses specifically on the router portion of the gateway. If you have more than one wired client, you will also need a switch. If you don&#8217;t have the need for VLANs, you can pick up an inexpensive unmanaged switch. You may also need to purchase a wireless access point if you want wifi.\u00a0However, if you are replacing an all-in-one router, you can reconfigure it to run in access point mode.<\/p>\n<h5>Port Usage<\/h5>\n<p>The ERL has 3 ports which can be used in many different configurations. One possibility is to support balancing between two WAN connections.\u00a0In my use case, I used the additional port for a DMZ. The DMZ could alternatively be implemented logically with a single port using VLANs, but this requires a switch with VLAN support. It is possible to configure it such that two ports belong to the same network, but I don&#8217;t recommend this configuration because it will hurt network performance. If not implementing a DMZ or using multiple WANs, \u00a0I recommend using one port for a wired LAN and one port for a wireless LAN.<\/p>\n<h2>Initial Configuration<\/h2>\n<p>Modify the gui to use non-standard ports. This allows us to port forward\u00a0the default 80 and 443 ports to a webserver hosted in the DMZ.<\/p>\n<pre>set service gui http-port 7080\nset service gui https-port 7443<\/pre>\n<p>Adjust the hostname and time zone to meet your needs.<\/p>\n<pre>set system host-name\u00a0<strong>myrouter<\/strong>\nset system time-zone America\/Chicago\n<\/pre>\n<p>One issue is that by default the DNS server will resolve the router&#8217;s hostname as 127.0.1.1. This may be undesirable if trying to ssh into the router from within the LAN or DMZ. To resolve this issue, you can override the IP returned when resolving the hostname of the router itself.<\/p>\n<pre>set system ip override-hostname-ip 192.168.102.1<\/pre>\n<h5>Initial Firewall Setup<\/h5>\n<p>Next, perform the initial firewall setup.<\/p>\n<pre>edit firewall\nset all-ping enable\nset broadcast-ping disable\nset ipv6-receive-redirects disable\nset ipv6-src-route disable\nset ip-src-route disable\nset log-martians enable\nset receive-redirects disable\nset send-redirects enable\nset source-validation disable\nset syn-cookies enable\ntop<\/pre>\n<h5>Allow-all Firewall<\/h5>\n<p>Create allow-all firewall, which allows through all connections.<\/p>\n<pre>edit firewall name allow-all\nset default-action accept\nset rule 1 action drop\nset rule 1 description 'Drop invalid state'\nset rule 1 log enable\nset rule 1 state invalid enable\ntop<\/pre>\n<h5>Allow-Established Firewall<\/h5>\n<p>Create the allow-est-drop-inv firewall, which allows through only established connections.<\/p>\n<pre>edit firewall name allow-est-drop-inv\nset default-action drop\nset enable-default-log\nset rule 1 action accept\nset rule 1 description 'Allow established connections'\nset rule 1 state established enable\nset rule 1 state related enable\nset rule 2 action drop\nset rule 2 description 'Drop invalid state'\nset rule 2 log enable\nset rule 2 state invalid enable\ntop<\/pre>\n<h2>Configure LAN Interface<\/h2>\n<p>eth2 is configured as my LAN interface with the static IP 192.168.101.1 and acts as the gateway for the 192.168.101.0\/24 subnet<\/p>\n<pre>edit interfaces ethernet eth2\nset address 192.168.101.1\/24\nset description LAN\nset duplex auto\nset speed auto\ntop<\/pre>\n<h5>Configure LAN DHCP<\/h5>\n<p>Next we setup the authoritative DHCP server for the LAN. We want it to make the LAN\u00a0port on the ERL the default route and DNS server for the LAN subnet. You specify the range of dynamic IP pools. The range of valid hosts is .1 to .254 but we are already using .1 for the router. Since my home network is small, I reserved the .2 through .99 IPs for use as static mappings. The lease 86400\u00a0setting indicates\u00a0a 24 hour\u00a0DHCP lease duration.<\/p>\n<pre>edit service dhcp-server shared-network-name LAN\nset authoritative enable\nset subnet 192.168.1.0\/24 default-router 192.168.101.1\nset subnet 192.168.1.0\/24 dns-server 192.168.101.1\nset subnet 192.168.1.0\/24 lease 86400\nset subnet 192.168.1.0\/24 start 192.168.101.100 stop 192.168.101.254\ntop<\/pre>\n<p>Next we configure a static mapping for each host in the DMZ using their MAC address.<\/p>\n<pre>edit service dhcp-server shared-network-name LAN subnet 192.168.1.0\/24\nset static-mapping myhost1 ip-address 192.168.101.2\nset static-mapping myhost1 mac-address 'ab:cd:ef:34:56:78'\nset static-mapping myhost2 ip-address 192.168.101.3\nset static-mapping myhost2 mac-address 'ab:cd:ef:56:78:90'\ntop<\/pre>\n<h5>Configure LAN DNS<\/h5>\n<p>Next we specify the desired alias and IP address for each host in the LAN.<\/p>\n<pre>edit system static-host-mapping\nset host-name myhost1.lan alias myhost1\nset host-name myhost1.lan inet 192.168.101.2\nset host-name myhost2.lan alias myhost2\nset host-name myhost2.lan inet 192.168.101.3\ntop<\/pre>\n<h2>Configure LAN firewall<\/h2>\n<p>First we create the zone policy for LAN to drop all traffic by default.<\/p>\n<pre>edit zone-policy zone LAN\nset interface eth2\nset default-action drop\ntop<\/pre>\n<p>Then we create the zone policy for local such that all traffic from local is allowed, but limited traffic to local is allowed.<\/p>\n<pre>edit zone-policy zone local\nset local-zone\nset default-action drop\nset from LAN firewall name lan-local\nset from local firewall name allow-all\ntop<\/pre>\n<h5>lan-local firewall<\/h5>\n<p>Create the lan-local firewall such that only\u00a0established connections, ICMP\/DNS\/DHCP traffic, and SSH\/HTTPS for router maintenance are allowed.<\/p>\n<pre>edit firewall name lan-local\nset default-action drop\nset enable-default-log\nset rule 1 action accept\nset rule 1 description 'Allow established connections'\nset rule 1 state established enable\nset rule 1 state related enable\nset rule 2 action drop\nset rule 2 description 'Drop invalid state'\nset rule 2 log enable\nset rule 2 state invalid enable\nset rule 3 action accept\nset rule 3 description 'Allow ICMP'\nset rule 3 protocol icmp\nset rule 4 action accept\nset rule 4 description 'Allow SSH\/HTTPS'\nset rule 4 destination port 22,7443\nset rule 4 protocol tcp\nset rule 5 action accept\nset rule 5 description 'Allow DNS'\nset rule 5 destination port 53\nset rule 5 protocol tcp_udp\nset rule 6 action accept\nset rule 6 description 'Allow DHCP'\nset rule 6 destination port 67,68\nset rule 6 protocol udp\ntop<\/pre>\n<h2>Configure WAN Interface<\/h2>\n<p>eth0 is configured as my WAN interface and uses DHCP to acquire a dynamic ISP from my ISP via the cable modem<\/p>\n<pre>edit interfaces ethernet eth0\nset address dhcp\nset description WAN\nset duplex auto\nset speed auto\ntop<\/pre>\n<p>To make this work properly, we need to use NAT to share the single WAN IP address with all hosts in our DMZ and LAN.<\/p>\n<pre>edit service nat rule 5010\nset description 'Masquerade for WAN'\nset outbound-interface eth0\nset type masquerade\ntop<\/pre>\n<p>Next, I configure the ERL as a forwarding DNS server. I prefer to use the google public DNS servers. Alternatively, you can use your ISP&#8217;s DNS servers, but at least my ISP, I have found them to be less reliable.<\/p>\n<pre>edit service dns forwarding\nset cache-size 150\nset listen-on eth2\nset listen-on eth1\nset name-server 8.8.8.8\nset name-server 8.8.4.4\ntop<\/pre>\n<h2>Configure LAN Firewall<\/h2>\n<p>Setup the zone policy for the DMZ, allowing all traffic from local and LAN, but only\u00a0limited traffic back from WAN and DMZ.<\/p>\n<pre>edit zone-policy zone WAN\nset interface eth0\nset default-action drop\nset from local firewall name allow-all\nset from LAN firewall name allow-all\ntop<\/pre>\n<p>Set firewall for WAN to LAN to only allow established connections.<\/p>\n<pre>edit zone-policy zone LAN\nset from WAN firewall name allow-est-drop-inv\ntop<\/pre>\n<p>Set firewall for WAN to local to wan-lan, which only allows established connections and SSH\/HTTPS for remote router maintenance.<\/p>\n<pre>edit zone-policy zone local\nset from WAN firewall name wan-local\ntop<\/pre>\n<h5>wan-local firewall<\/h5>\n<p>Create the wan-local firewall, such that only established connections and SSH\/HTTPS (for remote router\u00a0maintenance)\u00a0are allowed.<\/p>\n<pre>edit firewall name wan-local\nset default-action drop\nset enable-default-log\nset rule 1 action accept\nset rule 1 description 'Allow established connections'\nset rule 1 state established enable\nset rule 1 state related enable\nset rule 2 action drop\nset rule 2 description 'Drop invalid state'\nset rule 2 log enable\nset rule 2 state invalid enable\nset rule 3 action accept\nset rule 3 description 'Allow SSH\/HTTPS'\nset rule 3 destination port 22,7443\nset rule 3 protocol tcp\ntop<\/pre>\n<h2>Configure DMZ Interface<\/h2>\n<p>The configuration for the DMZ is almost identical to that for the LAN.<\/p>\n<p>eth1 is configured as my DMZ interface with the static IP 192.168.102.1 and acts as the gateway for the 192.168.102.0\/24 subnet<\/p>\n<pre>edit interfaces ethernet eth1\nset address 192.168.102.1\/24\nset description DMZ\nset duplex auto\nset speed auto\ntop<\/pre>\n<h5>Configure DMZ DHCP<\/h5>\n<p>Next we setup the authoritative DHCP server for the DMZ. We want it to make the DMZ port on the ERL the default route and DNS server for the DMZ subnet. You specify the range of dynamic IP pools. The range of valid hosts is .1 to .254 but we are already using .1 for the router. Since my home network is small, I reserved the .2 through .99 IPs for use as static mappings. The lease 86400\u00a0setting indicates\u00a0a 24 hour\u00a0DHCP lease duration.<\/p>\n<pre>edit service dhcp-server shared-network-name DMZ\nset authoritative enable\nset subnet 192.168.102.0\/24 default-router 192.168.102.1\nset subnet 192.168.102.0\/24 dns-server 192.168.102.1\nset subnet 192.168.102.0\/24 lease 86400\nset subnet 192.168.102.0\/24 start 192.168.2.100 stop 192.168.102.254\ntop<\/pre>\n<p>Next we configure a static mapping for each host in the DMZ using their MAC address.<\/p>\n<pre>edit service dhcp-server shared-network-name DMZ subnet 192.168.102.0\/24\nset static-mapping myhost3 ip-address 192.168.102.2\nset static-mapping myhost3 mac-address 'ab:cd:ef:12:34:56'\nset static-mapping myhost4 ip-address 192.168.102.3\nset static-mapping myhost4 mac-address 'ab:cd:ef:23:45:67'\ntop<\/pre>\n<h5>Configure DMZ DNS<\/h5>\n<p>Next we specify the desired alias and IP address for each host in the LAN and DMZ.<\/p>\n<pre>edit system static-host-mapping\nset host-name myhost3.dmz alias myhost3\nset host-name myhost3.dmz inet 192.168.102.2\nset host-name myhost4.dmz alias myhost4\nset host-name myhost4.dmz inet 192.168.102.3\ntop<\/pre>\n<h5>Port Forwarding<\/h5>\n<p>Depending on what services you are hosting within your DMZ, you will need to setup port forwarding to allow external clients to reach your server(s).<\/p>\n<p>For example, if your server with IP 192.168.102.2 is listening for connections on the standard SSH port of 22, you can forward connections to port 2222 to the server.<\/p>\n<pre>edit service nat rule 3\nset description 'Port forward 2222 to 22'\nset destination port 2222\nset inbound-interface eth+\nset inside-address address 192.168.102.2\nset inside-address port 22\nset log disable\nset protocol tcp\nset type destination\ntop<\/pre>\n<h2>Configure DMZ firewall<\/h2>\n<p>Setup the zone policy for the DMZ, allowing all traffic from local, but allowing only limited traffic from the LAN and WAN.<\/p>\n<pre>edit zone-policy zone DMZ\nset interface eth1\nset default-action drop\nset from LAN firewall name lan-dmz\nset from WAN firewall name wan-dmz\nset from local firewall name allow-all\ntop<\/pre>\n<p>Set firewall for\u00a0DMZ to WAN to only allow all.<\/p>\n<pre>edit zone-policy zone WAN\nset from DMZ firewall name allow-all\ntop<\/pre>\n<p>Set firewall for\u00a0DMZ to LAN to only allow established connections.<\/p>\n<pre>edit zone-policy zone LAN\nset from DMZ firewall name allow-est-drop-inv\ntop<\/pre>\n<p>Set firewall for\u00a0DMZ to local\u00a0to dmz-local to only allow established connections.<\/p>\n<pre>edit zone-policy zone local\nset from DMZ firewall name dmz-local\ntop<\/pre>\n<h5>dmz-local firewall<\/h5>\n<p>Create dmz-local firewall such that only ICMP\/DNS\/DHCP traffic, established connections, and SSH\/HTTPS (for router maintenance) are allowed.<\/p>\n<pre>edit firewall name dmz-local\nset default-action drop\nset enable-default-log\nset rule 1 action accept\nset rule 1 description 'Allow established connections'\nset rule 1 state established enable\nset rule 1 state related enable\nset rule 2 action drop\nset rule 2 description 'Drop invalid state'\nset rule 2 log enable\nset rule 2 state invalid enable\nset rule 3 action accept\nset rule 3 description 'Allow ICMP'\nset rule 3 protocol icmp\nset rule 4 action accept\nset rule 4 description 'Allow SSH\/HTTP\/HTTPS'\nset rule 4 destination port 22,7443\nset rule 4 protocol tcp\nset rule 5 action accept\nset rule 5 description 'Allow DNS'\nset rule 5 destination port 53\nset rule 5 protocol tcp_udp\nset rule 6 action accept\nset rule 6 description 'Allow DHCP'\nset rule 6 destination port 67,68\nset rule 6 protocol udp\ntop<\/pre>\n<h5>lan-dmz Firewall<\/h5>\n<p>Create lan-dmz firewall such that only ICMP traffic, NetBIOS\/SSH\/SMB\/HTTPS to a specific host, and established connections\u00a0are allowed.<\/p>\n<pre>edit firewall name lan-dmz\nset default-action drop\nset enable-default-log\nset rule 1 action accept\nset rule 1 description 'Allow established connections'\nset rule 1 state established enable\nset rule 1 state related enable\nset rule 2 action drop\nset rule 2 description 'Drop invalid state'\nset rule 2 log enable\nset rule 2 state invalid enable\nset rule 3 action accept\nset rule 3 description 'Allow ICMP'\nset rule 3 protocol icmp\nset rule 4 action accept\nset rule 4 description 'Allow SSH\/SMB\/HTTPS'\nset rule 4 destination address 192.168.102.2\nset rule 4 destination port 22,445,443\nset rule 4 protocol tcp\nset rule 5 action accept\nset rule 5 description 'Allow NetBIOS'\nset rule 5 destination address 192.168.102.2\nset rule 5 destination port 137,138,139\nset rule 5 protocol tcp_udp\ntop<\/pre>\n<h5>wan-dmz Firewall<\/h5>\n<p>Create wan-dmz firewall such that only established connections and SSH\/HTTPS traffic to a specific host are allowed.<\/p>\n<pre>edit firewall name wan-dmz\nset default-action drop\nset enable-default-log\nset rule 1 action accept\nset rule 1 description 'Allow established connections'\nset rule 1 state established enable\nset rule 1 state related enable\nset rule 2 action drop\nset rule 2 description 'Drop invalid state'\nset rule 2 log enable\nset rule 2 state invalid enable\nset rule 3 action accept\nset rule 3 description 'Allow SSH\/HTTPS'\nset rule 3 destination address 192.168.102.2\nset rule 3 destination port 22,443\nset rule 3 log disable\nset rule 3 protocol tcp\ntop<\/pre>\n<h2>Configure Hairpinning<\/h2>\n<p>A common issue you may encounter is if a host within your LAN uses the public IP address of your router to reach a service hosted within your DMZ, then you need to setup what is known as hairpinning (or loopback NAT). The following commands may be used for accessing a webserver via HTTPS within your DMZ from your LAN using your public IP address. Note that the destination address and port reflect the values after port forwarding\u00a0rules have been applied.<\/p>\n<pre>edit service nat rule 5011\nset description 'MASQ for hairpin'\nset destination address 192.168.102.0\/24\nset destination port 443\nset log disable\nset outbound-interface eth1\nset protocol tcp\nset source address 192.168.102.0\/24\nset type masquerade\ntop<\/pre>\n<h2>Setup Dynamic DNS<\/h2>\n<p>If you are hosting any services from your home network, it is important to know your public IP address. However, one common problem is that many residential ISPs don&#8217;t offer static public IP addresses (or only offer them with an expensive monthly charge). Thus, the ISP instead assigns you a dynamic public IP address that may change over time. One way to overcome this is to use a dynamic DNS service which periodically updates a DNS record with your new IP address.<\/p>\n<p>If you do not have a static public IP address, I highly recommend using dynamic DNS to ensure you always know the public IP address of your router. The easiest and cheapest way to accomplish this is to \u00a0sign up for an account on duckdns.org for free. The ERL can then automatically keep your IP address up-to-date using the dyndns2 protocol. Once signed up, you just need to replace the values for host-name and password listed in bold below.<\/p>\n<pre>edit service dns dynamic interface eth0 service custom-duckdns\nset host-name <strong>myhostname<\/strong>\nset login nouser\nset password <strong>12345678-1234-1234-1234-123456789012<\/strong>\nset protocol dyndns2\nset server www.duckdns.org\ntop<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Background The Ubiquiti EdgeRouter Lite (ERL) is a bit different than your typical SOHO &#8220;router&#8221;, which is a combination of a router, a switch, and an access point. I have had some pretty bad experiences with these all-in-one products. The firmware provided with all-in-one routers tends to be very buggy. The idea behind the ERL [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":357,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2],"tags":[6],"class_list":["post-220","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-netadmin","tag-edgerouter"],"_links":{"self":[{"href":"https:\/\/codemonkeyden.com\/index.php?rest_route=\/wp\/v2\/posts\/220","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/codemonkeyden.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/codemonkeyden.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/codemonkeyden.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/codemonkeyden.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=220"}],"version-history":[{"count":1,"href":"https:\/\/codemonkeyden.com\/index.php?rest_route=\/wp\/v2\/posts\/220\/revisions"}],"predecessor-version":[{"id":497,"href":"https:\/\/codemonkeyden.com\/index.php?rest_route=\/wp\/v2\/posts\/220\/revisions\/497"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/codemonkeyden.com\/index.php?rest_route=\/wp\/v2\/media\/357"}],"wp:attachment":[{"href":"https:\/\/codemonkeyden.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=220"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/codemonkeyden.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=220"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/codemonkeyden.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=220"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}