1
0
Fork 0

Add headscale

This commit is contained in:
Ethan Reece 2025-02-22 06:01:14 -06:00
parent 3ff323ccca
commit 785b3c2b56
Signed by: me
GPG key ID: 198E9EB433DB1B28
18 changed files with 271 additions and 21 deletions

View file

@ -1 +1,2 @@
HCLOUD_TOKEN="your_token_here"
CLOUDFLARE_API_TOKEN="your_token_here"

1
.gitignore vendored
View file

@ -4,5 +4,4 @@
*.tfstate
*.tfstate.backup
*.tfstate.*.backup
.terraform.lock.hcl
result

View file

@ -1,6 +1,6 @@
# OpenTofu server configuration
# VPN server configuration
This is an experimental configuration for my Hetzner VPS using OpenTofu and Nix, based on [NixOS/nixos-wiki-infra on Github](https://github.com/NixOS/nixos-wiki-infra).
This is an experimental configuration for my Hetzner VPS and Cloudflare to run a VPN using OpenTofu and Nix, based on [NixOS/nixos-wiki-infra on Github](https://github.com/NixOS/nixos-wiki-infra).
## How to use
@ -14,4 +14,19 @@ For cross-compiling, you will need to add a builder by visiting the following re
Run `nix develop` at the root of the project directory to access a shell where OpenTofu is accessible.
In the `targets` directory, go to the system and run the corresponding shell files to make modifications.
In the `targets` directory, run `./apply.sh` to update the configurations.
## VPN
To set up the VPN, on the VPS run:
```bash
headscale users create default
headscale preauthkeys create --user default --reusable
```
On the client run:
```bash
tailscale up --login-server <HEADSCALE_URL> --auth-key <KEY>
```

View file

@ -29,6 +29,7 @@
pkgs.terraform-providers.null
pkgs.terraform-providers.external
pkgs.terraform-providers.local
pkgs.terraform-providers.cloudflare
]);
in {
devShells.default = pkgs.mkShell {

37
targets/.terraform.lock.hcl generated Normal file
View file

@ -0,0 +1,37 @@
# This file is maintained automatically by "tofu init".
# Manual edits may be lost in future updates.
provider "registry.opentofu.org/cloudflare/cloudflare" {
version = "4.51.0"
hashes = [
"h1:lRBARGOEAeuBm5aC1P0bAAvs+F8+kSxV/UWiOWOIm44=",
]
}
provider "registry.opentofu.org/hashicorp/external" {
version = "2.3.4"
hashes = [
"h1:i0CiDzSau8J/NcGlv6A3luRuYkqbnuO2c+XVrJ6YOoA=",
]
}
provider "registry.opentofu.org/hashicorp/local" {
version = "2.5.2"
hashes = [
"h1:eWrRygqR0Pmcg61LyF+vADOO3oewcqeHasTJ6niHGNk=",
]
}
provider "registry.opentofu.org/hashicorp/null" {
version = "3.2.3"
hashes = [
"h1:tIPswUCP63F9jN+FulrFOJfVriHAMtLUPEkalbwa+Ys=",
]
}
provider "registry.opentofu.org/hetznercloud/hcloud" {
version = "1.49.1"
hashes = [
"h1:dyK3/rOb8IJOM0trh328NovbYb+Rz33qui2/fg85hU8=",
]
}

37
targets/dns/.terraform.lock.hcl generated Normal file
View file

@ -0,0 +1,37 @@
# This file is maintained automatically by "tofu init".
# Manual edits may be lost in future updates.
provider "registry.opentofu.org/cloudflare/cloudflare" {
version = "4.51.0"
hashes = [
"h1:lRBARGOEAeuBm5aC1P0bAAvs+F8+kSxV/UWiOWOIm44=",
]
}
provider "registry.opentofu.org/hashicorp/external" {
version = "2.3.4"
hashes = [
"h1:i0CiDzSau8J/NcGlv6A3luRuYkqbnuO2c+XVrJ6YOoA=",
]
}
provider "registry.opentofu.org/hashicorp/local" {
version = "2.5.2"
hashes = [
"h1:eWrRygqR0Pmcg61LyF+vADOO3oewcqeHasTJ6niHGNk=",
]
}
provider "registry.opentofu.org/hashicorp/null" {
version = "3.2.3"
hashes = [
"h1:tIPswUCP63F9jN+FulrFOJfVriHAMtLUPEkalbwa+Ys=",
]
}
provider "registry.opentofu.org/hetznercloud/hcloud" {
version = "1.49.1"
hashes = [
"h1:dyK3/rOb8IJOM0trh328NovbYb+Rz33qui2/fg85hU8=",
]
}

30
targets/dns/terraform.tf Normal file
View file

@ -0,0 +1,30 @@
terraform {
required_providers {
cloudflare = {
source = "cloudflare/cloudflare"
}
}
}
module "dns" {
source = "../../terraform/dns"
}
variable "vpn_ipv4" {
type = string
description = "IPv4 address for VPN"
}
variable "vpn_hostname" {
type = string
description = "Hostname for VPN"
}
resource "cloudflare_record" "vpn" {
zone_id = module.dns.zone_id_netname
name = "${var.vpn_hostname}.${module.dns.domain_netname}"
value = var.vpn_ipv4
type = "A"
ttl = 3600
proxied = false
}

14
targets/terraform.tf Normal file
View file

@ -0,0 +1,14 @@
module "admins" {
source = "./admins"
}
module "vpn" {
source = "./vpn"
}
module "dns" {
source = "./dns"
vpn_ipv4 = module.vpn.ipv4_address
vpn_hostname = module.vpn.hostname
}

View file

@ -1,7 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
cd "$(dirname "$0")"
rm -f .terraform.lock.hcl
tofu init
tofu apply "$@"

View file

@ -12,23 +12,73 @@ in
imports = [
self.nixosModules.hcloud
];
users.users.root = {
openssh.authorizedKeys.keys = nixosVars.ssh_keys;
initialPassword = "nixos";
};
system.stateVersion = "23.11";
networking = {
hostName = "vpn";
domain = "sudoer777.dev";
hostName = nixosVars.hostname;
domain = nixosVars.domain_netname;
firewall = {
allowedUDPPorts = [3478];
allowedTCPPorts = [80 443];
};
};
services.openssh = {
services = {
openssh = {
enable = true;
settings.PasswordAuthentication = false;
};
services.cloud-init.enable = lib.mkForce false;
cloud-init.enable = lib.mkForce false;
headscale = {
enable = true;
address = "0.0.0.0";
port = 8080;
settings = {
server_url = "https://${nixosVars.hostname}.${nixosVars.domain_netname}";
logtail.enabled = false;
dns = {
base_domain = "ts.${nixosVars.domain_netname}";
magic_dns = true;
search_domains = ["${nixosVars.domain_netname}"];
nameservers.global = [
"1.1.1.1"
"9.9.9.9"
];
};
ip_prefixes = [
"100.64.0.0/10"
];
};
};
caddy = {
enable = true;
virtualHosts."${nixosVars.hostname}.${nixosVars.domain_netname}".extraConfig = ''
reverse_proxy * 127.0.0.1:8080
'';
};
};
systemd.network.networks."10-wan" = {
matchConfig.MACAddress = "96:00:04:16:ed:c5";
address = ["${nixosVars.ipv4_address}/32"];
routes = [
{
Gateway = "172.31.1.1";
GatewayOnLink = true;
}
];
linkConfig.RequiredForOnline = "routable";
};
boot.supportedFilesystems = ["btrfs"];
environment.systemPackages = [
@ -36,6 +86,9 @@ in
pkgs.shadow
pkgs.vim
pkgs.speedtest-cli
pkgs.git
pkgs.hcloud
pkgs.dhcpcd
];
}

View file

@ -1 +1 @@
{"ipv6_address":"2a01:4ff:1f0:ce35::1","ssh_keys":["ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJWUVBj2uBVfXGjWwXmOTQmqP1oc2ZfDtylhTEox6JBm ssh@sudoer777.dev"]}
{"domain_netname":"sudoer777.dev","domain_realname":"ethanreece.com","hostname":"vpn","ipv4_address":"5.78.133.184","ipv6_address":"2a01:4ff:1f0:ce35::1","ssh_keys":["ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJWUVBj2uBVfXGjWwXmOTQmqP1oc2ZfDtylhTEox6JBm ssh@sudoer777.dev"]}

View file

@ -15,3 +15,7 @@ output "ipv4_address" {
output "ipv6_address" {
value = module.vpn.ipv6_address
}
output "hostname" {
value = module.vpn.hostname
}

23
terraform/dns/main.tf Normal file
View file

@ -0,0 +1,23 @@
data "cloudflare_zone" "realname" {
name = var.domain_realname
}
data "cloudflare_zone" "netname" {
name = var.domain_netname
}
output "domain_realname" {
value = var.domain_realname
}
output "domain_netname" {
value = var.domain_netname
}
output "zone_id_realname" {
value = data.cloudflare_zone.realname.id
}
output "zone_id_netname" {
value = data.cloudflare_zone.netname.id
}

View file

@ -0,0 +1,7 @@
terraform {
required_providers {
cloudflare = {
source = "cloudflare/cloudflare"
}
}
}

View file

@ -0,0 +1,11 @@
variable "domain_realname" {
type = string
default = "ethanreece.com"
description = "Domain for real name"
}
variable "domain_netname" {
type = string
default = "sudoer777.dev"
description = "Domain for internet name"
}

View file

@ -1,5 +1,8 @@
module "dns" {
source = "../dns"
}
data "hcloud_ssh_keys" "nixos_vpn" {
//with_selector = "vpn=true"
}
resource "hcloud_server" "nixos_vpn" {
@ -29,6 +32,10 @@ module "deploy" {
locals {
nixos_vars = {
hostname = var.hostname
domain_realname = module.dns.domain_realname
domain_netname = module.dns.domain_netname
ipv4_address = hcloud_server.nixos_vpn.ipv4_address
ipv6_address = hcloud_server.nixos_vpn.ipv6_address
ssh_keys = data.hcloud_ssh_keys.nixos_vpn.ssh_keys.*.public_key
}
@ -41,3 +48,15 @@ output "ipv4_address" {
output "ipv6_address" {
value = hcloud_server.nixos_vpn.ipv6_address
}
output "domain_realname" {
value = module.dns.domain_realname
}
output "domain_netname" {
value = module.dns.domain_netname
}
output "hostname" {
value = var.hostname
}

View file

@ -10,6 +10,12 @@ variable "server_location" {
description = "Hetzner cloud server location"
}
variable "hostname" {
type = string
default = "vpn"
description = "Host name for server"
}
variable "nixos_vars_file" {
type = string
description = "File to write NixOS configuration variables to"