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"
|
HCLOUD_TOKEN="your_token_here"
|
||||||
|
CLOUDFLARE_API_TOKEN="your_token_here"
|
||||||
|
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -4,5 +4,4 @@
|
||||||
*.tfstate
|
*.tfstate
|
||||||
*.tfstate.backup
|
*.tfstate.backup
|
||||||
*.tfstate.*.backup
|
*.tfstate.*.backup
|
||||||
.terraform.lock.hcl
|
|
||||||
result
|
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
|
## 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.
|
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.null
|
||||||
pkgs.terraform-providers.external
|
pkgs.terraform-providers.external
|
||||||
pkgs.terraform-providers.local
|
pkgs.terraform-providers.local
|
||||||
|
pkgs.terraform-providers.cloudflare
|
||||||
]);
|
]);
|
||||||
in {
|
in {
|
||||||
devShells.default = pkgs.mkShell {
|
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 = [
|
imports = [
|
||||||
self.nixosModules.hcloud
|
self.nixosModules.hcloud
|
||||||
];
|
];
|
||||||
|
|
||||||
users.users.root = {
|
users.users.root = {
|
||||||
openssh.authorizedKeys.keys = nixosVars.ssh_keys;
|
openssh.authorizedKeys.keys = nixosVars.ssh_keys;
|
||||||
initialPassword = "nixos";
|
initialPassword = "nixos";
|
||||||
};
|
};
|
||||||
|
|
||||||
system.stateVersion = "23.11";
|
system.stateVersion = "23.11";
|
||||||
|
|
||||||
networking = {
|
networking = {
|
||||||
hostName = "vpn";
|
hostName = nixosVars.hostname;
|
||||||
domain = "sudoer777.dev";
|
domain = nixosVars.domain_netname;
|
||||||
|
|
||||||
|
firewall = {
|
||||||
|
allowedUDPPorts = [3478];
|
||||||
|
allowedTCPPorts = [80 443];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
services.openssh = {
|
services = {
|
||||||
|
openssh = {
|
||||||
enable = true;
|
enable = true;
|
||||||
settings.PasswordAuthentication = false;
|
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"];
|
boot.supportedFilesystems = ["btrfs"];
|
||||||
environment.systemPackages = [
|
environment.systemPackages = [
|
||||||
|
@ -36,6 +86,9 @@ in
|
||||||
pkgs.shadow
|
pkgs.shadow
|
||||||
pkgs.vim
|
pkgs.vim
|
||||||
pkgs.speedtest-cli
|
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" {
|
output "ipv6_address" {
|
||||||
value = module.vpn.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" {
|
data "hcloud_ssh_keys" "nixos_vpn" {
|
||||||
//with_selector = "vpn=true"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "hcloud_server" "nixos_vpn" {
|
resource "hcloud_server" "nixos_vpn" {
|
||||||
|
@ -29,6 +32,10 @@ module "deploy" {
|
||||||
|
|
||||||
locals {
|
locals {
|
||||||
nixos_vars = {
|
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
|
ipv6_address = hcloud_server.nixos_vpn.ipv6_address
|
||||||
ssh_keys = data.hcloud_ssh_keys.nixos_vpn.ssh_keys.*.public_key
|
ssh_keys = data.hcloud_ssh_keys.nixos_vpn.ssh_keys.*.public_key
|
||||||
}
|
}
|
||||||
|
@ -41,3 +48,15 @@ output "ipv4_address" {
|
||||||
output "ipv6_address" {
|
output "ipv6_address" {
|
||||||
value = hcloud_server.nixos_vpn.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"
|
description = "Hetzner cloud server location"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
variable "hostname" {
|
||||||
|
type = string
|
||||||
|
default = "vpn"
|
||||||
|
description = "Host name for server"
|
||||||
|
}
|
||||||
|
|
||||||
variable "nixos_vars_file" {
|
variable "nixos_vars_file" {
|
||||||
type = string
|
type = string
|
||||||
description = "File to write NixOS configuration variables to"
|
description = "File to write NixOS configuration variables to"
|
||||||
|
|
Loading…
Add table
Reference in a new issue