14

I want to automatically create an access point, if there is no network found, so that I can connect to my Raspberry Pi everywhere.

If nobody is connected to the hotspot for a while it should search for the networks defined in wpa_supplicant.conf again.

I don't want to install any additional software and to use only wpa_supplicant, wpa_cli and systemd-networkd.

jake
  • 1,129
  • 7
  • 21

1 Answers1

9

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.

jake
  • 1,129
  • 7
  • 21
  • Since Raspbian 2019-04-08 you do not need to install rng-tools anymore. There is a typo. For network files you use `/lib/systemd/network/` but in the script you use `/etc/systemd/network/`. You do not need `network.target` if you use `network-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
  • Thanks, @Ingo, I edited it! I'm using `/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
  • I tend to use systemctl to control services due to stability. So I haven't had a detailed look at the links and I cannot say much about them but I avoid to touch things in `/lib/`. – Ingo Jul 02 '19 at 11:40
  • @Ingo But you can't manage .network files with `systemctl`, can you? But maybe it is better to disable `08-Client.network` with a drop-in file and move everything to `/etc/systemd/network`. I'll test this. – jake Jul 02 '19 at 11:54
  • Network files and links are managed by systemctl. As far as I understand your script you check the status of a service and start and stop them. You can do it with `systemctl is-active my.service` and `systemctl [en/dis]able --now my.service`. – Ingo Jul 02 '19 at 20:03
  • 1
    This is great! Thanks for the write-up. I've got it running here. A couple of comments: 1) Switching to networkd-resolved doesn't seem mandatory based on my (limited) testing. I haven't sorted how to get search-domain settings passed through with my dhcp-to-preassigned addresses. Still investigating, because I'd like to get there. 2) The 'ln' command is missing an 'f' at the end (should be '.conf'). 3) Typo in the comments: wpa_supllicant-wlan0.conf. 4) Lastly, some sort of naming convention for scripts and conf files might be helpful, but not mandatory. – bls Jul 03 '19 at 00:46
  • Ah, found a fix for my issue. I have dhcp set up providing fixed, assigned addresses (use IP X for MAC address Y). systemd-resolved doesn't request the search domain option, but it is handled properly if it comes back. So, per a reply at https://github.com/systemd/systemd/issues/8174 I can use option dhcp-parameter-request-list 1,3,6,12,15,42,119; (with 119 being the impt one) for affected hosts, and all is good. I have a tool for managing the dhcp config DB so it's pretty painless. Thx again! – bls Jul 03 '19 at 02:22
  • @Ingo, could you tell by which commands you can manage .network files? Couldn't find them. I don't want to start or stop services, but to reconfigure the interface depending on its state (manged or ap mode). If there's ab better way then moving the file please tell me! – jake Jul 04 '19 at 19:53
  • Ah, now I understand that you move the configuration files in `/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 run `sudo systemctl daemon-reload` but if it works without, it may not be needed in your case. – Ingo Jul 04 '19 at 21:51
  • Isn't it also a solution to have the access point always on and let wpa_supplicant just do the roaming with its client connections as usual? To have some more ideas I should setup your solution but just now I have some trouble with the new RPi 4. I will come back soon to your setup. Now I don't understand why this switching does not work automagically with the priority of the network blocks in wpa_supplicant.conf. – Ingo Jul 04 '19 at 22:22
  • @Ingo That would be great! wpa_supplicant does not switch back if the access point is enabled once, or it least I don't know ho to tell him to do that. And I need of course to reconfigure the interface then. I also don't like to do that by restarting systemd-networkd, but I couldn't find a better way. Thanks helping! I think many people would be glad about a simple solution to that (I find volumios 300 lines of JavaScript a bit overkill). – jake Jul 04 '19 at 22:47
  • But I like to use a RPi 4B, so I can look at its new hardware. A visual compare of `iw 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](https://raspberrypi.stackexchange.com/questions/92557/how-can-i-use-an-init-ramdisk-initramfs-on-boot-up-raspberry-pi/100261#comment165011_100261) in the pipeline – Ingo Jul 04 '19 at 23:23
  • Based on my (admittedly not deep) knowledge of systemd, I think the implementation is quite elegant, and "just works". Also, have found a wonderful use case for it. When I make a card for a new Pi, I put this in place and ensure that it won't join my network. Once the new Pi boots, I can join the Pi AP network and configure the Pi, as well as adding it to my dhcp/bind infrastructure. This is great because I don't have to hook up a monitor at all...just use ssh or VNC to connect to the AP. – bls Jul 05 '19 at 21:50
  • @bls Thank you! That's just what I made for, that you can access and configure your device headless no matter if you typed in a the wrong wifi passphrase or not etc. I'm glad that it works for you! – jake Jul 06 '19 at 01:20
  • @jake I still do not understand why to switch of the access point when a client connection is established. Why? – Ingo Jul 07 '19 at 09:52
  • @ingo SInce, I guess, in this scenario the access point has the only purpose to make the device accessible if it s not connected to any network at all. – user5950 Jul 07 '19 at 12:49
  • @user5950 But again: why to switch off? If it is always on you can always connect to it. The access point must not switched off to establish in addition a client connection. – Ingo Jul 07 '19 at 18:03
  • @Ingo I know you can have a virtual interface spawning an access point at the same time. But why should it be there if it's not needed? I think it's good to have a simple setup for this, so you can access your pi even if you typed in a wrong password etc., and you keep the environment clean off unneeded access points; but maybe theses thoughts are a bit old fashioned, when every light bulb has it's own hotspot now. Actually I wanted to find a better solution then volumio's one. They do basically the same, but their service delays the boot process for half a minute on a RPI 0. – jake Jul 08 '19 at 00:49
  • @ingo If you use a flashlight in a dark environment, to replace a broken fuse, you sure could leave the flashlight on after you replaced it. – user5950 Jul 08 '19 at 20:40
  • @jake You asked how to avoid to restart the complete networking stack with `systemctl restart systemd-networkd` on every network change. You should be able to use **wpa_cli** to manage the connections. With `wpa_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
  • @user5950 Yes, I understand now that switching off an unneeded service is a valid requirement. – Ingo Jul 09 '19 at 09:09
  • I noticed that@jake's GitHub has been taken down. I took the code here, fixed the waiting/reconfiguration logic, and built an installer for it. It's at https://github.com/gitbls/autoAP The README has a good description on how it operates, and I provided a script to switch from either dhcpcd or Network Manager to systemd-networkd. – bls Aug 05 '19 at 01:09
  • @bls Well, it's not. I just renamed it an forgot to update here, but I'm glad you are using the code! – jake Aug 05 '19 at 01:41
  • Ah! There it is! Thanks! – bls Aug 05 '19 at 01:43