virtuallypotato/content/posts/tailscale-golink-private-shortlinks-tailnet/index.md
2023-01-12 17:09:26 -06:00

5.9 KiB
Raw Blame History

title date description featured draft toc usePageBundles codeLineNumbers series tags comment
Tailscale golink: Private Shortlinks for your Tailnet 2023-01-08T13:51:42-06:00 How to deploy Tailscale's golink service in a Docker container. false true true true false Tips
docker
vpn
tailscale
wireguard
containers
true

I've shared in the past about how I use custom search engines in Chrome as quick web shortcuts. And I may have mentioned my love for Tailscale a time or two as well. Well I recently learned of a way to combine these two passions: Tailscale golink. The golink announcement poston the Tailscale blog offers a great overview of the service:

Using golink, you can create and share simple go/name links for commonly accessed websites, so that anyone in your network can access them no matter the device theyre on — without requiring browser extensions or fiddling with DNS settings. And because golink integrates with Tailscale, links are private to users in your tailnet without any separate user management, logins, or security policies.

And these go links don't have to be simply static shortcuts; the system is able to leverage go templates to conditionally insert text into the target URL - similar to my custom search engine setup. The Tailscale blog also has some clever suggestions on how to use this capability.

Sounds great - but how do you actually make golink available on your tailnet? Well, here's what I did to deploy the golink Docker image on a Photon OS VM I set up running on my Quartz64 running ESXi-ARM.

Tailnet prep

There are three things I'll need to do in the Tailscale admin portal before moving on.

Create an ACL tag

I assign ACL tags to devices in my tailnet based on their location and/or purpose, and I'm then able to use those in a policy to restrict access between certain devices. To that end, I'm going to create a new tag:golink tag for this purpose. Creating a new tag in Tailscale is really just going to the Access Controls page of the admin console and editing the policy to specify a tagOwner who is permitted to assign the tag:

	"groups":
		"group:admins": ["john@example.com"],
	},
	"tagOwners": {
		"tag:home":   ["group:admins"],
		"tag:cloud":  ["group:admins"],
		"tag:client": ["group:admins"],
		"tag:dns":    ["group:admins"],
		"tag:rsync":  ["group:admins"],
		"tag:funnel": ["group:admins"],
		"tag:golink": ["group:admins"],
	},

Configure ACL access

This step is really only necessary since I've altered the default Tailscale ACL and prevent my nodes from communicating with each other unless specifically permitted. I want to make sure that everything on my tailnet can access golink:

"acls": [
		{
			// make golink accessible to everything
			"action": "accept",
			"users":  ["*"],
			"ports": [
				"tag:golink:80",
			],
		},
  ...
	],

Create an auth key

The last prerequisite task is to create a new authentication key that the golink container can use to log in to Tailscale since I won't be running tailscale interactively. This can easily be done from the Settings page. I'll go ahead and set the key to expire in 1 day (since I'm going to use it in just a moment), make sure that the Epheral option is disabled (since I don't want the new node to lose its authorization once it disconnects), and associate it with my new tag:golink tag.

Creating a new auth key

Applying that tag does two things for me: (1) it makes it easy to manage access with the ACL policy file edited above, and (2) it automatically sets it so that the node's token won't automatically expire. Once it's auth'd and connected to my tailnet, it'll stay there.

After clicking the Generate key button, the key will be displayed. This is the only time it will be visible so be sure to copy it somewhere safe!

Docker setup

The golink repo offers this command for running the container:

docker run -it --rm ghcr.io/tailscale/golink:main

The doc also indicates that I can pass the auth key to the golink service via the TS_AUTHKEY environment variable, and that all the configuration will be stored in /home/nonroot (which will be owned by uid/gid 65532). I'll take this knowledge and use it to craft a docker-compose.yml to simplify container management.

mkdir -p golink/data
cd golink
chmod 65536:65563 data
vi docker-compose.yaml
# golink docker-compose.yaml
version: '3'
services:
  golink:
    container_name: golink
    restart: unless-stopped
    image: ghcr.io/tailscale/golink:main
    environment:
      - TS_AUTHKEY: MY_TS_AUTHKEY
    volumes:
      - './data:/home/nonroot'