diff --git a/.env.example b/.env.example index bafecdb..0910189 100644 --- a/.env.example +++ b/.env.example @@ -1,3 +1,6 @@ +# Config for: Environment variables template +# Applied by: Copy to .env and fill in values; sourced by shell scripts + # Porkbun API credentials PORKBUN_API_KEY=pk1_your_key_here PORKBUN_SECRET_KEY=sk1_your_key_here @@ -11,4 +14,4 @@ GITEA_RUNNER_TOKEN=your_token_here # Grafana admin password GRAFANA_ADMIN_PASSWORD=your_password_here -AUTHENTIK_PROXY_TOKEN=your_token_here \ No newline at end of file +AUTHENTIK_PROXY_TOKEN=your_token_here diff --git a/README.md b/README.md index 4641d78..b2d5e53 100644 --- a/README.md +++ b/README.md @@ -27,25 +27,58 @@ Infrastructure-as-Code for a 3-machine homelab running K3s. | Service | URL | Notes | |---|---|---| | Traefik | — | Ingress controller, Let's Encrypt | +| Authentik | `https://authentik.home.arpa` | SSO/identity provider | | Gitea | `https://gitea.home.arpa` | Git + Docker registry, SSH on port 2222 | | Pi-hole | `https://pihole.home.arpa/admin` | Primary DNS, resolves `*.home.arpa` → 192.168.7.77 | +| Grafana | `https://grafana.home.arpa` | Monitoring dashboards (kube-prometheus-stack) | +| Jellyfin | `https://jellyfin.home.arpa` | Media server | +| qBittorrent | `https://qbittorrent.home.arpa` | Torrent client | +| JDownloader | `https://jdownloader.home.arpa` | Download manager | +| Dashy | `https://dashy.home.arpa` | Dashboard | +| Glances | `https://glances.home.arpa` | System monitoring | ## Repo Structure ``` ansible/ - inventory.yaml # host definitions + inventory.yaml # host definitions playbooks/ - bootstrap-minisforum.yaml # OS hardening, packages, UFW, /data dirs - setup-k3s.yaml # K3s server install, Helm, kubeconfig + bootstrap-minisforum.yaml # OS hardening, packages, UFW, /data dirs + deploy-watch-party.yaml # deploy watch-party app + join-debian-agent.yaml # join Debian as K3s agent + setup-gitea-runner.yaml # set up Gitea Actions runner + setup-glances-debian.yaml # deploy Glances on Debian host + setup-k3s.yaml # K3s server install, Helm, kubeconfig + setup-monitoring.yaml # deploy monitoring stack + setup-nfs-debian.yaml # configure NFS server on Debian roles/ - common/ # user, SSH hardening, UFW, base packages - k3s-server/ # K3s server install + Helm + common/ # user, SSH hardening, UFW, base packages + gitea-runner/ # Gitea Actions runner setup + glances/ # Glances system monitor + k3s-agent/ # K3s agent node join + k3s-server/ # K3s server install + Helm + monitoring/ # Prometheus/Grafana monitoring + nfs-server/ # NFS server configuration + watch-party/ # Watch-party app deployment +config/ + dashy/conf.yaml # Dashy dashboard config +manifests/ + authentik/ # Authentik ingress, middleware, proxy outpost, secrets + cert-manager/ # ClusterIssuers and porkbun-secret.sh + core/ # Dashy, Glances, CA installer, apply-dashy-config.sh + gitea/ # Gitea PV, runner, backup, runner secret + media/ # Jellyfin, qBittorrent, JDownloader + monitoring/ # Grafana/Loki datasource, PVs, grafana-secret.sh + network/ # DDNS, Traefik dashboard, ingress routes, pihole patch values/ - traefik.yaml ✅ deployed - gitea.yaml 🔧 in progress - pihole.yaml 🔧 in progress -old.debian-data/ # gitignored — backup of pre-migration configs + authentik.yaml # Authentik SSO + cert-manager.yaml # cert-manager + gitea.yaml # Gitea + kube-prometheus-stack.yaml # Prometheus + Grafana + loki-stack.yaml # Loki log aggregation + pihole.yaml # Pi-hole (Minisforum) + pihole-debian.yaml # Pi-hole (Debian) + traefik.yaml # Traefik ingress controller ``` ## Prerequisites @@ -92,8 +125,29 @@ helm repo add mojo2600 https://mojo2600.github.io/pihole-kubernetes/ && helm rep helm upgrade --install pihole mojo2600/pihole \ --namespace pihole --create-namespace \ -f values/pihole.yaml + +# cert-manager +helm repo add jetstack https://charts.jetstack.io && helm repo update +helm upgrade --install cert-manager jetstack/cert-manager \ + --namespace cert-manager --create-namespace \ + -f values/cert-manager.yaml + +# Authentik +helm repo add authentik https://charts.goauthentik.io && helm repo update +helm upgrade --install authentik authentik/authentik \ + --namespace authentik --create-namespace \ + -f values/authentik.yaml + +# kube-prometheus-stack +helm repo add prometheus-community https://prometheus-community.github.io/helm-charts && helm repo update +helm upgrade --install kube-prometheus-stack prometheus-community/kube-prometheus-stack \ + --namespace monitoring --create-namespace \ + -f values/kube-prometheus-stack.yaml + +# Loki +helm repo add grafana https://grafana.github.io/helm-charts && helm repo update +helm upgrade --install loki grafana/loki-stack \ + --namespace monitoring --create-namespace \ + -f values/loki-stack.yaml ``` -## See Also - -- [migration-plan.md](migration-plan.md) — full phase-by-phase migration plan diff --git a/ansible.cfg b/ansible.cfg index 4683d3a..6801959 100644 --- a/ansible.cfg +++ b/ansible.cfg @@ -1,3 +1,6 @@ +# Config for: Ansible +# Applied by: Automatically loaded by ansible-playbook when run from repo root + [defaults] inventory = ansible/inventory.yaml roles_path = ansible/roles diff --git a/ansible/inventory.yaml b/ansible/inventory.yaml index 807f2f1..86bb467 100644 --- a/ansible/inventory.yaml +++ b/ansible/inventory.yaml @@ -1,3 +1,5 @@ +# Config for: Ansible inventory +# Applied by: Referenced by all ansible-playbook commands with -i flag all: vars: ansible_user: nik @@ -19,4 +21,4 @@ all: mac_mini: hosts: mac-mini: - ansible_host: 192.168.7.96 \ No newline at end of file + ansible_host: 192.168.7.96 diff --git a/ansible/playbooks/bootstrap-minisforum.yaml b/ansible/playbooks/bootstrap-minisforum.yaml index 80e6c2a..e504717 100644 --- a/ansible/playbooks/bootstrap-minisforum.yaml +++ b/ansible/playbooks/bootstrap-minisforum.yaml @@ -1,13 +1,6 @@ --- -# Run: ansible-playbook -i ansible/inventory.yaml ansible/playbooks/bootstrap-minisforum.yaml -# Requires: SSH access to 192.168.7.7 as root (or a user with NOPASSWD sudo) -# -# What this does: -# - Creates the 'nik' user with sudo access -# - Hardens SSH (no password auth, no root login) -# - Installs base packages -# - Configures UFW firewall -# - Creates /data/* directories for persistent volumes +# Run: ansible-playbook ansible/playbooks/bootstrap-minisforum.yaml -i ansible/inventory.yaml +# Description: Bootstraps the Minisforum server with user setup, SSH hardening, base packages, UFW firewall, and persistent data directories. - name: Bootstrap Minisforum hosts: minisforum diff --git a/ansible/playbooks/deploy-watch-party.yaml b/ansible/playbooks/deploy-watch-party.yaml index 25aa8b7..1b17c71 100644 --- a/ansible/playbooks/deploy-watch-party.yaml +++ b/ansible/playbooks/deploy-watch-party.yaml @@ -1,18 +1,10 @@ --- -# Run: ansible-playbook ansible/playbooks/deploy-watch-party.yaml -# -# What this does: -# - Pulls latest watch-party repo from Gitea -# - Starts containers via Docker Compose using registry images -# -# Prerequisites: -# - .env file must exist at ~/repo/watch-party/.env on Mac Mini -# - Docker Desktop must be running on Mac Mini -# - Images must be built and pushed to gitea.home.arpa registry +# Run: ansible-playbook ansible/playbooks/deploy-watch-party.yaml -i ansible/inventory.yaml +# Description: Deploys the watch-party application on Mac Mini by pulling from Gitea and starting containers via Docker Compose. - name: Deploy Watch Party on Mac Mini hosts: mac-mini gather_facts: true roles: - - watch-party \ No newline at end of file + - watch-party diff --git a/ansible/playbooks/join-debian-agent.yaml b/ansible/playbooks/join-debian-agent.yaml index 4f5e586..89dc07d 100644 --- a/ansible/playbooks/join-debian-agent.yaml +++ b/ansible/playbooks/join-debian-agent.yaml @@ -1,10 +1,6 @@ --- -# Run: ansible-playbook ansible/playbooks/join-debian-agent.yaml -K -e "k3s_node_token=$K3S_NODE_TOKEN" -# Requires: K3S_NODE_TOKEN in .env -# -# What this does: -# - Joins Debian as a K3s agent node -# - Labels it as node-role=storage +# Run: ansible-playbook ansible/playbooks/join-debian-agent.yaml -i ansible/inventory.yaml -K -e "k3s_node_token=$K3S_NODE_TOKEN" +# Description: Joins the Debian machine as a K3s agent node and labels it as storage. - name: Join Debian as K3s agent hosts: debian @@ -12,4 +8,4 @@ gather_facts: true roles: - - k3s-agent \ No newline at end of file + - k3s-agent diff --git a/ansible/playbooks/setup-gitea-runner.yaml b/ansible/playbooks/setup-gitea-runner.yaml index 04377e8..b013c99 100644 --- a/ansible/playbooks/setup-gitea-runner.yaml +++ b/ansible/playbooks/setup-gitea-runner.yaml @@ -1,9 +1,6 @@ --- -# Run: ansible-playbook ansible/playbooks/setup-gitea-runner.yaml -# -# What this does: -# - Installs act_runner as a systemd service on Minisforum -# - Registers runner with Gitea +# Run: ansible-playbook ansible/playbooks/setup-gitea-runner.yaml -i ansible/inventory.yaml +# Description: Installs and registers the Gitea Actions runner as a systemd service on Minisforum. - name: Deploy Gitea Actions Runner on Minisforum hosts: minisforum @@ -12,4 +9,4 @@ gitea_runner_token: "{{ lookup('env', 'GITEA_RUNNER_TOKEN') }}" roles: - - gitea-runner \ No newline at end of file + - gitea-runner diff --git a/ansible/playbooks/setup-glances-debian.yaml b/ansible/playbooks/setup-glances-debian.yaml index 8cf0047..63dcb8c 100644 --- a/ansible/playbooks/setup-glances-debian.yaml +++ b/ansible/playbooks/setup-glances-debian.yaml @@ -1,13 +1,10 @@ --- -# Run: ansible-playbook ansible/playbooks/setup-glances-debian.yaml -# -# What this does: -# - Deploys Glances on Debian as a Docker container -# - Accessible at http://192.168.7.183:61208 +# Run: ansible-playbook ansible/playbooks/setup-glances-debian.yaml -i ansible/inventory.yaml +# Description: Deploys Glances as a Docker container on the Debian host for system monitoring. - name: Deploy Glances on Debian hosts: debian gather_facts: true roles: - - glances \ No newline at end of file + - glances diff --git a/ansible/playbooks/setup-k3s.yaml b/ansible/playbooks/setup-k3s.yaml index f4034e0..600e67c 100644 --- a/ansible/playbooks/setup-k3s.yaml +++ b/ansible/playbooks/setup-k3s.yaml @@ -1,21 +1,6 @@ --- -# Run: ansible-playbook ansible/playbooks/setup-k3s.yaml -K -# -# What this does: -# - Installs K3s in server mode (with Traefik disabled) -# - Installs Helm -# - Fetches kubeconfig to ~/.kube/config on your workstation -# - Labels the node as node-role=primary -# -# After this playbook: -# kubectl get nodes # should show minisforum as Ready -# -# Then deploy Traefik: -# helm repo add traefik https://helm.traefik.io/traefik -# helm repo update -# helm upgrade --install traefik traefik/traefik \ -# --namespace traefik --create-namespace \ -# -f values/traefik.yaml +# Run: ansible-playbook ansible/playbooks/setup-k3s.yaml -i ansible/inventory.yaml -K +# Description: Installs K3s server, Helm, fetches kubeconfig, and labels the Minisforum node as primary. - name: Install K3s server hosts: minisforum diff --git a/ansible/playbooks/setup-monitoring.yaml b/ansible/playbooks/setup-monitoring.yaml index 1c2596a..d609201 100644 --- a/ansible/playbooks/setup-monitoring.yaml +++ b/ansible/playbooks/setup-monitoring.yaml @@ -1,4 +1,8 @@ +--- +# Run: ansible-playbook ansible/playbooks/setup-monitoring.yaml -i ansible/inventory.yaml +# Description: Creates monitoring data directories for Prometheus and Loki on Minisforum. + - name: Prepare monitoring storage on Minisforum hosts: minisforum roles: - - monitoring \ No newline at end of file + - monitoring diff --git a/ansible/playbooks/setup-nfs-debian.yaml b/ansible/playbooks/setup-nfs-debian.yaml index 7cd3735..4c1a300 100644 --- a/ansible/playbooks/setup-nfs-debian.yaml +++ b/ansible/playbooks/setup-nfs-debian.yaml @@ -1,9 +1,6 @@ --- -# Run: ansible-playbook ansible/playbooks/setup-nfs-debian.yaml -K -# -# What this does: -# - Installs NFS server on Debian -# - Exports /mnt/storage to Minisforum (read-only) +# Run: ansible-playbook ansible/playbooks/setup-nfs-debian.yaml -i ansible/inventory.yaml -K +# Description: Installs and configures NFS server on Debian, exporting /mnt/storage to Minisforum. - name: Set up NFS server on Debian hosts: debian @@ -11,4 +8,4 @@ gather_facts: true roles: - - nfs-server \ No newline at end of file + - nfs-server diff --git a/ansible/roles/common/defaults/main.yaml b/ansible/roles/common/defaults/main.yaml index cb5b45a..2383cca 100644 --- a/ansible/roles/common/defaults/main.yaml +++ b/ansible/roles/common/defaults/main.yaml @@ -1,4 +1,8 @@ --- +# Part of role: common +# Called by: ansible/playbooks/bootstrap-minisforum.yaml +# Description: Default variables for the common role including user, packages, firewall ports, and data directories. + username: nik timezone: Asia/Tokyo @@ -12,7 +16,7 @@ base_packages: - ca-certificates - gnupg - lsb-release - - nfs-common # needed in Phase 4 for Jellyfin NFS mount from Debian + - nfs-common ufw_allowed_ports: - { port: 430, proto: tcp, comment: SSH } diff --git a/ansible/roles/common/handlers/main.yaml b/ansible/roles/common/handlers/main.yaml index 6998953..685e654 100644 --- a/ansible/roles/common/handlers/main.yaml +++ b/ansible/roles/common/handlers/main.yaml @@ -1,4 +1,8 @@ --- +# Part of role: common +# Called by: ansible/playbooks/bootstrap-minisforum.yaml +# Description: Handlers for the common role, including SSH service restart. + - name: Restart sshd ansible.builtin.service: name: sshd diff --git a/ansible/roles/common/tasks/main.yaml b/ansible/roles/common/tasks/main.yaml index f134e70..46d2dd5 100644 --- a/ansible/roles/common/tasks/main.yaml +++ b/ansible/roles/common/tasks/main.yaml @@ -1,4 +1,8 @@ --- +# Part of role: common +# Called by: ansible/playbooks/bootstrap-minisforum.yaml +# Description: Sets timezone, installs base packages, creates user, hardens SSH, configures UFW, and creates data directories. + - name: Set timezone community.general.timezone: name: "{{ timezone }}" diff --git a/ansible/roles/gitea-runner/handlers/main.yaml b/ansible/roles/gitea-runner/handlers/main.yaml index ee619fa..07b53ea 100644 --- a/ansible/roles/gitea-runner/handlers/main.yaml +++ b/ansible/roles/gitea-runner/handlers/main.yaml @@ -1,6 +1,10 @@ --- +# Part of role: gitea-runner +# Called by: ansible/playbooks/setup-gitea-runner.yaml +# Description: Handlers for the gitea-runner role, including service restart. + - name: Restart act_runner ansible.builtin.systemd: name: act_runner state: restarted - become: true \ No newline at end of file + become: true diff --git a/ansible/roles/gitea-runner/tasks/main.yaml b/ansible/roles/gitea-runner/tasks/main.yaml index f1adb25..bc48602 100644 --- a/ansible/roles/gitea-runner/tasks/main.yaml +++ b/ansible/roles/gitea-runner/tasks/main.yaml @@ -1,4 +1,8 @@ --- +# Part of role: gitea-runner +# Called by: ansible/playbooks/setup-gitea-runner.yaml +# Description: Downloads, configures, and registers act_runner as a systemd service connected to the Gitea instance. + - name: Download act_runner binary ansible.builtin.get_url: url: https://gitea.com/gitea/act_runner/releases/download/v0.2.11/act_runner-0.2.11-linux-amd64 @@ -101,4 +105,4 @@ enabled: true state: started daemon_reload: true - become: true \ No newline at end of file + become: true diff --git a/ansible/roles/glances/handlers/main.yaml b/ansible/roles/glances/handlers/main.yaml index 27003d4..6fd2630 100644 --- a/ansible/roles/glances/handlers/main.yaml +++ b/ansible/roles/glances/handlers/main.yaml @@ -1,6 +1,10 @@ --- +# Part of role: glances +# Called by: ansible/playbooks/setup-glances-debian.yaml +# Description: Handlers for the glances role, including container restart. + - name: Restart Glances container community.docker.docker_container: name: glances state: started - restart: true \ No newline at end of file + restart: true diff --git a/ansible/roles/glances/tasks/main.yaml b/ansible/roles/glances/tasks/main.yaml index 73064fd..67daef0 100644 --- a/ansible/roles/glances/tasks/main.yaml +++ b/ansible/roles/glances/tasks/main.yaml @@ -1,4 +1,8 @@ --- +# Part of role: glances +# Called by: ansible/playbooks/setup-glances-debian.yaml +# Description: Deploys Glances as a Docker container with host networking for system monitoring. + - name: Create Glances config directory ansible.builtin.file: path: /etc/glances @@ -32,4 +36,4 @@ - /proc:/proc:ro - /sys:/sys:ro - /mnt:/mnt:ro - - /etc/glances:/etc/glances:ro \ No newline at end of file + - /etc/glances:/etc/glances:ro diff --git a/ansible/roles/k3s-agent/defaults/main.yaml b/ansible/roles/k3s-agent/defaults/main.yaml index e367fe5..8b8e0bf 100644 --- a/ansible/roles/k3s-agent/defaults/main.yaml +++ b/ansible/roles/k3s-agent/defaults/main.yaml @@ -1,4 +1,8 @@ --- +# Part of role: k3s-agent +# Called by: ansible/playbooks/join-debian-agent.yaml +# Description: Default variables for the k3s-agent role including version, server URL, and join token. + k3s_version: v1.32.2+k3s1 k3s_server_url: https://192.168.7.77:6443 -k3s_node_token: "" # pass via -e or vault \ No newline at end of file +k3s_node_token: "" diff --git a/ansible/roles/k3s-agent/tasks/main.yaml b/ansible/roles/k3s-agent/tasks/main.yaml index 7fb3557..9f2fded 100644 --- a/ansible/roles/k3s-agent/tasks/main.yaml +++ b/ansible/roles/k3s-agent/tasks/main.yaml @@ -1,4 +1,8 @@ --- +# Part of role: k3s-agent +# Called by: ansible/playbooks/join-debian-agent.yaml +# Description: Installs K3s in agent mode, joins the cluster, and labels the node as storage. + - name: Download and install K3s agent ansible.builtin.shell: cmd: > @@ -23,4 +27,4 @@ node-role=storage --overwrite delegate_to: minisforum become: true - changed_when: false \ No newline at end of file + changed_when: false diff --git a/ansible/roles/k3s-server/defaults/main.yaml b/ansible/roles/k3s-server/defaults/main.yaml index e201f8d..d3ab8b0 100644 --- a/ansible/roles/k3s-server/defaults/main.yaml +++ b/ansible/roles/k3s-server/defaults/main.yaml @@ -1,11 +1,14 @@ --- -k3s_version: v1.32.2+k3s1 # pin to a specific version; update deliberately +# Part of role: k3s-server +# Called by: ansible/playbooks/setup-k3s.yaml +# Description: Default variables for the k3s-server role including version, IP, and server configuration. + +k3s_version: v1.32.2+k3s1 k3s_server_ip: 192.168.7.77 -# Written to /etc/rancher/k3s/config.yaml on the server k3s_server_config: disable: - - traefik # we deploy Traefik ourselves via Helm + - traefik flannel-backend: vxlan node-ip: "{{ k3s_server_ip }}" tls-san: diff --git a/ansible/roles/k3s-server/tasks/main.yaml b/ansible/roles/k3s-server/tasks/main.yaml index 258fda3..056149a 100644 --- a/ansible/roles/k3s-server/tasks/main.yaml +++ b/ansible/roles/k3s-server/tasks/main.yaml @@ -1,4 +1,8 @@ --- +# Part of role: k3s-server +# Called by: ansible/playbooks/setup-k3s.yaml +# Description: Installs K3s server, fetches kubeconfig, installs Helm, and labels the node as primary. + - name: Create K3s config directory ansible.builtin.file: path: /etc/rancher/k3s @@ -17,7 +21,7 @@ curl -sfL https://get.k3s.io | INSTALL_K3S_VERSION={{ k3s_version }} sh - - creates: /usr/local/bin/k3s # skip if already installed + creates: /usr/local/bin/k3s - name: Wait for K3s to be ready ansible.builtin.wait_for: @@ -39,7 +43,7 @@ ansible.builtin.set_fact: k3s_node_token: "{{ k3s_token_raw['content'] | b64decode | trim }}" -- name: Print node token (needed for Phase 2 agent join) +- name: Print node token ansible.builtin.debug: msg: "K3s node token: {{ k3s_node_token }}" @@ -65,4 +69,4 @@ - name: Label server node as primary ansible.builtin.shell: cmd: k3s kubectl label node minisforum node-role=primary --overwrite - changed_when: false # label is idempotent but shell module always reports changed + changed_when: false diff --git a/ansible/roles/monitoring/tasks/main.yaml b/ansible/roles/monitoring/tasks/main.yaml index 847463f..0259d7b 100644 --- a/ansible/roles/monitoring/tasks/main.yaml +++ b/ansible/roles/monitoring/tasks/main.yaml @@ -1,11 +1,16 @@ +--- +# Part of role: monitoring +# Called by: ansible/playbooks/setup-monitoring.yaml +# Description: Creates data directories with correct ownership for Prometheus and Loki. + - name: Create monitoring data directories - file: + ansible.builtin.file: path: "{{ item.path }}" state: directory owner: "{{ item.owner }}" group: "{{ item.owner }}" mode: "0755" loop: - - { path: /data/prometheus, owner: "65534" } # nobody — Prometheus UID - - { path: /data/loki, owner: "10001" } # Loki UID - become: true \ No newline at end of file + - { path: /data/prometheus, owner: "65534" } + - { path: /data/loki, owner: "10001" } + become: true diff --git a/ansible/roles/nfs-server/defaults/main.yaml b/ansible/roles/nfs-server/defaults/main.yaml index 85ec6cd..fcd53fa 100644 --- a/ansible/roles/nfs-server/defaults/main.yaml +++ b/ansible/roles/nfs-server/defaults/main.yaml @@ -1,3 +1,7 @@ --- +# Part of role: nfs-server +# Called by: ansible/playbooks/setup-nfs-debian.yaml +# Description: Default variables for the nfs-server role including export path and allowed client IP. + nfs_export_path: /mnt/storage -nfs_allowed_ip: 192.168.7.77 \ No newline at end of file +nfs_allowed_ip: 192.168.7.77 diff --git a/ansible/roles/nfs-server/handlers/main.yaml b/ansible/roles/nfs-server/handlers/main.yaml index 016bc80..16aa288 100644 --- a/ansible/roles/nfs-server/handlers/main.yaml +++ b/ansible/roles/nfs-server/handlers/main.yaml @@ -1,6 +1,10 @@ --- +# Part of role: nfs-server +# Called by: ansible/playbooks/setup-nfs-debian.yaml +# Description: Handlers for the nfs-server role, including NFS service restart. + - name: Restart NFS server ansible.builtin.service: name: nfs-kernel-server state: restarted - become: true \ No newline at end of file + become: true diff --git a/ansible/roles/nfs-server/tasks/main.yaml b/ansible/roles/nfs-server/tasks/main.yaml index 2435c82..4e08dd7 100644 --- a/ansible/roles/nfs-server/tasks/main.yaml +++ b/ansible/roles/nfs-server/tasks/main.yaml @@ -1,4 +1,8 @@ --- +# Part of role: nfs-server +# Called by: ansible/playbooks/setup-nfs-debian.yaml +# Description: Installs NFS server, configures exports, and ensures the backup directory exists. + - name: Install NFS server ansible.builtin.apt: name: @@ -32,4 +36,4 @@ owner: "1001" group: "1001" mode: "0755" - become: true \ No newline at end of file + become: true diff --git a/ansible/roles/nfs-server/templates/exports.j2 b/ansible/roles/nfs-server/templates/exports.j2 index cd6f31b..4cc7b7f 100644 --- a/ansible/roles/nfs-server/templates/exports.j2 +++ b/ansible/roles/nfs-server/templates/exports.j2 @@ -1,5 +1,7 @@ +# Part of role: nfs-server +# Description: NFS exports template rendered to /etc/exports # /etc/exports - managed by Ansible # NFS exports for K3s cluster /mnt/storage 192.168.7.77(ro,sync,no_subtree_check,no_root_squash,fsid=1) -/home/nik/backups 192.168.7.77(rw,sync,no_subtree_check,no_root_squash,fsid=2) \ No newline at end of file +/home/nik/backups 192.168.7.77(rw,sync,no_subtree_check,no_root_squash,fsid=2) diff --git a/ansible/roles/watch-party/defaults/main.yaml b/ansible/roles/watch-party/defaults/main.yaml index 61969c4..0d8b4a1 100644 --- a/ansible/roles/watch-party/defaults/main.yaml +++ b/ansible/roles/watch-party/defaults/main.yaml @@ -1,3 +1,7 @@ --- +# Part of role: watch-party +# Called by: ansible/playbooks/deploy-watch-party.yaml +# Description: Default variables for the watch-party role including repo URL and local directory. + watch_party_repo: https://gitea.home.arpa/nik/watch-party.git -watch_party_dir: /Users/nik/repo/watch-party \ No newline at end of file +watch_party_dir: /Users/nik/repo/watch-party diff --git a/ansible/roles/watch-party/tasks/main.yaml b/ansible/roles/watch-party/tasks/main.yaml index 20a6f73..b803246 100644 --- a/ansible/roles/watch-party/tasks/main.yaml +++ b/ansible/roles/watch-party/tasks/main.yaml @@ -1,4 +1,8 @@ --- +# Part of role: watch-party +# Called by: ansible/playbooks/deploy-watch-party.yaml +# Description: Pulls the latest watch-party code from Gitea and deploys it via Docker Compose. + - name: Pull latest watch-party from Gitea ansible.builtin.git: repo: "{{ watch_party_repo }}" @@ -24,4 +28,4 @@ project_src: "{{ watch_party_dir }}" state: present pull: always - become: false \ No newline at end of file + become: false diff --git a/config/dashy/conf.yml b/config/dashy/conf.yaml similarity index 97% rename from config/dashy/conf.yml rename to config/dashy/conf.yaml index fe26e7a..4ab8bfc 100644 --- a/config/dashy/conf.yml +++ b/config/dashy/conf.yaml @@ -1,3 +1,6 @@ +# Config for: Dashy dashboard +# Applied by: manifests/apply-dashy-config.sh (creates ConfigMap from this file) + pageInfo: title: Good morning, Nik description: How's your day going? @@ -33,7 +36,7 @@ appConfig: backdrop-filter: blur(12px); } - /* Item tiles feel less “boxed” */ + /* Item tiles feel less "boxed" */ .item { border-radius: 14px !important; } @@ -217,4 +220,4 @@ sections: itemSize: large cutToHeight: true rows: 1 - cols: 1 \ No newline at end of file + cols: 1 diff --git a/manifests/apply-dashy-config.sh b/manifests/apply-dashy-config.sh deleted file mode 100644 index c049966..0000000 --- a/manifests/apply-dashy-config.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/bash -# Usage: bash manifests/apply-dashy-config.sh -# Updates Dashy config from config/dashy/conf.yml -set -e - -kubectl create configmap dashy-config \ - --from-file=conf.yml=config/dashy/conf.yml \ - --namespace dashy \ - --dry-run=client -o yaml | kubectl apply -f - - -kubectl rollout restart deployment/dashy -n dashy -echo "Dashy config updated" \ No newline at end of file diff --git a/manifests/authentik-gitea-secret.sh b/manifests/authentik/authentik-gitea-secret.sh similarity index 58% rename from manifests/authentik-gitea-secret.sh rename to manifests/authentik/authentik-gitea-secret.sh index 81443a4..78b8714 100755 --- a/manifests/authentik-gitea-secret.sh +++ b/manifests/authentik/authentik-gitea-secret.sh @@ -1,6 +1,8 @@ -#!/bin/bash +#!/usr/bin/env bash +# Usage: bash manifests/authentik/authentik-gitea-secret.sh +# Description: Creates the Authentik OAuth secret for Gitea integration set -euo pipefail -source "$(dirname "$0")/../.env" +source "$(dirname "$0")/../../.env" kubectl create secret generic authentik-gitea-oauth \ --namespace gitea \ diff --git a/manifests/authentik-grafana-secret.sh b/manifests/authentik/authentik-grafana-secret.sh similarity index 59% rename from manifests/authentik-grafana-secret.sh rename to manifests/authentik/authentik-grafana-secret.sh index 116dcbd..8888375 100755 --- a/manifests/authentik-grafana-secret.sh +++ b/manifests/authentik/authentik-grafana-secret.sh @@ -1,6 +1,8 @@ -#!/bin/bash +#!/usr/bin/env bash +# Usage: bash manifests/authentik/authentik-grafana-secret.sh +# Description: Creates the Authentik OAuth secret for Grafana integration set -euo pipefail -source "$(dirname "$0")/../.env" +source "$(dirname "$0")/../../.env" kubectl create secret generic authentik-grafana-oauth \ --namespace monitoring \ diff --git a/manifests/authentik-ingress.yaml b/manifests/authentik/authentik-ingress.yaml similarity index 70% rename from manifests/authentik-ingress.yaml rename to manifests/authentik/authentik-ingress.yaml index 330a029..3a031b1 100644 --- a/manifests/authentik-ingress.yaml +++ b/manifests/authentik/authentik-ingress.yaml @@ -1,3 +1,6 @@ +# Apply: kubectl apply -f manifests/authentik/authentik-ingress.yaml +# Delete: kubectl delete -f manifests/authentik/authentik-ingress.yaml +# Description: TLS certificate and Traefik IngressRoute for Authentik at auth.home.arpa. apiVersion: cert-manager.io/v1 kind: Certificate metadata: diff --git a/manifests/authentik-middleware.yaml b/manifests/authentik/authentik-middleware.yaml similarity index 74% rename from manifests/authentik-middleware.yaml rename to manifests/authentik/authentik-middleware.yaml index 9653b71..d55d49e 100644 --- a/manifests/authentik-middleware.yaml +++ b/manifests/authentik/authentik-middleware.yaml @@ -1,3 +1,6 @@ +# Apply: kubectl apply -f manifests/authentik/authentik-middleware.yaml +# Delete: kubectl delete -f manifests/authentik/authentik-middleware.yaml +# Description: Traefik forwardAuth middleware for Authentik and LAN bypass IP allowlist. apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: @@ -28,4 +31,4 @@ metadata: spec: ipAllowList: sourceRange: - - 192.168.7.0/24 \ No newline at end of file + - 192.168.7.0/24 diff --git a/manifests/authentik-proxy-outpost.yaml b/manifests/authentik/authentik-proxy-outpost.yaml similarity index 81% rename from manifests/authentik-proxy-outpost.yaml rename to manifests/authentik/authentik-proxy-outpost.yaml index f131512..326f50a 100644 --- a/manifests/authentik-proxy-outpost.yaml +++ b/manifests/authentik/authentik-proxy-outpost.yaml @@ -1,3 +1,6 @@ +# Apply: kubectl apply -f manifests/authentik/authentik-proxy-outpost.yaml +# Delete: kubectl delete -f manifests/authentik/authentik-proxy-outpost.yaml +# Description: Authentik proxy outpost deployment and service for forward-auth integration. apiVersion: v1 kind: ServiceAccount metadata: @@ -50,4 +53,4 @@ spec: ports: - name: http port: 9000 - targetPort: 9000 \ No newline at end of file + targetPort: 9000 diff --git a/manifests/authentik-proxy-secret.sh b/manifests/authentik/authentik-proxy-secret.sh similarity index 51% rename from manifests/authentik-proxy-secret.sh rename to manifests/authentik/authentik-proxy-secret.sh index 2ffb057..49a90c0 100755 --- a/manifests/authentik-proxy-secret.sh +++ b/manifests/authentik/authentik-proxy-secret.sh @@ -1,6 +1,8 @@ -#!/bin/bash +#!/usr/bin/env bash +# Usage: bash manifests/authentik/authentik-proxy-secret.sh +# Description: Creates the Authentik proxy outpost API token secret set -euo pipefail -source "$(dirname "$0")/../.env" +source "$(dirname "$0")/../../.env" kubectl create secret generic authentik-proxy-token \ --namespace authentik \ diff --git a/manifests/authentik-public-ingress.yaml b/manifests/authentik/authentik-public-ingress.yaml similarity index 65% rename from manifests/authentik-public-ingress.yaml rename to manifests/authentik/authentik-public-ingress.yaml index cfc8c13..0c7d5bf 100644 --- a/manifests/authentik-public-ingress.yaml +++ b/manifests/authentik/authentik-public-ingress.yaml @@ -1,5 +1,6 @@ -# authentik public ingress -# Apply: kubectl apply -f manifests/authentik-public-ingress.yaml +# Apply: kubectl apply -f manifests/authentik/authentik-public-ingress.yaml +# Delete: kubectl delete -f manifests/authentik/authentik-public-ingress.yaml +# Description: Public TLS certificate and Traefik IngressRoute for Authentik at auth.nik4nao.com. apiVersion: cert-manager.io/v1 kind: Certificate metadata: @@ -28,4 +29,4 @@ spec: - name: authentik-server port: 80 tls: - secretName: authentik-public-tls \ No newline at end of file + secretName: authentik-public-tls diff --git a/manifests/authentik-secret.sh b/manifests/authentik/authentik-secret.sh similarity index 58% rename from manifests/authentik-secret.sh rename to manifests/authentik/authentik-secret.sh index f1e89b6..71ff4cf 100755 --- a/manifests/authentik-secret.sh +++ b/manifests/authentik/authentik-secret.sh @@ -1,5 +1,7 @@ -#!/bin/bash -# Run once to create the Authentik secret. Safe to re-run (dry-run + apply). +#!/usr/bin/env bash +# Usage: bash manifests/authentik/authentik-secret.sh +# Description: Creates the Authentik secret-key and PostgreSQL password (safe to re-run) +set -euo pipefail kubectl create secret generic authentik-secrets \ --namespace authentik \ --from-literal=secret-key="$(openssl rand -base64 50)" \ diff --git a/manifests/cert-manager/cluster-issuer-internal.yaml b/manifests/cert-manager/cluster-issuer-internal.yaml index c299d34..17a0711 100644 --- a/manifests/cert-manager/cluster-issuer-internal.yaml +++ b/manifests/cert-manager/cluster-issuer-internal.yaml @@ -1,5 +1,6 @@ -# Internal CA for *.home.arpa # Apply: kubectl apply -f manifests/cert-manager/cluster-issuer-internal.yaml +# Delete: kubectl delete -f manifests/cert-manager/cluster-issuer-internal.yaml +# Description: Internal CA ClusterIssuers and root certificate for *.home.arpa TLS. apiVersion: cert-manager.io/v1 kind: ClusterIssuer metadata: @@ -30,4 +31,4 @@ metadata: name: internal-ca-issuer spec: ca: - secretName: internal-ca-cert \ No newline at end of file + secretName: internal-ca-cert diff --git a/manifests/cert-manager/cluster-issuer-letsencrypt.yaml b/manifests/cert-manager/cluster-issuer-letsencrypt.yaml index fab889c..a488d31 100644 --- a/manifests/cert-manager/cluster-issuer-letsencrypt.yaml +++ b/manifests/cert-manager/cluster-issuer-letsencrypt.yaml @@ -1,5 +1,6 @@ -# Let's Encrypt HTTP-01 issuer for *.nik4nao.com # Apply: kubectl apply -f manifests/cert-manager/cluster-issuer-letsencrypt.yaml +# Delete: kubectl delete -f manifests/cert-manager/cluster-issuer-letsencrypt.yaml +# Description: Let's Encrypt production and staging ClusterIssuers with HTTP-01 via Traefik. apiVersion: cert-manager.io/v1 kind: ClusterIssuer metadata: @@ -28,4 +29,4 @@ spec: solvers: - http01: ingress: - ingressClassName: traefik \ No newline at end of file + ingressClassName: traefik diff --git a/manifests/cert-manager/porkbun-secret.sh b/manifests/cert-manager/porkbun-secret.sh index 6c802ba..be47e39 100755 --- a/manifests/cert-manager/porkbun-secret.sh +++ b/manifests/cert-manager/porkbun-secret.sh @@ -1,8 +1,7 @@ -#!/bin/bash +#!/usr/bin/env bash # Usage: bash manifests/cert-manager/porkbun-secret.sh -# Requires: .env file in repo root with PORKBUN_API_KEY and PORKBUN_SECRET_API_KEY - -set -e +# Description: Creates the Porkbun API credentials secret for cert-manager DNS01 challenges +set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" ENV_FILE="$SCRIPT_DIR/../../.env" diff --git a/manifests/core/apply-dashy-config.sh b/manifests/core/apply-dashy-config.sh new file mode 100644 index 0000000..383abec --- /dev/null +++ b/manifests/core/apply-dashy-config.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +# Usage: bash manifests/core/apply-dashy-config.sh +# Description: Updates the Dashy ConfigMap from config/dashy/conf.yaml and restarts the deployment +set -euo pipefail + +kubectl create configmap dashy-config \ + --from-file=conf.yml=config/dashy/conf.yaml \ + --namespace dashy \ + --dry-run=client -o yaml | kubectl apply -f - + +kubectl rollout restart deployment/dashy -n dashy +echo "Dashy config updated" \ No newline at end of file diff --git a/manifests/ca-installer/ca-installer.yaml b/manifests/core/ca-installer/ca-installer.yaml similarity index 83% rename from manifests/ca-installer/ca-installer.yaml rename to manifests/core/ca-installer/ca-installer.yaml index d35adf4..0baec78 100644 --- a/manifests/ca-installer/ca-installer.yaml +++ b/manifests/core/ca-installer/ca-installer.yaml @@ -1,16 +1,14 @@ -# ca-installer.yaml -# CA Trust Installer — serves CA cert + iOS mobileconfig at ca.home.arpa +# Apply: kubectl apply -f manifests/core/ca-installer/ca-installer.yaml +# Delete: kubectl delete -f manifests/core/ca-installer/ca-installer.yaml +# Description: Nginx-based CA certificate installer serving ca.crt and iOS mobileconfig at ca.home.arpa. # # Pre-requisites (run once, or after CA cert rotation): # kubectl create configmap ca-installer-web -n ca-installer \ -# --from-file=index.html=manifests/ca-installer/web/index.html +# --from-file=index.html=manifests/core/ca-installer/web/index.html # # kubectl create configmap ca-installer-files -n ca-installer \ # --from-file=ca.crt=/tmp/homelab-ca.crt \ # --from-file=ca.mobileconfig=/tmp/homelab-ca.mobileconfig -# -# Apply: kubectl apply -f manifests/ca-installer/ca-installer.yaml ---- apiVersion: v1 kind: Namespace metadata: @@ -28,13 +26,11 @@ data: server_name ca.home.arpa; root /usr/share/nginx/html; - # CA cert — must be application/x-x509-ca-cert for iOS to recognise it location = /ca.crt { default_type application/x-x509-ca-cert; try_files /ca.crt =404; } - # iOS mobileconfig — must be this exact MIME type location = /ca.mobileconfig { default_type application/x-apple-aspen-config; try_files /ca.mobileconfig =404; @@ -112,8 +108,6 @@ metadata: name: ca-installer namespace: ca-installer annotations: - # No TLS — this page is how you GET the CA, serving over HTTP avoids - # the chicken-and-egg problem. Once CA is trusted, *.home.arpa is fine. traefik.ingress.kubernetes.io/router.entrypoints: web,websecure spec: ingressClassName: traefik @@ -127,4 +121,4 @@ spec: service: name: ca-installer port: - number: 80 \ No newline at end of file + number: 80 diff --git a/manifests/ca-installer/web/index.html b/manifests/core/ca-installer/web/index.html similarity index 99% rename from manifests/ca-installer/web/index.html rename to manifests/core/ca-installer/web/index.html index 9d2d876..7cd5606 100644 --- a/manifests/ca-installer/web/index.html +++ b/manifests/core/ca-installer/web/index.html @@ -1,3 +1,5 @@ + + diff --git a/manifests/dashy.yaml b/manifests/core/dashy.yaml similarity index 89% rename from manifests/dashy.yaml rename to manifests/core/dashy.yaml index 3de154b..8ca5227 100644 --- a/manifests/dashy.yaml +++ b/manifests/core/dashy.yaml @@ -1,5 +1,6 @@ -# Dashy — homelab dashboard -# Apply: kubectl apply -f manifests/dashy.yaml +# Apply: kubectl apply -f manifests/core/dashy.yaml +# Delete: kubectl delete -f manifests/core/dashy.yaml +# Description: Dashy homelab dashboard with Ingress at dashy.home.arpa. apiVersion: v1 kind: Namespace metadata: @@ -12,7 +13,6 @@ metadata: namespace: dashy data: conf.yml: | - # contents will be replaced by kustomize or kubectl apply --- apiVersion: apps/v1 kind: Deployment @@ -89,4 +89,4 @@ spec: service: name: dashy port: - number: 80 \ No newline at end of file + number: 80 diff --git a/manifests/glances.yaml b/manifests/core/glances.yaml similarity index 89% rename from manifests/glances.yaml rename to manifests/core/glances.yaml index 7ec21fc..d1cb3f9 100644 --- a/manifests/glances.yaml +++ b/manifests/core/glances.yaml @@ -1,5 +1,6 @@ -# Glances — system monitoring -# Apply: kubectl apply -f manifests/glances.yaml +# Apply: kubectl apply -f manifests/core/glances.yaml +# Delete: kubectl delete -f manifests/core/glances.yaml +# Description: Glances system monitoring DaemonSet with Ingress at glances.home.arpa. apiVersion: v1 kind: Namespace metadata: @@ -91,4 +92,4 @@ spec: service: name: glances port: - number: 61208 \ No newline at end of file + number: 61208 diff --git a/manifests/gitea-backup.yaml b/manifests/gitea/gitea-backup.yaml similarity index 93% rename from manifests/gitea-backup.yaml rename to manifests/gitea/gitea-backup.yaml index 0ff455e..003711e 100644 --- a/manifests/gitea-backup.yaml +++ b/manifests/gitea/gitea-backup.yaml @@ -1,4 +1,6 @@ ---- +# Apply: kubectl apply -f manifests/gitea/gitea-backup.yaml +# Delete: kubectl delete -f manifests/gitea/gitea-backup.yaml +# Description: CronJob that backs up Gitea to NFS every 7 days, with RBAC and PV/PVC. apiVersion: v1 kind: ServiceAccount metadata: diff --git a/manifests/gitea-pv.yaml b/manifests/gitea/gitea-pv.yaml similarity index 67% rename from manifests/gitea-pv.yaml rename to manifests/gitea/gitea-pv.yaml index 4646567..fbc6499 100644 --- a/manifests/gitea-pv.yaml +++ b/manifests/gitea/gitea-pv.yaml @@ -1,3 +1,6 @@ +# Apply: kubectl apply -f manifests/gitea/gitea-pv.yaml +# Delete: kubectl delete -f manifests/gitea/gitea-pv.yaml +# Description: PersistentVolume for Gitea data on the minisforum node. apiVersion: v1 kind: PersistentVolume metadata: @@ -20,4 +23,4 @@ spec: - key: kubernetes.io/hostname operator: In values: - - minisforum \ No newline at end of file + - minisforum diff --git a/manifests/gitea-runner-secret.sh b/manifests/gitea/gitea-runner-secret.sh similarity index 52% rename from manifests/gitea-runner-secret.sh rename to manifests/gitea/gitea-runner-secret.sh index 6df7c8c..454950f 100644 --- a/manifests/gitea-runner-secret.sh +++ b/manifests/gitea/gitea-runner-secret.sh @@ -1,9 +1,9 @@ -#!/bin/bash -# Usage: bash manifests/gitea-runner-secret.sh -# Creates gitea-runner-secret from .env -set -e +#!/usr/bin/env bash +# Usage: bash manifests/gitea/gitea-runner-secret.sh +# Description: Creates the Gitea runner registration token secret +set -euo pipefail -source "$(dirname "$0")/../.env" +source "$(dirname "$0")/../../.env" kubectl create secret generic gitea-runner-secret \ --namespace gitea-runner \ diff --git a/manifests/gitea-runner.yaml b/manifests/gitea/gitea-runner.yaml similarity index 92% rename from manifests/gitea-runner.yaml rename to manifests/gitea/gitea-runner.yaml index f46365a..832aee6 100644 --- a/manifests/gitea-runner.yaml +++ b/manifests/gitea/gitea-runner.yaml @@ -1,5 +1,6 @@ -# Gitea Actions Runner -# Apply: kubectl apply -f manifests/gitea-runner.yaml +# Apply: kubectl apply -f manifests/gitea/gitea-runner.yaml +# Delete: kubectl delete -f manifests/gitea/gitea-runner.yaml +# Description: Gitea Actions runner deployment with host Docker socket and internal CA trust. apiVersion: v1 kind: Namespace metadata: diff --git a/manifests/jdownloader.yaml b/manifests/media/jdownloader.yaml similarity index 88% rename from manifests/jdownloader.yaml rename to manifests/media/jdownloader.yaml index b2c69dd..2752d94 100644 --- a/manifests/jdownloader.yaml +++ b/manifests/media/jdownloader.yaml @@ -1,5 +1,6 @@ -# JDownloader + jd-bridge -# Apply: kubectl apply -f manifests/jdownloader.yaml +# Apply: kubectl apply -f manifests/media/jdownloader.yaml +# Delete: kubectl delete -f manifests/media/jdownloader.yaml +# Description: JDownloader deployment with Ingress at jdownloader.home.arpa. apiVersion: apps/v1 kind: Deployment metadata: @@ -82,4 +83,4 @@ spec: service: name: jdownloader port: - number: 80 \ No newline at end of file + number: 80 diff --git a/manifests/jellyfin.yaml b/manifests/media/jellyfin.yaml similarity index 92% rename from manifests/jellyfin.yaml rename to manifests/media/jellyfin.yaml index b6d65ae..9fffef0 100644 --- a/manifests/jellyfin.yaml +++ b/manifests/media/jellyfin.yaml @@ -1,11 +1,11 @@ -# Jellyfin — media server -# Apply: kubectl apply -f manifests/jellyfin.yaml +# Apply: kubectl apply -f manifests/media/jellyfin.yaml +# Delete: kubectl delete -f manifests/media/jellyfin.yaml +# Description: Jellyfin media server with NFS media PV, local config PVC, and Ingress at jellyfin.home.arpa. apiVersion: v1 kind: Namespace metadata: name: jellyfin --- -# PV for media — NFS mount from Debian apiVersion: v1 kind: PersistentVolume metadata: @@ -28,7 +28,6 @@ spec: values: - minisforum --- -# PVC for media apiVersion: v1 kind: PersistentVolumeClaim metadata: @@ -45,7 +44,6 @@ spec: requests: storage: 10Ti --- -# PVC for Jellyfin config — local storage on Minisforum apiVersion: v1 kind: PersistentVolumeClaim metadata: @@ -154,4 +152,4 @@ spec: service: name: jellyfin port: - number: 80 \ No newline at end of file + number: 80 diff --git a/manifests/qbittorrent.yaml b/manifests/media/qbittorrent.yaml similarity index 90% rename from manifests/qbittorrent.yaml rename to manifests/media/qbittorrent.yaml index a05f240..f3d557d 100644 --- a/manifests/qbittorrent.yaml +++ b/manifests/media/qbittorrent.yaml @@ -1,5 +1,6 @@ -# qBittorrent -# Apply: kubectl apply -f manifests/qbittorrent.yaml +# Apply: kubectl apply -f manifests/media/qbittorrent.yaml +# Delete: kubectl delete -f manifests/media/qbittorrent.yaml +# Description: qBittorrent deployment with Ingress at qbittorrent.home.arpa. apiVersion: v1 kind: Namespace metadata: @@ -102,4 +103,4 @@ spec: service: name: qbittorrent port: - number: 80 \ No newline at end of file + number: 80 diff --git a/manifests/grafana-loki-datasource.yaml b/manifests/monitoring/grafana-loki-datasource.yaml similarity index 57% rename from manifests/grafana-loki-datasource.yaml rename to manifests/monitoring/grafana-loki-datasource.yaml index 376e050..89dcc4b 100644 --- a/manifests/grafana-loki-datasource.yaml +++ b/manifests/monitoring/grafana-loki-datasource.yaml @@ -1,5 +1,6 @@ -# Grafana Loki datasource configuration for Grafana in the monitoring namespace -# Apply: kubectl apply -f manifests/grafana-loki-datasource.yaml +# Apply: kubectl apply -f manifests/monitoring/grafana-loki-datasource.yaml +# Delete: kubectl delete -f manifests/monitoring/grafana-loki-datasource.yaml +# Description: ConfigMap that provisions Loki as a Grafana datasource in the monitoring namespace. apiVersion: v1 kind: ConfigMap metadata: @@ -17,4 +18,4 @@ data: url: http://loki-stack.monitoring.svc.cluster.local:3100 isDefault: false version: 1 - editable: true \ No newline at end of file + editable: true diff --git a/manifests/grafana-secret.sh b/manifests/monitoring/grafana-secret.sh similarity index 59% rename from manifests/grafana-secret.sh rename to manifests/monitoring/grafana-secret.sh index d8579ae..7fdad79 100755 --- a/manifests/grafana-secret.sh +++ b/manifests/monitoring/grafana-secret.sh @@ -1,6 +1,8 @@ -#!/bin/bash +#!/usr/bin/env bash +# Usage: bash manifests/monitoring/grafana-secret.sh +# Description: Creates the Grafana admin credentials secret set -euo pipefail -source "$(dirname "$0")/../.env" +source "$(dirname "$0")/../../.env" kubectl create secret generic grafana-admin-secret \ --namespace monitoring \ diff --git a/manifests/monitoring-pvs.yaml b/manifests/monitoring/monitoring-pvs.yaml similarity index 74% rename from manifests/monitoring-pvs.yaml rename to manifests/monitoring/monitoring-pvs.yaml index ddb0423..6275e3f 100644 --- a/manifests/monitoring-pvs.yaml +++ b/manifests/monitoring/monitoring-pvs.yaml @@ -1,3 +1,6 @@ +# Apply: kubectl apply -f manifests/monitoring/monitoring-pvs.yaml +# Delete: kubectl delete -f manifests/monitoring/monitoring-pvs.yaml +# Description: PersistentVolumes for Prometheus, Grafana, and Loki data directories. apiVersion: v1 kind: PersistentVolume metadata: @@ -38,4 +41,4 @@ spec: persistentVolumeReclaimPolicy: Retain storageClassName: "" hostPath: - path: /data/loki \ No newline at end of file + path: /data/loki diff --git a/manifests/ddns-cronjob.yaml b/manifests/network/ddns-cronjob.yaml similarity index 95% rename from manifests/ddns-cronjob.yaml rename to manifests/network/ddns-cronjob.yaml index 9283696..7cff9c9 100644 --- a/manifests/ddns-cronjob.yaml +++ b/manifests/network/ddns-cronjob.yaml @@ -1,6 +1,6 @@ -# DDNS CronJob — updates home.nik4nao.com on Porkbun every 5 minutes -# Requires: porkbun-ddns secret in ddns namespace -# Apply: kubectl apply -f manifests/ddns-cronjob.yaml +# Apply: kubectl apply -f manifests/network/ddns-cronjob.yaml +# Delete: kubectl delete -f manifests/network/ddns-cronjob.yaml +# Description: CronJob that updates home.nik4nao.com DNS on Porkbun every 5 minutes. apiVersion: v1 kind: Namespace metadata: @@ -93,7 +93,6 @@ spec: --arg fqdn "$RECORD_FQDN" \ '.records[] | select(.type=="A" and .name==$fqdn) | .id' | head -1)" - # Skip if already correct (single record, correct IP) if [ "$RECORD_COUNT" -le 1 ] && [ "$WAN_IP" = "$DNS_IP" ]; then echo "[$(timestamp)] No change, skipping." @@ -121,4 +120,4 @@ spec: echo "[$(timestamp)] Response: $(echo "$RESP" | jq -c .)" echo "$RESP" | grep -q '"status":"SUCCESS"' && \ echo "[$(timestamp)] Update successful" || \ - echo "[$(timestamp)] Update failed" \ No newline at end of file + echo "[$(timestamp)] Update failed" diff --git a/manifests/ddns-secret.sh b/manifests/network/ddns-secret.sh similarity index 68% rename from manifests/ddns-secret.sh rename to manifests/network/ddns-secret.sh index 1336b14..488a6f3 100644 --- a/manifests/ddns-secret.sh +++ b/manifests/network/ddns-secret.sh @@ -1,9 +1,10 @@ -#!/bin/bash -# Usage: bash manifests/ddns-secret.sh -set -e +#!/usr/bin/env bash +# Usage: bash manifests/network/ddns-secret.sh +# Description: Creates the Porkbun DDNS API credentials secret +set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -ENV_FILE="$SCRIPT_DIR/../.env" +ENV_FILE="$SCRIPT_DIR/../../.env" if [ ! -f "$ENV_FILE" ]; then echo "Error: .env file not found" diff --git a/manifests/glances-debian-ingress.yaml b/manifests/network/glances-debian-ingress.yaml similarity index 77% rename from manifests/glances-debian-ingress.yaml rename to manifests/network/glances-debian-ingress.yaml index 8db7a85..6326819 100644 --- a/manifests/glances-debian-ingress.yaml +++ b/manifests/network/glances-debian-ingress.yaml @@ -1,5 +1,6 @@ -# Glances — Debian node, proxied via Traefik -# Apply: kubectl apply -f manifests/glances-debian-ingress.yaml +# Apply: kubectl apply -f manifests/network/glances-debian-ingress.yaml +# Delete: kubectl delete -f manifests/network/glances-debian-ingress.yaml +# Description: External Endpoints, Service, and Ingress to proxy Glances on the Debian node via Traefik. apiVersion: v1 kind: Endpoints metadata: @@ -46,4 +47,4 @@ spec: service: name: glances-debian port: - number: 61208 \ No newline at end of file + number: 61208 diff --git a/manifests/pihole-debian-patch.sh b/manifests/network/pihole-debian-patch.sh similarity index 59% rename from manifests/pihole-debian-patch.sh rename to manifests/network/pihole-debian-patch.sh index 00524d6..a351edc 100755 --- a/manifests/pihole-debian-patch.sh +++ b/manifests/network/pihole-debian-patch.sh @@ -1,7 +1,7 @@ -#!/bin/bash -# Usage: bash manifests/pihole-debian-patch.sh -# Patches pihole-debian DNS services with externalIPs after helm upgrade -set -e +#!/usr/bin/env bash +# Usage: bash manifests/network/pihole-debian-patch.sh +# Description: Patches pihole-debian DNS services with externalIPs after helm upgrade +set -euo pipefail kubectl patch svc pihole-debian-dns-tcp -n pihole \ -p '{"spec":{"externalIPs":["192.168.7.183"]}}' diff --git a/manifests/traefik-dashboard-ingress.yaml b/manifests/network/traefik-dashboard-ingress.yaml similarity index 83% rename from manifests/traefik-dashboard-ingress.yaml rename to manifests/network/traefik-dashboard-ingress.yaml index 6985fe9..0c4f8a8 100644 --- a/manifests/traefik-dashboard-ingress.yaml +++ b/manifests/network/traefik-dashboard-ingress.yaml @@ -1,5 +1,6 @@ -# Traefik dashboard IngressRoute and TLS certificate for accessing the dashboard at https://traefik.home.arpa. The dashboard is protected by the authentik authentication middleware, with a bypass for LAN clients. -# Apply: kubectl apply -f manifests/traefik-dashboard-ingress.yaml +# Apply: kubectl apply -f manifests/network/traefik-dashboard-ingress.yaml +# Delete: kubectl delete -f manifests/network/traefik-dashboard-ingress.yaml +# Description: Traefik dashboard IngressRoute with Authentik auth, root redirect, and TLS certificate. apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: @@ -64,4 +65,4 @@ spec: name: internal-ca kind: ClusterIssuer dnsNames: - - traefik.home.arpa \ No newline at end of file + - traefik.home.arpa diff --git a/manifests/watch-party-ingress.yaml b/manifests/network/watch-party-ingress.yaml similarity index 77% rename from manifests/watch-party-ingress.yaml rename to manifests/network/watch-party-ingress.yaml index 0778b61..d3ed572 100644 --- a/manifests/watch-party-ingress.yaml +++ b/manifests/network/watch-party-ingress.yaml @@ -1,5 +1,6 @@ -# Watch Party — external service on Mac Mini -# Apply: kubectl apply -f manifests/watch-party-ingress.yaml +# Apply: kubectl apply -f manifests/network/watch-party-ingress.yaml +# Delete: kubectl delete -f manifests/network/watch-party-ingress.yaml +# Description: External Endpoints, Service, and Ingress for Watch Party on Mac Mini at watch-party.nik4nao.com. apiVersion: v1 kind: Endpoints metadata: @@ -46,4 +47,4 @@ spec: service: name: watch-party-mac-mini port: - number: 3000 \ No newline at end of file + number: 3000 diff --git a/values/authentik.yaml b/values/authentik.yaml index 3330531..6868f0b 100644 --- a/values/authentik.yaml +++ b/values/authentik.yaml @@ -1,10 +1,5 @@ -# authentik Helm values -# Deploy: -# helm upgrade --install authentik authentik/authentik \ -# --namespace authentik \ -# --version 2026.2.1 \ -# --values values/authentik.yaml \ -# --wait --timeout 5m +# Apply: helm upgrade --install authentik authentik/authentik -f values/authentik.yaml -n authentik --create-namespace +# Description: Helm values for Authentik SSO/identity provider authentik: secret_key: "" # kept blank — comes from existingSecret via env below diff --git a/values/cert-manager.yaml b/values/cert-manager.yaml index fdbfc39..4b353e0 100644 --- a/values/cert-manager.yaml +++ b/values/cert-manager.yaml @@ -1,10 +1,5 @@ -# cert-manager Helm values -# Deploy: -# helm repo add jetstack https://charts.jetstack.io -# helm repo update -# helm upgrade --install cert-manager jetstack/cert-manager \ -# --namespace cert-manager --create-namespace \ -# -f values/cert-manager.yaml +# Apply: helm upgrade --install cert-manager jetstack/cert-manager -f values/cert-manager.yaml -n cert-manager --create-namespace +# Description: Helm values for cert-manager TLS certificate automation crds: enabled: true diff --git a/values/gitea.yaml b/values/gitea.yaml index 161f94a..8b52e7a 100644 --- a/values/gitea.yaml +++ b/values/gitea.yaml @@ -1,8 +1,5 @@ -# Gitea Helm values -# Deploy: -# helm upgrade --install gitea gitea-charts/gitea \ -# --namespace gitea --create-namespace \ -# -f values/gitea.yaml +# Apply: helm upgrade --install gitea gitea-charts/gitea -f values/gitea.yaml -n gitea --create-namespace +# Description: Helm values for Gitea git server and Docker registry replicaCount: 1 diff --git a/values/kube-prometheus-stack.yaml b/values/kube-prometheus-stack.yaml index 7816ea8..79b8b1e 100644 --- a/values/kube-prometheus-stack.yaml +++ b/values/kube-prometheus-stack.yaml @@ -1,9 +1,5 @@ -# kube-prometheus-stack -# Chart: 82.10.2 / App: v0.89.0 -# -# helm upgrade --install kube-prometheus-stack prometheus-community/kube-prometheus-stack \ -# --namespace monitoring --create-namespace \ -# -f values/kube-prometheus-stack.yaml +# Apply: helm upgrade --install kube-prometheus-stack prometheus-community/kube-prometheus-stack -f values/kube-prometheus-stack.yaml -n monitoring --create-namespace +# Description: Helm values for Prometheus, Grafana, and Alertmanager monitoring stack grafana: admin: diff --git a/values/loki-stack.yaml b/values/loki-stack.yaml index 5e5ad6f..e1d3918 100644 --- a/values/loki-stack.yaml +++ b/values/loki-stack.yaml @@ -1,9 +1,5 @@ -# loki-stack (Loki + Promtail) -# Chart: 2.10.3 / App: v2.9.3 -# -# helm upgrade --install loki-stack grafana/loki-stack \ -# --namespace monitoring --create-namespace \ -# -f values/loki-stack.yaml +# Apply: helm upgrade --install loki-stack grafana/loki-stack -f values/loki-stack.yaml -n monitoring --create-namespace +# Description: Helm values for Loki log aggregation and Promtail log collector loki: persistence: diff --git a/values/pihole-debian.yaml b/values/pihole-debian.yaml index 92d69eb..c953c0c 100644 --- a/values/pihole-debian.yaml +++ b/values/pihole-debian.yaml @@ -1,10 +1,5 @@ -# Pihole — secondary instance on Debian node -# Pihole Helm values -# Chart: mojo2600/pihole -# Deploy: -# helm upgrade --install pihole-debian mojo2600/pihole \ -# --namespace pihole \ -# -f values/pihole-debian.yaml +# Apply: helm upgrade --install pihole-debian mojo2600/pihole -f values/pihole-debian.yaml -n pihole --create-namespace +# Description: Helm values for Pi-hole secondary instance on Debian node replicaCount: 1 diff --git a/values/pihole.yaml b/values/pihole.yaml index d4cd043..7dd3551 100644 --- a/values/pihole.yaml +++ b/values/pihole.yaml @@ -1,11 +1,5 @@ -# Pihole Helm values -# Chart: mojo2600/pihole -# Deploy: -# helm repo add mojo2600 https://mojo2600.github.io/pihole-kubernetes/ -# helm repo update -# helm upgrade --install pihole mojo2600/pihole \ -# --namespace pihole --create-namespace \ -# -f values/pihole.yaml +# Apply: helm upgrade --install pihole mojo2600/pihole -f values/pihole.yaml -n pihole --create-namespace +# Description: Helm values for Pi-hole DNS server on Minisforum replicaCount: 1 diff --git a/values/traefik.yaml b/values/traefik.yaml index 6afd3a5..f668484 100644 --- a/values/traefik.yaml +++ b/values/traefik.yaml @@ -1,13 +1,5 @@ -# Traefik Helm values — compatible with Traefik chart v34+ (Traefik v3) -# Traefik Helm values — Phase 1 -# Chart: traefik/traefik -# Deploy: -# helm repo add traefik https://helm.traefik.io/traefik -# helm repo update -# helm upgrade --install traefik traefik/traefik \ -# --namespace traefik --create-namespace \ -# -f values/traefik.yaml -# Minimal Traefik v3 / chart v39 compatible values +# Apply: helm upgrade --install traefik traefik/traefik -f values/traefik.yaml -n traefik --create-namespace +# Description: Helm values for Traefik v3 ingress controller with Let's Encrypt deployment: replicas: 1