Dropserver Progress - February 2025

This is the progress report from Dropserver for February 2025. The previous report is here.

This month was extra-short thanks to a much-needed ski vacation, but I did manage to make some solid progress on integrating Tailscale into ds-host.

Tailscale Users as Appspace Users

After grinding on Vue templates, DB calls and everything in between, it’s now possible to assign multiple auth credentials to a single user. This means an appspace user can access the appspace via Tailscale, or via the public network or local network interchangeably.

The UI needs some polish to say the least but the essence is there:

Create a new user or assign the Tailscale identity to an existing appspace user:

A screenshot showing a user selecting a tailscale user

See who the peers are and the connected appspace user:

A screenshot showing users as tailscale peers associated with appspcae users.

All this works while the Tailscale peers can change at any instant. The data is kept up-to-date on the frontend UI through a system of events inside of ds-host, and Server Sent Events to the browser (see September 2024 progress report). While I don’t love all-JS frontends, Vue reactivity is great for reflecting the latest state as soon as it shows up.

Commit: “feat(ds-host): implement multiple auths per appspace user, including tsnetid” 10f4770

Identifying Tailscale and Headscale Users

Tailscale users have a pretty solid looking ID that I understand is stable and unique. Using that to identify peers is natural, but there are a couple of gotchas.

Headscale user IDs are plain integers starting with 1. So user ids are 1, 2, 3, 4… There can be many Headscale instances in the world therefore there are many Headscale users with ID 1, ID 2, etc… If an admin changes / moves / rebuilds their instance, relying solely on the user ID like I do with Tailscale isn’t enough.

To mitigate this I am doing two things:

  • ids in the appspace DB are stored as <id>@<headscale-control-domain>. If you change to a different Headscale instance at a different domain, this will ensure that user-1 in one instance is not the same as user-1 in a different instance.
  • I added an extra_name column in the DB, which stores the email address of the Headscale user. I haven’t implemented this part yet but it should help deal with situations where a Headscale user is not who the system thinks they are.

Commit: “add extra name to appspace user auth” b77fd83.

Tags, Key Expiry and Auth Keys

Tailscale expects non-user nodes to be “tagged” (see Tailscale docs.) As such appspace nodes should be tagged. This triggers the following do-list:

  • UI to input tag when creating node
  • read actual tags for the node
  • disable use of appspace node if there are no tags

With the above done, I set up the UI to warn the user when the node has no tags, and point them to a remedy.

A screenshot showing a box with a warning that there are no tags.

Auth Keys

If you try to create an appspace Tailscale node the ds-host UI will display a link to click, which takes you to Tailscale (or your Headscale instance) where you authenticate to finish creating the node. It’s convenient and requires no prior steps to complete.

An alternative is to create an auth key in Tailscale (or Headscale). Conveniently you can select tags to set on nodes created with that auth key.

I added support for creating a node using an auth key. In many cases this will be a superior workflow for users, so long as they have the forethought of creating an auth key. It’s also possible to create multiple nodes with the same auth key.

Node key expiry

Tailscale nodes expire, but you can disable the expiry date of the node if it’s meant to run unattended like a server. In fact, if you create a node with a tag, key expiry is disabled automatically.

If in spite of the work above the appspace node is created without a tag and an expiry date is in effect, the UI points out the issue along with steps to resolve. (It’s easy to do, but if you don’t know you don’t know.)

A screenshot showing a box with a that key expiry is enabled and a hint to resolve.

With the above, the user should be able to create a node and get it to usable state even if things didn’t go according to plan the first time around. ds-host detects all “gotcha” situations that I can think of and points the user in the right direction to resolve. This is key to get Tailscale working for users who may not be familiar with it.

Commits: “add tsnet tags input and key expiry date to status” 604d0e3 and “create tsnet node using AuthKey” 7f122d4.

Getting CLoser

It feels like Tailscale integration is finally getting closer to being done. I’m punting on a few things that are related but not critical: handling avatars, and better user management.

I am now working on making the ds-host admin panel accessible from Tailscale as well. Naturally it’s not nearly as simple as I would like it to be.

Aerospace Engineer turned sofware developer and bootstrappin' entrepreneur.