sowwy you dont have webgl :(

or the client side is just loading i'll implement a proper check someday :^)

hello, it's kay 🦊 (she - elle), kay 🤖 (they/it - ielles/lae), we do web development mainly (mostly, no clue what we're doing)

we're a 27 year-old trans 🏳️‍⚧️ non-binary borg system. you can use any neutral pronouns for us (english: they or it, french: ielle/iel ou lae/lea ou ca/cela). currently lives near paris. likes anything that has to do with technology and hacking stuff (code, video, music, games, electronics, etc.). likes to share what we make and learn and teach stuff. very much pro data rights and more broadly against rising worldwide fascistic ideology and oppression.

this post is still a work in progress

2024-07-21

getting headscale setup on nixos

setting up a headscale server and connecting tailscale peers to it


why?


i recently switched all my machines to nix and nixos. this includes my desktop computer, my laptop, my vps and my phone (nix-on-droid)

i wanted to setup a vpn so that any of them could access any other without any issues, and headscale seems to be popular these days so i gave it a try

how?


prerequisites


1. the first thing you need is a domain, i used headscale.juke.fr, make sure you setup an A record that points to the host that will host the headscale server


you can also use a dynamic dns service but setting one of these up is not covered in this guide but if you go that route you might want to look into ddclient


2. then you need to make sure that 80/TCP, 443/TCP and 3478/UDP are all allowed in your firewall (for nixos this is covered later in this guide, but if you are running on a VPS like i am on oracle you might need to also open them elsewhere)

headscale nixos configuration


create a headscale.nix module that you import in your nixos configuration that contains the following, adjust accoring to your needs


{
  config,
  ...
}:
let
  domain = "juke.fr"; # domain to use
  derpPort = 3478; # default derp port
in
{
  services = {
    # enable headscale service and configure
    headscale = {
      enable = true;
      address = "127.0.0.1";
      port = 8085; # use any port you please, it gets reversed tunnelled anyways
      settings = {
        dns_config = {
          override_local_dns = true;
          base_domain = domain;
          magic_dns = true; # this enables you to access hosts via $HOSTNAME.$USER.juke.fr
          domains = [ "hs.${domain}" ];
          nameservers = [
            "1.1.1.1"
            "9.9.9.9"
          ];
        };
        server_url = "https://headscale.${domain}";
        metrics_listen_addr = "127.0.0.1:8095"; # use any port you please, it gets reversed tunnelled anyways
        logtail = {
          enabled = false;
        };
        log = {
          level = "warn";
        };
        derp.server = {
          enable = true;
          region_id = 999;
          stun_listen_addr = "0.0.0.0:${toString derpPort}";
        };
      };
    };

    # reverse proxy with ssl
    nginx = {
      enable = true;
      virtualHosts."headscale.${domain}" = {
        forceSSL = true;
        enableACME = true;
        locations = {
          "/" = {
            proxyPass = "http://localhost:${toString config.services.headscale.port}";
            proxyWebsockets = true;
          };
          "/metrics" = {
            proxyPass = "http://${config.services.headscale.settings.metrics_listen_addr}/metrics";
          };
        };
      };
    };
  };

  # configure ssl certificate options
  security.acme = {
    defaults.email = "acme@juke.fr";
    acceptTerms = true;
  };

  # punch through firewall
  networking.firewall.allowedUDPPorts = [ derpPort ];
  networking.firewall.allowedTCPPorts = [
    80
    443
  ];

  # add headscale package to system
  environment.systemPackages = [ config.services.headscale.package ];
}
            

switch nixos configurations and make sure everything is working correctly by accessing headscale.juke.fr/metrics

you also need to create a namespace (which will create a user) for use later on

sudo headscale namespaces create net # replace net with the namespace name you want

tailscale nixos configuration


next we want to setup the tailscale service in tailscale.nix and import it in our common configuration for everybody to use


{
  lib,
  ...
}:
{
  services.tailscale = {
    enable = true;
    useRoutingFeatures = lib.mkDefault "client";
  };
  networking.firewall = {
    checkReversePath = "loose";
    allowedUDPPorts = [ 41641 ]; # Facilitate firewall punching
  };
}

            

rebuild nixos and now to join the headscale instance we can use

sudo tailscale up --login-server https://headscale.juke.fr/

this will direct you to a login page that will generate a command you should type on the headscale server replacing $USER with the namespace we created earlier, don't forget to add sudo also


your client is now connected to headscale and you can access it with $HOSTNAME.$NAMESPACE.$domain for example nixos-home.net.juke.fr