Use headscale Replace tailscale

Posted on Jun 22, 2024
Headscale is open source, self-hosted implementation of the Tailscale control server, You can use headscale to replace tailscale. (headscale version > 0.22.3)

DOWNLOADS & BUILD INSTALL

# headscale version > 0.22.3
git clone [email protected]:juanfont/headscale.git
cd headscale
go mod tidy
go build ./cmd/headscale

useradd headscale
mkdir /usr/local/headscale
cp headscale /usr/local/headscale/

chown headscale:headscale /usr/local/headscale/

GENERATE PRIVATE KEY

/usr/local/headscale/headscale generate private-key > headscale/data/private.key /usr/local/headscale/headscale generate private-key > headscale/data/noise_private.key

CONFIGURATION

/usr/local/headscale/config.yaml

# The url clients will connect to.
# Typically this will be a domain like:
#
# https://myheadscale.example.com:443
#
server_url: https://<IPADDRESS>:8080

# Address to listen to / bind to on the server
listen_addr: 0.0.0.0:8080

# Address to listen to /metrics, you may want
# to keep this endpoint private to your internal
# network
metrics_listen_addr: 127.0.0.1:9090

# Address to listen for gRPC.
grpc_listen_addr: 127.0.0.1:50443

# Allow the gRPC admin interface to run in INSECURE
grpc_allow_insecure: false

# The Noise section includes specific configuration for the
# TS2021 Noise protocol
noise:
  private_key_path: /usr/local/headscale/data/noise_private.key

# List of IP prefixes to allocate tailaddresses from.
prefixes:
  v4: 100.65.0.0/16
  allocation: sequential

# DERP server configuration (if using an embedded DERP server)
derp:
  server:
    enabled: false
    region_id: 999
    region_code: "headscale"
    region_name: "Headscale Embedded DERP"
    stun_listen_addr: "0.0.0.0:3478"
    private_key_path: /usr/local/headscale/data/private.key
    automatically_add_embedded_derp_region: true

  # List of externally available DERP maps encoded in JSON
  urls:
    - https://controlplane.tailscale.com/derpmap/default

  # Paths to local DERP map files (if any)
  paths: []

  # Auto-update DERP map
  auto_update_enabled: true
  update_frequency: 24h

# Disables the automatic check for headscale updates on startup
disable_check_updates: false

# Time before an inactive ephemeral node is deleted
ephemeral_node_inactivity_timeout: 30m

database:
  type: sqlite3
  sqlite:
    path: /usr/local/headscale/data/db.sqlite

### TLS configuration ###
# Use already defined certificates:
tls_cert_path: "/usr/local/headscale/data/ssl/server.crt"
tls_key_path: "/usr/local/headscale/data/ssl/server.key"

log:
  format: text
  level: info

# DNS configuration
dns_config:
  override_local_dns: false
  nameservers:
    - 1.1.1.1
  magic_dns: false
  base_domain: example.com

# Unix socket used for the CLI to connect without authentication
unix_socket: /usr/local/headscale/headscale.sock
unix_socket_permission: "0770"

# Logtail configuration (if using)
logtail:
  enabled: false

# Randomize client port for WireGuard traffic
randomize_client_port: false

SYSTEMD

/lib/systemd/system/headscale.service

[Unit]
After=syslog.target
After=network.target
Description=headscale coordination server for Tailscale
X-Restart-Triggers=/usr/local/headscale/config.yaml

[Service]
Type=simple
User=headscale
Group=headscale
ExecStart=/usr/local/headscale/headscale -c  /usr/local/headscale/config.yaml serve
Restart=always
RestartSec=5
WorkingDirectory=/usr/local/headscale
ReadWritePaths=/usr/local/headscale /var/run

AmbientCapabilities=CAP_NET_BIND_SERVICE CAP_CHOWN
CapabilityBoundingSet=CAP_NET_BIND_SERVICE CAP_CHOWN
LockPersonality=true
NoNewPrivileges=true
PrivateDevices=true
PrivateMounts=true
PrivateTmp=true
ProcSubset=pid
ProtectClock=true
ProtectControlGroups=true
ProtectHome=true
ProtectHome=yes
ProtectHostname=true
ProtectKernelLogs=true
ProtectKernelModules=true
ProtectKernelTunables=true
ProtectProc=invisible
ProtectSystem=strict
RemoveIPC=true
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX
RestrictNamespaces=true
RestrictRealtime=true
RestrictSUIDSGID=true
RuntimeDirectory=headscale
RuntimeDirectoryMode=0750
StateDirectory=headscale
StateDirectoryMode=0750
SystemCallArchitectures=native
SystemCallFilter=@chown
SystemCallFilter=@system-service
SystemCallFilter=~@privileged
UMask=0077

[Install]
WantedBy=multi-user.target

RUN HEADSCALE

test:
/usr/local/headscale/headscale -c /usr/local/headscale/config.yaml serve

with systemd:
systemctl start headscale.service

CONNECT

create user

/usr/local/headscale/headscale -c /usr/local/headscale/config.yaml user create default
/usr/local/headscale/headscale -c /usr/local/headscale/config.yaml user list

client login server

# linux & macos
sudo tailscale up --operator=default --login-server http://<IPADDRESS>:8080
# windows
tailscale login --login-server http://<IPADDRESS>:8080

server register

headscale nodes register --user USERNAME --key mkey:xx...xxx

# check node
/usr/local/headscale/headscale -c /usr/local/headscale/config.yaml -c config.yaml  nodes list