Skip to content
DnsLister Forum

Where domain hunters compare notes

Single File Driven Automation Suite for my Multiplatform Homelab

My homelab is multiplatform. I run some services on docker, some crucial infrastructure items on Kubernetes, and some on Proxmox as a mix of LXCs and VMs. Over time, I found it a pain in the butt to do everything I needed to for each new app. Below is the checklist I made for myself whenever I had to deploy a new app:

  • Create DHCP reservation
  • Create A record in .homelab zone
  • Create CNAME in local mydomain.com zone (I have split brain DNS)
  • Create PTR record
  • Generate Knot DNS Configmap
  • Restart Knot DNS
  • Create CNAME records in Cloudflare (if applicable)
  • Add Traefik service
  • Add Traefik router
  • Generate Traefik Configmap
  • Add Authelia ACLs/OIDC client
  • Create OIDC sealed secret
  • Apply OIDC sealed secret
  • Add OIDC secret to Authelia deployment
  • Generate Authelia configmap
  • Restart Authelia
  • Create Postgres user (if applicable)
  • Create Postgres database (if applicable)
  • Find what Redis database is available (if applicable)
  • Add VM to Netbox
  • Add VM interface to Netbox
  • Add IP to netbox
  • Update DNS docs (cloudflare, .homelab domain, local mydomain.com)
  • Update Traefik docs
  • Update Authelia docs
  • Update list of services
  • Update database docs

As you can imagine, this became a burden. I got sick and tired of doing all of these steps each time I wanted to deploy a new app. So, I created one metadata file that all my apps (and hosts) have where I can define everything an app could need. I came up with the entire file schema, and LLMs wrote all the accompanying scripts. Here is what the file looks like:

metadata: app: name: my-app platform: <docker,kubernetes,lxc,vm> host: <unraid,proxmox,pi-ha> network: - name: main vlan: 40 ip: # auto assigned at CI from available IPs in the correct vlan from Netbox dns: homelab-zone: - domain: my-app.homelab # Auto assigned from app name if blank type: A target: main # target is a network name as defined above mydomain-zone: - domain: my-app.mydomain.com type: CNAME public: true # Adds the record to Cloudflare target: local: @ public: @ - domain: my-app-intenral.mydomain.com type: CNAME public: false target: local: @ proxy: http: - domain: my-app.mydomain.com backend: type: <internal (traefik api), cluster (k8s), external)> host: my-app.homelab port: 80 https: false # Does the app serve self signed certs? middlewares: - strip-http3-headers tls: cloudflare - domain: my-app-internal.mydomain.com backend: type: external port: 3466 https: false middlewares: - authelia-forwardauth tls: cloudfalre auth: forward-auth: - domain: my-app-internal.mydomain.com rules: - policy: bypass resources: - "^/api.*$" - "^/ping.*$" - policy: one_factor subject: "group:users" oidc: redirect_uris: - "https://my-app.mydomain.com/oauth/complete/oidc/" # remaining OIDC client config in Authelia syntax guest_deploy: enabled: true ansible_user: root proxmox: cluster: homelab started: true start_on_boot: true startup: order: 0 reboot_after_update: true cpu: cores: 2 sockets: 1 memory: dedicated_mb: 6144 swap_mb: 512 floating_mb: 0 monitoring: gatus: enabled: trye group: ops endpoints: - name: my-app url: my-app.mydomain.com conditions: - "[STATUS] == 200" - '[BODY] == "OK"' prometheus: enabled: true # Prometheus scrape config databases: postgres: enabled: true assignments: - name: my-app user: my-app redis: enabled: true assignments: - name: main index: 2 server: host: redis.homelab port: 6379 

This one file controls everything an app might need, and then generates appropriate config. Here is what happens in CI before the pull request is merged:

  1. A detect job detects which app was edited. Fails if more than one app changed per mr. (gets in the way when doing bulk work but usuaully a good guard)
  2. Add defaults to the metadata file
  3. Validate the metadata. I have a bunch of rules. Things like if network block exists then DNS needs to exist. Or if the authelia-forward auth metadata exists then the auth section must exist etc.
  4. Provision VMs on Netbox. I model all docker containers, Kubernetes deployments, LXCs and real VMS as VMs on Netbox. Then each Docker service, each Kubernetes service, and each LXC and VM interface gets modelled as an interface on the Netbox VM. This stage only provisions the VM on Netbox.
  5. Assign Redis. All Redis assignments are stored on Netbox as a custom field on VMs. Script finds next available Redis db, attaches it to VM on netbox, and adds to metadata file.
  6. Assign IP. Assigns available IP based on platform (docker/kubernetes/LXC/VM) and VLAN. All IPs and IP ranges stored in Netbox.
  7. Generate an accompanying secrets.yml file. Generates secrets like Postgres passwords, OIDC secrets, etc.
  8. Add all the changes to the metadata file.
  9. Inject into docker compose (if docker app). This manages things like macvlans according to vlan, environment variables like secrets, default users, container names, etc.
  10. Generate resources. All of the following crawls through all the metadata files in the entire repo (not just the app), and genereates a manifest of all the resources that need to be generated.
  • Generates .tfvars for DNS records. homelab zone, internal mydomain zone, and cloudflare.
  • Generate Postgres manifest. This is an encrypted file with users, databases, and passwods of all PG databases.
  • Generates kubernetes resources for Traefik External Name services, TLS certs, Ingress Routes.
  • Generate authelia resources. Generates authelia-acl.yaml and authelia-oidc.yml files.
  • Generate proxmox resources. A json file of all the VMS and LXCs with their hardware configs.
  • Generate proxmox inventory for use with Ansible.
  • Generate Gatus config
  • Generate Prometheus config
  1. Update all the wiki tables
  2. Create deployment doc for the app
  3. Commit all the changes back to the PR with [skip ci]

After PR is merged, the following happens:

  1. Opentofu deploys Traefik, Authelia, DNS, Postgres, Twingate (for external monitoring) resources
  2. Prometheus and Gatus configs get rsync'd to the VPS
  3. Ansible uses Portainer API to deploy Docker containers
  4. Opentofu deploys the hardware on Proxmox
  5. Ansible configures the new hardware on Proxmox
  6. Wiki gets rebuilt and rsync'd to the wiki server

I realize this is a long post. I wanted to share the automation setup that has taken over the last year of my life tweaking and prompting to create. This is an approach that works for me, that won't work for anybody else, so I will not be sharing my scripts. I hope this post will inspire some of you to create similar automations in your homelab.

Source: r/homelab · by /u/Electrical_Fault_915

Leave a Reply

Your email address will not be published. Required fields are marked *