feat: add Gitea Actions runner on private compute

Adds a private runner server on the Hetzner private network with NAT
through the gitea server for outbound internet access. Includes
Terraform resources, Ansible playbooks, and iptables forwarding rules.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-15 21:40:08 -04:00
parent af5d40d84e
commit 4cb6eaf091
10 changed files with 312 additions and 73 deletions

View File

@@ -60,3 +60,23 @@ resource "hcloud_firewall_attachment" "server_fw_attachment" {
firewall_id = hcloud_firewall.server_firewall.id
server_ids = [hcloud_server.server_instance.id]
}
resource "hcloud_server" "runner_instance" {
name = "runner-server"
image = local.server_image
server_type = local.server_type
datacenter = local.datacenter
ssh_keys = [hcloud_ssh_key.ssh_key.id]
public_net {
ipv4_enabled = false
ipv6_enabled = false
}
network {
network_id = hcloud_network.private_network.id
ip = local.runner_ip
}
depends_on = [hcloud_network_subnet.private_subnet]
}

24
terraform/network.tf Normal file
View File

@@ -0,0 +1,24 @@
resource "hcloud_network" "private_network" {
name = "repository-network"
ip_range = local.network_cidr
}
resource "hcloud_network_subnet" "private_subnet" {
network_id = hcloud_network.private_network.id
type = "cloud"
network_zone = local.network_zone
ip_range = local.subnet_cidr
}
resource "hcloud_server_network" "server_network" {
server_id = hcloud_server.server_instance.id
network_id = hcloud_network.private_network.id
ip = local.server_ip
}
resource "hcloud_network_route" "nat_route" {
network_id = hcloud_network.private_network.id
destination = "0.0.0.0/0"
gateway = local.server_ip
}

View File

@@ -1,11 +1,17 @@
output "server_ip" {
description = "The public address of the server."
value = hcloud_server.server_instance.ipv4_address
sensitive = false
value = hcloud_server.server_instance.ipv4_address
sensitive = false
}
output "server_fqdn" {
description = "The public domain of the server."
value = "${local.subdomain}.${local.domain}"
sensitive = false
value = "${local.subdomain}.${local.domain}"
sensitive = false
}
output "runner_ip" {
description = "The private network address of the runner."
value = local.runner_ip
sensitive = false
}

View File

@@ -5,6 +5,12 @@ locals {
domain = "maximhutz.com"
subdomain = "git"
network_zone = "eu-central"
network_cidr = "10.0.0.0/16"
subnet_cidr = "10.0.1.0/24"
server_ip = "10.0.1.2"
runner_ip = "10.0.1.3"
}
# ---------------------------------------------------------------------------- #