1
0
Fork 0

Compare commits

..

No commits in common. "7e20cace41485b67dfa5fd8b7f2c9a2052675124" and "df8ab4016a560fef2394671e3be1bb309e280648" have entirely different histories.

24 changed files with 69 additions and 369 deletions

View file

@ -1 +0,0 @@
HCLOUD_TOKEN="your_token_here"

3
.gitignore vendored
View file

@ -1,7 +1,6 @@
*.tfvars
.terraform/
*.env
.terraform.lock.hcl
*.tfstate
*.tfstate.backup
*.tfstate.*.backup
.terraform.lock.hcl

View file

@ -4,9 +4,15 @@ This is an experimental configuration for my Hetzner VPS using OpenTofu and Nix.
## How to use
Copy `.env.example` to `.env` and fill in the values.
Copy `secret.tfvars.example` to `secret.tfvars` and fill in the values.
To generate a token with Hetzner, go to the project and click `Security -> API Tokens`.
Run `nix develop` to access a shell where OpenTofu is accessible.
## Aliases
The following aliases in the development shell include the secrets file automatically.
- `tofu-plan`
- `tofu-apply`

65
flake.lock generated
View file

@ -1,45 +1,5 @@
{
"nodes": {
"disko": {
"inputs": {
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1739841949,
"narHash": "sha256-lSOXdgW/1zi/SSu7xp71v+55D5Egz8ACv0STkj7fhbs=",
"owner": "nix-community",
"repo": "disko",
"rev": "15dbf8cebd8e2655a883b74547108e089f051bf0",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "disko",
"type": "github"
}
},
"flake-parts": {
"inputs": {
"nixpkgs-lib": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1738453229,
"narHash": "sha256-7H9XgNiGLKN1G1CgRh0vUL4AheZSYzPm+zmZ7vxbJdo=",
"owner": "hercules-ci",
"repo": "flake-parts",
"rev": "32ea77a06711b758da0ad9bd6a844c5740a87abd",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "flake-parts",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1739866667,
@ -58,30 +18,7 @@
},
"root": {
"inputs": {
"disko": "disko",
"flake-parts": "flake-parts",
"nixpkgs": "nixpkgs",
"srvos": "srvos"
}
},
"srvos": {
"inputs": {
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1740012831,
"narHash": "sha256-u6Y5ttXBuQ+tyyCei07QnbNL6Gydv55OpoGh4fXzTqg=",
"owner": "numtide",
"repo": "srvos",
"rev": "f6ddf92bc61e021ea05c971a055624509ffac429",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "srvos",
"type": "github"
"nixpkgs": "nixpkgs"
}
}
},

View file

@ -1,49 +1,32 @@
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
flake-parts.url = "github:hercules-ci/flake-parts";
flake-parts.inputs.nixpkgs-lib.follows = "nixpkgs";
disko.url = "github:nix-community/disko";
disko.inputs.nixpkgs.follows = "nixpkgs";
srvos.url = "github:numtide/srvos";
srvos.inputs.nixpkgs.follows = "nixpkgs";
};
outputs = inputs@{ flake-parts, nixpkgs, ... }:
flake-parts.lib.mkFlake { inherit inputs; } {
systems = [
"x86_64-linux"
"aarch64-linux"
];
imports = [
./targets/flake-module.nix
./modules/flake-module.nix
];
perSystem = { system, pkgs, ... }:
outputs = { self, nixpkgs, ... }:
let
allSystems = [ "x86_64-linux" "aarch64-linux" ];
in
{
devShells = nixpkgs.lib.genAttrs allSystems (system:
let
pkgs = import nixpkgs { inherit system; };
tofuPkg = pkgs.opentofu.withPlugins (p: [
pkgs.terraform-providers.hcloud
pkgs.terraform-providers.null
pkgs.terraform-providers.external
pkgs.terraform-providers.local
]);
in {
devShells.default = pkgs.mkShell {
default = pkgs.mkShell {
buildInputs = [
tofuPkg
pkgs.terraform-ls
pkgs.hcloud
];
shellHook = ''
set -a
source ./.env
set +a
alias tofu-plan="tofu plan -var-file=secret.tfvars"
alias tofu-apply="tofu apply -var-file=secret.tfvars"
'';
};
};
};
}
);
};
}

46
main.tf Normal file
View file

@ -0,0 +1,46 @@
terraform {
required_providers {
hcloud = {
source = "hetznercloud/hcloud"
version = "~> 1.45"
}
}
}
variable "hcloud_token" {
sensitive = true
}
provider "hcloud" {
token = var.hcloud_token
}
resource "hcloud_ssh_key" "main" {
name = "my-ssh-key"
public_key = file("~/.ssh/id_ed25519.pub")
}
resource "hcloud_server" "vpn" {
name = "vpn"
image = "debian-12"
server_type = "cpx11"
location = "hil"
ssh_keys = [hcloud_ssh_key.main.id]
//provisioner "local-exec" {
// command = "sleep 120"
//}
provisioner "remote-exec" {
connection {
type = "ssh"
user = "root"
host = self.ipv4_address
// private_key = file("~/.ssh/id_ed25519")
agent = true
}
inline = [
"curl https://raw.githubusercontent.com/elitak/NixOS-infect/master/NixOS-infect | PROVIDER=hetznercloud Nix_CHANNEL=NixOS-Unstable bash 2>&1 | tee /tmp/infect.log",
]
}
}

View file

@ -1,10 +0,0 @@
{ inputs, ... }:
{
flake.nixosModules = {
hcloud.imports = [
inputs.srvos.nixosModules.server
inputs.srvos.nixosModules.hardware-hetzner-cloud
./single-disk.nix
];
};
}

View file

@ -1,41 +0,0 @@
{ self, ... }:
let
partitions = {
boot = {
size = "1M";
type = "EF02"; # for grub MBR
};
esp = {
size = "500M";
type = "EF00"; # for grub MBR
content = {
type = "filesystem";
format = "vfat";
mountpoint = "/boot";
};
};
root = {
size = "100%";
content = {
type = "filesystem";
format = "btrfs";
mountpoint = "/";
};
};
};
in
{
imports = [
self.inputs.disko.nixosModules.disko
];
disko.devices = {
disk.sda = {
type = "disk";
device = "/dev/sda";
content = {
type = "gpt";
inherit partitions;
};
};
};
}

1
secret.tfvars.example Normal file
View file

@ -0,0 +1 @@
hcloud_token = "your_token_here"

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

@ -1,6 +0,0 @@
module "vpn" {
source = "../../terraform/admins"
ssh_keys = {
sudoer777 = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJWUVBj2uBVfXGjWwXmOTQmqP1oc2ZfDtylhTEox6JBm ssh@sudoer777.dev"
}
}

View file

@ -1,26 +0,0 @@
{ lib, self, ... }:
let
entries = builtins.attrNames (builtins.readDir ./.);
configs = builtins.filter (dir: builtins.pathExists (./. + "/${dir}/configuration.nix")) entries;
in
{
flake.nixosConfigurations = lib.listToAttrs (
builtins.map (
name:
lib.nameValuePair (builtins.replaceStrings [ "." ] [ "-" ] name) (
lib.nixosSystem {
system = "x86_64-linux";
# Make flake available in modules
specialArgs = {
self = {
inputs = self.inputs;
nixosModules = self.nixosModules;
};
};
modules = [ (./. + "/${name}/configuration.nix") ];
}
)
) configs
);
}

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

@ -1,30 +0,0 @@
{
self,
lib,
config,
pkgs,
...
}:
let
nixosVars = builtins.fromJSON (builtins.readFile ./nixos-vars.json);
in
{
imports = [
self.nixosModules.hcloud
];
users.users.root.openssh.authorizedKeys.keys = nixosVars.ssh_keys;
system.stateVersion = "23.11";
networking = {
hostName = "vpn";
};
services.openssh = {
enable = true;
settings.PasswordAuthentication = false;
};
boot.supportedFilesystems = ["btrfs"];
environment.systemPackages = [pkgs.btrfs-progs];
}

View file

@ -1,15 +0,0 @@
#!/usr/bin/env bash
set -euxo pipefail
nixBuild() {
if command -v nom -v &>/dev/null; then
nom build "$@"
else
nix build "$@"
fi
}
nixBuild .#nixosConfigurations.vpn.config.system.build.toplevel -L
if ! nixos-rebuild switch --flake .#vpn --target-host root@vpn; then
nixos-rebuild switch --flake .#vpn --target-host root@vpn
fi

View file

@ -1 +0,0 @@
{"ipv6_address":"2a01:4ff:1f0:ce35::1","ssh_keys":["ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJWUVBj2uBVfXGjWwXmOTQmqP1oc2ZfDtylhTEox6JBm ssh@sudoer777.dev"]}

View file

@ -1,17 +0,0 @@
module "vpn" {
source = "../../terraform/nixos-vpn"
nixos_flake_attr = "vpn"
nixos_vars_file = "${path.module}/nixos-vars.json"
tags = {
Terraform = "true"
Target = "vpn"
}
}
output "ipv4_address" {
value = module.vpn.ipv4_address
}
output "ipv6_address" {
value = module.vpn.ipv6_address
}

View file

@ -1,8 +0,0 @@
resource "hcloud_ssh_key" "hcloud" {
for_each = var.ssh_keys
name = each.key
public_key = each.value
labels = {
"wiki" = "true"
}
}

View file

@ -1,5 +0,0 @@
terraform {
required_providers {
hcloud = { source = "hetznercloud/hcloud" }
}
}

View file

@ -1,4 +0,0 @@
variable "ssh_keys" {
type = map(string)
description = "SSH public keys for admin user (name -> key)"
}

View file

@ -1,43 +0,0 @@
data "hcloud_ssh_keys" "nixos_vpn" {
//with_selector = "vpn=true"
}
resource "hcloud_server" "nixos_vpn" {
name = "nixos-vpn"
image = "debian-12"
keep_disk = true
server_type = var.server_type
location = var.server_location
ssh_keys = data.hcloud_ssh_keys.nixos_vpn.ssh_keys.*.name
backups = false
lifecycle {
ignore_changes = [ssh_keys]
prevent_destroy = true
}
}
module "deploy" {
depends_on = [local_file.nixos_vars]
source = "github.com/numtide/nixos-anywhere//terraform/all-in-one"
nixos_system_attr = ".#nixosConfigurations.vpn.config.system.build.toplevel"
nixos_partitioner_attr = ".#nixosConfigurations.vpn.config.system.build.diskoScriptNoDeps"
target_host = hcloud_server.nixos_vpn.ipv4_address
instance_id = hcloud_server.nixos_vpn.id
debug_logging = true
}
locals {
nixos_vars = {
ipv6_address = hcloud_server.nixos_vpn.ipv6_address
ssh_keys = data.hcloud_ssh_keys.nixos_vpn.ssh_keys.*.public_key
}
}
output "ipv4_address" {
value = hcloud_server.nixos_vpn.ipv4_address
}
output "ipv6_address" {
value = hcloud_server.nixos_vpn.ipv6_address
}

View file

@ -1,18 +0,0 @@
resource "local_file" "nixos_vars" {
content = jsonencode(local.nixos_vars)
filename = var.nixos_vars_file
file_permission = "600"
provisioner "local-exec" {
interpreter = ["bash", "-c"]
command = "git add -f '${var.nixos_vars_file}'"
}
# also pro-actively add hosts and flake-module.nix to git so nix can find it.
provisioner "local-exec" {
interpreter = ["bash", "-c"]
command = <<EOT
git add "$(dirname '${var.nixos_vars_file}')"/{hosts,flake-module.nix}
EOT
on_failure = continue
}
}

View file

@ -1,6 +0,0 @@
terraform {
required_providers {
hcloud = { source = "hetznercloud/hcloud" }
local = { source = "hashicorp/local" }
}
}

View file

@ -1,27 +0,0 @@
variable "server_type" {
type = string
default = "cpx11"
description = "Hetzner cloud server type"
}
variable "server_location" {
type = string
default = "hil"
description = "Hetzner cloud server location"
}
variable "nixos_vars_file" {
type = string
description = "File to write NixOS configuration variables to"
}
variable "nixos_flake_attr" {
type = string
description = "NixOS configuration flake attribute"
}
variable "tags" {
type = map(string)
default = {}
description = "Tags to add to the server"
}