Luigit
repositories / bugabinga.net

bugabinga.net

personal infrastructure for bugabinga!

owned by admin

templates/cloud-init.yaml.tftpl

Raw
#cloud-config
package_update: true
package_upgrade: true

packages:
  - openssh-server
  - wireguard-tools
  - fail2ban
  - dnf-automatic

users:
  - name: root
    ssh_authorized_keys:
      - ${ssh_public_key}

write_files:
  - path: /etc/sysctl.d/99-forwarding.conf
    content: |
      net.ipv4.ip_forward = 1
      net.ipv6.conf.all.forwarding = 1
      # Force accept RA even when forwarding is enabled (Critical for Hetzner IPv6)
      net.ipv6.conf.eth0.accept_ra = 2
    permissions: '0644'

  - path: /etc/wireguard/wg0.conf
    content: |
      [Interface]
      Address = ${wg_server_ip}/24, ${wg_server_ipv6}/64
      ListenPort = 51820
      PrivateKey = ${wg_server_private_key}
      MTU = ${wg_mtu}
      Table = off

      [Peer]
      PublicKey = ${wg_peer_public_key}
      AllowedIPs = 0.0.0.0/0, ${wg_peer_ipv6}/128
    permissions: '0600'
    owner: root:root

  - path: /etc/sysconfig/nftables.conf
    content: |
      #!/usr/sbin/nft -f

      flush ruleset

      table inet filter {
        chain input {
          type filter hook input priority filter; policy drop;

          # Allow loopback
          iif "lo" accept

          # Allow established/related connections
          ct state established,related accept

          # Allow ICMP
          ip protocol icmp accept
          ip6 nexthdr ipv6-icmp accept

          # Allow SSH (Management)
          iif "eth0" tcp dport ${ssh_port} accept

          # Allow WireGuard (Tunnel)
          iif "eth0" udp dport 51820 accept

          # Git SSH is DNATed to klops; do not accept it locally here.

          # Allow HTTP (80) for ACME HTTP-01 challenge
          iif "eth0" tcp dport 80 accept
        }

        chain forward {
          type filter hook forward priority filter; policy drop;

          # Allow HTTP/HTTPS, Git SSH, and Luci SSH from internet to WireGuard peer
          iif "eth0" oif "wg0" tcp dport { 80, 443, ${vcs_ssh_peer_port}, ${luci_ssh_peer_port} } accept

          # Allow return traffic from WireGuard peer to internet
          iif "wg0" oif "eth0" ct state established,related accept

          # Allow established/related
          ct state established,related accept
        }

        chain output {
          type filter hook output priority filter; policy accept;
        }
      }

      table ip nat {
        chain prerouting {
          type nat hook prerouting priority dstnat; policy accept;

          # DNAT HTTP/HTTPS to WireGuard peer
          iif "eth0" tcp dport { 80, 443 } dnat to ${wg_peer_ip}

          # DNAT public Git SSH to Soft Serve on WireGuard peer
          iif "eth0" tcp dport ${vcs_ssh_public_port} dnat to ${wg_peer_ip}:${vcs_ssh_peer_port}

          # DNAT public Luci SSH to Luci on WireGuard peer
          iif "eth0" tcp dport ${luci_ssh_public_port} dnat to ${wg_peer_ip}:${luci_ssh_peer_port}
        }

        chain postrouting {
          type nat hook postrouting priority srcnat; policy accept;

          # Masquerade traffic from WireGuard peer going to internet
          ip saddr ${wg_peer_ip} oif "eth0" masquerade
        }
      }

      table ip6 nat {
        chain prerouting {
          type nat hook prerouting priority dstnat; policy accept;

          # DNAT HTTP/HTTPS to WireGuard peer IPv6 ULA
          iif "eth0" tcp dport { 80, 443 } dnat to ${wg_peer_ipv6}

          # DNAT public Git SSH to Soft Serve on WireGuard peer IPv6 ULA
          iif "eth0" tcp dport ${vcs_ssh_public_port} dnat to [${wg_peer_ipv6}]:${vcs_ssh_peer_port}

          # DNAT public Luci SSH to Luci on WireGuard peer IPv6 ULA
          iif "eth0" tcp dport ${luci_ssh_public_port} dnat to [${wg_peer_ipv6}]:${luci_ssh_peer_port}
        }
      }
    permissions: '0755'

  - path: /etc/fail2ban/jail.local
    content: |
      [DEFAULT]
      banaction = nftables-multiport
      banaction_allports = nftables-allports
      chain = input

      [sshd]
      enabled = true
      mode    = aggressive
      port    = ${ssh_port}
      logpath = %(sshd_log)s
      backend = systemd
      maxretry = 3
      bantime = 1h
    permissions: '0644'

  - path: /etc/dnf/automatic.conf
    content: |
      [commands]
      upgrade_type = security
      random_sleep = 0
      network_online_timeout = 60
      download_updates = yes
      apply_updates = yes

      [emitters]
      emit_via = stdio

      [base]
      debuglevel = 1
    permissions: '0644'

  - path: /etc/ssh/sshd_config.d/port.conf
    content: |
      Port ${ssh_port}
    permissions: '0644'

  - path: /etc/systemd/system/nftables.service.d/after-wg.conf
    content: |
      [Unit]
      After=wg-quick@wg0.service
    permissions: '0644'

runcmd:
  - sysctl -p /etc/sysctl.d/99-forwarding.conf
  - systemctl daemon-reload
  - systemctl enable --now wg-quick@wg0
  - systemctl enable --now nftables
  - systemctl enable --now fail2ban
  - systemctl enable --now dnf-automatic.timer
  - systemctl restart sshd