I am using Raspberry Pi using Raspbian which is just Debian.

I would like to bridge from the primary WiFi network router that connects to Cox Cable to my cabled router here for my subnet to have reliable internet access.

It needs to be a WiFi-to-Ethernet bridge.

I have set /etc/networks for a static address for the USB wlan1 with the external adapter and hi-gain antenna. wpa_supplicant is configured to log in to the master router properly.

So right now it is set up so I can login to the proper network with the password, on external wlan1. Static address is set in /etc/networks. Gateway and nameserver are OK. I can browse web pages, etc.

The missing link is to bridge this to the eth0 port so my router can connect also, to provide service to my subnet.

No need for any extra network services like routing or nat or dhcp, etc. Just a simple bridge.

Can anyone please point me in the right direction to make this happen?

  • Did you try a very basic bridge by setting no IP on your Ethernet device, creating a bridge with brctl addbr br0, adding both devices to the bridge with brctl addif br0 device, and then setting your original Ethernet address and route on br0? May 6, 2017 at 0:35
  • You have not documented how your wlan0 is configured atm. May 6, 2017 at 8:42
  • Good point. I added some edits to clarify. I like your answer below. It is precisely the opposite of what I am trying to do, but that's OK because I think it is enough information to get me moving. Thank you for posting it.
    – SDsolar
    May 6, 2017 at 17:25
  • Found this one and the first answer is funny. 'too broadly correct' - so this bridging stuff apparently requires magic, also. unix.stackexchange.com/questions/272146/…
    – SDsolar
    May 8, 2017 at 23:13
  • 3
    Update from the future (late 2018): Since 2.6.33, you can't bridge wlan to eth. You can bridge wlan to eth only if you switched then wlan0 into 4addr mode. Not all drivers support that. You can read more about it here.
    – peterh
    Dec 13, 2018 at 11:46

3 Answers 3


For configuring a bridge from ethernet to wifi, it is as simple as doing in your /etc/network/interfaces:

auto eth0
allow-hotplug eth0
iface eth0 inet manual

auto wlan0
allow-hotplug wlan0
iface wlan0 inet manual

auto br0
iface br0 inet static
bridge_ports eth0 wlan0

Replace the IP address with something more appropriate to your network.

If you prefer the IP attribution done via DHCP, change it to:

auto br0
iface br0 inet dhcp
bridge_ports eth0 wlan0

After changing /etc/network/interfaces, either restarting Debian or doing

service networking restart

Will activate this configuration.

You will have to make sure for this configuration to have bridge-utils installed. You can install it with:

sudo apt install bridge-utils

For more information, see:


The wlan0 interface also has to be condigured to connect to your remote AP so this configuration is not be used verbatim.

Additional note: bridging eth0 and wlan0 together means in poor layman´s terms that br0 will present itself as a single logical interface englobing the interfaces that make part of the bridge. Usually such configuration is made when both extend or belong to the same network.

  • 2
    It is not actually the opposite; if you want wifi clients to connect to the raspberry you need hostapd on top of this configuration; I actually have an openwrt that has been configured here to do what you are asking May 6, 2017 at 17:50
  • It is simpler than, it is a matter of configuring the wpa_supplicant May 6, 2017 at 19:54
  • 6
    I'm a little bit confused. If I try your setup and do sudo ifup -a I get the error message can't add wlan0 to bridge br0: Operation not supported. This was widely discussed with Bridging wlan0 to eth0. What I'm missing with your setup?
    – Ingo
    Feb 28, 2018 at 20:00
  • 3
    No problem to open a new question but I'm unsure if it make sense. I think your answer is outdated and should be corrected. Since kernel >=2.6.33 you cannot add wifi to a bridge (except when WDS is used). This is what is discussed in Bridging wlan0 to eth0.
    – Ingo
    Feb 28, 2018 at 21:28
  • 1
    Side notice: I learned in the past few days is, that bridging wifi to eth interfaces with running dhcp requires 4addr mode sudo iw dev wlp2s0 set 4addr on for both, AP and clients. To do this, all of the involved wifi interfaces must support interface mode AP, see iw list | less and connections need to take down for 4addr on first, and then take up again, to prevent the Operation not supported error message, as mentioned by @Ingo
    – ddlab
    Dec 17, 2021 at 14:49

See https://wiki.debian.org/BridgeNetworkConnections#Bridging_with_a_wireless_NIC

Bridging with a wireless NIC Just like you can bridge two wired ethernet interfaces, you can bridge between an ethernet interface and a wireless interface. However, most Access Points (APs) will reject frames that have a source address that didn’t authenticate with the AP. Since Linux does ethernet bridging transparently (doesn’t modify outgoing or incoming frames), we have to set up some rules to do this with a program called ebtables.

For an alternative Layer 3 approach using proxy ARP and routing, see BridgeNetworkConnectionsProxyArp.

ebtables Overview ebtables is essentially like iptables, except it operates on the MAC sublayer of the data-link layer of the OSI model, instead of the network layer. In our case, this allows to change the source MAC address of all of our frames. This is handy because we fool our AP into thinking that all of our forwarded frames come from the machine which authenticated to the AP.

... The instructions there go on to manage a list of addresses on one side, I couldn't follow.

Comment Reply: I don't see where you get 3. For 4 it depends on how you divide things between L1 and L2, if you draw a box around the radio signals that indicate "This WiFi radio is going to transmit" and include the first 2 addresses... And view those as part of the L1 session meaning they form a physical connection between 2 radios. Then there is no problem with too many L2 addresses, we are safely back at 2.

I'd be interested in documentation that describes how ebtables manages all these addresses.


I am told that, for those of us who have advanced hardware and firmware, the accepted bridge solution works. But for me, using open source linux firmware for ath9k, combined with an open source atheros qualcom chip set, the above answer does not work. So, if you try the bridge and you get the 'Operation Not Permitted' error...

WiFi and Ethernet cannot be directly bridged via the Debian bridge-utils package containing brctl because the level 3 package protocols are different. WiFi assumes that every packet comes from another source and includes that information, while Ethernet does not. Spoofing/cheating methods exist, but they are recognized as a threat by the outside world and blocked.

You must rebuild the level 3 package to convert Ethernet headers to WiFi headers via a Linux service called dnsmasq.service which masquerades packages, rebuilding the level 3 headers. The declaration of what is to happen may be created via Linux iptables wnich may employ a process called Network Address Translation.

# wifi2eth
# Tested on Debian GNU/Linux bullseye/sid system.
# Used to connect a Magic Jack Ethernet device so that I may use a corded telephone through the computer which connects to a cellular to WiFi hot-spot device (the MiFi-8000).
# There are certain numbers which, when dialed out, where I can hear the person I called, but they cannot hear me. The problem was resolved by adding UNTRACKED to the list of packets which should be forwarded from WiFi to Ethernet (the telephone).
# When an incoming packet is marked as UNTRACKED, then the state mechanism is broken. I have no problem yet, but if UNTRACKED is used by a sender which is not part of VOIP, then that will create a browsing problem. I would prefer my computer disrespect UNTRACKED requests.

# This program creates a functioning WiFi to Ethernet 'bridge'

# Step 0: Reset
{ # the redirect of this block also hides bash -x
    sudo ifdown --all
    for zUp in $(ip addr show | sed -nEe 's/[0-9]+: ([^:]+).* UP .*/\1/p' | tr '\n' ' '); do
        sudo ip link set "$zUp" down # force interface down which ifdown was unable to bring down
    sudo iptables -F
    sudo iptables -t nat -F
    sudo systemctl stop dnsmasq.service
    sudo systemctl disable dnsmasq.service
} &> /dev/null

sudo ifup --all
sudo ifup wlNet 2>&1 | grep -Ee "^Listening on" -e "^DHCPDISCOVER" -e "^bound to"
if [[ $(ip link show wlNet) = *' state DOWN '* ]]; then
    echo "$(tput setaf 1)!!! $(basename "$0"): Could not ifup wlNet !!!$(tput sgr0)"

# Step 1: Create the iptables
aEthernet="enTele" # the Ethernet output I want for magicJack
aWireless="wlNet" # the functioning wireless input
aNext=192.168.2 # the next subnet after 192.168.1
aIp_address="$aNext.1" # use the next subnet to create internal network
aNetmask="" # the network mask
# aNetwork="$aNext.0" # the external inet representing the internal block
# aBroadcast="$aNext.255" # the broadcast IP
aDhcp_range_start="$aNext.50" # inet addresses to be available in subnet
aDhcp_range_end="$aNext.100" # inet addresses to be available in subnet
aDhcp_time="12h" # address lease duration

sudo iptables --flush
sudo iptables -F
sudo iptables -A FORWARD -i $aWireless -o $aEthernet -m state --state RELATED,ESTABLISHED,UNTRACKED -j ACCEPT
sudo iptables -A FORWARD -i $aEthernet -o $aWireless -j ACCEPT
sudo iptables -t nat -F
sudo iptables -t nat -A POSTROUTING -o $aWireless -j MASQUERADE

# Step 2: Turn on IP forwarding.
sudo sh -c "echo 1 > /proc/sys/net/ipv4/ip_forward"
sudo ifconfig $aEthernet $aIp_address netmask $aNetmask
# May also have to uncomment net.ipv4.ip_forward=1 in /etc/sysctl.conf
# Remove possible default route created by dhcpcd.
# Hide error if route does not exist.
sudo ip route del 0/0 dev $aEthernet &> /dev/null

# Step 3: Reconfigure and restart domain name masquerade.
sudo systemctl stop dnsmasq
cat - > /tmp/custom-dnsmasq.conf <<-EOF
sudo rm -r /etc/dnsmasq.d/*
sudo mv /tmp/custom-dnsmasq.conf /etc/dnsmasq.d/custom-dnsmasq.conf
sudo systemctl start dnsmasq

# Show off what we did
sudo iptables-save | grep --no-group-separator -e '^-A' -e '^*' | grep -ve '^#'

# End Of Code
# The iptables language:
#   iptables understands ipv4 (ip6tables understand ipv6 (not used))
#   apt-get install iptables # comes preinstalled with debian
#   An iptable stores a chain of rules which redirects packets.
#     The first match in a chain determines the packet destination. 
#   The iptables table name determines when and how the table is used.
#     An iptables name is not random or arbitrary.
#   --table 'filter' is the default and is for firewall creation
#   --table 'mangle' is for chaning packet headers (TTL values...)
#   --table 'nat' is for routing packets to different hosts via Network Address Translation
#   --table 'raw' is a stateful firewall (knows if packet is part of a new or existing connection...)
#   Chains of a table determine the inspection point.
#     PREROUTING chain is for arriving packets in tables 'nat', 'mangle' and 'raw'.
#     INPUT is chain for packets going to local process in tables 'mangle' and 'filter'.
#     OUTPUT is chain for packets from a process in tables 'raw', 'mangle', 'nat', and 'filter'.
#     FORWARD is chain for packets routed through localhost in tables 'mangle', 'filter'.
#     POSTROUTING is chain for exiting packets in tables 'nat', 'mangle'.
#     MASQUERADE chain...
#       When it receives a datagram from a computer on the LAN
#         it takes note of the type of datagram it is, "TCP," "UDP," "ICMP," etc.
#         and modifies the datagram so that it looks like it was generated by the router machine itself
#         and remembers that it has done so.
#       It then transmits the datagram onto the Internet with its single connected IP address.
#       When the destination host receives this datagram,
#         it believes the datagram has come from the routing host and sends any reply datagrams back to that address.
#       When the Linux masquerade router receives a datagram from its Internet connection,
#         it looks in its table of established masqueraded connections
#         to see if this datagram actually belongs to a computer on the LAN,
#         if it does, it reverses the modification it did on the forward path
#         and transmits the datagram to the LAN computer.
#   The target of a rule defines what happens to matched packets.
#     ACCEPT is the default which forwards or allows the packet.
#     DROP acts as if the packet did not exist.
#     REJECT responds with an error (then drop).
#     LOG creates a kernel log entry (in /var/log/syslog or /var/log/messesages) (then drop).
# The iptables interface:
#   sudo iptables
#     -L|--list -v|--verbose list current ip table entries (no --table shows filter table)
#     -F|--flush empty all ip table entries (no --table flushes filter table)
#     -A|--append creates a new rule
#     -j|--jump where to send the packet if the packet matches the rule
#     -i|--in-interface where packet must come for for a match
#     -o|--out-interface where packet must be going to for for a match
#     -m|--match state list,of,states allowed or a match
#     note: see man iptables for many other types of matching rules
#   Packets have a state:
#     NEW for the very first packet of a connection
#     ESTABLISHED for packets that are part of an existing connection
#     RELATED for packets related to another established connection (ftp)
#     INVALID for packets whose state is unknown or improper
#     UNTRACKED for packets specifically exempted from connection tracking
#     DNAT for packets whose destination address was changed by the table
#     SNAT for packets whose source address was changed by the table
#   Anything you block on the INPUT chain, you can’t access either.
#      --state RELATED,ESTABLISHED --jump ACCEPT declares "allow existing connections to continue"
# Save/restore iptables:
#   Once declared, iptables may be saved and restored to/from files of your choice.
#   $ sudo iptables-save > iptables.rules # write current rules to configuration file
#   $ sudo iptables-restore < iptables.rules # restore rules from configuration file
#   $ sudo apt-get install iptables-persistent # package for automated iptables-save/restore

Above is a program needing chmod +x which creates the NAT forwarding 'bridge' when executed. It will not automatically create the 'bridge' when you reboot.

Note: Packages like network-manager, wicd, connman, etc. all do their own thing. Such packages add configuration, GUI, and control layers which, in my opinion, serve only to convolute everything. Uninstall all of them. This method uses only packages which actually perform a required task: dnsmasq, iptables, and wpasupplicant. The simpler you system, the more comprehendible and reliable your solution.

Basic commands:

$ ip addr show # list every network interface and its current situation
$ sudo ifup INTERFACE # raise interface declared in /etc/network/interfaces
$ sudo ifdown INTERFACE # lower interface declared in /etc/network/interfaces

Best wishes in your pursuit to remain totally open source.

  • They can be bridged if the WiFi device can be run as an access point rather than an end node. Unfortunately many easy available devices do not come with the necessary firmware to run in this mode Dec 4, 2020 at 21:58
  • I think this can be done with L3 switching, where only the L2 addresses are masqed and 'routing' is done using the L3 headers. See 'ebtables' Apr 4, 2021 at 0:06
  • A word of warning: If you start using Network Address Translation (NAT), the hosts on the Ethernet will be able to contact the rest of the network and the outside world, but you will not be able to contact the hosts on the Ethernet from other places in your network. That may be a deal-breaker for your setup. It is for mine. Oct 12, 2022 at 18:40

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .