The following can also easily be installed from a github repository that I created here .
First we need to change over completely to systemd
(which might be the future anyway), as Ingo has explained here:
# deinstall classic networking
sudo -Es # if not already done
apt --autoremove purge ifupdown dhcpcd5 isc-dhcp-client isc-dhcp-common rsyslog
apt-mark hold ifupdown dhcpcd5 isc-dhcp-client isc-dhcp-common rsyslog raspberrypi-net-mods openresolv
rm -r /etc/network /etc/dhcp
# setup/enable systemd-resolved and systemd-networkd
apt --autoremove purge avahi-daemon
apt-mark hold avahi-daemon libnss-mdns
apt install libnss-resolve
ln -sf /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf
systemctl enable systemd-networkd.service systemd-resolved.service
1. Configure wpa_supplicant
Your wpa_supplicant-wlan0.conf
should look something like this:
country=FR
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
ap_scan=1
your access point/hotspot
network={
ssid="RaspberrypiAP" # your hotspot's name
mode=2
key_mgmt=WPA-PSK
psk="passphrase" # your hotspot's password
frequency=2462
}
your network(s)
network={
priority=10 # add a priority higher then 0 to any networks
ssid="yourWifi" # except the access point's one!
psk="passphrase"
}
We have to add a priority=
higher then 0 to any network section except the hotspot's one, so wpa_supplicant
will prefer them. Only if none of these networks is found, wpa_supplicant
will create an access point/hotspot. If wpa_supplicant
has created a hotspot the interface has to be given a static address and we need a DHCP server, so that we can connect our devices to it. This will be done by systemd-networkd
.
2. Configure wireless interface with systemd-networkd
We need to create the following files. The first one will configure your device as client, the second one as access point. The first one is the default due to the smaller number.
sudoedit /etc/systemd/network/08-CLI.network
[Match]
Name=wlan0
[Network]
DHCP=yes
LinkLocalAddressing=yes
MulticastDNS=yes
sudoedit /etc/systemd/network/12-AP.network
[Match]
Name=wlan0
[Network]
Address=192.168.4.1/24
DHCPServer=yes
LinkLocalAddressing=yes
MulticastDNS=yes
3. Setup a systemd.service
to automatically configure the interface based on wpa_supplicant
events
This service will run wpa_cli
, which executes the script below on certain events.
Run sudo systemctl edit --full --force wpa_cli@wlan0.service
and paste the following lines to it:
Description=Wpa_cli to Automatically Create an Accesspoint if no Client Connection is Available
After=wpa_supplicant@%i.service
BindsTo=wpa_supplicant@%i.service
[Service]
ExecStart=/sbin/wpa_cli -i %I -a /usr/local/bin/autoAP.sh
Restart=on-failure
RestartSec=1
[Install]
WantedBy=multi-user.target
4. The script needed for the service
This script has to be saved to the path defined in the ExecStart=
section. It will configure the device as client if connected to some wifi, or as access point if wpa_supplicant
has created one, which it will do automatically if no other network is found.
If nobody is connected to the access point for a while it will restart wpa_supplicant
to make it search for wifi networks again.
sudoedit /usr/local/bin/autoAP.sh
#!/bin/bash
device=wlan0
configure_ap () {
if [ -e /etc/systemd/network/08-CLI.network ]; then
mv /etc/systemd/network/08-CLI.network /etc/systemd/network/08-CLI.network~
systemctl restart systemd-networkd
fi
}
configure_client () {
if [ -e /etc/systemd/network/08-CLI.network~ ] && wpa_cli -i$device status | grep -q "mode=station"; then
mv /etc/systemd/network/08-CLI.network~ /etc/systemd/network/08-CLI.network
systemctl restart systemd-networkd
fi
}
reconfigure_wpa_supplicant () {
sleep "$1"
if [ "$(wpa_cli -i $device all_sta)" = ""]; then
wpa_cli -i $device reconfigure
fi
}
case "$2" in
# Configure access point if one is created
AP-ENABLED)
configure_ap
reconfigure_wpa_supplicant 2m &
;;
# Configure as client, if connected to some network
CONNECTED)
configure_client
;;
# Reconfigure wpa_supplicant to search for your wifi again,
# if nobody is connected to the ap
AP-STA-DISCONNECTED)
reconfigure_wpa_supplicant 20 &
;;
esac
Make the script executable chmod +x /path/to/script/autoAP.sh
.
Now we have to run sudo systemctl enable --now wpa_cli@wlan0.service
, reboot the Pi and everything should work.
I'll be glad for any suggestions on how to improve this setup.
/lib/systemd/network/
but in the script you use/etc/systemd/network/
. You do not neednetwork.target
if you usenetwork-online.target
but it doesn't matter.Type=simple
is default. There are some very nice ideas. Thanks for it. – Ingo Jul 02 '19 at 10:55/etc/systemd/network/08-CLI.network
for masking the file in/lib/...
. You think it is better to rename it? – jake Jul 02 '19 at 11:16/lib/
. – Ingo Jul 02 '19 at 11:40systemctl
, can you? But maybe it is better to disable08-Client.network
with a drop-in file and move everything to/etc/systemd/network
. I'll test this. – jake Jul 02 '19 at 11:54systemctl is-active my.service
andsystemctl [en/dis]able --now my.service
. – Ingo Jul 02 '19 at 20:03/etc/systemd/network/
. Haven't seen it before. Forget my comment about that. I have looked at the symlinks in/etc/systemd/system/
, a confusion. If you say you don't want to start or stop services: you restart the complete network setup with all depending services on every change. If you modify the network setting (as you do) then it is recommended to runsudo systemctl daemon-reload
but if it works without, it may not be needed in your case. – Ingo Jul 04 '19 at 21:51iw phy
with a RPi 3B+ does not show any relevant difference on the wifi configuration. My hope was that RPi 4B supports WDS for bridging client connections but it seems not to be the case. But that's off topic here... And I have another project in the pipeline – Ingo Jul 04 '19 at 23:23systemctl restart systemd-networkd
on every network change. You should be able to use wpa_cli to manage the connections. Withwpa_cli -h | less
you will find many useful options. reassociate, reattach, select_network and others are interesting options to manage connections manual. – Ingo Jul 09 '19 at 09:04