Server

vim docker-compose.yml
-----
services:
  headscale:
    image: headscale/headscale:stable
    container_name: headscale
    volumes:
      - ./config:/etc/headscale
      - ./data:/var/lib/headscale
    ports:
      - 8081:8080
    command: serve
    restart: unless-stopped
  headscale-ui:
    image: ghcr.io/gurucomputing/headscale-ui:latest
    restart: unless-stopped
    container_name: headscale-ui
    ports:
      - 8443:8443
      - 8080:8080
-----
vim ./config/config.yaml
-----
server_url: https://yourdomain.com:443
listen_addr: 0.0.0.0:8080
 
dns:
  magic_dns: false
  base_domain: host.yourdomain.com
    global:
      - 114.114.114.114
      - 119.29.29.29
      # - 2606:4700:4700::1111
      # - 2606:4700:4700::1001
-----
vim /etc/caddy/Caddyfile
-----
yourdomain.com {
	log {
		output file /var/log/caddy/yourdomain.com.log {
			roll_size 100MiB
			roll_keep 7
			roll_keep_for 240h
			roll_gzip true
		}
	}
	encode zstd gzip
	reverse_proxy /web* http://127.0.0.1:8080
	reverse_proxy * http://127.0.0.1:8081
}
-----
vim ~/.zshrc
-----
alias headscale="docker exec headscale headscale"
-----

Add a namespace “default”

# Add a namespace
headscale namespaces create home
 
# List namespaces
headscale namespaces list

Get headscale api key

headscale apikeys create -e 720d

Client (OPNsense)

Install tailscale

opnsense-code ports
 
cd /usr/ports/security/tailscale
make install
 
service tailscaled enable
service tailscaled start

Start tailscale

# Registry node
tailscale up --login-server=https://yourdomain.com:443 --accept-routes=true --accept-dns=false --advertise-routes=192.168.123.0/24 --reset
 
# Then visit the terminal output url, then execute browser return command at headscale server
## Remanber to replace `USERNAME` to your namespace

Enable route (Server)

# (Server)
headscale routes list
headscale routes enable -r <route item number>

Add interface at OPNsense control panel