Basic Raspberry Pi Home Wifi Router

The Goal of This Post:

This post is an extension to Jacob Salema’s Guide that was picked up by Lifehacker. My main issue with his post is that he refers to the end result as a wireless router, which is not entirely accurate. This device is not meant to be internet-facing and is really more of a wireless/ethernet bridge with the configurations provided.

My goal here was to extend what was provided in his initial post and make it suitable for placing a Raspberry Pi directly behind a cable modem and fully exposed to the internet.

image kindly borrowed from adafruit


  • Raspberry Pi B (gen 2 model) any Raspberry Pi could potentially work here though
  • Edimax EW-7811Un
  • Short piece of Ethernet (to connect to cable modem)
  • Power Adapter and cord for Pi
  • SD card with Raspbian installed
  • (Optional) USB Keyboard and HDMI Monitor to access the PI. All of these steps can be performed over SSH with a little creativity however.


The Raspberry Pi’s performance is limited by the USB throughput of the WLAN adapter; which on the Raspberry Pi is a USB2.0 hub limited to a theoretical maximum of 480mbps, so you’ll never be able to pull gigabit ethernet here but this will get the job done for small sites. However if you have really crappy broadband like I do in this location the chokepoint will be the crappy broadband and not the Raspberry Pi.

I have maxed out my crappy broadband connection with the following performance results:

A BLAZING — 2.78mbps download
A SIMILARLY BLAZING — 1.28mbps upload

I repeated the same tests using a top-notch Lenovo X1 Gen3 laptop and got the exact same results so there is no lag using the raspberry pi here (for this crappy broadband connection). Since my broadband is so crappy here I’m using 802.11G wifi which won’t choke anything.

Note: I probably wouldn’t trust this for anything over 10mbps. I think the Raspberry Pi 2 with 802.11n wifi could handle a standard 40mbps connection based on some of the numbers I’m seeing here.

1). Required Installs:

Perform these first before any of the other steps.

sudo apt-get update -y
sudo apt-get install rfkill zd1211-firmware hostapd hostap-utils iw dnsmasq bridge-utils -y


2). Interfaces Configuration (/etc/network/interfaces):

Modify the interfaces file (/etc/network/interfaces) as shown below.

allow-hotplug wlan0
allow-hotplug eth0

auto lo
iface lo inet loopback

auto eth0
iface eth0 inet dhcp
auto wlan0
iface wlan0 inet static

3). DNSmasq Configuration (/etc/dnsmasq.conf):

Modify the DNSmasq configuration file to look exactly like what you see below.

Feel free to modify your domain.

4). HostAPD Configuration (/etc/hostapd/hostapd.conf):

Modify the configuration file for hostapd to have the following content.

Notice we’re using the “hw_mode=g” option here this is because my limited internet connection couldn’t support max throughput of a wifi-N connection so there would be minimal benefit. If you’re interested in N and have a Raspberry Pi2 and a faster internet connection it may make sense to enable that in your scenario.

Also feel free to modify the SSID to whatever you like and modify the password too, you’ll need at least 8 characters for the password. The channel can also be set to any value between 1-14 (1,6,11,14 are common in the USA)


5). HostAPD Default Configuration (/etc/default/hostapd):

Modify the defaults file for hostapd (/etc/default/hostapd) to have the same DAEMON_CONF line. The type of quotes used to surround the /etc/hostapd/hostapd.conf file are mission critical; if you use the wrong kind of quotes, hostapd will not start. You can debug the start of hostapd with the command “hostapd -d /etc/hostapd/hostapd.conf” which puts it into debugging mode.

# Defaults for hostapd initscript
# See /usr/share/doc/hostapd/README.Debian for information about alternative
# methods of managing hostapd.
# Uncomment and set DAEMON_CONF to the absolute path of a hostapd configuration
# file and hostapd will be started during system boot. An example configuration
# file can be found at /usr/share/doc/hostapd/examples/hostapd.conf.gz

# Additional daemon options to be appended to hostapd command:-
# -d show more debug messages (-dd for even more)
# -K include key data in debug messages
# -t include timestamps in some debug messages
# Note that -B (daemon mode) and -P (pidfile) options are automatically
# configured by the init.d script and must not be added to DAEMON_OPTS.

6). Reboot the Pi

Reboot the Pi to apply the interfaces config, start the hostapd daemon, start dnsmasq daemon. After the reboot you should see your new wireless SSID being broadcast and you should be able to login to it too with your provided password. At this point we need to proceed with the IP tables configuration to setup routing and PAT (port address translation).

7). Enable NAT and Routing Non-Persistently

Execute the following commands to enable NAT and routing for this particular session (we will make these settings persistent across reboots in steps 9 and 10).

#Enable Routing
sudo sysctl -w net.ipv4.ip_forward=1

#Apply the NAT/PAT config 
sudo iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

Routing allows the Pi to move (or “route”) packets between the two interfaces (Wlan0 and Eth0). Making the Pi a Router allows packets which come in on the Wlan interfaces to be forwarded through the Pi and out the Eth0 port.

NAT stands for Network Address Translation. In this case we’re technically performing PAT or Port Address Translation because we are aggregating the connections and streams of multiple downstream/client IP addresses across a single public IP address using different source ports. As a result packets will be re-written as they pass through a NAT router to be sourced from the public IP address of the NAT router. This re-write hides the original source IP address of the client which generated the traffic. In order to keep track of which stream should be returned to which client, the NAT router keeps a table that maps the Egress destination port to an client IP and source port. This table is called a NAT translation table. You can view the content of the Translation table at any time with the following command:

cat /proc/net/ip_conntrack

8). IP Tables Configuration:

IPtables is a program which interacts with the networking stack in the Linux kernel and tells the kernel how to handle incoming network traffic. There are all kinds of customizations that can be made to an internet facing router. What I show below are pretty basic and generally recognized as safe defaults.

Apply the default config by pasting the following commands into the command line on your device:

#allow incoming traffic from the localhost
sudo iptables -A INPUT -i lo -j ACCEPT
#explicitly allow all icmp/ping traffic
sudo iptables -A INPUT -p icmp -m icmp --icmp-type any -j ACCEPT
#explicitly allow all traffic that is already established
sudo iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
#Allow new traffic only from the local/WLAN network
sudo iptables -A INPUT -i wlan0 -m state --state NEW -j ACCEPT
#Drop all other new traffic
sudo iptables -A INPUT -p tcp -m tcp ! --tcp-flags FIN,SYN,RST,ACK SYN -m state --state NEW -j DROP<
#Drop all fragments
sudo iptables -A INPUT -f -j DROP 
# Drop XMAS packets
sudo iptables -A INPUT -p tcp --tcp-flags ALL ALL -j DROP
# Drop NULL packets
sudo iptables -A INPUT -p tcp --tcp-flags ALL NONE -j DROP
#allow our dns traffic 
sudo iptables -A INPUT -i wlan0 -p udp -m udp --sport 53 -j ACCEPT
#log everything else that is about to get dropped. 
sudo iptables -A INPUT -j LOG --log-prefix "IPTABLES Dropped: " --log-level 7 
#drop everything else that has made it this far down and not matched. 
sudo iptables -A INPUT -j DROP

You can see the presently applied iptables rules using the “iptables-save” command with sudo.

pi@raspberrypi:~ $ sudo iptables-save
# Generated by iptables-save v1.4.21 on Thu Dec 24 17:37:34 2015
:PREROUTING ACCEPT [7039:855804]
:INPUT ACCEPT [1138:80267]
:OUTPUT ACCEPT [1167:81793]
# Completed on Thu Dec 24 17:37:34 2015
# Generated by iptables-save v1.4.21 on Thu Dec 24 17:37:34 2015
:FORWARD ACCEPT [444346:360889024]
:OUTPUT ACCEPT [4390:510099]
-A INPUT -i lo -j ACCEPT
-A INPUT -p icmp -m icmp --icmp-type any -j ACCEPT
-A INPUT -i wlan0 -m state --state NEW -j ACCEPT
-A INPUT -p tcp -m tcp ! --tcp-flags FIN,SYN,RST,ACK SYN -m state --state NEW -j DROP
-A INPUT -p tcp -m tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG NONE -j DROP
-A INPUT -i wlan0 -p udp -m udp --sport 53 -j ACCEPT
-A INPUT -j LOG --log-prefix "IPTABLES Dropped: " --log-level 7
# Completed on Thu Dec 24 17:37:34 2015

Once you’ve setup the rules you’d like, and you’ve tested that they behave as expected, proceed to step 8 to save the IP tables rules.

9). Make the IPtables Settings Persistent

During the installation of the iptables-persistent program it will ask you if you want to save the presently applied rules, select YES.

sudo apt-get install iptables-persistent -y

Once the rules are saved, they can be edited at the /etc/iptables/rules.v4 (for normal IPv4 traffic). If you’re testing your iptables changes by applying the rules directly using the iptables syntax in step 7 then as you make changes, they can be made persistent by writing the output of the “iptables-save” command directly to the rules.v4 file like so.

sudo iptables-save > /etc/iptables/rules.v4

10). Enable Routing Persistently

The following change allows the Raspi Router to move packets from one interface (wlan0) to another (eth0) by making the device a router.

sudo sed -i 's/#net.ipv4.ip_forward=1/net.ipv4.ip_forward=1/g' /etc/sysctl.conf

11 thoughts on “Basic Raspberry Pi Home Wifi Router”

  1. I got a chuckle out of it, but “Short piece of Ethernet” should probably be “A short Ethernet cable”

    Looks good tho. A good next step might be integrating either the Pi-Hole or Adafruit’s (out of date) Adblocking access point via Pi.


  2. Hi, thank you for the write-up. I’ve followed yours from Jacob’s original post, as like you said, his wasn’t a router per se. Some issues I encountered with your post:

    . Not sure why you have the ‘driver=rtl871xdrv’ in the hostapd.conf. That doesn’t correspond to your wlan0.

    . The ‘sudo iptables -A POSTROUTING -o eth0 -j MASQUERADE’ fails with a ‘iptables: No chain/target/match by that name’ error.

    . You didn’t specify how to ‘apply [iptables] default config with the following commands’, so I just copy/pasted them into the console, then run ‘sudo iptables-save’ afterward. I assume this is correct.

    I’m presently stuck on the POSTROUTING error. I’ve re-checked all my entries for typos, but unfortunately don’t yet know enough of the linux environment to extricate myself from what seems to be a simple error. Please advise, if you would. Thanks in advance.

    I should state I’m running Jessie on a RPi2, which I’ve just started exploring. All packages have been updated/upgraded via apt-get.



    1. Hoang — That was my mistake I missed the table specification with the call to enable the NAT/PAT configuration. The command should read “sudo iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE” I will correct this in the post. Also you did applied the default config correctly, just copy-paste. I’ll make a note of that too. Thanks for the comments!


  3. **Please delete my previous 2 comments**

    Hi ugmoe2k, sorry about the delay in response. I just got back to trying this again. Following is a recounting of my progress and thoughts therefrom:

    “OK, so just a typo.” [tap,tap,tap] “OK fixed, now onto the rest.” [tap,tap,tap,tap…]

    [reaching end of post]

    “Er, so is that it???” “Maybe it’s activated already hah!”

    [grab my tablet to see if it picks up the new SSID]


    “OK nothing, maybe I gotta reboot for it to work. Reboots fix everything!” [reboot RPi]

    [grab tablet again, no SSID]

    [stare down contest with blank screen]

    “OK so mebbe I gotta go back and run some stuff manually.” [scanning post] “This hostapd bit looks ripe! Let’s try it!”

    [“sudo hostapd /etc/hostapd/hostapd.conf”]

    [“Line 3: invalid/unknown driver ‘rtl871xdrv'”]

    “Drat! I knew that line was whacked! lsusb shows I got RTL8187, so how to find driver name?! Google, of course!”

    [Google: “linux driver rtl8187”]

    [2nd entry: rtl818x – Debian Wiki]

    “OK let’s try ‘driver=rtl818xdrv’!”

    [“Line 3: invalid/unknown driver ‘rtl818xdrv'”] “Drat!”

    [drumming temple to dredge up long-lost memory of obscure linux commands that might do something]

    “Hey! I know! Let’s try lsmod!…Oooh, let’s try this one…mac80211…it’s used by rtl8187!”

    [tap,tap into conf file]

    [“Line 3: invalid/unknown driver ‘mac80211′”]

    [big razzberry at the screen with lots of juicy spit]
    Cutting to the end of the chase…with cap in hand…Oh please can you tell me how to fix driver= error in hostapd.conf, and can ya tell me how to start it… 😦


    1. That rtl818x likely means “put your actual last digit where the x is” as a shortcut to avoid listng a half dozen lins different by one digit. Put in rtl8187 and see what happens. Also your example didn’t have drv on the end, so maybe you ought not add it..


  4. Use “sudo hostapd -d /etc/hostapd/hostapd.conf” to better debug hostapd startup failures. I’ll assume that it’s a driver issue as you suggest. What is the exact model of WIFI dongle you have? Could you attach the output from sudo lsmod and sudo lsusb and sudo lshw.


  5. Great article and I’m probably going to give it a try as well for boat usage; I only will be mounting the PI in the top of mast and add a 2nd WIFI local adapter like the little edimax on the 2nd USB port for outdoor boat usage as I my boat is from steel and I put the LAN cable down the mast for inside usage through another router. My issue is only that you sometimes need to logon to a website to just hit accept to get WIFI access. Would that still be possible? Thnx for the great write-up!


    1. I see no reason why that wouldn’t work. Any wireless users just masquerade as the raspberry pi so the wireless traffic looks like it is coming from a single device.


  6. First of all, great article! That was actually the one that made it work for me and I tested a bunch of them.
    I just had a problem to make it persistent, so what I did was add this line
    “up iptables-restore < /etc/iptables.ipv4.nat"
    to the very end of the file /etc/network/interfaces and now it works. Don't know if anyone else had this problem, but that worked for me.
    Btw, I took that line from this


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s