Setting up the final piece of the new network puzzle, the wireless access points…

These are TP-Link EAP225 accesspoints which can be managed with TP-Link’s Omada Controller Software. As I have 3, to provide coverage throughout our house and into the garden, it’s worth setting up the controller software.

Install the controller software

The documentation has very little information about the software itself, just very minimalist install instructions that consist of ‘just run our script as root or download and install out package’. No information on configuring which network interface it listens on, firewall requirements or what files it actually contains. This all smells bad to me, so I decided to use a 3rd party Docker container instead. The information on how to run it tells me what ports it needs etc. and I can also constrain its ports to only be exposed on a particular interface.

All of this is done via Salt:

  1. Create a new role ‘tplink-omada-controller’ in my state tree.
  2. Include the existing ‘docker’ role in the role’s sls file.
  3. Have it force-download (to keep it up to date) the Docker container (via docker_image.present)
  4. Add creation of the necessary volumes (tplink-omada-data, tplink-omada-work and tplink-omada-logs)
  5. Run the container with restart always (via docker_container.running) based on the recipe from DockerHub, modified to limit it to the switch management network interface and using the volumes above.
  6. Add the role to the host that will run the container via the host-specific role list in pillar.
  7. Run the state tree on the host to apply the changes.

The new role’s configuration is:

include:
  - roles.docker

mbentley/omada-controller:
  docker_image.present:
    - tag: latest
    - force: True
    - require:
      - pkg: docker-pkgs

tplink-omada-data:
  docker_volume.present:
    - require:
      - pkg: docker-pkgs

tplink-omada-work:
  docker_volume.present:
    - require:
      - pkg: docker-pkgs

tplink-omada-logs:
  docker_volume.present:
    - require:
      - pkg: docker-pkgs

tplink-omada-controller:
  docker_container.running:
    - image: mbentley/omada-controller:latest
    - port_bindings:
      # ...
    - environment:
      - TZ: Europe/London
      - SMALL_FILE: 'false'
    - binds:
      - tplink-omada-data:/opt/tplink/EAPController/data
      - tplink-omada-work:/opt/tplink/EAPController/work
      - tplink-omada-logs:/opt/tplink/EAPController/logs
    - watch:
      - docker_image: mbentley/omada-controller
    - require:
      - docker_volume: tplink-omada-data
      - docker_volume: tplink-omada-work
      - docker_volume: tplink-omada-logs

Backup the container volumes

Before actually setting up the WAPs, I wanted to ensure that the container volumes are being backed up. Using the recipe from the Docker documentation I created this script, run by dropping it in cron.daily (N.B. the system’s filesystem is already backed up regularly so dumping it somewhere like this is sufficient to start getting snapshots):

#!/bin/bash
BACKUP_DIR=/srv/backups/tplink-omada-controller
BACKUP_FILE=backup.tar.gz
ONEDAY=$(( 60*60*24 )) # 60s * 60m * 24h = seconds in a day

age_warn() {
  # Function to check the age of the backup is less than 24 hours.
  # Optionally takes an argument to exit with that argument's value as state if it is not.
  if [[ $(( $(date +%s) - $(stat -c %Y ${BACKUP_DIR}/${BACKUP_FILE}) )) -gt ${ONEDAY} ]]
  then
    echo "WARNING: Backup is over 24 hours old!" >&2
    [[ -z "$1" ]] || exit $1
  fi
}
echo "Checking old backup:"
age_warn
docker run --rm --volumes-from tplink-omada-controller -v ${BACKUP_DIR}:/backup alpine tar czf /backup/${BACKUP_FILE}-new /opt/tplink/EAPController && mv ${BACKUP_DIR}/${BACKUP_FILE}{-new,}
bad_state=$?
echo "Checking age after new backup:"
age_warn 1
exit $bad_state # Exit with the exit state of the docker command

It is crude and really needs wrapping in my cron wrapper so it only triggers cron emails on failure.

Open a web-browser and navigate to port 8088 where you installed it (e.g. for me http://omada.home.entek.org.uk:8088/), then follow the setup wizard.

During set-up it will try and detect an access point - because Omada is running inside docker it is horribly confused what its network is and it only tries to find devices on the local network. The easiest way to deal with this is to download the Omada Discover Utility, plug a Windows or Mac (No Linux support - eww!) device into the switch management network and configure them with the controller’s details.

I also gave them sticky IP assignments and host-names via DHCP (via Salt).

The rest was a case of clicking ‘next’ and configuring each AP (naming and putting the management interface onto the switch management VLAN) and the wireless networks.

Even setting up the guest network as a captive portal was very, very straight-forward through the Omada software, however the portal runs on the controller so I had to allow client access to it in the controller host’s firewall - something I’d have preferred not to do. It should be possible to restrict clients on the guest network to only accessing the portal sub-url via a transparent proxy (e.g. Squid) but I’ve not set that up at the moment. I also had to remove the local DNS server from the list the DHCP server hands out to guest clients (which with hindsight is probably the right thing to do anyway) because the ‘Guest Network’ tick-box causes the access points to automatically block access to all private IP addresses, which includes the local DNS server.