Raspberry Pi WiFi access point

Setting up a WiFi access point on Raspbian is actually pretty straight forward. This post is going to run though the steps to do this.

Checking the wireless interface

Later versions of the Raspberry Pi, such as the Raspberry Pi 3 model B have a built in WiFi interface. However USB interfaces can also be used. It is important that the interface supports AP mode. You can check this with the iw command:

pi@raspberrypi:~ $ iw list
Wiphy phy0
        max # scan SSIDs: 10
        max scan IEs length: 2048 bytes
        Retry short limit: 7
        Retry long limit: 4
        Coverage class: 0 (up to 0m)
        Device supports roaming.
        Device supports T-DLS.
        Supported Ciphers:
                * WEP40 (00-0f-ac:1)
                * WEP104 (00-0f-ac:5)
                * TKIP (00-0f-ac:2)
                * CCMP (00-0f-ac:4)
                * CMAC (00-0f-ac:6)
        Available Antennas: TX 0 RX 0
        Supported interface modes:
                 * IBSS
                 * managed
                 * AP
                 * P2P-client
                 * P2P-GO
                 * P2P-device

Configuring a static IP

Once you're happy the interface supports access point mode, the next step is to set up a static IP address. This can be done with the following command:

ip addr add 192.168.0.1/24 dev wlan0

You can verify the IP address is assigned correctly with the ip command:

$ ip addr show wlan0
3: wlan0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc pfifo_fast state DOWN group default qlen 1000
    link/ether b8:27:de:ad:be:ef brd ff:ff:ff:ff:ff:ff
    inet 192.168.0.1/24 scope global wlan0
       valid_lft forever preferred_lft forever
    inet6 fe80::e4e7:5d3:e5c9:eaab/64 scope link tentative
       valid_lft forever preferred_lft forever

To make this configuration persistent, create /etc/network/interfaces.d/wlan0 with the following content:

auto wlan0
iface wlan0 inet static
    address 192.168.0.1
    netmask 255.255.255.0

You will also want to add the following to /etc/dhcpcd.conf to prevent dhcpcd trying to assign an IP address to the interface via DHCP:

# Use a static address for wlan0
interface wlan0
static ip_address=192.168.0.1/24

Setup Hostapd

Hostapd (Host access point daemon) can be used to put the WiFi interface into AP mode. The first thing to do is install the package:

sudo apt-get update
sudo apt-get install hostapd

Once Hostapd is installed, create /etc/hostapd/hostapd.conf with contents similar to the following:

interface=wlan0
driver=nl80211
ssid="Pi AP"
channel=1
macaddr_acl=0

Note: /usr/share/doc/hostapd/examples/hostapd.conf.gz has additional information on valid configuration options, including enabling encryption.

Update /etc/default/hostapd to reference the new config:

sed -i \
  's|^#DAEMON_CONF=.*|DAEMON_CONF=/etc/hostapd/hostapd.conf|' \
  /etc/default/hostapd

And restart the hostapd service:

systemctl restart hostapd.service

If everything goes well Hostapd should be running, and you should be able to see the access point from other WiFi devices.

Running a DHCP server

Most devices will try to use DHCP when connecting to the access point to obtain an IP address. To handle this dnsmasq can be used to handle DHCP requests. First install the dnsmasq package:

sudo apt-get update
sudo apt-get install dnsmasq

Once the package is installed, create a new config file called /etc/dnsmasq.d/wifi with the following content:

interface=wlan0
dhcp-range=192.168.0.50,192.168.0.150,255.255.255.0,12h
domain-needed

Then reload the dnsmasq service:

systemctl restart dnsmasq.service

Note: make sure iptables allows UDP connections on port 67 and 53.

Forwarding traffic

You should now be able to connect a device, however you will likely want to forward traffic outside the network. Start by allowing IPv4 forwarding:

echo 1 > /proc/sys/net/ipv4/ip_forward

To make this rule persistent create a new config file for sysctl:

echo 'net.ipv4.ip_forward = 1' > /etc/sysctl.d/10-ip_forward.conf

Iptables rules can then be added to forward outbound traffic:

iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
iptables -A FORWARD -i eth0 -o wlan0 -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -A FORWARD -i wlan0 -o eth0 -j ACCEPT

To make the rules above persistent create a config file:

iptables-save > /etc/network/iptables

Finally create a script called /etc/network/if-pre-up.d/iptables with the following contents to load the rules at boot:

#!/bin/sh
#
# Load iptables rules before the network comes online.
#
/sbin/iptables-restore < /etc/network/iptables

Note: don't forget to add execute permissions to the script.