CoovaChilli is the most capable open-source captive portal daemon available for OpenWrt. It handles guest isolation, UAM (Universal Access Method) splash page redirect, RADIUS accounting, and per-session bandwidth and data limits โ€” all without requiring proprietary cloud infrastructure. This guide walks through the full install path for Weird Network providers: package install, UAM configuration, RADIUS settings, and end-to-end session verification.

Prerequisites: An OpenWrt device running 21.02 or newer (ath79, ipq40xx, x86/64, or any target with sufficient flash). Minimum 16 MB flash / 128 MB RAM recommended โ€” CoovaChilli + dependencies consume ~2.5 MB installed. You need SSH access and a working WAN connection on the router before starting.

1. Install CoovaChilli

CoovaChilli is available in the standard OpenWrt package feed as coova-chilli. SSH into your router and run:

SSH โ†’ OpenWrt shell
opkg update
opkg install coova-chilli

This installs the daemon, its UCI config schema, and the init script at /etc/init.d/chilli. The package also pulls in kmod-tun (TUN/TAP kernel module) automatically. Verify the install succeeded:

Check installed version
opkg info coova-chilli | grep Version

Flash space: If opkg reports insufficient space, CoovaChilli can be installed on a USB-attached ext4 volume using extroot overlay. See the OpenWrt extroot docs before proceeding. Do not attempt the install on a device with less than 4 MB free.

2. Network Interface Setup

CoovaChilli manages a dedicated guest network interface. It bridges or aliases off one of your LAN ports โ€” guests connect to that interface and are placed in an unauthenticated state until they complete the captive portal flow.

Create the guest interface

In this example the guest SSID is served on wlan0 and CoovaChilli will create a virtual interface tun0 for its internal network. Edit /etc/config/network and add:

/etc/config/network (add this block)
config interface 'guest'
    option ifname   'wlan0'
    option proto    'none'

Setting the proto to none tells OpenWrt not to assign an IP to this interface โ€” CoovaChilli handles addressing for the guest network internally via the TUN device it creates (tun0 by default).

Create a guest SSID in wireless config

/etc/config/wireless (add this block)
config wifi-iface
    option device   'radio0'
    option mode     'ap'
    option ssid     'Guest WiFi'
    option network  'guest'
    option encryption 'none'
    option isolate  '1'

isolate 1 prevents guests from communicating with each other on the wireless segment โ€” essential for a shared guest network. No WPA passphrase is set because CoovaChilli controls access at layer 3.

Multiple SSIDs: If your device has two radios (2.4 GHz + 5 GHz), add a second wifi-iface block pointing to radio1 with the same network 'guest' binding. CoovaChilli will control both through the same TUN interface.

3. UAM Captive Portal Configuration

CoovaChilli's main config lives at /etc/chilli/config. The file is sourced by the init script and supports both UCI (/etc/config/chilli) and flat key-value formats. The flat format shown here works on all OpenWrt releases:

/etc/chilli/config
# Network interface CoovaChilli listens on (the guest SSID interface)
HS_WANIF=eth0          # your WAN/uplink interface
HS_LANIF=wlan0         # guest-facing interface

# IP pool for guest devices (CoovaChilli DHCP range)
HS_NETWORK=10.1.0.0
HS_NETMASK=255.255.255.0
HS_UAMLISTEN=10.1.0.1  # CoovaChilli's own IP on the guest segment
HS_UAMPORT=3990        # Port for the UAM HTTP listener

# UAM โ€” where unauthenticated guests are redirected
HS_UAMSERVER=https://weird-network.io/portal/<YOUR_LOCATION_ID>

# Walled garden: hosts reachable before authentication
HS_UAMALLOWED=weird-network.io,weird-network.polsia.app,fonts.googleapis.com,fonts.gstatic.com

# UAM shared secret (used to sign redirect URLs โ€” must match your Weird Network portal config)
HS_UAMSECRET=change_this_to_a_strong_random_secret

# DNS servers pushed to guest devices
HS_DNS1=8.8.8.8
HS_DNS2=8.8.4.4

# Logging
HS_SYSLOG=on

Replace <YOUR_LOCATION_ID> with the location ID from your Weird Network provider dashboard (Settings โ†’ Locations โ†’ copy the ID). The HS_UAMSECRET value must match exactly what you enter in the portal's router configuration screen.

HTTPS redirect requirement: HS_UAMSERVER must use HTTPS. Browsers block plaintext captive portal redirects on many modern operating systems. Weird Network's portal endpoint is always HTTPS โ€” do not change it to HTTP.

Optional: session limits

Add these lines to /etc/chilli/config to enforce per-session caps:

/etc/chilli/config โ€” optional session limits
# Session timeout (seconds) โ€” 3600 = 1 hour, 0 = no limit
HS_DEFsessiontimeout=3600

# Idle timeout (seconds) โ€” kick inactive guests after N seconds
HS_DEFIDLETIMEOUT=600

# Per-session data cap (bytes) โ€” 107374182400 = 100 GB, 0 = unlimited
HS_DEFBANDWIDTHMAXDOWN=10000000   # 10 Mbps download cap per session
HS_DEFBANDWIDTHMAXUP=2000000      # 2 Mbps upload cap per session

4. RADIUS Settings

CoovaChilli uses RADIUS for authentication and accounting. If you are using Weird Network's built-in session tracking (recommended), you can point to the Weird Network RADIUS bridge or run without RADIUS for simpler deployments.

Option A: Weird Network RADIUS bridge (recommended)

Weird Network provides a RADIUS-compatible endpoint that maps authentication events to captive portal sessions in your dashboard. Add to /etc/chilli/config:

/etc/chilli/config โ€” RADIUS section
# RADIUS authentication server
HS_RADIUS=radius.weird-network.io
HS_RADIUS2=radius.weird-network.io   # failover (same host, retry)
HS_RADSECRET=<YOUR_RADIUS_SECRET>   # from provider dashboard โ†’ Locations โ†’ RADIUS

# RADIUS accounting (sends session start/stop events)
HS_RADIUSACC=radius.weird-network.io
HS_RADIUSACC2=radius.weird-network.io

# NAS identifier โ€” use your location ID for clean dashboard attribution
HS_NASID=<YOUR_LOCATION_ID>
HS_NASSTATIONID=<YOUR_LOCATION_ID>

The RADIUS secret is generated per-location in your provider dashboard under Settings โ†’ Locations โ†’ RADIUS Config. It is separate from the UAM secret.

Option B: No RADIUS (UAM-only mode)

If you prefer to skip RADIUS and report sessions directly via the Weird Network REST API instead, omit the HS_RADIUS* lines and set:

/etc/chilli/config โ€” UAM-only mode
# Disable RADIUS (use UAM callback + Weird Network session API instead)
HS_NORADIUS=on

In this mode, session start/end events fire via the UAM callback URL. Your captive portal page calls POST /api/sessions/start and POST /api/sessions/:id/end directly. See Section 8 for details.

5. Firewall and Walled Garden

CoovaChilli sets up its own iptables rules automatically, but you need to configure the OpenWrt firewall to allow the guest zone to reach the CoovaChilli UAM port and your WAN.

/etc/config/firewall (add this zone and forwarding)
config zone
    option name     'guest'
    option network  'guest'
    option input    'DROP'
    option output   'ACCEPT'
    option forward  'DROP'

config forwarding
    option src  'guest'
    option dest 'wan'

CoovaChilli intercepts packets from the guest zone before they reach the firewall forwarding rules. Unauthenticated traffic is redirected to the UAM port (10.1.0.1:3990); authenticated sessions are forwarded to WAN by CoovaChilli's own iptables chain, not by the OpenWrt forwarding rule above. The forwarding rule is a fallback for edge cases only.

Allow CoovaChilli management port

CoovaChilli exposes a JSON management interface on port 4990 (localhost only by default). If you want to query it from your server scripts, add a loopback rule:

iptables rule (add to /etc/firewall.user)
# Allow CoovaChilli JSON interface from localhost only
iptables -A INPUT -i lo -p tcp --dport 4990 -j ACCEPT

6. Start and Enable the Service

Apply the wireless and network changes, then start CoovaChilli:

1

Reload network and wireless

/etc/init.d/network reload
wifi down && wifi up
2

Start CoovaChilli

/etc/init.d/chilli start
3

Enable at boot

/etc/init.d/chilli enable
4

Check the process is running

ps | grep chilli

You should see two chilli processes โ€” the parent daemon and the child worker. If only one appears, check logread | grep chilli for startup errors.

Confirm TUN device: Run ip link show tun0 โ€” if CoovaChilli started correctly you will see the tun0 interface with state UP. If it is absent, CoovaChilli failed to bind to the guest interface; double-check HS_LANIF in /etc/chilli/config.

7. Verify Captive Portal Redirect

Connect a test device (phone or laptop) to the guest SSID. Open a browser and navigate to any HTTP URL โ€” do not use HTTPS for the initial test, as modern browsers skip HTTP for cached HTTPS sites. Try http://neverssl.com.

1

Confirm DHCP assignment

The test device should receive an IP in the 10.1.0.x range (or whatever range you set in HS_NETWORK). If it stays on APIPA (169.254.x.x), CoovaChilli's built-in DHCP is not running โ€” verify tun0 is up and HS_LANIF matches the actual interface name.

2

Confirm redirect fires

Navigating to http://neverssl.com should redirect the browser to your HS_UAMSERVER URL with query parameters appended: ?mac=<device_mac>&ip=<device_ip>&called=<...>&nasid=<...>.

3

Confirm walled garden access

Before completing the portal, the device should be able to load weird-network.io but NOT reach arbitrary internet hosts. If internet is fully open pre-auth, HS_UAMALLOWED is too permissive or CoovaChilli's iptables rules weren't applied โ€” restart the daemon and check iptables -L -n | grep chilli.

4

Complete a test authentication

Submit the portal form (email capture or voucher). Weird Network's portal calls back to CoovaChilli's UAM interface at http://10.1.0.1:3990/json with an Accept action to authorize the MAC. The device should then have unrestricted internet access.

8. Connect to Weird Network Session API

Weird Network's captive portal page handles session creation automatically when a guest authenticates. Under the hood it calls the session API on your behalf. For reference, here is what happens on each auth event:

Session start (on portal form submit)

POST /api/sessions/start
POST https://weird-network.io/api/sessions/start
Content-Type: application/json

{
  "mac_address":  "aa:bb:cc:dd:ee:ff",
  "ip_address":   "10.1.0.42",
  "provider_id":  "<YOUR_PROVIDER_ID>",
  "location_id":  "<YOUR_LOCATION_ID>",
  "router_id":    "<YOUR_ROUTER_ID>",     // optional โ€” from pairing flow
  "auth_method":  "form_capture"             // or "voucher" / "social_gate"
}

The API returns a session_id (UUID). The portal page stores this and sends the UAM Accept call to CoovaChilli to grant internet access for that MAC address.

Session end (on disconnect or timeout)

CoovaChilli sends a RADIUS Accounting-Stop packet when a session ends. If you are using the Weird Network RADIUS bridge, this automatically closes the session record. In UAM-only mode, you can fire the end event from a script that polls http://localhost:4990/json (CoovaChilli's local management interface):

Query CoovaChilli local JSON interface
curl -s http://localhost:4990/json | python3 -m json.tool

The response lists all active sessions with MAC, IP, bytes in/out, and session duration. A session absent from this list has disconnected and should be ended via POST /api/sessions/:id/end.

Router pairing: To surface this router in your Weird Network provider dashboard (router status, alerts, firmware tracking), complete the pairing flow: generate a pairing code in your dashboard under Routers โ†’ Generate Code, then call POST /api/routers/pair with the code and the router's MAC address. Paired routers appear in session records and trigger router-offline alerts automatically.

9. Troubleshooting

Common issues and fixes:

!

Guests get DHCP but no redirect

CoovaChilli is running but iptables rules are not intercepting traffic. Run iptables -t nat -L -n | grep -i chilli โ€” if empty, CoovaChilli's rules were not inserted. Try /etc/init.d/chilli restart. Also confirm HS_LANIF matches exactly the interface name shown in ip link output.

!

Redirect loop โ€” portal keeps redirecting back

The UAM Accept callback from the portal is not reaching CoovaChilli. Verify HS_UAMLISTEN is the correct IP of the tun0 interface and that port 3990 is not firewalled. Run netstat -tlnp | grep 3990 to confirm CoovaChilli is listening.

!

RADIUS authentication rejected

Double-check HS_RADSECRET against the secret shown in your provider dashboard. Shared secrets are case-sensitive and whitespace-sensitive. Run logread | grep -i radius to see the raw RADIUS error code โ€” Access-Reject usually means a bad secret; timeout means the server is unreachable (check DNS and port 1812/UDP firewall rules).

!

Portal page loads but form submit does nothing

The UAM secret mismatch. The portal signs its callback URL using HS_UAMSECRET โ€” if the secret in your provider dashboard differs from the one in /etc/chilli/config, CoovaChilli will reject the callback silently. Update both values to match and restart the daemon.

!

Guests can access internet before authenticating

CoovaChilli's iptables DROP rules are being overridden by an existing OpenWrt firewall rule. Check iptables -L FORWARD -n for broad ACCEPT rules above CoovaChilli's chain. Move the guest zone to option forward DROP and remove any catch-all ACCEPT rules in /etc/config/firewall that match the guest interface.

Logs: All CoovaChilli events go to syslog when HS_SYSLOG=on is set. Run logread | grep chilli for a real-time view, or logread -f | grep chilli to tail. Session start/end, RADIUS events, and UAM callbacks all appear here.

10. Reporting sessions to Weird Network

CoovaChilli doesn't natively POST to a third-party API, so the recommended pattern is to wire a tiny shim into CoovaChilli's HS_UAM_SCRIPT hook (which fires on every successful authentication). The shim translates each event into the POST /api/sessions/start shape your dashboard already understands, and a successful run shows up in the /provider/sessions live page within about 10 seconds.

Quick start (HS_UAM_SCRIPT wrapper)

Install the script and a one-line wrapper on the router:

# /etc/chilli/report-form.sh โ€” invoked by CoovaChilli on auth success
#!/bin/bash
exec /opt/wn/report-session.sh \
  --mac "$1" \
  --ip "${HS_REMOTEIP:-}" \
  --auth form_capture \
  --location "$WEIRD_NETWORK_LOCATION_ID"

Then point CoovaChilli at it from /etc/chilli/config:

HS_UAM_SCRIPT="/etc/chilli/report-form.sh"

The full script (with argument validation, env fallback, exit codes, and cron / hotplug alternatives) lives at /coovachilli/report-session.sh with full setup notes at /coovachilli/README.md.

Manual smoke test

After saving the script (don't forget to chmod +x), verify the network path:

./report-session.sh \
  --api-url https://weird-network.io/api/sessions/start \
  --mac AA:BB:CC:DD:EE:FF \
  --auth form_capture \
  --provider 42 --location 7

Open /provider/sessions in another tab โ€” the row should appear within the next 10-second poll and flash for 2 seconds. If you see FAIL http=... on the router, walk through the exit codes in the README.

Tip: If your router can't reach weird-network.io directly (NAT, captive portals on the management network), set WEIRD_NETWORK_API_URL in the script's environment to a reachable mirror or Render host.

Related Guides

Other router setup guides and references for Weird Network providers: