49 of 54 Corrected setting of IPMasquerade to the wlan0 interface

━━━ 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 <<EOF
country=DE
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1

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.


♦ Setting up a stand alone access point

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.


♦ Setting up an access point and with eth0, without routing

Example for this setup:

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

Setup

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.

Details

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.


♦ Setting up an access point and with eth0, with NAT (recommended)

Example for this setup:

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

Setup

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.

Details

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.


♦ Setting up an access point and with eth0, with routing

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

Setup

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.


♦ Setting up an access point with a bridge

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.

Setup

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.

Details

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.


♦ Optimizing

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 True Random Number Generator (TRNG). We can use it and speed up getting random numbers by installing a piece of software (3) 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.


♦ Troubleshooting

systemd-networkd

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.

wifi

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 (2) 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.


references:
[1] Howto migrate from networking to systemd-networkd with dynamic failover
[2] List of WLAN channels
[3] Rng-tools