Before I began, I thought I should see if there’s a newer OpenWrt version my router can run. I always start on the Supported Devices page of the wiki, but on this visit I was treated to a warning:
If you read the 4/32 warning, the crux of the matter is that there may not be enough RAM to run OpenWrt without crashing. And the small flash area means possibly not having enough room to install LuCI, the web interface, and the packages to access LuCI via HTTPS. Also, there’s this:
Previous versions of OpenWrt (such as earlier versions of 17.01.x, 15.05.x “Chaos Calmer” and prior) contain now-known security vulnerabilities in the kernel, wireless implementation, and/or application code. […] In many cases, these known vulnerabilities are being actively targeted, potentially including by advanced, likely state-sponsored or state-affiliated actor or actors.
Ugh, I was using one of those older versions, and now I’m paranoid (as I should be) that my router could be used as a tool by nation-states to do their bidding. Nicely, there’s a link on the supported devices page titled “I want to buy a router which is supported by OpenWrt.” It links to their supported hardware table, pre-filtered by units that can run the latest stable version of OpenWrt – 19.07.4 at time of writing.
I spent some time browsing this list compared to what was available at my local Micro Center. I tried to find one that had the best OpenWrt support with the fewest known issues, and landed on the TP-Link C7 AC1750 for $70. If I like this one after a month or so, I’m going to buy another for better coverage.
OpenWrt ddns-scripts install
With the hardware choice out of the way, I installed OpenWrt 19.07.4. Then I needed to add support for Dynamic DNS. Go to System -> Software in the Web UI (LuCI). Click Update lists…, then type ddns in the filter input and press <Enter> to filter the list. The packages to install to use nsupdate.info are ddns-scripts_nsupdate and luci-i18n-ddns-en (or whatever language package you need):
Installing those will also install their dependencies, such as the base ddns-scripts and luci-app-ddns. Once they’re installed, reboot your router and you’ll have a Services -> Dynamic DNS menu.
You might see the menu before rebooting, but you’ll likely get this error if you try to visit it:
/usr/lib/lua/luci/controller/ddns.lua:116: attempt to index field '?' (a nil value)
Following it will lead you to a hints page and let you know you need to install a couple more packages: curl and bind-host. Follow the same installation process as above. After they’re installed, the Hints section will go away.
DNS Configuration
The only configuration you have to do at your DNS provider is add a CNAME record for the domain you want to use:
your.domain.com CNAME yourdomain.nsupdate.info
Then when you go to nsupdate.info, on the Overview page click Add Host and put in the subdomain (example: yourdomain from above) in the Name field, then select nsupdate.info under Domain:
Conveniently, after creating your new host entry, nsupdate.info will print your update secret and include specific configuration parameters for OpenWrt:
OpenWrt Configuration
You can use the configuration info from nsupdate.info, but it’s just as easy to paste the info into the LuCI panel. It’s worth noting that you only need to generate one host and host secret at nsupdate.info, but you’ll have two separate configurations in OpenWrt for IPv4 and IPv6.
In OpenWrt’s Dynamic DNS page, click Edit on the myddns_ipv4 row. The first thing you’ll want to do is update the DDNS Service provider to nsupdate.info and click Change provider:
Only then can you enter all of the information from nsupdate.info:
Enter your nsupdate.info FQDN in all of these fields:
Lookup Hostname
Domain
Username
Then put your secret in the Password field. Check both Enabled and Use HTTP Secure, then add /etc/ssl/certs to Path to CA-Certificate. Click Save & Apply, then repeat the same process with the same info for the other myddns_ipv6 entry.
From the Dynamic DNS overview page in OpenWrt, click the Start buttons for each row under Process ID Start / Stop. This only needs to be done once when you’re done configuring Dynamic DNS.
Test
Starting the Dynamic DNS process in OpenWrt should trigger your first update at nsupdate.info. You can see it easily on the Overview page:
If it all worked, your IPv4 and IPv6 address should be updated, hopefully with a green TLS indicator noting that it was done securely. If there are any problems, the numbers under Faults will increase – C for Client, S for Server.
If there are problems, you can see API messages on nsupdate.info by clicking on your hostname to get further details. You can also view detailed logs in OpenWrt by clicking Edit on the myddns_ipv4 or myddns_ipv6 rows. Then click the Log File Viewer tab and click the Read / Reread Log File button.
I was able to configure this in under an hour, hopefully you find it useful. Let me know if you have any troubles getting things to work.
So you’re getting ready to move your website. You’ve got the new hosting plan purchased, and you’ve got the files and data copied over. You set up your hosts file to point to the new host, but something doesn’t look quite right 😕
You could keep editing your hosts file and refreshing your browser to try to figure out what is different… Or you could take 5 minutes to set up a socks proxy so you can view both the new and old site in two different browsers at the same time! Here’s how to do it: Continue reading →
Prerequisites
Two browsers, one of which is Firefox.
A server you can connect to via SSH
The server can be anything, your new host (if they allow ssh), a friend’s server, a linode server, a digital ocean droplet, etc.
Start an SSH tunnel to act as a proxy
In a terminal on your local system run:
ssh -D 1080 -N user@your-ssh-host
-D instructs ssh to do dynamic port forwarding by creating a socket on that port locally. Any port number will do, but something above 1024 is best. I went with 1080 in this example.
-N tells ssh to not run any remote commands (like bash). This is needed to have our connection just forward data.
Configure Firefox
In Firefox open Preferences. Search for proxy. In more recent versions of Firefox, it’s at the bottom of the general section. Click the proxy Settings... button to bring up the proxy connection settings dialog:
Make the changes as indicated. Select Manual proxy configuration. Add localhost to the SOCKS Host field, and 1080 to Port and select SOCKS v5. Check the box for Proxy DNS when using SOCKS v5.
Browse in Firefox
Anything you visit in Firefox will now use the DNS information from your proxy. You’d typically use the Firefox version for the original – what is soon to be the “old” site.
I set up a new testing environment for IE11 through VirtualBox on my computer running Ubuntu. But I couldn’t get to any of my sites that are served by the Ubuntu host. I had to do some tricks to get this working on my old work Mac, and the same principle applies for Ubuntu.
On my Ubuntu system, I use Dnsmasq for local DNS so I can test sites locally like client1.test, client2.test, etc. Normally those fake top-level domains resolve to a localhost IP: 127.0.0.1. But when you bring VirtualBox into the mix, the host and the guest both have their own notions of localhost. We need a common ground to communicate on. This is solved with a loopback alias.
Loopback Alias
A loopback alias is just another IP that you can assign to your localhost loopback device. To add one, add the following to your network interfaces configuration file:
Now instead of having your fake TLDs resolve to 127.0.0.1, we need them to resolve to our loopback alias address – 10.254.254.254. Depending if you’re using Dnsmasq with or without NetworkManager, you can edit/add the following file (respectively):
sudo vi /etc/NetworkManager/dnsmasq.d/01_localhost
OR sudo vi /etc/dnsmasq.d/01_localhost
I’m using the 2nd option to make the guest use the host’s DNS settings:
VBoxManage modifyvm "VM name" --natdnshostresolver1 on
Test everything out by starting your VM guest and pinging 10.254.254.254 for network connectivity. Then try to ping a .test domain from the guest. If it looks good you should be able to load a .test domain through Internet Explorer on the guest OS.
When the internet really started catching steam, email was one of it’s flagship services. Back then it was simple but somewhat archaic – it’s goal was to be redundant enough to get your message through even if it required several tries. It was the digital equivalent of:
Neither snow nor rain nor heat nor gloom of night stays these couriers from the swift completion of their appointed rounds.
Think of all the stuff that has been added atop of email such as encryption and MIME encoding to send attachments. But it was our must-deliver mantra that was used by the spammers for their personal gain. Then even more layers for spam and virus filtering were added. Spammers have sort of negated that “must deliver” image of email to where I click send and think, “I hope it will be delivered.”
I used to manage my own email server. Postfix SMTP, Courier POP/IMAP, Amavis/Freshclam SPAM & Antivirus. I don’t like being an email administrator. It’s frankly too much to keep up with. I just want email to work. Recently I switched my self-managed email to google mail. I figured it would be a set-it-and-forget-it type of deal. I was wrong.
The reason I still had issues is because I still wanted control of my DNS. Turns out there is a lot contained within DNS besides MX records that can effect mail delivery. I found this DNS TXT record page at google that got me started, but each individual entry could use some additional explanation.
SPF Records
Before moving to google, I had added this SPF record:
IN SPF "v=spf1 mx a ip4:198.58.117.237 -all"
IN TXT "v=spf1 mx a ip4:198.58.117.237 -all"
I’m not sure why the SPF record exists on its own and in a TXT record, but I don’t really care, as long as email goes through. But it wasn’t going through. The problem with this set up is, it tells the receiver that anything received from my domain is good if it came from my server IP (mostly system & website generated notifications). But my google mail comes from google, not my IP. So I was getting bounce-backs from picky providers. The solution was to add google into the mix and loosen the failure type on the “all” mechanism:
IN SPF "v=spf1 mx a ip4:198.58.117.237 include:_spf.google.com ~all"
IN TXT "v=spf1 mx a ip4:198.58.117.237 include:_spf.google.com ~all"
Google Site Verification
This is one of those things you probably already did by putting a HTML file on your site to prove to google that you own it. This gives your ownership even more credibility. It’s not required for email delivery, but since I was going over the list of TXT records, I figured I’d add it. Locating this section in the webmaster tools is tricky, so I made a video:
Add the verification key to your DNS file:
IN TXT "google-site-verification=DqPNHNAJ5DnBpLr1TzZe38vQucZZ49wnCGiU9e75RTo"
After saving your changes and restarting bind, you can test to make sure your new TXT entries are showing using dig. I recommend using the ‘@nameserver’ parameter so you can query your own nameserver before the changes have propagated internet-wide.
$ dig @ns.foell.org TXT foell.org
...
;; QUESTION SECTION:
;foell.org. IN TXT
;; ANSWER SECTION:
foell.org. 604800 IN TXT "v=spf1 mx a ip4:198.58.117.237 include:_spf.google.com ~all"
foell.org. 604800 IN TXT "google-site-verification=DqPNHNAJ5DnBpLr1TzZe38vQucZZ49wnCGiU9e75RTo"
DKIM
I don’t know the full details of how DKIM works, but it’s an encryption key added to your domain name which helps insure that the email received was sent from who you think it was. It works because your email provider (google) adds a DKIM domain key to the header of the email, and the receiver can validate it by using the DKIM public key saved on your DNS record.
Here’s how to get your DKIM key:
Add it to your DNS file:
google._domainkey IN TXT "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCnCPVKm4lCMECaU/eFOQewJaGpAk/hx4D8pQCRQ+Iq1Y7pUL09iyFImWRveBTBRccOEy/gchsZoseBVMvAS4L86GQhUgi+4tk4VvpxkQLgbuPouoLs54W4kIDUhgZcmNe4fBjoIMgHQvRfXc1G6MnwBZcU3a0URtxfhExFCflfUwIDAQAB"
DMARC combines both DKIM and SPF to combat phishing and protect your domain’s reputation. I added this to my bind resource record:
_dmarc IN TXT "v=DMARC1; p=quarantine\; pct=100\; rua=mailto:postmaster@foell.org"
Test using dig
$ dig @ns.foell.org TXT _dmarc.foell.org
Again, I’m not exactly sure how it all works, but I now get informational reports from servers that I’ve sent emails to, letting me know my “standing” from an email perspective as they see it. I don’t plan on being proactive about them, but they’ll be useful if I start getting bounce messages again.
The OpenWrt router isn’t strictly necessary. You could, of course do the dynamic DNS updates with a cheap Linux firewall, but I’ll cover the configuration for OpenWrt.
The file naming conventions used here are for a BIND installation on Debian. Your distribution may use a different naming convention, however, the concepts should be the same.
On the DNS server (as root):
# dnssec-keygen -C -a HMAC-MD5 -b 512 -n HOST sub.domain.com.
You can use your domain name (or subdomain) as the key name if you’d like. That’s what I did in this example – it helps me keep things straight. The -C switch is for compatibility mode since it’s likely the nsupdate binary on OpenWrt will be older than the BIND installation on your DNS server. The contents of the key file will look something like this:
I like to keep BIND’s key configuration in a separate file to make sure it doesn’t get overwritten with software upgrades, so I created a file called /etc/bind/keys.conf. Using the MD5 from the key file (the cryptic string(s) that ends in ‘==’, after the sets of numbers), create a keys.conf file:
Then in /etc/bind/named.conf, add this at the top:
include "/etc/bind/keys.conf";
In my /etc/bind/named.conf.local (which has all of the zones actually hosted on the server), the zone for the domain I want to make dynamic has the following:
zone "domain.com" IN {
type master;
file "/etc/bind/db.domain";
update-policy {
grant sub.domain.com. name sub.domain.com. A TXT;
};
notify no;
};
You would substitute your domain for “domain.com” and “sub.domain.com,” and have your own zone file in a different file named after your domain (/etc/bind/db.yourdomainname).
The “update-policy” section is the part that is added. The first parameter to the “grant” statement is the name of the key, and the “name” parameter is the domain name – which I’ve made the same in this case. There’s nothing different about /etc/bind/db.domain than any of my other zone db files, except it’s owned by the “bind” user & group — that way when it receives a DNS update, it can change the file (dynamically!).
Also the /etc/bind directory should be owned by group “bind” so that it can create /etc/bind/db.domain.jnl — a journal file BIND will use.
OpenWrt Configuration
Install the “bind-client” package on your OpenWrt router. I like to use the LuCI web interface. In LuCI you can find it by searching under the software administration menu.
SCP the private & key files you created on your DNS server to your OpenWrt router. I keep my DNS files in root’s home directory: /root.
Create a hotplug file to update the DNS when the WAN interface obtains an address. Put it in /etc/hotplug.d/iface/30-nsupdate:
[ "$INTERFACE" != "wan" ] && ( [ "$ACTION" != "ifup" ] || [ "$ACTION" != "update" ] ) && exit 0
rdate -s time.nist.gov
include /lib/network
scan_interfaces
config_get ipaddr wan ipaddr
echo "server your.bindserver.com
zone domain.com
update delete sub.domain.com A
update add sub.domain.com. 86400 A $ipaddr
show
send" | nsupdate -k /root/Ksub.domain.com.+157+54658.key -v
Again, Replace “domain.com” with the name of your zone, and “sub.domain.com” with the name of your dynamic domain (they could be named the same). Replace “your.bindserver.com” with the name or IP of your DNS server. The rdate command is in there to make sure your time is set correctly before running nsupdate. BIND will complain if the time difference between the client & server differs too much. While only the key file is referenced in the script, both files need to be present (usually in the same directory as each other) for nsupdate to make a valid request.
You can (and should) test the script without disrupting your network connection by SSHing into your OpenWrt router and running the following command:
Often BIND will complain about time, permissions, auth keys, etc. Running the test above is the best way to find out what’s going on. If there’s no output, the update probably went through. Try to ping your dynamic domain name and see if all is well.