49 of 57
Corrected setting of IPMasquerade to the wlan0 interface
Ingo
  • 41.4k
  • 15
  • 81
  • 192

━━━ Setting up an access point ━━━

We are talking about an access point together with an ethernet port **eth0**.

If you want an access point together with a wlan0 client connection to another wifi network (wlan repeater) then look at Access point as WiFi router/repeater, optional with bridge.

It is possible to configure Raspbian Stretch as a wifi access point without installing additional software. All needed components are available: networking, DHCP server and bridging comes with systemd-networkd and wifi can be setup with wpa_supplicant. Connecting two interfaces eth0 and wlan0 can be done by routing or by bridging. Below first the setup for quick installation and then the details. First we have to switch over to systemd-networkd.

Tested with
Raspbian Stretch Lite 2019-04-08 on a Raspberry Pi 3B+ updated at 2019-04-14.
Raspbian Buster Lite 2019-07-10 on a Raspberry Pi 4B updated at 2019-07-20.
Updates done with sudo apt update && sudo apt full-upgrade && sudo reboot.


♦ General setup

Switch over to systemd-networkd

For detailed information look at (1). Here only in short. Execute these commands:

# disable classic networking
rpi ~$ sudo -Es
rpi ~# systemctl mask networking.service dhcpcd.service
rpi ~# mv /etc/network/interfaces /etc/network/interfaces~
rpi ~# sed -i '1i resolvconf=NO' /etc/resolvconf.conf

# enable systemd-networkd
rpi ~# systemctl enable systemd-networkd.service systemd-resolved.service
rpi ~# ln -sf /run/systemd/resolve/resolv.conf /etc/resolv.conf

Configure wpa_supplicant as access point

To configure *wpa_supplicant* as access point create this file with your settings for `country=`, `ssid=`, `psk=` and maybe `frequency=`. You can just copy and paste this in one block to your command line beginning with `cat` and including both EOF (delimiter EOF will not get part of the file): ``` rpi ~# cat > /etc/wpa_supplicant/wpa_supplicant-wlan0.conf network={ ssid="RPiNet" mode=2 frequency=2437 #key_mgmt=NONE # uncomment this for an open hotspot # delete next 3 lines if key_mgmt=NONE key_mgmt=WPA-PSK proto=RSN WPA psk="password" } EOF

    rpi ~# chmod 600 /etc/wpa_supplicant/wpa_supplicant-wlan0.conf
    rpi ~# systemctl disable wpa_supplicant.service
    rpi ~# systemctl enable wpa_supplicant@wlan0.service

Finished General setup. Go back.
<br/>

------------------------------------------------------
<h2>&diams; Setting up a stand alone access point</h2>
Example for this setup:

                     wifi
    mobile-phone <~.~.~.~.~> (wlan0)RPi(eth0)
                \             /
               (dhcp)   192.168.4.1

Do **"General setup"** then create the following file to configure **wlan0**. We only have the access point. There is no ethernet device configured.

    rpi ~# cat > /etc/systemd/network/08-wlan0.network <<EOF
    [Match]
    Name=wlan0
    [Network]
    Address=192.168.4.1/24
    DHCPServer=yes
    EOF

If you want this then reboot.  
That's it.  
Otherwise go on, no need to reboot at this time.
<br/><br/>

--------------------------------------------------------------------------
<h2>&diams; Setting up an access point and with eth0, without routing</h2>
Example for this setup:

                                     |
                     wifi            |           wired            wan
    mobile-phone <~.~.~.~.~> (wlan0)RPi(eth0) <---------> router <---> INTERNET
                \             /      |     \             /
               (dhcp)   192.168.4.1  |    (dhcp)   192.168.50.1

<h3>Setup</h3>
Do **"Setting up a stand alone access point"** then create the following file to configure **eth0**.

    rpi ~# cat > /etc/systemd/network/04-eth0.network <<EOF
    [Match]
    Name=eth0
    [Network]
    DHCP=yes
    EOF

Reboot.  
That's it.

<h3>Details</h3>
Interface **eth0** is connected with an ethernet cable to the internet router and gets it configuration by DHCP from the internet router. It is no problem to give it a static ip address with e.g. `Address=192.168.50.2` instead of `DHCP=yes`.

Without routing you cannot get into the internet with the mobile-phone. You can only get into it from the RPi itself to get updates or something like.
<br/><br/>

-----------------------------------------------------------------------
<h2>&diams; Setting up an access point and with eth0, with NAT (recommended)</h2>
Example for this setup:

                     wifi                        wired            wan
    mobile-phone <~.~.~.~.~> (wlan0)RPi(eth0) <---------> router <---> INTERNET
                \             /            \
               (dhcp)   192.168.4.1       (dhcp)

<h3>Setup</h3>
Do **"General setup"** then create the following files to configure **wlan0** and **eth0**. Be sure that you use a different subnet for the access point than that from the router. The router in this example does not use subnet 192.168.4.0/24. If you need another subnet then just change the Address line, e.g. `Address=192.168.5.1/24`.

    rpi ~# cat > /etc/systemd/network/08-wlan0.network <<EOF
    [Match]
    Name=wlan0
    [Network]
    Address=192.168.4.1/24
    IPMasquerade=yes   # this is doing NAT
    DHCPServer=yes
    [DHCPServer]
    DNS=84.200.69.80 1.1.1.1
    EOF

    rpi ~# cat > /etc/systemd/network/04-eth0.network <<EOF
    [Match]
    Name=eth0
    [Network]
    DHCP=yes
    IPForward=yes
    EOF

Reboot.  
That's it.

<h3>Details</h3>
If you have no access to the internet router you can fake it with NAT (network address translation) to tell it a lie that all packages are coming from your RasPi AP. But this is not clean routing and has limitations. Clients on the subnet of the router cannot connect to clients on the wifi. But in most cases this is not needed so this setup is recommended because it simplifies the setup. If you need to connect to the wifi clients from the router network then you have to use full routing as desribed in the next section.
<br/><br/>

-----------------------------------------------------------------------
<h2>&diams; Setting up an access point and with eth0, with routing</h2>
Example for this setup:

                     wifi                        wired            wan
    mobile-phone <~.~.~.~.~> (wlan0)RPi(eth0) <---------> router <---> INTERNET
                \             /            \              /
               (dhcp)   192.168.4.1   192.168.50.2   192.168.50.1

<h3>Setup</h3>
Do **"General setup"** then create the following files to configure **wlan0** and **eth0**. Be sure that you use different subnets for the access point and the router network. We have to use static ip addresses because we must use them as gateways.

    rpi ~# cat > /etc/systemd/network/08-wlan0.network <<EOF
    [Match]
    Name=wlan0
    [Network]
    Address=192.168.4.1/24
    DHCPServer=yes
    [DHCPServer]
    DNS=84.200.69.80 1.1.1.1
    EOF

    rpi ~# cat > /etc/systemd/network/04-eth0.network <<EOF
    [Match]
    Name=eth0
    [Network]
    Address=192.168.50.2/24
    Gateway=192.168.50.1
    DNS=84.200.69.80 1.1.1.1
    IPForward=yes
    EOF

Reboot.

To get routing complete working you have to set a static route in your internet router so it can find the route for back coming packages over the RasPi to the clients connected by wifi to the access point. On most internet router you can set a static route but how to do that varies from model to model. It's up to you to find it out. For example your RasPi **eth0** interface has the static ip address 192.168.50.2. Then on your router the gateway (next hop) is 192.168.50.2, destination network is 192.168.4.0/24 (or 192.168.4.0 netmask 255.255.255.0).

That means for the internet router: "send all packages belonging to subnet `192.168.4.0/24` (destination network from AP) to the next router on my subnet, the RasPi AP `192.168.50.2` (gateway). It knows where to go on."

That's it.
<br/><br/>

---------------------------------------------------------
<h2>&diams; Setting up an access point with a bridge</h2>
Example for this setup:

                                   RPi
                   wifi   ┌──────bridge──────┐   wired            wan
    mobile-phone <.~.~.~> │(wlan0) br0 (eth0)│ <-------> router <-----> INTERNET
                \                   |                   / DHCP-server
               (dhcp              (dhcp           192.168.50.1
            from router)       from router)

If you have already an ethernet network with DHCP server and internet router and you want to expand it with a wifi access point but with the same ip addresses then you use a bridge. This is often used as an uplink to a router.

<h3>Setup</h3>
Do **"General setup"** then clean up directory /etc/systemd/network but don't touch `99-default.link` if present. Create the following three files to configure **eth0** and **br0**. The ip addresses are examples. You have to set your own.

    rpi ~# cat > /etc/systemd/network/02-br0.netdev <<EOF
    [NetDev]
    Name=br0
    Kind=bridge
    EOF

    rpi ~# cat > /etc/systemd/network/04-br0_add-eth0.network <<EOF
    [Match]
    Name=eth0
    [Network]
    Bridge=br0
    EOF

    rpi ~# cat > /etc/systemd/network/12-br0_up.network <<EOF
    [Match]
    Name=br0
    [Network]
    DHCP=yes
    # to use static IP uncomment these and comment DHCP=yes
    #Address=192.168.50.60/24
    #Gateway=192.168.50.1
    #DNS=84.200.69.80 1.1.1.1
    EOF

Now we have to tell *wpa_supplicant* to use a bridge. We do it by modifying its service with:

    rpi ~# systemctl edit wpa_supplicant@wlan0.service

In the empty editor insert these statements, save them and quit the editor:

    [Service]
    ExecStartPre=/sbin/iw dev %i set type __ap
    ExecStartPre=/bin/ip link set %i master br0

    ExecStart=
    ExecStart=/sbin/wpa_supplicant -c/etc/wpa_supplicant/wpa_supplicant-%I.conf -Dnl80211,wext -i%I -bbr0

    ExecStopPost=-/bin/ip link set %i nomaster
    ExecStopPost=-/sbin/iw dev %i set type managed

Reboot.  
That's it.

<h3>Details</h3>
We have to tell *wpa_supplicant* that its interface **wlan0** is slave of a bridge. Otherwise it will reject client connects with "wrong password" means the key negotiation does not work. When we tell */sbin/wpa_supplicant* with option `-dbr0` to use a bridge for **wlan0** then the interface must already be a member of the bridge. That's what we do with the drop in file (overlay) for the *wpa_supplicant* service. The empty statement `ExecStart=` deletes the old entry. Otherwise you have two lines `ExecStart=` and *wpa_supplicant* will start two times. The original `ExecStart=` you can view with `systemctl cat wpa_supplicant@wlan0.service`.

Normally the router you are connected to with the ethernet cable has a DHCP server enabled. The bridge is also transparent for DHCP requests from the stations (devices connected to the access point) so you don't have to worry about configuration of its interfaces with ip addresses and options. The router will serve it.  
**excursus:**  
But if the router doesn't have a DHCP server, you can setup one on the RasPi. *systemd-networkd* has options to configure its built-in DHCP server but the problem is that *systemd-networkd* assumes it is running on the router itself and that's not true in this case. It will serve wrong options to the stations, in particular the *router* option. There is no way to configure it. So we have to install `dnsmasq` in this case that can be configured as needed. Install and configure it with (example, use your own ip addresses):

    rpi ~$ sudo -Es
    rpi ~# apt install dnsmasq
    rpi ~# systemctl stop dnsmasq
    rpi ~# mv /etc/dnsmasq.conf /etc/dnsmasq.conf.orig

    rpi ~# cat > /etc/dnsmasq.conf <<EOF
    interface=br0
      dhcp-range=192.168.50.128,192.168.50.164,255.255.255.0,24h
      dhcp-option=option:router,192.168.50.1
      dhcp-option=option:dns-server,8.8.8.8,1.1.1.1
    EOF

    rpi ~# systemctl start dnsmasq
    rpi ~# exit
    rpi ~$

In this example are ip addresses 192.168.50.128 to 192.168.50.164 reserved to give to stations. For other static ip addresses use one outside this pool, also the ip address for the bridge itself.
<br/><br/>

---------------------------
<h2>&diams; Optimizing</h2>
When starting *wpa_supplicant* you mostly get this messages in the journal:

    wpa_supplicant[427]: random: Cannot read from /dev/random: Resource temporarily unavailable
    wpa_supplicant[427]: random: Only 12/20 bytes of strong random data available from /dev/random
    wpa_supplicant[427]: random: Not enough entropy pool available for secure operations
    wpa_supplicant[427]: WPA: Not enough entropy in random pool for secure operations - update keys later when the first station connects

It is not a big issue. *wpa_supplicant* needs random numbers to generate encrpyting keys. This is done a little bit slow so it has to wait. Fortunately the RasPi has a build in **T**rue **R**andom **N**umber **G**enerator (TRNG). We can use it and speed up getting random numbers by installing a piece of software [<sup>**(3)**</sup>](https://wiki.archlinux.org/index.php/Rng-tools) with:

    rpi ~$ sudo apt install rng-tools

**Update:**  
Since **Raspbian Stretch 2019-04-08** there is no need to install `rng-tools`. They are installed by default.
<br/><br/>

--------------------------------
<h2>&diams; Troubleshooting</h2>
<h3>systemd-networkd</h3>
Look at the status of a service:

    rpi ~$ systemctl status systemd-networkd.service
    rpi ~$ systemctl status wpa_supplicant@wlan0.service

Or even a bit more:

    rpi ~$ journalctl --boot --pager-end

I found it helpful to follow the ongoing logging:

    rpi ~$ journalctl --boot --follow

If you have made a drop in file you can look at the result:

    rpi ~$ systemctl cat wpa_supplicant@wlan0.service

To check the runtime environment of a unit you can show it and for example look if there are two `ExecStart=` lines:

    rpi ~$ systemctl show wpa_supplicant@wlan0.service

And if nothing others help you can enable the debug option from `/sbin/wpa_supplicant` with `-d` in a drop in file:

    rpi ~$ sudo systemctl edit wpa_supplicant@wlan0.service
    ExecStart=
    ExecStart=/sbin/wpa_supplicant -c/etc/wpa_supplicant/wpa_supplicant-%I.conf -Dnl80211,wext -i%I -bbr0 -d

The output is in the journal. This way I have found the issue with the wrong key negotiation.

<h3>wifi</h3>
If you have setup the access point you should find it with a mobile phone. Showing the available networks, it is presented with name **RPiNet** and you can connect to it. On the RasPi you can also use the command:

    rpi ~$ sudo iw dev wlan0 info
    phy#0
            Interface wlan0
                    ifindex 3
                    wdev 0x2
                    addr b8:27:eb:06:e8:8b
                    ssid RPiNet
                    type AP
                    channel 1 (2412 MHz), width: 20 MHz, center1: 2412 MHz

As you can see it is type AP (access point) and it will also show you what channel it is using. A problem may be to translate a channel into frequency. The frequency must match a channel. You can look at [<sup>**(2)**</sup>](https://en.wikipedia.org/wiki/List_of_WLAN_channels) for a list of WLAN channels. For example to use channel 36 on the 5.1 GHz band you have to set `frequency=5180` in `/etc/wpa_supplicant\wpa_supplicant.conf`. But you must be sure that your wifi supports the 5.1 GHz band. You can check with `sudo iw phy`. This will give you a bunch of information. It must also contain supported frequencies above 5000 MHz. If you only see frequencies of 24xx MHz then of course you can only use this.

Another point could be random numbers. For encrypting keys for secured connections wpa_supplicant needs random numbers. Generating this is very slow on a Raspberry Pi. If it does not have enough entropy to generate encrypting keys wpa_supplicant will reject the authentication. You can look with `cat /proc/sys/kernel/random/entropy_avail` how many entropy is available. It should be >1000 to work quick enough. To speed up this, the `rng-tools` are installed by default. Look at the section **Optimizing** for further information.

<br/>**references:**  
[1] [Howto migrate from networking to systemd-networkd with dynamic failover](https://raspberrypi.stackexchange.com/a/78788/79866)  
[2] [List of WLAN channels](https://en.wikipedia.org/wiki/List_of_WLAN_channels)  
[3] [Rng-tools](https://wiki.archlinux.org/index.php/Rng-tools)
Ingo
  • 41.4k
  • 15
  • 81
  • 192