I am trying to create a captive portal wifi hotspot.

Aim of the setup:

  1. Users connecting to hotspot through wlan0 should never be allowed to access the internet through eth1.

  2. For the "Sign into wifi network" to appear on android, iphone and any device that would connect, i am trying to route the requests that go to
    http://clients1.google.com/generate_204 and other url for other operating systems, i havent figured out yet, to my local server and return what the real servers would return.

I use dnsmasq and hostapd to achieve this.

The Problem : when I use address=/#/ in dnsmasq.conf, the internet requests that go from internal scripts also fail. I think I am following the dnsmasq config man page that says how to use dnsmasq to filter only wlan0 interface traffic.

what should I do further.

The machine has these interfaces

    eth1      Link encap:Ethernet  HWaddr 00:1e:06:30:5b:03
          inet addr:  Bcast:  Mask:
          inet6 addr: fe80::21e:6ff:fe30:5b03/64 Scope:Link
          RX packets:37047 errors:0 dropped:0 overruns:0 frame:0
          TX packets:1752 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:3351437 (3.1 MiB)  TX bytes:176100 (171.9 KiB)

lo        Link encap:Local Loopback
          inet addr:  Mask:
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:796 errors:0 dropped:0 overruns:0 frame:0
          TX packets:796 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:284838 (278.1 KiB)  TX bytes:284838 (278.1 KiB)

wlan0     Link encap:Ethernet  HWaddr 98:de:d0:1b:95:5a
          inet addr:  Bcast:  Mask:
          inet6 addr: fe80::9ade:d0ff:fe1b:955a/64 Scope:Link
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:6 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:0 (0.0 B)  TX bytes:576 (576.0 B)

The DNSMASQ looks like this

interface=wlan0      # Use interface wlan0
listen-address= # Explicitly specify the address to listen on
#bind-interfaces      # Bind to the interface to make sure we aren't sending things elsewher$
server=       # Forward DNS requests to Google DNS
domain-needed        # Don't forward short names
bogus-priv           # Never forward addresses in the non-routed address spaces.
dhcp-range=,,12h # Assign IP addresses between and 172.24$

I use a nodejs express server and do this

 app.get('/generate_204', function(req, res) {
        console.log('generate 204 hit');
        res.statusCode = 302;
        res.setHeader("Location", "/");

I created the hotspot using hostapd, the config is

    # This is the name of the WiFi interface we configured above

# Use the nl80211 driver with the brcmfmac driver

# This is the name of the network

# Use the 2.4GHz band

# Use channel 6

# Enable 802.11n

# Enable WMM

# Enable 40MHz channels with 20ns guard interval

# Accept all MAC addresses

# Use WPA authentication

# Require clients to know the network name

# Use WPA2

# Use a pre-shared key

# The network passphrase

# Use AES, instead of TKIP

I have tried to explain the requirement, I am not sure if I have done the explaining part well. There is another question i raised here on serverfault for the same issue,which got marked off-topic, Reading it will make you understand the requirement clearly. https://serverfault.com/questions/823139/iptables-for-linux-captive-portal-wifi-hotspot

  • Don't redirect specific URLs, redirect ALL traffic for users who have not yet signed in to the network. Jan 11, 2017 at 18:04
  • @MichaelHampton Doing that makes the android detect the wifi hotspot as a "No internet connection" hotspot. This doesn't make the user's phone open up the local portal automatically. I hope I got your point right. I am a newbie when it comes to networking with Linux.
    – 55597
    Jan 11, 2017 at 18:21
  • 1
    It's impossible to say unless you describe exactly what you did. As for being a newbie, building a captive portal from scratch is definitely not something I would expect someone new to be capable of. Consider using an off the shelf solution such as PacketFence instead. Jan 11, 2017 at 18:27
  • @MichaelHampton I dont want an authentication mechanism for the users to login with. My only moto is to make the user who connects to my wifi to open a particular webpage, hence i thought i will redirect them using this technique of sign in to wifi hotspot.
    – 55597
    Jan 12, 2017 at 10:46

3 Answers 3


when I use address=/#/, the internet requests that go from internal scripts also fail

It seems that your internal scripts use to resolve DNS names the same local dnsmasq server as you wifi clients.

Check your /etc/resolv.conf configuration and if there is present your dnsmasq server address ( or or other) - remove it. Instead use you ISP DNS servers, or Google DNS, or any other you prefer, which do not replace any addresses to

Note. If you system use resolvconf to generate /etc/resolv.conf (in resolv.conf present warning like # DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTEN), then you need to edit configs in /etc/resolvconf/resolv.conf.d/ instead, and after it regenerate /etc/resolv.conf (restart networking or better - restart whole system)

Another possibility: remove package resolvconf and edit /etc/resolv.conf

  • this is the content of resolv.conf # Dynamic resolv.conf(5) file for glibc resolver(3) generated by resolvconf(8) # DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTEN nameserver
    – 55597
    Jan 16, 2017 at 13:54
  • Try replace nameserver to nameserver
    – Slipeer
    Jan 16, 2017 at 13:55
  • But what about the message saying dont edit by hand and changes will be overwritten? Also, in my dnsmasq, i have included except-interface=eth1. Then why does it still affect traffic going through eth1?
    – 55597
    Jan 16, 2017 at 13:57
  • That's right. Your system (not indicated in what) uses resolvconf- need to edit its configuration. Consult the documentation of your distribution. You internal scripts resolve DNS trouth loopback interface, by deny it in dnsmasq.conf - bad idea. /etc/resolv.conf - system wide configuration - change resolvconf config and regenerate /etc/resolv.conf
    – Slipeer
    Jan 16, 2017 at 14:02
  • Doesnt work when i follow your instructions. Can you help ?
    – 55597
    Feb 1, 2017 at 5:51

In case anyone is curious about an update (in 2017) to this question... I was able to recreate the issue and figured out a solution.

Disable dnsmasq from resolving for the loopback interface (in /etc/dnsmasq.conf):


Add to the tail file of resolvconf (in /etc/resolvconf/resolvconf.conf.d/tail)


Restart Services

sudo systemctl restart dnsmasq
sudo resolvconf -u

What this does

dnsmasq will now reject any DNS Request make on the localhost, and the localhost will then have to resort to using the second Name Server in line (which is now

What if there isn't a /etc/resolvconf/resolvconf.conf.d/ directory?

You might have openresolv installed instead... I uninstalled openresolv and installed resolvconf. You'll run into other issues - but that's probably not relevant to this answer.


If I understood correctly, what you are trying to do is: all devices are forced to open the captive portal...? Whether or not you have internet to offer. Simply modify the 'hosts' file, and perhaps the 'dhcp' file.

hosts: clients1.google.com clients3.google.com clients.4.google.com www.msftconnecttest.com mobile-gtalk.l.google.com


config domain
    option name 'connectivitycheck.gstatic.com'
    option ip ''

config domain
    option name 'clients1.google.com'
    option ip ''

config domain
    option name 'clients3.google.com'
    option ip ''

config domain
    option name 'clients.4.google.com'
    option ip ''

config domain
    option name 'www.msftconnecttest.com'
    option ip ''

You are welcome. Greetings

You must log in to answer this question.

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