nix: add cc-ci-hetzner host (cpx32, nixos-infect hardware, all root SSH keys)
Port from terraform-hetzner branch. Adds the Hetzner cc-ci flake host with all 3 root authorized keys so nixos-rebuild doesn't lock out SSH access. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
11
flake.nix
11
flake.nix
@ -39,6 +39,17 @@
|
|||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# Hetzner Cloud host (cpx32, nbg1). Provisions via `terraform/` + nixos-infect.
|
||||||
|
# Used in parallel with cc-ci (Incus) during transition; becomes canonical after cutover.
|
||||||
|
# See terraform/README.md for the full apply + Stage 2 (nixos-rebuild switch) workflow.
|
||||||
|
nixosConfigurations.cc-ci-hetzner = nixpkgs.lib.nixosSystem {
|
||||||
|
inherit system;
|
||||||
|
modules = [
|
||||||
|
sops-nix.nixosModules.sops
|
||||||
|
./nix/hosts/cc-ci-hetzner/configuration.nix
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
devShells.${system} = {
|
devShells.${system} = {
|
||||||
# Devshell for working on the harness/bridge locally (tools + lint toolchain).
|
# Devshell for working on the harness/bridge locally (tools + lint toolchain).
|
||||||
default = pkgs.mkShell {
|
default = pkgs.mkShell {
|
||||||
|
|||||||
75
nix/hosts/cc-ci-hetzner/configuration.nix
Normal file
75
nix/hosts/cc-ci-hetzner/configuration.nix
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
# cc-ci on Hetzner Cloud — NixOS configuration.
|
||||||
|
# Extends the shared cc-ci modules (same services as the Incus host) with
|
||||||
|
# Hetzner-specific hardware + networking. Run in parallel with the Incus cc-ci
|
||||||
|
# host during transition; make this the canonical cc-ci after cutover (plan §7).
|
||||||
|
#
|
||||||
|
# To apply after `terraform apply` + nixos-infect:
|
||||||
|
# git clone --recursive https://git.autonomic.zone/recipe-maintainers/cc-ci.git /etc/cc-ci
|
||||||
|
# install -m600 <age-private-key> /var/lib/sops-nix/key.txt
|
||||||
|
# nixos-rebuild switch --flake /etc/cc-ci#cc-ci-hetzner
|
||||||
|
{ pkgs, lib, ... }:
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
./hardware.nix
|
||||||
|
./networking.nix
|
||||||
|
../../modules/packages.nix
|
||||||
|
../../modules/secrets.nix
|
||||||
|
../../modules/swarm.nix
|
||||||
|
../../modules/docker-prune.nix
|
||||||
|
../../modules/abra.nix
|
||||||
|
../../modules/proxy.nix
|
||||||
|
../../modules/drone.nix
|
||||||
|
../../modules/drone-runner.nix
|
||||||
|
../../modules/bridge.nix
|
||||||
|
../../modules/dashboard.nix
|
||||||
|
../../modules/backupbot.nix
|
||||||
|
../../modules/harness.nix
|
||||||
|
../../modules/warm-keycloak.nix
|
||||||
|
../../modules/nightly-sweep.nix
|
||||||
|
];
|
||||||
|
|
||||||
|
# Timezone (same as Incus host — see configuration.nix there for rationale).
|
||||||
|
time.timeZone = "UTC";
|
||||||
|
environment.etc."timezone".text = "UTC\n";
|
||||||
|
|
||||||
|
# Tailscale — keeps the orchestrator→cc-ci access path unchanged (direct peer).
|
||||||
|
# On the Hetzner host the auth key is also seeded via /etc/ts-auth-key.
|
||||||
|
services.tailscale = {
|
||||||
|
enable = true;
|
||||||
|
authKeyFile = "/etc/ts-auth-key";
|
||||||
|
extraUpFlags = [ "--hostname=cc-ci" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
# SSH — allow root login over tailscale (same as Incus host).
|
||||||
|
services.openssh = {
|
||||||
|
enable = true;
|
||||||
|
settings.PermitRootLogin = "yes";
|
||||||
|
};
|
||||||
|
|
||||||
|
# Root SSH authorized keys — preserved across nixos-rebuild switches.
|
||||||
|
users.users.root.openssh.authorizedKeys.keys = [
|
||||||
|
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOk8NaeBdPbS2gfUvbny8h0AkZlVjGYHzx4QPXSJ38gd claude@claude-vm"
|
||||||
|
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJVlfoLBPseQ9fA9534KmRg2KWcksKZGzAJIpHJ2JpsI mfowler.email@protonmail.com"
|
||||||
|
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAcyTGb/wVgdhg5oBCZZvBaR1RuUQRY/3WHnOQpNDCsp claude-cc-ci-sandbox@20260526"
|
||||||
|
];
|
||||||
|
|
||||||
|
# Firewall — Hetzner has a public IP, so open 80+443 for Traefik.
|
||||||
|
# Tailscale interface is trusted (no port restrictions for orchestrator access).
|
||||||
|
# Plan §6: v1 keeps the sops wildcard cert; evaluate ACME-on-public-IP as follow-up.
|
||||||
|
networking.firewall = {
|
||||||
|
enable = true;
|
||||||
|
trustedInterfaces = [ "tailscale0" ];
|
||||||
|
allowedTCPPorts = [ 22 80 443 ];
|
||||||
|
};
|
||||||
|
|
||||||
|
environment.systemPackages = with pkgs; [
|
||||||
|
curl
|
||||||
|
git
|
||||||
|
jq
|
||||||
|
openssh
|
||||||
|
];
|
||||||
|
|
||||||
|
nix.settings.experimental-features = [ "nix-command" "flakes" ];
|
||||||
|
|
||||||
|
system.stateVersion = "24.11";
|
||||||
|
}
|
||||||
35
nix/hosts/cc-ci-hetzner/hardware.nix
Normal file
35
nix/hosts/cc-ci-hetzner/hardware.nix
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
# Hardware configuration for cc-ci on Hetzner Cloud (cpx32: AMD 4 vCPU / 8 GB / x86_64).
|
||||||
|
# Generated by nixos-infect from a Debian 12 base image, then committed here.
|
||||||
|
#
|
||||||
|
# nixos-infect uses GRUB + EFI on Hetzner (not systemd-boot), with a qemu-guest profile
|
||||||
|
# because Hetzner Cloud uses KVM virtualisation.
|
||||||
|
#
|
||||||
|
# IMPORTANT: networking.nix (below) contains the server's static public IP.
|
||||||
|
# When provisioning a new server via `terraform apply`, copy the fresh networking.nix
|
||||||
|
# from /etc/nixos/networking.nix on the new host and commit it here before rebuilding.
|
||||||
|
{ modulesPath, ... }:
|
||||||
|
{
|
||||||
|
imports = [ (modulesPath + "/profiles/qemu-guest.nix") ];
|
||||||
|
|
||||||
|
boot.loader = {
|
||||||
|
efi.efiSysMountPoint = "/boot/efi";
|
||||||
|
grub = {
|
||||||
|
efiSupport = true;
|
||||||
|
efiInstallAsRemovable = true;
|
||||||
|
device = "nodev";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
fileSystems."/boot/efi" = {
|
||||||
|
device = "/dev/disk/by-uuid/D978-69EE";
|
||||||
|
fsType = "vfat";
|
||||||
|
};
|
||||||
|
|
||||||
|
boot.initrd.availableKernelModules = [ "ata_piix" "uhci_hcd" "xen_blkfront" "vmw_pvscsi" ];
|
||||||
|
boot.initrd.kernelModules = [ "nvme" ];
|
||||||
|
|
||||||
|
fileSystems."/" = {
|
||||||
|
device = "/dev/sda1";
|
||||||
|
fsType = "ext4";
|
||||||
|
};
|
||||||
|
}
|
||||||
40
nix/hosts/cc-ci-hetzner/networking.nix
Normal file
40
nix/hosts/cc-ci-hetzner/networking.nix
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
# Hetzner static networking — generated by nixos-infect at provision time.
|
||||||
|
#
|
||||||
|
# This file is server-specific: the IP, gateway, and MAC address are tied to a
|
||||||
|
# particular Hetzner instance. When provisioning a new server:
|
||||||
|
# 1. After `terraform apply` + nixos-infect completes, run:
|
||||||
|
# ssh root@<new-ip> 'cat /etc/nixos/networking.nix'
|
||||||
|
# 2. Replace this file's contents with the output and commit.
|
||||||
|
# 3. Then: `nixos-rebuild switch --flake .#cc-ci-hetzner --target-host root@<new-ip>`
|
||||||
|
#
|
||||||
|
# Current instance: 91.98.47.73 (fsn1, Hetzner server 134485294, provisioned 2026-05-31).
|
||||||
|
{ lib, ... }: {
|
||||||
|
networking = {
|
||||||
|
nameservers = [
|
||||||
|
"185.12.64.1"
|
||||||
|
"185.12.64.2"
|
||||||
|
];
|
||||||
|
defaultGateway = "172.31.1.1";
|
||||||
|
defaultGateway6 = {
|
||||||
|
address = "";
|
||||||
|
interface = "eth0";
|
||||||
|
};
|
||||||
|
dhcpcd.enable = false;
|
||||||
|
usePredictableInterfaceNames = lib.mkForce false;
|
||||||
|
interfaces = {
|
||||||
|
eth0 = {
|
||||||
|
ipv4.addresses = [
|
||||||
|
{ address = "91.98.47.73"; prefixLength = 32; }
|
||||||
|
];
|
||||||
|
ipv6.addresses = [
|
||||||
|
{ address = "fe80::9000:8ff:fe04:152e"; prefixLength = 64; }
|
||||||
|
];
|
||||||
|
ipv4.routes = [{ address = "172.31.1.1"; prefixLength = 32; }];
|
||||||
|
ipv6.routes = [{ address = ""; prefixLength = 128; }];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
services.udev.extraRules = ''
|
||||||
|
ATTR{address}=="92:00:08:04:15:2e", NAME="eth0"
|
||||||
|
'';
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user