Sometimes, you need to provide network access to wired devices through a WiFi network. If you have an unused Raspberry Pi (e.g. a ver. 3B+, which is what I used for this guide), it can be used for this very purpose.
Why this page? Well, it seems there is a handful of guides out here on WWW on how to do this, but all I have found only show how to set things up manually, hackishly, through custom scripts and not in a reboot-and-it-will-still-work way. Furthermore, they seem to be outdated in many ways. This guide aims to set things up using regular tools and frameworks, in a way that will also survive a reboot.
It is assumed that you are running a standard Raspbian (32 or 64 bit doesn't matter).
Here we let the WiFi be the WAN and the RPI's Ethernet NIC serve an internal network with DHCP and then do NAT.
Use one of various methods to configure the WiFi. Having done that, you will have (at least) one entry in /etc/wpa_supplicant/wpa_supplicant.conf
which is the place to keep WiFi configuration. (E.g. setting it in /etc/network/interfaces
would limit you to support only 1 wireless network and you might to want several configured.)
To enable IP forwarding in a persistent way that will survive reboots, edit /etc/sysctl.conf
and make sure you have the entry:
net.ipv4.ip_forward=1
Run sysctl
to apply the update:
# sysctl -p
Verify that it worked by making sure /proc/sys/net/ipv4/ip_forward
contains 1:
# cat /proc/sys/net/ipv4/ip_forward 1
Find out your device's NIC names, e.g. by running ifconfig
or ip
:
# ifconfig
# ip link show
On contemporary (when this was written) versions of Raspbian, the WiFi NIC has the name wlan0
whereas the Ethernet NIC gets a name according to the Predictable Interface Names naming scheme: enx<macaddress>
. (E.g. enxb8ac6fc0ffee
; if you truly hate the Predictable Interface Names you can configure udev
to go with the old school ethN scheme.)
Edit /etc/network/interfaces
to configure your NICs:
auto wlan0 iface wlan0 inet dhcp wpa-driver nl80211 wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf up iptables -t nat -A POSTROUTING -o $IFACE -j MASQUERADE down iptables -t nat -D POSTROUTING -o $IFACE -j MASQUERADE metric 0 auto enxb8ac6fc0ffee iface enxb8ac6fc0ffee inet static address 192.168.0.1 netmask 255.255.255.0 up iptables -A FORWARD -i wlan0 -o $IFACE -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT up iptables -A FORWARD -i $IFACE -o wlan0 -j ACCEPT down iptables -D FORWARD -i $IFACE -o wlan0 -j ACCEPT down iptables -D FORWARD -i wlan0 -o $IFACE -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT metric 10
For wlan0
, we tell it to use the nl80211
WiFi driver and the WPA supplicant configuration to connect to a suitable WiFi network. We expect to get our network info via DHCP. Furthermore, we activate postrouting when the interface is brought up, and then clean up that very rule when the interface is taken down. The $IFACE
variable expands to the name of the interface, i.e. wlan0
here. To prevent the system from routing Internet traffic on the Ethernet interface, we set the metric 0
to show that wlan0
is the most prioritized NIC.
For the Ethernet interface, we set the static IP address 192.168.0.1 and the netmask 255.255.255.0. Furthermore, we set up forwarding IP rules that will allow your local devices to contact whatever, but devices from the outside will only be able to reach local devices that have made the first move, which is good ol'
best practice for these setups. The down
entries make sure the iptables rules are properly cleaned up when the interface is taken down. The $IFACE
variable expands to the name of the interface, i.e. enxb8ac6fc0ffee
here. Finally, we set the metric 10
(could have been any number >0) to make sure that wlan0
is the main NIC for routing traffic.
I use the isc-dhcp-server
package for DHCP:
# apt-get install -y isc-dhcp-serverConfigure it with
/etc/dhcp/dhcpd.conf
.
# Must be set to get the clients' /etc/resolv.conf right, but can be anything option domain-name "my.domain"; # Use Google's DNS servers, they work everywhere option domain-name-servers 8.8.4.4, 8.8.8.8; # These lines are probably already enabled in the default config default-lease-time 600; max-lease-time 7200; ddns-update-style none; # Declare your subnet, must match your static configuration for the Ethernet # NIC in /etc/network/interfaces subnet 192.168.0.0 netmask 255.255.255.0 { option routers 192.168.0.1; option subnet-mask 255.255.255.0; range 192.168.0.2 192.168.0.254; allow unknown-clients; }
Add your Ethernet NIC to the INTERFACESv4
entry in /etc/default/isc-dhcp-server
INTERFACESv4="enxb8ac6fc0ffee"
Fire up the DHCP server:
# systemctl restart isc-dhcp-server
Verify that the DHCP server is up and running:
# systemctl status isc-dhcp-server
Run
# systemctl restart networking
and your device should be up and running (and work just the same even after a reboot).
Another variant would of course to bridge the WiFi NIC and the Ethernet NIC. In theory, that would be quite convenient and only a quick brige setup with the WiFi NIC and the Ethernet NIC. But it is not as simple as that. Actually, things get ugly and complicated pretty fast with this approach, so I will simply recommend you to go with the first alternative.