Install Tailscale DERP server for increased privacy and lower latency.

Operating system.

$ lsb_release --all
No LSB modules are available.
Distributor ID:	Ubuntu
Description:	Ubuntu 22.04 LTS
Release:	22.04
Codename:	jammy

Firewall service

Install dynamically managed firewall daemon.

$ sudo apt install firewalld

Inspect network interfaces.

$ ip -br a
lo               UNKNOWN        127.0.0.1/8 ::1/128 
ens3             UP             192.0.2.113/23

Inspect public zone.

$ sudo firewall-cmd --list-all --zone public
public (active)
  target: default
  icmp-block-inversion: no
  interfaces:
  sources: 
  services: dhcpv6-client ssh
  ports: 
  protocols: 
  forward: yes
  masquerade: no
  forward-ports: 
  source-ports: 
  icmp-blocks: 
  rich rules: 

Add external interface to public zone.

$ sudo firewall-cmd --add-interface ens3 --zone public
success

Allow incoming connections on HTTP, HTTPS, STUN ports to DERP server.

$ sudo firewall-cmd --add-port 80/tcp --add-port 443/tcp --add-port 3478/udp --zone public
success

Inspect public zone.

$ sudo firewall-cmd --list-all --zone public
public (active)
  target: default
  icmp-block-inversion: no
  interfaces: ens3
  sources: 
  services: dhcpv6-client ssh
  ports: 80/tcp 443/tcp 3478/udp
  protocols: 
  forward: yes
  masquerade: no
  forward-ports: 
  source-ports: 
  icmp-blocks: 
  rich rules: 

Install Go programming language

Do not install golang package which provides Go 1.18, as DERP server requires Go 1.19.

Open Go download page and follow these instructions.

$ wget --output-document /opt/go1.19.4.linux-amd64.tar.gz https://go.dev/dl/go1.19.4.linux-amd64.tar.gz
$ sudo rm -rf /usr/local/go && sudo tar --directory /usr/local --extract --gzip --file /opt/go1.19.4.linux-amd64.tar.gz

Join Tailscale network

Open Tailscale download page and follow these instructions.

Install dependencies.

$ sudo apt install wget

Download package signing key.

$ sudo wget --output-document /usr/share/keyrings/tailscale-archive-keyring.gpg https://pkgs.tailscale.com/stable/ubuntu/jammy.noarmor.gpg

Download repository definition.

$ sudo wget --output-document /etc/apt/sources.list.d/tailscale.list https://pkgs.tailscale.com/stable/ubuntu/jammy.tailscale-keyring.list

Update package index.

$ sudo apt update

Install Tailscale.

$ sudo apt install tailscale

Connect your machine to your Tailscale network.

$ sudo tailscale up

This step is important as we want to ensure that this DERP server will serve verified clients.

Install DERP server

Create derp user that will be used to run service.

$ sudo useradd --system --create-home --home-dir /opt/derp --shell /bin/bash derp

Ensure that it can execute Go binaries.

$ echo 'export PATH=$PATH:/usr/local/go/bin' | sudo tee -a /opt/derp/.profile 

Verify that assumption.

$ sudo -u derp -i go version
go version go1.19.4 linux/amd64

Install DERP server.

$ sudo -u derp -i go install tailscale.com/cmd/derper@main
go: downloading github.com/mitchellh/go-ps v1.0.0
go: downloading github.com/fxamacker/cbor/v2 v2.4.0
go: downloading github.com/hdevalence/ed25519consensus v0.0.0-20220222234857-c00d1f31bab3
go: downloading github.com/x448/float16 v0.8.4
go: downloading filippo.io/edwards25519 v1.0.0-rc.1
go: downloading go4.org/netipx v0.0.0-20220725152314-7e7bdc8411bf

Display help information.

$ sudo -u derp -i /opt/derp/go/bin/derper --help
Usage of /opt/derp/go/bin/derper:
  -a string
    	server HTTPS listen address, in form ":port", "ip:port", or for IPv6 "[ip]:port". If the IP is omitted, it defaults to all interfaces. (default ":443")
  -accept-connection-burst int
    	burst limit for accepting new connection (default 9223372036854775807)
  -accept-connection-limit float
    	rate limit for accepting new connection (default +Inf)
  -bootstrap-dns-names string
    	optional comma-separated list of hostnames to make available at /bootstrap-dns
  -c string
    	config file path
  -certdir string
    	directory to store LetsEncrypt certs, if addr's port is :443 (default "/opt/derp/.cache/tailscale/derper-certs")
  -certmode string
    	mode for getting a cert. possible options: manual, letsencrypt (default "letsencrypt")
  -derp
    	whether to run a DERP server. The only reason to set this false is if you're decommissioning a server but want to keep its bootstrap DNS functionality still running. (default true)
  -dev
    	run in localhost development mode
  -hostname string
    	LetsEncrypt host name, if addr's port is :443 (default "derp.tailscale.com")
  -http-port int
    	The port on which to serve HTTP. Set to -1 to disable. The listener is bound to the same IP (if any) as specified in the -a flag. (default 80)
  -mesh-psk-file string
    	if non-empty, path to file containing the mesh pre-shared key file. It should contain some hex string; whitespace is trimmed.
  -mesh-with string
    	optional comma-separated list of hostnames to mesh with; the server's own hostname can be in the list
  -stun
    	whether to run a STUN server. It will bind to the same IP (if any) as the --addr flag value. (default true)
  -stun-port int
    	The UDP port on which to serve STUN. The listener is bound to the same IP (if any) as specified in the -a flag. (default 3478)
  -unpublished-bootstrap-dns-names string
    	optional comma-separated list of hostnames to make available at /bootstrap-dns and not publish in the list
  -verify-clients
    	verify clients to this DERP server through a local tailscaled instance.

Ensure that it can open required ports as regular user.

$ sudo setcap 'cap_net_bind_service=+ep' /opt/derp/go/bin/derper

Create systemd service.

$ sudo tee /etc/systemd/system/derper.service <<'EOF'
[Unit]
Description=DERP Server
After=network.target
 
[Service]
User=derp
Group=derp
Environment=DOMAIN=derper.example.org
Environment=DIRECTORY=/opt/derp
ExecStart=/bin/bash -c "${DIRECTORY}/go/bin/derper -c ${DIRECTORY}/derp.conf --hostname ${DOMAIN} --verify-clients"
Restart=always

[Install]
WantedBy=multi-user.target
EOF
[Unit]
Description=DERP Server
After=network.target
 
[Service]
User=derp
Group=derp
Environment=DOMAIN=derper.example.org
Environment=DIRECTORY=/opt/derp
ExecStart=/bin/bash -c "${DIRECTORY}/go/bin/derper -c ${DIRECTORY}/derp.conf --hostname ${DOMAIN} --verify-clients"
Restart=always

[Install]
WantedBy=multi-user.target

Reload systemd configuration.

$ sudo systemctl daemon-reload

Enable DERP server.

$ systemctl enable --now derper
Created symlink /etc/systemd/system/multi-user.target.wants/derper.service → /etc/systemd/system/derper.service.

Check service status.

$ sudo systemctl status derper
● derper.service - DERP Server
     Loaded: loaded (/etc/systemd/system/derper.service; enabled; vendor preset: enabled)
     Active: active (running) since Fri 2022-12-30 21:58:32 CET; 2s ago
   Main PID: 12625 (derper)
      Tasks: 4 (limit: 2242)
     Memory: 2.0M
        CPU: 7ms
     CGroup: /system.slice/derper.service
             └─12625 /opt/derp/go/bin/derper -c /opt/derp/derp.conf --hostname derper.example.org --verify-clients

Dec 30 21:58:32 derper.example.org systemd[1]: Started DERP Server.
Dec 30 21:58:32 derper.example.org bash[12625]: 2022/12/30 21:58:32 derper: serving on :443 with TLS
Dec 30 21:58:32 derper.example.org bash[12625]: 2022/12/30 21:58:32 running STUN server on [::]:3478

Add DERP map to your Access Control policy.

// Example/default ACLs for unrestricted connections.
{
	// Declare static groups of users beyond those in the identity service.
	"groups": {
		"group:example": ["user1@example.com", "user2@example.com"],
	},

	// Declare convenient hostname aliases to use in place of IP addresses.
	"hosts": {
		"example-host-1": "100.100.100.100",
	},

	// Access control lists.
	"acls": [
		// Match absolutely everything.
		// Comment this section out if you want to define specific restrictions.
		{"action": "accept", "users": ["*"], "ports": ["*:*"]},
	],
	"ssh": [
		// Allow all users to SSH into their own devices in check mode.
		// Comment this section out if you want to define specific restrictions.
		{
			"action": "check",
			"src":    ["autogroup:members"],
			"dst":    ["autogroup:self"],
			"users":  ["autogroup:nonroot", "root"],
		},
	],
	"derpMap": {
		"OmitDefaultRegions": true,
		"Regions": {
			"900": {
				"RegionID":   900,
				"RegionCode": "kraken",
				"Nodes": [
					{
						"Name":     "derper",
						"RegionID": 900,
						"HostName": "derper.example.org",
					},
				],
			},
		},
	},
}

That is all, inspect machine status to see latency from your own Tailscale relay (DERP) server.