Add headscale
This commit is contained in:
parent
3ff323ccca
commit
785b3c2b56
18 changed files with 271 additions and 21 deletions
|
@ -1 +1,2 @@
|
|||
HCLOUD_TOKEN="your_token_here"
|
||||
CLOUDFLARE_API_TOKEN="your_token_here"
|
||||
|
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -4,5 +4,4 @@
|
|||
*.tfstate
|
||||
*.tfstate.backup
|
||||
*.tfstate.*.backup
|
||||
.terraform.lock.hcl
|
||||
result
|
||||
|
|
21
README.md
21
README.md
|
@ -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>
|
||||
```
|
||||
|
|
|
@ -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
37
targets/.terraform.lock.hcl
generated
Normal 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
37
targets/dns/.terraform.lock.hcl
generated
Normal 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
30
targets/dns/terraform.tf
Normal 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
14
targets/terraform.tf
Normal 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
|
||||
}
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
cd "$(dirname "$0")"
|
||||
rm -f .terraform.lock.hcl
|
||||
tofu init
|
||||
tofu apply "$@"
|
|
@ -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 = {
|
||||
enable = true;
|
||||
settings.PasswordAuthentication = false;
|
||||
services = {
|
||||
openssh = {
|
||||
enable = true;
|
||||
settings.PasswordAuthentication = 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
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
services.cloud-init.enable = lib.mkForce false;
|
||||
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
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
@ -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"]}
|
|
@ -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
23
terraform/dns/main.tf
Normal 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
|
||||
}
|
7
terraform/dns/providers.tf
Normal file
7
terraform/dns/providers.tf
Normal file
|
@ -0,0 +1,7 @@
|
|||
terraform {
|
||||
required_providers {
|
||||
cloudflare = {
|
||||
source = "cloudflare/cloudflare"
|
||||
}
|
||||
}
|
||||
}
|
11
terraform/dns/variables.tf
Normal file
11
terraform/dns/variables.tf
Normal 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"
|
||||
}
|
|
@ -1,5 +1,8 @@
|
|||
module "dns" {
|
||||
source = "../dns"
|
||||
}
|
||||
|
||||
data "hcloud_ssh_keys" "nixos_vpn" {
|
||||
//with_selector = "vpn=true"
|
||||
}
|
||||
|
||||
resource "hcloud_server" "nixos_vpn" {
|
||||
|
@ -29,8 +32,12 @@ module "deploy" {
|
|||
|
||||
locals {
|
||||
nixos_vars = {
|
||||
ipv6_address = hcloud_server.nixos_vpn.ipv6_address
|
||||
ssh_keys = data.hcloud_ssh_keys.nixos_vpn.ssh_keys.*.public_key
|
||||
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
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
|
Loading…
Add table
Reference in a new issue