Fibre Optics Header

Access your modem’s status page behind a UniFi USG router

With a full UniFi network setup (a UniFi USG router, switches, access points and so on), the UniFi router is separate from any modem needed to connect to the Internet. Your setup might look a little like this:

Because your computer isn’t directly connected to the modem, the modem is effectively “hidden” by the UniFi USG. You can still get online, but you can’t see your connection statistics and logs.

Here’s how to fix it:

Pre-requisites

First thing’s first, you need to know the IP address of your modem, and the network range for the UniFi network. The IP address of the modem must also be different to the UniFi network range. In my case, the modem IP address is 192.168.0.1 and the UniFi network range is 192.168.1.0/24.

So the instructions below will work, enter your modem IP address, the network mask in CIDR notation (without the /), enter an unused firewall rule index (the example is probably fine for a USG, but may not be for other Ubiquiti devices), and finally choose the port your modem is connected to.

Once complete, click Update:

Configuration

The remaining steps assume you have a UniFi Network Controller online somewhere, and in that controller you have Advanced Features turned on.

Log into the controller, navigate to the site where your UniFi USG is configured and go to Settings. At the bottom of the screen is the Device Authentication section – copy the SSH authentication details, then SSH into the IP address of the UniFi USG.

Enter the following commands, one line at a time:

configure
set interfaces pseudo-ethernet pREPLACEME4 link REPLACEME4
set interfaces pseudo-ethernet pREPLACEME4 address REPLACEME1/REPLACEME2
set interfaces pseudo-ethernet pREPLACEME4 description "Access to modem"
set service nat rule REPLACEME3 type masquerade
set service nat rule REPLACEME3 destination address REPLACEME0
set service nat rule REPLACEME3 outbound-interface pREPLACEME4
commit
save
exit

You should now be able to access your modem’s status page at http://REPLACEME0/.

Assuming that worked, you need to make the changes permanent with a configuration file for your UniFi Network Controller. Save the following into a text file called config.gateway.json:

{
    "interfaces": {
        "pseudo-ethernet": {
            "pREPLACEME4": {
                "address": ["REPLACEME1/REPLACEME2"],
                "description": "Access to modem",
                "link": ["REPLACEME4"]
            }
        }
    },
    "service": {
        "nat": {
            "rule": {
                "REPLACEME3": {
                    "destination": {
                        "address": ["REPLACEME0"]
                    },
                    "outbound-interface": ["pREPLACEME4"],
                    "type": "masquerade"
                }
            }
        }
    }
}

Upload this file into the UniFi Network Controller. The directory you need to upload to will depend on which site you’re configuring; the UI support article for this topic is quite detailed and I’d recommend reading it.

TL;DR: I uploaded mine to /unifi/data/sites/default/ – but read the support article for yourself; don’t assume this is the correct directory for your Network Controller!

Extra: NBN modems

For readers from Australia – there are a few things to know about the modems (or NCD / NTDs) supplied by NBNCo. Some you can access, some you can’t:

NBN Connection TypeAccess to modem?
FTTPn/a
HFCYes*
FTTCNo
FTTN/FTTBYes

The two other connection types (Fixed Wireless and Satellite) I have no idea about, so I haven’t included them in this table.

HFC

For HFC, the modem makes it difficult to access the connection statistics page. Thankfully, it’s fairly easy to get in – follow the instructions above (the modem IP is 192.168.0.1), then hard reset the modem by inserting a pin in the reset hole for around 10 seconds.

The reset is complete when the green lights go out and a blue light flashes a couple times – once you see that, release the pin and load http://192.168.0.1/main.html in a browser. Chances are very good you’ll need to refresh several times before the status page displays.

If the modem restarts for any reason (power outage, NBN outage etc), you’ll need to do another hard reset to get back in.

FTTN/FTTB

For these connection types, you supply your own modem – no special instructions required. 🙂 Refer to your modem’s documentation to understand what the default IP address and access details are.

References

I found the following sites helpful in writing this post:

https://owennelson.co.uk/accessing-a-modem-through-a-ubiquiti-usg/
https://forums.whirlpool.net.au/archive/90ym1z23

UniFi Controller 5.11, Let’s Encrypt SSL and Docker

A slight change of plans from earlier posts on the topic of UniFi Controllers! Here’s how to get a UniFi Controller running inside a Docker container, along with a trusted Let’s Encrypt SSL certificate.

Note: this guide assumes you’re configuring things on a server or VM with public Internet access. You’ll also need a fixed public IP and functional DNS to get an SSL certificate.

Here we go:

Firewall

UniFi needs a bunch of inbound ports open. Here’s the official list – it differs slightly to what I use:

PortDescription
UDP/3478STUN – required for device communication with the controller
TCP/8080Inform – required to adopt devices
TCP/8443GUI – required even if you use the Cloud Controller access
TCP/8880Captive Portal – HTTP – only needed if you use the captive portal feature
TCP/8843Captive Portal – HTTPS – only needed if you use the captive portal feature
TCP/6789Speed Test – only needed if you use the speed test feature

Let’s Encrypt also needs a port open:

PortDescription
TCP/80HTTP – required for the HTTP-01 challenge type

I use ufw to configure iptables – first, set up an application definition for the UniFi Controller – in /etc/ufw/applications.d/unifi:

[unifi]
title=unifi
description=UniFi Controller
ports=6789,8080,8880,8443,8843/tcp|3478/udp

Run the following four commands to configure and enable the firewall. I’ve made some assumptions about what’s needed – you may need to customise things a little more:

sudo ufw allow ssh
sudo ufw allow http
sudo ufw allow unifi
sudo ufw enable

User Account

UniFi probably shouldn’t be run as root – this is generally a good idea, plus it may also become a requirement for the Docker image I’m using in the future. This will also affect what ports you can configure the controller to use – the default ports work fine for any user, but changing any of the ports to <1024 requires root.

Create the unifi user and group accounts:

sudo adduser unifi --system --group --no-create-home

Pay attention to the UID and GID that get created; you need them in the Docker Compose file below.

Docker

Here’s the tl;dr version of the installation instructions, but if you want to read the full version with all the details – check the Docker website.

Configure the Docker repository – it contains a more up-to-date version:

sudo apt-get update && sudo apt-get upgrade
sudo apt-get install apt-transport-https ca-certificates curl gnupg2 software-properties-common
curl -fsSL https://download.docker.com/linux/debian/gpg | sudo apt-key add -
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/debian $(lsb_release -cs) stable"

Install Docker and related tools:

sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io

UniFi Controller

There are a number of UniFi Docker images out there, but I like the one by jacobalberty as it’s kept up to date – plus it exposes a volume for adding trusted certificates. His Docker Compose file isn’t quite to my taste, so I’ve adjusted things. Create the file /opt/unifi/docker-compose.yml:

version: '2.2'
services:
  mongo:
    image: 'mongo:3.4'
    restart: always
    volumes:
      - db:/data/db
  controller:
    image: 'jacobalberty/unifi:${TAG:-latest}'
    depends_on:
      - mongo
    init: true
    restart: always
    volumes:
      - data:/unifi/data
      - log:/unifi/log
      - cert:/unifi/cert
      - init:/unifi/init.d
    environment:
      RUNAS_UID0: 'false'
      UNIFI_UID: 100
      UNIFI_GID: 100
      JVM_MAX_THREAD_STACK_SIZE: 1280k
      DB_URI: mongodb://mongo/unifi
      STATDB_URI: mongodb://mongo/unifi_stat
      DB_NAME: unifi
    ports:
      - '3478:3478/udp'
      - '6789:6789/tcp'
      - '8080:8080/tcp'
      - '8443:8443/tcp'
      - '8880:8880/tcp'
      - '8843:8843/tcp'
  logs:
    image: bash
    depends_on:
      - controller
    command: bash -c 'tail -F /unifi/log/*.log'
    restart: always
    volumes:
      - log:/unifi/log

volumes:
  db:
  data:
  log:
  cert:
  init:

Note: if you’re going to change the location of this file, it should be in a directory called ‘unifi’. Bring the stack up like so (it will take a fair while first time around):

sudo docker-compose up -d

Install SSL

This part requires a few sections that need to be completed in order – first you need a script to load the SSL certificate into the UniFi Docker cert volume, then you need to run a certbot command to obtain the certificate.

If you use a provider other than Let’s Encrypt for SSL certificates, these instructions will need to be adjusted.

UniFi SSL Deploy Script

It may seem backwards, but the deploy script needs to exist before obtaining the certificate. Read through this script carefully and adjust any domains and directories as needed. Create the file /opt/unifi/unifi-ssl-deploy.sh:

#!/bin/sh

set -e

for domain in $RENEWED_DOMAINS; do
  case $domain in
  unifi.example.com)
    # Where does the Docker cert data volume live?
    cert_root=/var/lib/docker/volumes/unifi_cert/_data
    # Where is the Docker Compose file?
    compose_file=/opt/unifi/docker-compose.yml

    # Make sure the certificate and private key files are
    # never world readable, even just for an instant while
    # we're copying them into cert_root.
    umask 077

    cp "$RENEWED_LINEAGE/cert.pem" "$cert_root/cert.pem"
    cp "$RENEWED_LINEAGE/privkey.pem" "$cert_root/privkey.pem"
    cp "$RENEWED_LINEAGE/chain.pem" "$cert_root/chain.pem"

    # Apply the proper file permissions
    # Files can be owned by root
    chmod 400 "$cert_root/cert.pem" \
      "$cert_root/privkey.pem" \
      "$cert_root/chain.pem"

    # Restart the Docker container
    docker-compose -p unifi -f $compose_file stop
    docker-compose -p unifi -f $compose_file start
    ;;
  esac
done

Now make the file executable:

sudo chmod a+x unifi-ssl-deploy.sh

Obtain SSL with Certbot

Conveniently, Certbot has its own mechanism for obtaining an SSL certificate without using a webserver. If you have a webserver configured, you will want to adjust these instructions accordingly.

As above, adjust the following to suit your domain:

sudo apt-get install certbot
sudo certbot certonly --standalone --domain unifi.example.com --deploy-hook /opt/unifi/unifi-ssl-deploy.sh

The command to obtain the certificate will ask a few questions – you may also see an error from the deploy script, but it’s not actually an error per se.

Note: After the deploy script has run, you need to wait up to 5 minutes for the UniFi Controller to fully start back up again. If you don’t, you’re likely to get an SSL error (PR_END_OF_FILE_ERROR) in the browser!

We’re all done – your UniFi Controller should now be available via: https://unifi.example.com:8443

Reverse Proxy

I’ve opted to not configure a reverse proxy, as I don’t believe one is needed. If port 8443 is blocked on your network, you can configure cloud access via https://unifi.ui.com.

If you want to configure a reverse proxy, note you’ll need something that handles websockets gracefully – Nginx and Traefik are probably your best options.

UniFi IPv6 and Dual Stack PPPoE

 

Internode offers Dual Stack IPv4/IPv6 connectivity to their broadband customers and has done so since 2011; sadly, said connectivity doesn’t work very well out of the box with the UniFi Security Gateway router.

The problem? UniFi’s router firmware (version 4.4.22.5086045) and cloud controller (version 5.8.30) configure DHCPv6 Prefix Delegation on both the WAN interface and the PPPoE interface; the outcome of which is that the router obtains an IPv6 address – but nothing else in the network does.

This bug manifests itself with any ISP who authenticates customers via PPPoE and provides dual stack connectivity on the PPPoE interface (and assigns a customer-end IPv6 address range via Prefix Delegation) – not just Internode.

Configure IPv6

In case you haven’t already done so, configure IPv6 in the Controller. Internode’s general instruction for IPv6 is that you get given a dynamic /64 for the PPP interface and a static /56 for your LAN, distributed via Prefix Delegation. So far, so easy.

In the Controller, select the site, then Settings -> Networks -> WAN. In the IPv6 section:

  • Connection Type: Using DHCPv6
  • Prefix Delegation Size: 56

Save, then select the local network you want to enable for IPv6. In the Configure IPv6 Network section:

  • IPv6 Interface Type: Prefix Delegation
  • IPv6 Prefix Delegation Interface: WAN (this is the giveaway for where the problem lies..)
  • IPv6 Prefix ID: 56 (unsure whether this is necessary)
  • IPv6 RA: Enable IPv6 Router Advertisement checked (leave settings at the default)
  • DHCPv6/RDNSS DNS Control: Auto

Save and then wait for everything to provision. In theory, this would be enough for everything to just work, but it’s not. If you SSH into the USG and run show interfaces, you’ll see that the ethx interface that corresponds to the local network you configured above doesn’t have an IPv6 address:

Codes: S - State, L - Link, u - Up, D - Down, A - Admin Down
Interface    IP Address                        S/L  Description
---------    ----------                        ---  -----------
eth0         -                                 u/u  WAN
eth1         192.168.1.1/24                    u/u  LAN
eth2         -                                 A/D
lo           127.0.0.1/8                       u/u
             ::1/128
pppoe0       my.public.ipv4.address            u/u
             2001:my:public:ipv6:address:d32f/64

Fix Stuff

Knowing that the problem relates to Prefix Delegation being configured on the WAN interface rather than the PPPoE interface, you need to create a script which disables DHCPv6 Prefix Delegation on the WAN interface and restarts DHCPv6-PD on the PPPoE interface.

SSH into the USG and create /config/scripts/post-config.d/dhcp.sh:

#!/bin/vbash
# Script is started on reboot and via a cronjob created during provisioning

readonly logFile="/var/log/postprovision.log"

source /opt/vyatta/etc/functions/script-template

configure > ${logFile}

# Delete cronjob that called this script
delete system task-scheduler task postprovision >> ${logFile}

# Remove DHCPv6-PD from eth0 (WAN)
delete interfaces ethernet eth0 dhcpv6-pd >> ${logFile}
commit
exit

# Obtain IPv6 addresses for Prefix Delegation
release dhcpv6-pd interface pppoe0 >> ${logFile}
delete dhcpv6-pd duid >> ${logFile}
renew dhcpv6-pd interface pppoe0 >> ${logFile}

Make the script executable: sudo chmod +x /config/scripts/post-config.d/dhcp.sh

SSH into the Controller and either create or update the file [unifi_base]/data/sites/site_ID/config.gateway.json – on Debian, and assuming the site ID is “default”, the config.gateway.json file is located at /usr/lib/unifi/data/sites/default/:

{
  "system": {
    "task-scheduler": {
      "task": {
        "postprovision": {
          "executable": {
            "path": "/config/scripts/post-config.d/dhcp.sh"
          },
          "interval": "2m"
        }
      }
    }
  }
}

Always check that the file contents are valid JSON using JSONLint – this will prevent problems with provisioning the USG.

Finally, force a provision of the USG – log into the Controller, select the site, then Devices -> USG -> Config -> Manage Device -> Provision.

Once provisioned, IPv6 should be working on your network!

Note: If your ISP requires a VLAN tag on the WAN interface, there are slightly different steps required – see the first source below.

Sources:
https://spflug.de/?p=175
https://help.ubnt.com/hc/en-us/articles/215458888-UniFi-USG-Advanced-Configuration