How to build a captive web portal with any router and a Raspberry Pi

 

This article explains how to build a captive web portal with a Raspberry PI, redirecting all clients to a web site on the internet.

This article is based on excellent port of Brennan available on this link (https://brennanhm.ca/knowledgebase/2016/10/raspberry-pi-access-point-and-captive-portal-without-internet/)

Situation

The following schema gives an overall view of the situation

We want that the clients connecting to our Hotspot are automatically redirected to a web site on the internet and nowhere else.

Creating the hotspot

Any router should do the job (here an Asus RT-AC66U)

Configure the router with the following parameters

  • Choose the SSID you want (here ASUS)
  • Configure the authentication to "Open"

Then, disable DHCP

Then configure the firewall to allow only connection to the captive web site

Configure the Raspberry Pi

Install required packages

Add the two following packages

 

apt-get install dnsmasq nginx

  • dnsmasq : provides DHCP and DNS services for small networks
  • nginx : a web server that will redirect our clients to the captive web site

Configure a static IP address for the Raspberry Pi

 

sudo nano /etc/dhcpcd.conf

Modify the file to fit your needs

 

# Example static IP configuration:
interface eth0
static ip_address=192.168.1.30/24
#static ip6_address=fd51:42f8:caae:d92e::ff/64
static routers=192.168.1.1
static domain_name_servers=8.8.8.8

Configure the hosts file

 

sudo nano /etc/hosts

Modify the file like bellow

 

127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters

127.0.1.1 raspberrypi
192.168.1.30 hotspot.localnet
212.147.79.236 gremaudpi.emf-informatique.ch

Notice the two entries at the end of the file

  • 192.168.1.30     is for the local host
  • 212.147.79.236     is the ip address of the captive web portal

Dnsmasq will upload this file on startup and answer DNS queries consequently

Configure dnsmasq

 

sudo nano /etc/dnsmasq.conf

Modify the file like bellow

 

# Never forward addresses in the non-routed address spaces.
bogus-priv
# Add other name servers here, with domain specs if they are for non-public d$
server=/localnet/192.168.1.30
# Add local-only domains here, queries in these domains are answered from /etc$
local=/localnet/
# Make all host names resolve to the Raspberry Pi's IP address
address=/#/192.168.1.30
# Specify the interface that will listen for DHCP and DNS requests
interface=eth0
# Set the domain for dnsmasq
domain=localnet
# Specify the range of IP addresses the DHCP server will lease out to devices, $
dhcp-range=192.168.1.100,192.168.1.254,1h
# Specify the default route
dhcp-option=3,192.168.1.1
# Specify the DNS server address
dhcp-option=6,192.168.1.30
# Set the DHCP server to authoritative mode.

Restart dnsmasq

 

sudo service dnsmasq restart

This configuration turns the Raspberry Pi into a fake DNS server.

It will resolve all DNS queries to it's own IP address, except the captive web portal (gremaudpi.emf-informatique.ch) that will be resolved to the IP address found in the hosts file (212.147.79.236 )

We can test the result by connecting to our hotspot with a laptop and launch following commands

We can see that www.google.com resolves to the Raspberry Pi address (192.168.1.30)

And our captive web site address (gremaudpi.emf-informatique.ch) resolves to the real address (212.147.79.236)

Configure nginx

Now we want to configure nginx to redirect all http and https requests to our captive web site.

 

sudo nano /etc/nginx/sites-available/default

 

# Default server configuration
#
server {
listen 80 default_server;
listen [::]:80 default_server;
listen 443 ssl;
listen [::]:443;

root /var/www/html;

# Add index.php to the list if you are using PHP
index index.html index.htm index.nginx-debian.html;

server_name _;

return 302 $scheme://gremaudpi.emf-informatique.ch/hotspot/;
}

Remark: Notice the last line that redirect all traffic to the captive web portal by answering with an HTTP status code "302 Found" which is a common way of performing a url redirection. This will allow most smartphones (android and iphones) to spontaneously open a popup to our web site when connecting to the hostspot.

Restart nginx

 

sudo service nginx restart

Configure the web site

The web site I will use is very basic and made of three pages

http://gremaudpi.emf-informatique.ch/hotspot/index.html

This page will serve following code

 

<html>
<body>
<br>
<h1>Welcome to my hotspot</h1>
<h1>&nbsp</h1>
<h1><a href="./page1/">Page1</a></h1>
<h1>&nbsp</h1>
<h1><a href="./page2/">Page2</a></h1>
</body>
</html>

http://gremaudpi.emf-informatique.ch/hotspot/page1/index.html

This page will serve following code

 

<html>
<body>
<h1>&nbsp</h1>
<h1>Welcome to Page 1</h1>
<h1>&nbsp</h1>
<h1><a href="../">Home</a></h1>
</body>
</html>

Test the result

Now, when you connect to the WIFI hotspot with a smartphone,

you should be automatically redirected to the captive web site.

Where you can navigate as you want

The only problem is that I could never get reed of the annoying header "Connexion Wi-Fi requise" nor of the footer "QUITTER"

If you have an idea how to do this, please post a comment.

That's all folks…

This Post Has One Comment

  1. Riccardo

    Hello,
    I've tryed your setup and it's working perfectly as a captive portal, but this configuration is not managing the complete request_uri.
    I try to explain: I have to redirect all the people that connects to a particular SSID to mywebsite.com when they try to reach any other website, BUT when they try to reach mywebsite.com/something they were redirected to the "homepage" without the "*.com/something".
    I am making a free audioguide for all the people visiting an astrophotography exhibition, pointing the query_uri to the particular photo; for example, audioguide.com/?1 is the first photo, audioguide.com/?2 is the second one and so on.. pointing the /?1 is useless because they are redirected to the main page.
    I am looking for a way to resolve this issue for like 2 months, reading nginx configuration and other ways.. please HELP!

    If I modify the response of nginx with the line below it works ONLY for the direct query like /?1 /?2 .. but i can't redirect everything to the "home"
    return 302 $scheme://audioguide.com/$request_uri

    Thanks in advance for your time.

    Greetings,
    Riccardo

Leave a Reply to Anonymous Cancel reply