This setup is DEPRECATED and no longer maintained!
Look at Access point as WiFi repeater, optional with bridge for a more flexible setup.
It is possible to use the wifi device on a Raspberry Pi as an access
point and at the same time connect as client to another already
established wlan. I have heard this is possible for RPi-0W, RPi-3B and
RPi-3B+. But better you check it by yourself on your hardware with:
rpi ~$ sudo iw list | grep -A4 "valid interface combinations:"
valid interface combinations:
* #{ managed } <= 1, #{ P2P-device } <= 1, #{ P2P-client, P2P-GO } <= 1,
total <= 3, #channels <= 2
* #{ managed } <= 1, #{ AP } <= 1, #{ P2P-client } <= 1, #{ P2P-device } <= 1,
total <= 4, #channels <= 1
The important part is: #{ managed } <= 1, #{ AP } <= 1
But it is not possible to configure a Raspberry Pi as a clean repeater because for this you need to bridge the wlan client interface. On wifi this is done with WDS (Wireless Distribution System). For this you have to extend the ip header with one additional address field with sudo iw dev wlan0 set 4addr on
. This is not supported by the wifi chip on the Raspberry Pi. For further information look at (3).
But you can use routing to connect the access point to the next wifi
router. The only disadvantage is that you have different ip addresses on
the network from the access point and from the next router.
Here is how to setup it. For reference I
use a RPi3B+ with Raspbian Stretch Lite
2018-06-27. In this
example I use
wifi wifi wan
mobile-phone <.~.~.~.~.~.> (ap0)RPi(wlan0) <.~.~.~.~.~.~.> router <-----> INTERNET
\ / \ /
(dhcp) 192.168.50.1 192.168.10.2 192.168.10.1
I've found that we have to setup the needed services in a strict
sequence, otherwise it won't work.
- create a virtual interface
ap0
for the access point
- start access point daemon
hostapd
using interface ap0
- start
wpa_supplicant
for wifi client using interface wlan0
Starting services depending on others can be done very well with
systemd
. So I will use that and consequently its network management
systemd-networkd
. All commands can simply copied and pasted (including
EOF) to your command line.
Step 1: setup systemd-networkd
For detailed information look at (1). Here only in short. Execute these commands:
pi@raspberrypi: ~$ sudo -Es
root@raspberrypi: ~# mkdir -p /var/log/journal
root@raspberrypi: ~# systemd-tmpfiles --create --prefix /var/log/journal #ignore warnings (*)
root@raspberrypi: ~# systemctl mask networking.service
root@raspberrypi: ~# systemctl mask dhcpcd.service
root@raspberrypi: ~# sudo mv /etc/network/interfaces /etc/network/interfaces~
root@raspberrypi: ~# sed -i '1i resolvconf=NO' /etc/resolvconf.conf
root@raspberrypi: ~# systemctl enable systemd-networkd.service
root@raspberrypi: ~# systemctl enable systemd-resolved.service
root@raspberrypi: ~# ln -sf /run/systemd/resolve/resolv.conf /etc/resolv.conf
(*) You will get one or two confusing warnings "...Cannot set file attribute..." This are not errors and doesn't matter in this case.
Create these files for interfaces wlan0 and ap0 with your settings:
root@raspberrypi:~ # cat > /etc/systemd/network/08-wlan0.network <<EOF
[Match]
Name=wlan0
[Network]
Address=192.168.10.2/24
Gateway=192.168.10.1
EOF
root@raspberrypi: ~# cat > /etc/systemd/network/12-ap0.network <<EOF
[Match]
Name=ap0
[Network]
Address=192.168.50.1/24
DHCPServer=yes
IPForward=yes
EOF
Setup wpa_supplicant with this file and your settings and enable it:
root@raspberrypi:~ # 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="wlan@hoeft-online.de"
psk="verySecretPw"
}
EOF
root@raspberrypi:~ # chmod 600 /etc/wpa_supplicant/wpa_supplicant-wlan0.conf
root@raspberrypi:~ # systemctl disable wpa_supplicant.service
root@raspberrypi:~ # systemctl enable wpa_supplicant@wlan0.service
root@raspberrypi:~ # exit
pi@raspberrypi:~ $
reboot.
Then you should be connected to your existent wlan as normal. Interface
wlan0 has state UP with an ip address 192.168.10.2. Check with ip addr
and/or systemctl status wpa_supplicant@wlan0.service
. You are able to
ping www.google.com
.
ap0 isn't set because the virtual interface isn't created yet.
Step 2: install hostapd
Hostapd is used to establish the access point. Install and stop it with:
pi@raspberrypi:~ $ sudo -Es
pi@raspberryrypi:~ # apt update
root@raspberrypi:~ # apt install rng-tools hostapd
root@raspberrypi:~ # systemctl stop hostapd
Create this file with your settings for ssid=
and wpa_passphrase=
:
root@raspberrypi:~ # cat > /etc/hostapd/hostapd.conf <<EOF
interface=ap0
driver=nl80211
ssid=RPiNet
hw_mode=g
channel=7
wmm_enabled=0
macaddr_acl=0
auth_algs=1
ignore_broadcast_ssid=0
wpa=2
wpa_passphrase=verySecretPw
wpa_key_mgmt=WPA-PSK
wpa_pairwise=TKIP
rsn_pairwise=CCMP
EOF
root@raspberrypi:~ # chmod 600 /etc/hostapd/hostapd.conf
Please use a passphrase that is long enough, I would say at least with 8 characters. It was told that 4 characters are to small and hostapd will refuse to accept connections. You will not find the access point RPiNet in your mobile phone (thanks to @Leo).
It should be said that a channel=
must be in the conf but it is
ignored. The wifi device can only work with one frequence (channel) so
the channel of the access point is always set to the channel the RasPi
is connected to the existent wlan.
Set DAEMON_CONF="/etc/hostapd/hostapd.conf" in /etc/default/hostapd with:
root@raspberrypi:~ # sed -i 's/^#DAEMON_CONF=.*$/DAEMON_CONF="\/etc\/hostapd\/hostapd.conf"/' /etc/default/hostapd
In /etc/init.d/hostapd
in section INIT INFO
you have to comment the line # Should-Start: $network
. It should have two ##
at first characters so it looks like:
## Should-Start: $network
If we comment this line (with the second #
) it will not come to play in this file. This network start is for old style SysV init system and conflicts with systemd. The network start is also managed by systemd and produces an error together with wpa_supplicant: "Found ordering cycle on hostapd.service/start" and prevents it to start. So we have to disable network start in /etc/init.d/hostapd
.
hostapd can only start when the interface ap0 is created. We do this with a drop-in file (2) so we don't have to touch the original unit for hostapd.service.
root@raspberrypi:~ # systemctl edit hostapd.service
In the empty editor insert these statements, save it and quit the editor:
[Service]
ExecStartPre=/sbin/iw dev wlan0 interface add ap0 type __ap
Check with systemctl cat hostapd.service
and/or systemctl status hostapd.service
.
Step 3: start wpa_supplicant after hostpad
Here we only set a dependency. We also do it with a drop-in file:
root@raspberrypi:~ # systemctl edit wpa_supplicant@wlan0.service
In the empty editor insert these statements, save it and quit the editor:
[Unit]
After=hostapd.service
Reboot.
Then you should have interfaces ap0 and wlan0 state UP, each with an ip address. You should also see the access point, here RPiNet, in your mobile phone and it should get an ip address by connecting to the access point. Check with ip addr
and/or systemctl status wpa_supplicant@wlan0.service
.
Step 4: setup routing
Ip forwarding must be enabled for routing. That we have already done with IPForward in /etc/systemd/network/12-ap0.network so it sends all packages with unknown destination addresses, e.g. internet addresses to the next hop. That is the internet router 192.168.10.1.
We have to set a static route in the internet router so it can find the route for returning packages from the internet over the RasPi to the network from the access point 192.168.50.0/24. 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 our example the gateway (next hop) is 192.168.10.2, destination network is 192.168.50.0/24 (or 192.168.50.0 netmask 255.255.255.0).
That means for the internet router: "send all packages belonging to subnet 192.168.50.0/24
(destination network) to the next router on my subnet, the RasPi access point 192.168.10.2
(gateway). It knows where to go on."
If you have setup your internet router then all is done.
The setup is finished.
Only 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. Set this on your Raspberry Pi:
rpi ~$ sudo iptables -t nat -A POSTROUTING -o wlan0 -j MASQUERADE
And delete it:
rpi ~$ sudo iptables -t nat -D POSTROUTING -o wlan0 -j MASQUERADE
This is also a quick check after step 3 to test if everything works as it should before reconfiguring the internet router. Setting a NAT, then with your mobile phone connected to the access point you should be able to browse the internet.
To make NAT persistent, execute sudo systemctl edit wpa_supplicant@wlan0.service
and append this in the editor:
[Service]
ExecStartPost=/sbin/iptables -t nat -A POSTROUTING -o wlan0 -j MASQUERADE
ExecStop=/sbin/iptables -t nat -D POSTROUTING -o wlan0 -j MASQUERADE
But this should only be the second choise because it's a hack and has limitations. With this you cannot connect from clients on the router wifi (192.168.10.0/24) to clients on the access point (192.168.50.0/24). Your internet router also uses NAT so we have a double NAT that's not good for performance.
refefences:
[1] Howto migrate from networking to systemd-networkd with dynamic failover
[2] man systemd.unit - Example 2. Overriding vendor settings
[3] Raspberry Pi WiFi to Ethernet Bridge for a server?