2025 August 16

Setting up Tailscale with Magic DNS on an OpenWrt Router

Recently I picked up a compact travel router that had an easy way of flashing OpenWrt. I had fun tinkering with it and I wanted to add it to my Headscale network (self-hosted Tailscale).

The Router

Following the initial setup in OpenWrt's Tailscale guide was straightforward. With forwarding set up I could connect to my other Tailscale machines by IP address, even without Tailscale installed on the router's clients, but conneting using just the machine name with Magic DNS doesn't work.

OpenWrt's Tailscale Guide

Either ways, you should follow the Initial Setup section of the guide there.

If you log in through SSH and have a look at /etc/resolv.conf you'll find Tailscale overwrites it with something like so:

# resolv.conf(5) file generated by tailscale
# For more info, see https://tailscale.com/s/resolvconf-overwrite
# DO NOT EDIT THIS FILE BY HAND -- CHANGES WILL BE OVERWRITTEN

nameserver 100.100.100.100
search xxxxxx.ts.net

The search xxxxxx.ts.net line sets the search domain, which behind the scenes adds it as a suffix when your query doesn't have a top level domain.

So when you try and connect to your machine via something like machine, it actually looks up machine.xxxxxx.ts.net on your Tailscale service's DNS nameserver at 100.100.100.100 and you get back the machine's Tailscale IP address.

While neat, I don't really like how Tailscale configures this by overwriting the /etc/resolv.conf file, so I tend to disable this with

tailscale set --accept-dns=false

Thankfully this still keeps the nameserver running, allowing us to replicate the rest manually or through OpenWrt's built-in tools.

To do this, we push the search domain to the router's clients by going to Network > Interfaces > lan > Edit > DHCP Server > Advanced Settings and adding an entry for DHCP-Options with option:domain-name,lan xxxxxx.ts.net.

Placing lan first lets us prioritise machine.lan over machine.xxxxxx.ts.net for speed, but if you were relying on Tailscale to bypass the target machine's local firewall, you can place it second or remove it.

Setting DHCP-Options

Next up, under Network > DHCP and DNS > Forwards we add an entry for DNS Forwards /*.xxxxxx.ts.net/100.100.100.100. Tailscale's DNS returns anything outside its purview with "not found" so we need to restrict it to just your Tailscale domain.

This is also where you can add other upstream DNS servers like Cloudflare's 1.1.1.1.

Setting DNS Forwards

If you'd rather do all this through command line you could use something like:

uci add_list dhcp.lan.dhcp_option='option:domain-name,lan xxxxxx.ts.net'
uci add_list dhcp.@dnsmasq[0].server='/*.xxxxxx.ts.net/100.100.100.100'

As a final touch my travel router has a switch on the side that OpenWrt can listen to and run commands. I wanted this switch to toggle on/off routing all traffic through one of my Tailscale exit nodes, making it a VPN switch.

So I wrote a script you can save to /etc/rc.button/BTN_0, or adapt it to your router's buttons if its different. (Don't forget to add it to your list of files to preserve when upgrading, under System > Backup / Flash Firmware > Configurations).

#!/bin/sh

[ "${BUTTON}" = "BTN_0" ] || exit 0

EXIT_NODE="nodename"

remove_wan_forwarding() {
    uci show firewall |\
    awk -F. '{print $2}' |\
    awk -F= '{print $1}' |\
    grep @forwarding |\
    sort -u |\
    while read i; do
        src=`uci get "firewall.$i.src"`
        dest=`uci get "firewall.$i.dest"`
        [[ "$src" = "lan" ]] && [[ "$dest" = "wan" ]] || continue
        uci delete "firewall.$i"
    done
}

if [ "${ACTION}" = "pressed" ]; then
    logger "tailscale tunnel on"
    tailscale set --exit-node="$EXIT_NODE" --exit-node-allow-lan-access=true
    remove_wan_forwarding
    uci commit firewall
    service firewall restart
elif [ "${ACTION}" = "released" ]; then 
    logger "tailscale tunnel off"
    tailscale set --exit-node= --exit-node-allow-lan-access=false
    remove_wan_forwarding
    uci add firewall forwarding
    uci set firewall.@forwarding[-1]=forwarding
    uci set firewall.@forwarding[-1].src=lan
    uci set firewall.@forwarding[-1].dest=wan
    uci commit firewall
    service firewall restart
fi

This whole thing took a couple of days of trial and error to figure out, but I hope it has been useful! For good measure I also added a script from OpenWrt's guide that simplifies reinstalling the Tailscale packages on upgrade.


2017 January 8

TwoSnakes

I have been working on a game on Godot for a while now but with the slow progress I decided to work on something simpler first, so I implemented Snake last weekend. However to make things a little more fun I made it into a race between two players and after some tweaks made TwoSnakes.

The left side player uses WASD (or ZQSD) while the right side player uses the arrow keys. Space bar starts the game. To win a round the player has to survive with the most food collected. There is no snake-to-snake collision (that’d make the game more like Tron) but the game does speed up as time passes each round.

You can find the source code and releases here on GitHub.


2016 September 13

BSPViewer Updated

While I was dusting off my old projects I noticed that one of them - BSPViewer - was not compiling anymore. It was written five years ago and was using Qt4. I decided for prosperity sake to spend the weekend freshening it up by porting it to SFML. I got most of it working and the only issue I had was trying to determine if a texture was meant to be transparent or not. One nice new feature is that it can now load data directly from a Quake 3 installation without unpacking anything, using the PhysicsFS library.

Screenshot

Interestingly, back then the main motivation of this program was that I wanted to develop a game that uses a map format featuring a good map editor. Unfortunately I found out that most of those tools were rather Quake 3 specific and I hadn’t touched it since.

Still, with these changes it should now be a lot less faff to compile and use. Feel free to check it out here:

https://github.com/leezh/bspviewer


2015 April 21

More RepRap Recycler Updates

So, it has been a while since the last update on the filament recycling project. Quite a bit has happened since then.

For starters, we came up with a name for the project, but later found out it was taken by a similar project. In the end we decided to just adopt the name of our senior’s old research project prototype “RepCycler”.

When the team heard that I had my blog they asked me to set one up dedicated to the project. Problem is, my blog lives on a virtual private server that I mess around with, and I didn’t feel like the project’s website should be affected by my shenanigans. While I felt that WordPress.com was the better blog system/host, I didn’t want to hassle them with managing so many accounts just for the project, so I decided to set it up on Blogger, since we were already using Google Drive for sharing documents. You can find the project site here.

Anyways, to start with, we decided to work backwards from the price we could sell the machine at to get the approximate cost making our machine should be. We looked at the competitors’ products and compared various characteristics, such as the extrusion speed and how fine the tolerances are. We rated those characteristics on a relative scale and by weighting those ratings, and came up with a performance index for each machine.

So, to make something that is actually competitive, we could either make something

  1. low-end at a really cheap price;
  2. high-end at a reasonable price; or
  3. much better than the competitors at a premium.

We decided to go with the second choice. Which meant that our target was to make something that could be sold for around £500, and had the same performance of something like the ProtoCycler.

Yeah, I’m not sure how well we could achieve that, but hey, that was what we were aiming for.

Next up we had a look at the functions the machine had to do. There were stuff such as the breakdown of the old plastic parts, getting the optimal mix of old and new plastic, melting and extruding the mixture and controlling the final diameter of the filament. I picked the extrusion part since I did a quite a bit of initial research in that and had a good idea of what to do.

That’s all for now, I’ll write-up about the rest later.


2015 February 22

Working on a RepRap Project

My engineering course this semester has a group business and design project where we work with a company on developing a product. Besides a couple of projects that you’d have to specifically sign up for, these projects were assigned to you and I was a bit nervous about it since I had no idea what the companies and projects were. I was incredibly glad when I ended up on a project sponsored by RepRapPro! 3D printing was something I’ve been meaning to dive into for a while now. I even got to meet Adrian Bowyer, the original RepRap developer (who used to give lectures at my university a few years ago!). It certainly was exciting and with their open source philosophy I was given the blessing to publicly discuss the project – something I wasn’t sure if I should do with my earlier projects. So now I can freely rant about it. Yay!

Now, about the project itself. The idea for the project is to develop an open source, desktop sized machine that can break down old 3D models and waste support structures and turn them into reusable filaments for more printing. There are a few similar plastic extrusion machines out there such as Filabot and ProtoCycler so we would have to work on setting ourselves apart from them. One thing we wanted to do was distribute ours under the GNU Public License, which does allow commercial derivatives, much like current RepRap machines. I do feel this is nice because I’m not entirely sure of the future of the project past the project deadline, and at the very least the project wouldn’t be dead if the group decides not to pick it up as a business when we graduate.

Nonetheless, it would be a fun project as one of the aims of the project is to produce a usable prototype before the project deadline in May.

Given that it’ll take time for me to write things up, my posts would be a while behind what’s actually going on.


« Older Posts

View All Posts