OpenWRT Guest Network (and beyond)

As my kids get to the age where both they and their friends have devices, this means granting access to our internet to a growing circle of people. OpenWRT has the ability to support guest networks and I’ve been meaning to set this up for some time.

Beyond simply having a guest network, I also want to setup an IoT network where I can isolate some of the network enabled things but not give them wide access to the rest of my internal infrastructure.

Let’s start with a simple guest network setup. This is well documented on the OpenWRT site. I’ll be using the CLI instructions to make these changes. FWIW this is based on the 21.02.0 version of OpenWRT.

The first part of this will be pretty much copy and paste from the OpenWRT instructions:

I of course modified the ipaddr for my setup, but pretty much used the command as is.

On the Web UI (LuCI) you should now see under Network->Interfaces a new Guest network. All of the changes landed in the /etc/config/network file.

Now we setup a wireless network configuration with the first radio

Again, I’ve pretty much followed the directions but have customized the SSID and not shared the password. I’ve rolled in the extras to isolate guest users and use encryption.

The LuCI web UI now looks a little more concerning (Network->Wireless)

But.. the previous Network->Interfaces now seems to have come to life.

Still the expected changes are reflected in /etc/config/wireless.

It took a bit of head-scratching, but I figured out what was wrong. I had not specified a wireless.guest.key that met the minimum length (8 to 63 characters) – this apparently caused everything to go sideways. Once I fixed this my new wireless interface came to life.

Let’s continue on with the DHCP configuration

And the Firewall

Now not only should you be able to see the new WiFi SSID available to connect to, but when you do you will be isolated from all other devices on the network and only able to see the internet. A network scan will turn up the existence of the router, but attempts to connect the web UI fail – that’s pretty cool isolation.

Devices connected to the guest network still show up in the OpenWRT status page. They are assigned a DHCP address from the network.guest.ipaddr subnet, which is distinct from my normal network.

Apparently I do give up a little performance having two (or more) networks hung off of the same radio, but the utility of having a restrictive guest network is pretty cool.

The Archer C7 has two radios, and we’ve not configured the guest network on the second radio. Let’s do that now.

Cool – now I have a guest network that is on both radio bands. You’ll note that I run both access points with the same SSID, this mostly just works and devices figure it out. I even run my dumb AP with the same SSID. This is one approach that works and let’s people move around the house with seamless connections.

I do know that some people try to force a device to a particular radio type, and will run their legacy network on a different SSID. This is of course also valid, it really depends what you’re looking to achieve. I’m taking the simple to configure devices approach, and giving the devices the responsibility to work out which radio band and which access point to connect to.

Now let’s create a second ‘guest’ like network for IoT devices. This time I’ll just combine all of the steps together

Nice – now I have a third subnet which will hand out DHCP addresses valid for 24hrs. The devices are all isolated from each other.

For devices on the IoT network, while I don’t want the device to be able to see anything other than the internet – for my own monitoring and use, I’d like to be able to see the devices on the IoT network from my normal lan network. This turns out to be very easy.

Connecting to the IoT network and doing as scan, shows me that I can only see myself and the router (because the device has to send traffic somewhere). Again, with the isolation I can’t connect to the web interface of the router. However, with this new “zone->forwardings” I can from my lan network see devices on the IoT network. Super cool, and actually very easy.

There plenty more tweaking we can do here, but to avoid going too far down the rabbit hole we’ll stop here.

Installing docker-mailserver

Everyone should have their own domain name (or several). Having a website on your domain is easy and a sensible use of that domain name. Almost no one should run their own email server, it’s complicated and makes you responsible for all of the problems.

There are lots of providers out there that run email services and allow you to bring your own domain. ProtonMail would be a good choice, you can even bring your own custom domain and still use ProtonMail. Alternatives are offered by Google, and Microsoft if you want to go that route, both provide support for custom domains.

If you are still thinking of running your own mail server, then grab your tinfoil hat and let’s look at the best way to operate a mail server in the age of containers. I’ve run my own email for a long time, mostly following the Ubuntu setup. Using the docker-mailserver solves all of the email problems with a single container.

I will mention there are many alternatives: mailu, iredmail, etc. The docker-mailserver project stands out for me as they have avoided database based configuration and have stuck with ‘files on disk’ as the model.

This is a long overdue mail upgrade. I started doing this way back in 2017, but never really finished the work. The SSD rebuild disrupted how I was doing things, and changing email is a little scary. The hard drive that stores my email is very old. It is a Seagate Barracuda 40GB (ST340014A). The SMART information says that the Power Cycle Count is only 502, but the Power On Hours is an astounding 130442 (that is 14.89 years). Every stat is in pre-fail or old age, it is definitely time to move my email off that drive.

Before starting, take the time to read through the documentation. Once you think you’re ready to start installing thing the ReadMe is the right path to follow. I’m going a slightly different path than the recommended one which uses docker-compose, and will build out a basic docker deployment.

First I grabbed the following two files

And the setup script for v10.0.0 as I intend to use the ‘stable’ version vs. ‘edge’. It is important to get the matching setup.sh script for the version you are deploying.

I used the docker-compose.yml file to inform me how to configure my Makefile based docker approach. Most of the create options are a direct mimic of the compose file.

I walked through the mailserver.env file and made a few changes

  • ONE_DIR=1
    I’m not totally sure about this, but the documentation reads: “consolidate all states into a single directory (/var/mail-state) to allow persistence using docker volumes.” which seems like a good idea.
  • ENABLE_CLAMAV=1
    My existing email server uses ClamAV 
  • ENABLE_FAIL2BAN=1
    I’m a fan of fail2ban for protecting my server from abuse
  • ENABLE_SPAMASSASSIN=1
    My existing email sever uses SpamAssassin

The volume pointing to letsencrypt is sort of a placeholder for now. Once we get things basically setup I will be changing the SSL_TYPE to enable encryption using my existing letsencrypt certificate that my webserver container has setup.

I later added the following additional configuration to enable logwatch.

  • LOGWATCH_INTERVAL=daily
    Having an email centric logwatch email vs. combining it with my server logwatch, seemed like a good idea.

  • LOGWATCH_RECIPIENT=postmaster@lowtek.ca
    Where to send the email.

With my Makefile based docker approach I have build, start and update targets. I can manually roll-back if needed as the previous container is has a -old name. The first step is to build the container.

At this point we are at the Get up and running section. We need to start the container and configure some email addresses.

Assuming all goes well, the mailserver container will be running. If we poke around the filesystem we’ll see a few files have been created

  • config/dovecot-quotas.cf
  • maillogs/clamav.log
  • maillogs/freshclam.log

We should be able to run the setup script and add a user, and configure some key aliases.

The creation of the account will cause some additional files to be created

  • config/postfix-accounts.cf
  • config/postfix-virtual.cf

At this point we have a running email server – but we need to start getting data to flow there. You may have to open ports in your firewall on the docker host to allow external traffic to connect to this new container.

This is very encouraging, but there is still a list of things I need to do

  1. Create accounts and aliases
  2. Configure smart host sending via AWS SES
  3. Enable SSL_TYPE
  4. Set up DKIM
  5. Change the port forwarding to point to my container host
  6. Migrate email using imapsync

The rest of this post is details on those steps

Continue reading “Installing docker-mailserver”

Pi-hole Ubuntu Server (take 2)

My past two posts have been the hardware setup and pi-hole deployment. You rarely get things right the first time and this is no exception.

I’ve already added an update to the first post about my nullmailer configuration. I had forgotten to modify /etc/mailname and thus a lot of the automated email was failing. I happened to notice this because my newly deployed pi-hole was getting a lot of reverse name lookups for my main router, which were triggered by the email system writing the error.

You may also want to go look at / clean out the /var/spool/nullmailer/failed directory, it likely has a bunch of emails that were not sent.

Once corrected, I started to get a bunch of emails. They were two different errors both triggered by visiting the pi-hole web interface

The first issue is a bit curious. Let’s start by looking at the /etc/resolv.conf file which is a generated file based on the DHCP configuration.

Then if we look at the static configuration that was created by the pi-hole install in /etc/dhcpcd.conf

Decoding the interaction here. The pi-hole setup script believes that we should have a static IP and it also has assigned the pi-hole to use DNS servers that are the same DNS servers that I specified as my custom entries for upstream resolution.

This feels like the pi-hole install script intentionally makes the pi-hole host machine not able to do local DNS resolutions. I wonder if all pi-hole installations have this challenge. I asked on the forum, – and after a long discussion I came to agree that I fell into a trap.

A properly configured linux machine will have the name from /etc/hostname also reflected in /etc/hosts (as I have done). My setup was working fine because the DNS service on my OpenWRT router was covering up this gap. While it’s nice that it just worked, the machine should really be able to resolve its own name without relying on DNS.

As my network has IPv6 as well, the pi-hole also gets an IPv6 DNS entry. Since the static configuration doesn’t specify an upstream IPv6 DNS – the ULA for the pi-hole leaks into the configuration. This is a  potentially scary DNS recursion problem, but it doesn’t seem to be getting used to forward the lookup of ‘myhost’ to the pi-hole so I’m going to ignore this for now.

And easy fix is to go modify /etc/hosts

Where myhost is whatever appears in /etc/hostname.

This will fix the first problem, and it seems the second problem was also caused by the same unable to resolve myhost. I think this is exactly what this post was describing when it was seeing the error messages. This is another thread and different solution to a similar problem.

Satisfied I’d solved that mystery, along the way I’d also created a list of things to ‘fix’

  1. Ditch rsyslog remote
  2. Run logwatch locally
  3. Run fluentbit locally
  4. Password-less sudo
  5. SSH key only access
  6. Add mosh

The rest of this post is just details on these 6 changes.

Continue reading “Pi-hole Ubuntu Server (take 2)”