What is a captive page and how to create one?
My issue: the expected "Sign into Wi-Fi network" prompt does not always appear automatically when I try to log into a public network that requires a login, like "WiFi on ICE" in Deutsche Bahn's intercity trains. Sometimes computers fail or refuse to display that page, making it hard to use the internet while travelling or working in a café.
Cannot reach public WIFI login page in Ubuntu, Captive Portal Issue, a post on AskUbuntu.com, has been viewed 23k times! How can so many people visit that page if they don't have internet? 🤔
What is happening here?
Many systems like Android, ChromiumOS, Apple's MacOS, or Microsoft Windows seem to have a built-in sign-in process that calls an external "captive page" like captive.apple.com
.
Ubuntu Linux doesn't, which might be one of the few disadvantages of using Linux, although technically speaking, we could rather say the captive portals hijack people's first internet requests, which is more easy to achieve on Windows and Apple devices than on Linux which mostly prioritizes security over convenience.
I tried to understand what is actually happening here and found it is not that simple and straightforward as it might seem on a first glance. Check Wikipedia and Chromium for more details.
A captive portal usually tries to capture your first website request using its DNS server, and if it doesn't, your operating system's connection manager will try to do so, at least on most operating system except Linux.
Even without setting up an automatic sign-in process, we can mostly achieve the same result by manually visiting one of the popular captive pages like http://captive.apple.com/ which will return a simple, unstyled, page with a "success" message without enforcing an encryted HTTPS connection.
There is no Internet
If it doesn't work, you might see another vintage style website telling you that there is no internet. I can tell you as I'm living in Germany. Despite the material wealth of our country, we are quite poor in other aspects of life, maybe emotionally but surely technologically, as Germany is infamous for its slow and unskillful adoption of new technology and its relatively slow and unreliable internet connections.
Understanding Captive Pages and their Limitations
Wikipedia lists different kinds of issues that might break the automatic portal process:
Captive portals often require the use of a web browser; this is usually the first application that users start after connected to the Internet, but users who first use an email client or other application that relies on the Internet may find the connection not working without explanation, and will then need to open a web browser to validate. [...] A similar problem can occur if the client uses AJAX or joins the network with pages already loaded into its web browser. Similarly, as HTTPS connections cannot be redirected (at least not without triggering security warnings), a web browser that only attempts to access secure websites before being authorized by the captive portal will see those attempts fail without explanation (the usual symptom is that the intended website appears to be down or inaccessible).
Building a Captive Page of our own
Wouldn't it be cool to have our own captive.localhost
or even a service like https://captive.open-mind-culture.org/ ready to go on any device?
While the actual captive mechanisms can do more or less complicated things like access control and intercepting network traffic, all that we want to build is a page that will trigger this mechanism.
So "creating a captive page" that we can call in our web browser to trigger the actual captive mechanism, is in fact nothing but a page that accepts an unencrypted HTTP request and returns a 204 or 200 status code without redirecting to HTTPS.
Using PHP to generate a Simple Page and Set HTTP Headers
One possible way to return a website and control its HTTP headers is by using PHP, which might be the simplest way if you already have a PHP-based application like WordPress up and running on a web server. If you haven't, you might prefer to deploy a node server to a cloud infrastructure or configure a "serverless" service.
Let's assume we have a PHP server ready, we can create a new directory and configure a new subdomain that points to that folder where we will then put a file called index.php
that sets the appropriate response headers, like preventing our browser or web proxies to cache the page.
Sending any Successful 2xx HTTP Status
As Apple's implementation shows, we don't have to send a 204 No Content
status. Many portals, like ICEportal of German long distance trains, use their captive page to display a consent or login form, advertise their services (like entertainment content stored on a local server) or display status information (like the current train line and upcoming station). But we don't have to bother putting too much content either, as we expect to get redirected to the real captive page once the external network intercepts our call and hijacks our first request anyway. Well, some do and some don't, so let's put some minimal content at least.
<?php
if (!headers_sent()) {
header('Status: 200 OK');
header('Cache-Control: no-cache');
header('Content-Type: text/html');
}
?><!DOCTYPE html>
<html lang="en">
<head>
<title>Success</title>
</head>
<body>
More content here...
Nice! Now we have to prove that it actually works and does its job, right? Here's the page, let's see it in action: http://captive.open-mind-culture.org
Everything seems to work as expected. No error, no redirect, no https in the first place, and an HTTP header to prevent caching.
Test, Discussion, and German Blogpost
Now all I have to do is test it "in the wild", taking my Linux laptop outside and try to use it in a public network known to require a captive page like Deutsche Bahn's WiFiOnICE or WiFi@DB.
This article has bee cross-posted as "There is no internet". A German version will be coming up in my Open Mind Culture webblog.
If you have any issues or feedback about my captive page and explanations, feel free to share your experience in the comments!
Top comments (4)
Further reading: Still no internet? How to prevent premature timeouts on Ubuntu?
Still no internet? How to prevent premature timeouts in Ubuntu?
Ingo Steinke ・ Jan 18
If you still can't connect using German railway Deutsche Bahn's WiFi on ICE network from a Ubuntu / Linux system, the reason might be that you're a dev an using Docker with the standard configuration which has an address conflict with WIFIonICE at
172.18.0.0/16
. Thanks to German UbuntuUsers forum: Probleme mit dem WIFIonICE for pointing out!A quick workaround, unless you actually have to use Docker while working on a train (of course you do), you can stop Docker, optionally also prune its networks and try to explicitly clear
172.18.0.0/16
using thebr-
address that you can find out using theifconfig
command. Thus:ip a
to check if you are actually connected to any network.ip a | grep docker
to check if Docker is a potential problem and find out its name to use for shutting it down.Last but not least, if needed, use
ifconfig
to find out the conflicting broadcast address.Then reload the captive page or iceportal.de/
See the forum post (or any other helpful documentation) on how to permanently reconfigure Docker to use an alternative network address, for example this post on ServerFault: Configuring Docker to not use the 172.17.0.0 range:
Tested today on FlixTrain: my HTTP page works and gets redirected to their portal page, which offers entertainment content, but no checkbox to accept the terms in my desktop browser, even after clearing cache and cookies, and no internet apart from their own page and Google. 🤔
Takeaway/reminder: always make as much data available offline as possible. Use a mail client software that stores emails and schedules to send them when online again.
German version is ready as well: Gibt es hier kein Internet? Was ist eine Captive Page und wie kann ich selbst eine bauen?