This is an old revision of the document!


DNS Split-Horizon Setup for BYOD and loaner digital guides on mobile devices

Visitors using Bring Your Own Device (BYOD) loaner devices to access a local audio guide or digital guide over wifi.

This guide explains how to provide a seamless experience for users who may access your audio guide or digital guide either from your local WiFi. By using a DNS split-horizon setup, you can automatically redirect devices to the internal server when on the local network while showing a fallback page with information for visitors still not connected to the wifi.

1. Why This Setup Helps

When visitors open your audioguide URL:

If they are on the local WiFi, they should automatically reach the local audioguide server.

If they are offsite, they should see a helpful fallback page explaining how to connect or providing external resources.

This improves the BYOD experience by reducing errors, unnecessary redirects, and user confusion.

2. Internet-Facing Requirements

To handle requests from outside your LAN:

Domain Name: Register a public domain, e.g., myaudioguide.net.

DNS Configuration: Point the myaudiogude.net to a publicly accessible web server. (Typically a small droplet on e.g. digital ocean) Point int.myaudioguide.net to th elocal servers local ip e.g. 10.2.0.10.

HTTPS Certificate: Ensure the certificate is valid for the public domain.

Fallback Webpage: This page will attempt to probe the local server:

If the probe succeeds, the visitor is redirected to the internal server.

If not, the visitor remains on the fallback page.

Note: Ensure the fallback page is served over HTTPS to avoid browser mixed-content warnings.

3. Local LAN Requirements

To make the audioguide work seamlessly on local WiFi:

DNS Configuration: Configure your local DNS so that both myaudioguide.net and int.myaudioguide.net resolve to the local audioguide server’s IP.

HTTPS Certificate: Use a certificate valid for both internal and public domain names (wildcard or SAN certificate).

Reverse Proxy: Nginx is recommended to handle internal routing and serve certificates.

Tip: Using Certbot with DNS challenges can simplify automatic certificate renewal for mixed public/private setups.

Example code for a fallback webpage:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="description" content="Internet redirect notice for local WiFi" />
  <meta name="keywords" content="audioguide myaudioguide digitalguide">
  <title>PIXILAB Guide</title>
  <style>
    body {
      margin: 1em;
      box-sizing: border-box;
      background: #000;
      color: #fff;
      font-family: "Trebuchet MS", sans-serif;
      font-size: 8vmin;
      text-align: center;
    }
    h1 { font-size: 1.5em; margin: 0.5em 0; }
    a { color: aliceblue; }
    #blurb { font-size: 0.6em; }
  </style>
</head>
<body>
  <div>
    <h1>PIXILAB Guide</h1>
    <p>You are not connected to the local WiFi required to access the audio guide.</p>
    <p>Please connect to the recommended WiFi, then return to this page.</p>
    <hr/>
    <p id="blurb">Learn more about PIXILAB's <br/><a href="http://pixilab.se/blocks">mobile guide</a>.</p>
  </div>
</body>
<script>
  // Probe the internal server to detect local network access
  retrySoon(100); // Initial quick probe

  function retrySoon(delay) {
    delay = delay || 4000;
    setTimeout(() => {
      const xhr = new XMLHttpRequest();
      xhr.timeout = 5000;
      xhr.onload = handleSuccess;
      xhr.onerror = handleError;
      xhr.ontimeout = handleTimeout;
      xhr.open("GET", "http://int.myaudioguide.net/img/invisible.png?buster=" + Date.now());
      xhr.send();
    }, delay);
  }

  function handleSuccess() {
    setTimeout(() => {
      location.href = "http://int.myaudioguide.net" + location.pathname + location.search;
    }, 200);
  }

  function handleError(evt) {
    console.log("Error connecting to internal server", evt.target.status);
    retrySoon();
  }

  function handleTimeout(evt) {
    console.log("Internal server probe timed out");
    retrySoon();
  }
</script>
</html>