add IPv6 connectivity via Hurricane Electric 6in4 tunnel

- Add public_ipv6 variable and AAAA records for all 34 non-proxied services
- Fix stale DNS records (85.130.108.6 → 176.12.22.76, old IPv6 → HE tunnel)
- Update SPF record with current IPv4/IPv6 addresses
- Add AAAA update support to Technitium DNS updater CLI
- Pin mailserver MetalLB IP to 10.0.20.201 for stable pfSense NAT
- pfSense: HE_IPv6 interface, strict firewall (80,443,25,465,587,993 + ICMPv6),
  socat IPv6→IPv4 proxy, removed dangerous "Allow all DEBUG" rules
This commit is contained in:
Viktor Barzin 2026-03-23 02:22:00 +02:00
parent 813f523170
commit 644562454c
6 changed files with 63 additions and 5 deletions

View file

@ -69,8 +69,8 @@ func UpdatePublicIPViaTechnitiumAPI(newIp net.IP, username string, password stri
return errors.Wrap(err, "failed to get A record for ns server")
}
currIp := net.ParseIP(currIpStr)
fmt.Printf("updating record %s to %s\n", nsRecordName, newIp.String())
err = UpdateTechnitiumNSARecord(token, nsRecordName, currIp, newIp)
fmt.Printf("updating A record %s to %s\n", nsRecordName, newIp.String())
err = UpdateTechnitiumNSRecord(token, nsRecordName, "A", currIp, newIp)
if err != nil {
return errors.Wrap(err, "failed to update NS A record")
}
@ -78,12 +78,39 @@ func UpdatePublicIPViaTechnitiumAPI(newIp net.IP, username string, password stri
return nil
}
func UpdateTechnitiumNSARecord(token, domain string, currIp, newIp net.IP) error {
func UpdatePublicIPv6ViaTechnitiumAPI(newIp net.IP, username string, password string) error {
token, err := createTechnitiumToken(username, password)
if err != nil {
return errors.Wrap(err, "failed to get technitium token")
}
for _, ns := range []string{"ns1", "ns2", "@"} {
nsRecordName := ""
if ns == "@" {
nsRecordName = "viktorbarzin.me."
} else {
nsRecordName = ns + ".viktorbarzin.me"
}
currIpStr, err := getRecordValue(token, nsRecordName, "AAAA")
if err != nil {
fmt.Printf("no existing AAAA record for %s, skipping\n", nsRecordName)
continue
}
currIp := net.ParseIP(currIpStr)
fmt.Printf("updating AAAA record %s to %s\n", nsRecordName, newIp.String())
err = UpdateTechnitiumNSRecord(token, nsRecordName, "AAAA", currIp, newIp)
if err != nil {
return errors.Wrap(err, "failed to update NS AAAA record")
}
}
return nil
}
func UpdateTechnitiumNSRecord(token, domain, recordType string, currIp, newIp net.IP) error {
baseURL := fmt.Sprintf("http://%s:5380/api/zones/records/update", TECHNITIUM_HOST)
params := map[string]string{
"token": token,
"domain": domain,
"type": "A",
"type": recordType,
"newIpAddress": newIp.String(),
"ipAddress": currIp.String(),
}

Binary file not shown.

View file

@ -8,6 +8,7 @@ variable "cloudflare_account_id" { type = string }
variable "cloudflare_zone_id" { type = string }
variable "cloudflare_tunnel_id" { type = string }
variable "public_ip" { type = string }
variable "public_ipv6" { type = string }
variable "cloudflare_proxied_names" {}
variable "cloudflare_non_proxied_names" {}
@ -36,6 +37,7 @@ module "cloudflared" {
cloudflare_zone_id = var.cloudflare_zone_id
cloudflare_tunnel_id = var.cloudflare_tunnel_id
public_ip = var.public_ip
public_ipv6 = var.public_ipv6
cloudflare_proxied_names = concat(var.cloudflare_proxied_names, nonsensitive(local.user_domains))
cloudflare_non_proxied_names = var.cloudflare_non_proxied_names
cloudflare_tunnel_token = data.vault_kv_secret_v2.secrets.data["cloudflare_tunnel_token"]

View file

@ -18,6 +18,10 @@ variable "cloudflare_tunnel_id" {
variable "public_ip" {
type = string
}
variable "public_ipv6" {
type = string
description = "Public IPv6 address for AAAA records (from HE tunnel broker)"
}
terraform {
@ -99,6 +103,16 @@ resource "cloudflare_record" "non_proxied_dns_record" {
}
resource "cloudflare_record" "non_proxied_dns_record_ipv6" {
for_each = local.cloudflare_non_proxied_names_map
name = each.key
content = var.public_ipv6
proxied = false
ttl = 1
type = "AAAA"
zone_id = var.cloudflare_zone_id
}
resource "cloudflare_record" "mail" {
content = "mail.viktorbarzin.me"
name = "viktorbarzin.me"

View file

@ -466,6 +466,7 @@ resource "kubernetes_service" "mailserver" {
spec {
type = "LoadBalancer"
load_balancer_ip = "10.0.20.201"
# external_traffic_policy = "Cluster"
external_traffic_policy = "Local"
selector = {

View file

@ -18,6 +18,10 @@ variable "cloudflare_tunnel_id" {
variable "public_ip" {
type = string
}
variable "public_ipv6" {
type = string
description = "Public IPv6 address for AAAA records (from HE tunnel broker)"
}
terraform {
@ -99,6 +103,16 @@ resource "cloudflare_record" "non_proxied_dns_record" {
}
resource "cloudflare_record" "non_proxied_dns_record_ipv6" {
for_each = local.cloudflare_non_proxied_names_map
name = each.key
content = var.public_ipv6
proxied = false
ttl = 1
type = "AAAA"
zone_id = var.cloudflare_zone_id
}
resource "cloudflare_record" "mail" {
content = "mail.viktorbarzin.me"
name = "viktorbarzin.me"