commit 05184d778dee17a1b077c98e978006e45875f1c0 Author: Volker Schleiffer Date: Mon Jul 6 16:45:51 2026 +0200 Initial Lab Setup diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..835e736 --- /dev/null +++ b/.gitignore @@ -0,0 +1,23 @@ +# Ansible artifacts +*.retry +.ansible_cache/ + +# Sensitive data (even if currently stored outside the repo) +.ansible_vault_pass +.env +*.token + +# Script outputs +unifi_firewall_rules.json + +# Editor-specific files (Vim) +*.swp +*.swo +*~ + +# OS-specific files (macOS) +.DS_Store + +# Logs +*.log + diff --git a/add_new_user.yml b/add_new_user.yml new file mode 100644 index 0000000..acb36a9 --- /dev/null +++ b/add_new_user.yml @@ -0,0 +1,31 @@ +- name: Setup new administrative user + hosts: tatooine + become: yes # This tells Ansible to run as root + remote_user: root + vars: + new_user: "volker" + # Replace this with your actual public key string or a path to the file + ssh_public_key: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCqKm6tSG73CudRxZkUnR/hcwKQnvSfkQM/Gq1gR6wswu4kcthHZ+YCxzRFIJmTR1+C0UXy8yRVtwprz31plFbHvU3Om913MGaN1oadunYOkKD8OmAtCtht9H+5wC5HtjwuhNf/MH1K727ecNUSH10DYovzXkOD6byJukfkvbU6CVKxWAI6W9PXTLOPRyUoy3TX0GEBascayneqHBFfPGpICnR76X9Ydi2avfgmNiGtTMzKkn1mNqm3a4eHCfde8XUBtqlxdMnO/pMlgMh14XoBSD5T+U3OqIUvMOiU3ZKlcq4W46wtPX1Im6iqfgFutwT1YqQ8UNY06urO41nH6d5rVfSA1BS7Fonho2xK5lQ3aqapn2+o9goXTIQ1avoOHyWS0j+W8m5BEL8Prvr+eqjTCivh5g4rKVe2SebKzZU89oZSEkV9Mj69qhS1g3LnyJds+oskl04CdRXrn5KSyxXP9X4m0EYYfbzWMAPRZ6SsltAOw9w4hwZtwIKSl2+bMQAqQmRojDof4FgK+DCQfdcThhrmknGtGiL1v3tJuCmmiikoKis5qOVBmVJOhJaSOTKSIhx3oTVVfCgzlEnGE0M7gUk1+Qh30p4TahsbyfcWg5v3+0vdIVgAWIdW0Kp0s9R0mU4qKeIuZ9ejHCmaGcQe2ZolQZc5UrTwMBb1PaqPQQ== key von macbook fuer rogueone" + + tasks: + - name: Ensure the user exists + ansible.builtin.user: + name: "{{ new_user }}" + state: present + shell: /bin/bash + groups: sudo # Use 'wheel' if you are on RHEL/CentOS/Fedora + append: yes # Ensures you don't remove them from other groups + + - name: Set up authorized keys for the new user + ansible.builtin.authorized_key: + user: "{{ new_user }}" + state: present + key: "{{ ssh_public_key }}" + + - name: Allow the user to use sudo without a password (Optional) + ansible.builtin.lineinfile: + path: /etc/sudoers.d/{{ new_user }} + line: "{{ new_user }} ALL=(ALL) NOPASSWD:ALL" + state: present + mode: '0440' + create: yes diff --git a/ansible.cfg b/ansible.cfg new file mode 100644 index 0000000..11c4cfa --- /dev/null +++ b/ansible.cfg @@ -0,0 +1,13 @@ +[defaults] +inventory = inventory.ini +# Disable those annoying deprecation warnings +deprecation_warnings = False +# Make the output more readable (shows time taken for each task) +callbacks_enabled = profile_tasks +# Optional: Use the 'yaml' callback for much prettier error messages +# # Use the default plugin but tell it to format as YAML +stdout_callback = default +result_format = yaml +vault_password_file = ~/.ansible_vault_pass +host_key_checking = False +collections_path = ~/.ansible/collections:/opt/homebrew/Cellar/ansible/14.0.0/libexec/lib/python3.14/site-packages/ansible_collections diff --git a/bootstrap_node.sh b/bootstrap_node.sh new file mode 100755 index 0000000..1342de5 --- /dev/null +++ b/bootstrap_node.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +# Usage: ./bootstrap_node.sh +IP=$1 +NEW_HOSTNAME=$2 +R_USER=${3:-pi} # Defaults to 'pi' if not specified + +echo "🚀 Bootstrapping $NEW_HOSTNAME at $IP..." + +# 1. Push SSH Keys (Mac -> Node) +# This removes the need for passwords immediately +ssh-copy-id -i ~/.ssh/id_ed25519.pub "$R_USER@$IP" + +# 2. Set Hostname and Passwordless Sudo +# We use a single SSH command to minimize login prompts +ssh -t "$R_USER@$IP" << EOF + sudo hostnamectl set-hostname $NEW_HOSTNAME + echo "$R_USER ALL=(ALL) NOPASSWD:ALL" | sudo tee /etc/sudoers.d/010-$R_USER-nopasswd + sudo apt update && sudo apt install -y python3 +EOF + +echo "✅ $NEW_HOSTNAME is ready for Ansible!" + +# Append to inventory if not already there +if ! grep -q "$NEW_HOSTNAME" inventory.ini; then + echo "$NEW_HOSTNAME ansible_host=$IP" >> inventory.ini + echo "Added $NEW_HOSTNAME to inventory.ini" +fi diff --git a/bootstrap_sentinel.yml b/bootstrap_sentinel.yml new file mode 100644 index 0000000..9817a15 --- /dev/null +++ b/bootstrap_sentinel.yml @@ -0,0 +1,12 @@ +--- +- name: Sentinel mit der originalen Common-Rolle auf Stand bringen + hosts: sentinel + gather_facts: yes + become: yes + + # Hier sagen wir Ansible, als welcher User er sich JETZT noch einwählen muss + vars: + ansible_user: root + + roles: + - common diff --git a/fix_jelly.yml b/fix_jelly.yml new file mode 100644 index 0000000..ff4fb39 --- /dev/null +++ b/fix_jelly.yml @@ -0,0 +1,31 @@ +- name: Fix InfluxData GPG Key expiration (Trixie/sqv fix) + become: true + block: + - name: Download the latest InfluxData archive key + ansible.builtin.get_url: + url: https://repos.influxdata.com/influxdata-archive.key + dest: /tmp/influxdata-archive.key + mode: '0644' + + - name: Dearmor key for sqv compatibility + ansible.builtin.shell: | + cat /tmp/influxdata-archive.key | gpg --dearmor > /usr/share/keyrings/influxdata-archive.gpg + args: + creates: /usr/share/keyrings/influxdata-archive.gpg + + - name: Ensure correct repository configuration + ansible.builtin.copy: + dest: /etc/apt/sources.list.d/influxdata.list + content: "deb [signed-by=/usr/share/keyrings/influxdata-archive.gpg] https://repos.influxdata.com/debian stable main" + + - name: Remove conflicting legacy list files + ansible.builtin.file: + path: "/etc/apt/sources.list.d/{{ item }}" + state: absent + loop: + - repos_influxdata_com_debian.list + - influxdb.list + +- name: Run apt update + ansible.builtin.apt: + update_cache: yes diff --git a/get_firewall.sh b/get_firewall.sh new file mode 100755 index 0000000..df51eeb --- /dev/null +++ b/get_firewall.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +# --- KONFIGURATION --- +UNIFI_IP="192.168.123.254" +API_TOKEN="DEIN_KOPIERTER_API_TOKEN" +OUTPUT_FILE="~/lab-rack/unifi_firewall_rules.json" + +echo "📥 Lade Firewall-Konfiguration via API-Token herunter..." + +# Der offizielle Endpunkt für die Sicherheits- und Firewallkonfiguration +curl -s -S -k -X GET \ + -H "X-API-KEY: $API_TOKEN" \ + -H "Content-Type: application/json" \ + "https://$UNIFI_IP/proxy/network/api/v2/sites/default/firewall/rules" \ + | jq '.' > $(eval echo $OUTPUT_FILE) + +echo "✅ Fertig!" diff --git a/get_unifi_facts.yml b/get_unifi_facts.yml new file mode 100644 index 0000000..0c18b6d --- /dev/null +++ b/get_unifi_facts.yml @@ -0,0 +1,15 @@ +--- +- name: Minimaler Unifi Test + hosts: unifi + gather_facts: no + collections: + - community.general + + tasks: + - name: Unifi Controller-spezifische Facts auslesen + unifi_facts: + user: "ansible-v2-ro" + password: "DeinSicheresReadOnlyPasswort" + host: "127.0.0.1" + port: 8443 + validate_certs: no diff --git a/group_vars/all.yml b/group_vars/all.yml new file mode 100644 index 0000000..a3d66a6 --- /dev/null +++ b/group_vars/all.yml @@ -0,0 +1,58 @@ +domain_name: "intern.wks20.de" +ansible_python_interpreter: "/usr/bin/python3" +#root_password_hash: "$6$kJcofjjySrjly.o/$XaP/4a0wDUIHyuykJbzd4k/HbA39SEyhaVE6dKaX7pO1blXR.4A87i45uPHrQ.AxXEvRBzzlgF8rkwCCNKUTf." + +# Security Variables (Encrypted) +# Security Variables (Encrypted with your Vault Password) +root_password_hash: !vault | + $ANSIBLE_VAULT;1.1;AES256 + 61363637383337623138306333386331643636643730333932656537323931666365643861316264 + 3666356131333166663538326266316334313663666663610a346263643932396535383834343065 + 65306530376265316535323962656532323936666562323761306662383962646130373062343233 + 3437373235633966360a343064363464323835636465666538373231323837313164353536663064 + 33356631366662623835306562386637343363343931323833303832326637633663386633653561 + 30376163393431616635643830653061383663383466333132663062633765316463353139363465 + 36383137346266396365643633376139383137626465646236333332376632633639386433333338 + 37363439356236326164396534343737373065643231626238623237643332393761643230653935 + 36346431393530623734356364613933326335363766353539643632336662393066613935643432 + 3931383864393736306638363365353263376162396137316232 + + +common_packages: + # --- System Management & Logic --- + - sudo + - aptitude # Better dependency resolution than standard apt + - needrestart # Checks which services need a restart after updates + - python3 # Requirement for Ansible + - nala + + # --- Networking & Service Discovery --- + - avahi-daemon # Enables hostname.local discovery + - lldpd # Link Layer Discovery (find physical switch ports) + - netcat-traditional + - net-tools # Classic 'ifconfig', 'route', etc. + - ethtool # Query/Control network driver/hardware + - prometheus-node-exporter + # --- Diagnostics & Performance Monitoring --- + - htop # Interactive process viewer + - ncdu # Ncurses disk usage analyzer + - btm + + # --- Transfer & Download Tools --- + - curl + - wget + - git + - rsync + - unzip + + # --- Terminal Multiplexers & Editors --- + - screen # Terminal session persistence + - tmux # Modern multiplexer + - vim # (Already handled by your role, but good to have) + + # --- Storage & File Systems --- + - exfatprogs # Essential for mounting your Pi backup drives +# Pakete, die nur auf modernem OS laufen (Debian 13+) +modern_os_packages: + - fastfetch + - btm diff --git a/group_vars/all/vault.yml b/group_vars/all/vault.yml new file mode 100644 index 0000000..4104a99 --- /dev/null +++ b/group_vars/all/vault.yml @@ -0,0 +1,7 @@ +$ANSIBLE_VAULT;1.1;AES256 +63626431383962356137626330343265373631376364383063363134393563356536663136303532 +3961663537373834383235373861386262656166643366330a303166363231653262343865613331 +33363463356565633435346565386630623439633739366363343166323837326366656131316239 +3631353237353439660a326363316234386562343034336464643132623665363135373437613165 +36396138383262623761306431383933383762653538313636396430343534333336376235323064 +3964613232663431393133336466323330376165313435313863 diff --git a/group_vars/smb_servers.yml b/group_vars/smb_servers.yml new file mode 100644 index 0000000..cb83486 --- /dev/null +++ b/group_vars/smb_servers.yml @@ -0,0 +1,17 @@ +samba_shares: + + - name: "stuff" + path: "/mnt/data1" + force_user: "volker" + group: "volker" + mode: "0770" + read_only: "no" + browseable: "yes" + guest_ok: "no" + + - name: "tank" + path: "/mnt/data2" + mode: "0775" + read_only: "no" + browseable: "yes" + guest_ok: "yes" diff --git a/install_telegraf.yml b/install_telegraf.yml new file mode 100644 index 0000000..0407b51 --- /dev/null +++ b/install_telegraf.yml @@ -0,0 +1,24 @@ +--- +- name: Deploy Telegraf to Goldeneye + hosts: endor + become: yes + tasks: + - name: Install Telegraf package + ansible.builtin.apt: + name: telegraf + state: present + update_cache: yes + + - name: Push Telegraf configuration + ansible.builtin.template: + src: templates/telegraf.conf.j2 + dest: /etc/telegraf/telegraf.conf + owner: root + group: root + mode: '0644' + + - name: Ensure Telegraf is started and enabled + ansible.builtin.service: + name: telegraf + state: restarted + enabled: yes diff --git a/inventory.ini b/inventory.ini new file mode 100644 index 0000000..505b7bf --- /dev/null +++ b/inventory.ini @@ -0,0 +1,64 @@ +# --- Individual Hosts --- + +[management] +sentinel ansible_host=127.0.0.1 ansible_connection=local + +[physical_iron] +endor ansible_host=192.168.123.210 # Your Proxmox Host +#goldeneye ansible_host=192.168.123.215 # Your Raspberry Pi +tatooine ansible_host=192.168.123.211 # Your Proxmox Host 2 + +[lxc_containers] +jump ansible_host=192.168.123.104 +smb03 ansible_host=192.168.123.115 +docker01 ansible_host=192.168.123.100 +watch-lan ansible_host=192.168.123.103 +mqtt ansible_host=192.168.111.102 +paperless ansible_host=192.168.123.105 +adguard ansible_host=192.168.123.108 +#debian ansible_host=192.168.123.118 +syslog ansible_host=192.168.123.109 +minio ansible_host=192.168.123.110 +jellyfin ansible_host=192.168.123.114 +tk-smb02 ansible_host=192.168.123.99 +podman01 ansible_host=192.168.123.116 +monitor ansible_host=192.168.123.101 + +# Add other VMs here as you create them + +[yunohost_servers] +rohan ansible_host=192.168.112.42 +bumb ansible_host=192.168.112.46 + +[proxmox_vms] +rohan ansible_host=192.168.112.42 +proxy ansible_host=192.168.112.7 +bumb ansible_host=192.168.112.46 + +[reverse_proxies] +proxy + +# --- Logic Groups (Used by site.yml) --- +[monitoring_servers] +monitor +# This creates 'all_nodes' by nesting the physical and VM groups +[all_nodes:children] +physical_iron +proxmox_vms +yunohost_servers +lxc_containers + +# Group for the Fileserver role +[smb_servers] +smb03 + +# Group for Backup logic (if you want to expand beyond just Goldeneye) +[backup_servers] +#goldeneye +[unifi] +agw01 ansible_host=192.168.123.254 + +# --- Connection Variables --- +[all:vars] +ansible_user=volker +ansible_ssh_private_key_file=~/.ssh/id_ed25519 diff --git a/main-yml-back-common-old b/main-yml-back-common-old new file mode 100644 index 0000000..e016611 --- /dev/null +++ b/main-yml-back-common-old @@ -0,0 +1,169 @@ +--- +- name: Ensure Proxmox GPG key is present (for Raspberry Pi/PBS) + ansible.builtin.get_url: + url: https://enterprise.proxmox.com/debian/proxmox-release-trixie.gpg + dest: /etc/apt/trusted.gpg.d/proxmox-release-trixie.gpg + mode: '0644' + become: yes # Added + when: ansible_distribution == 'Debian' + tags: [setup] + +- name: Set hostname + ansible.builtin.hostname: + name: "{{ inventory_hostname }}" + become: yes # Added + tags: [identity] + +- name: Update /etc/hosts for FQDN resolution + ansible.builtin.lineinfile: + path: /etc/hosts + regexp: '^127\.0\.1\.1' + line: "127.0.1.1 {{ inventory_hostname }}.{{ domain_name }} {{ inventory_hostname }}" + become: yes # Added + tags: [identity] + +- name: Check for NetworkManager + ansible.builtin.command: systemctl is-active NetworkManager + register: nm_status + ignore_errors: yes + changed_when: false + tags: [identity, network] + +- name: Configure NetworkManager Search Domain (Raspberry Pi/mDNS Style) + when: nm_status.rc == 0 + tags: [identity, network] + block: + - name: Get active connection name + ansible.builtin.shell: "nmcli -t -f NAME connection show --active | head -n 1" + register: active_conn + changed_when: false + + - name: Apply search domain via nmcli + ansible.builtin.command: "nmcli connection modify '{{ active_conn.stdout }}' ipv4.dns-search '{{ domain_name }}'" + when: active_conn.stdout != "" + notify: Reload NetworkManager + +- name: Configure systemd-resolved Search Domain (Vanilla Debian Style) + ansible.builtin.ini_file: + path: /etc/systemd/resolved.conf + section: Resolve + option: Domains + value: "{{ domain_name }}" + become: yes # Added + notify: Restart systemd-resolved + when: nm_status.rc != 0 + tags: [identity, network] + +- name: Set system timezone + community.general.timezone: + name: Europe/Berlin + become: yes + tags: [localization] + +#- name: Ensure locales are generated +# ansible.builtin.locale_gen: +# name: en_US.UTF-8 +# state: present +# become: yes +# tags: [localization] + +#- name: Set system locale +# ansible.builtin.debconf: +# name: locales +# question: locales/default_environment_locale +# value: en_US.UTF-8 +# vtype: select +# become: yes +# tags: [localization] + +#- name: Force 24h clock format globally +# ansible.builtin.lineinfile: +# path: /etc/default/locale +# regexp: '^LC_TIME=' +# line: 'LC_TIME=en_DK.UTF-8' # en_DK is the standard trick for English lang + 24h clock +# become: yes +# tags: [localization] + +#- name: Set system-wide locale and 24h clock +# ansible.builtin.command: > +# update-locale LANG=en_US.UTF-8 LC_TIME=en_DK.UTF-8 +# become: yes +# changed_when: true + +#- name: Ensure en_US.UTF-8 is generated +# ansible.builtin.locale_gen: +# name: en_US.UTF-8 +# state: present +# become: yes +# tags: [localization] + +- name: Generate required locales + ansible.builtin.locale_gen: + name: "{{ item }}" + state: present + become: yes + loop: + - en_US.UTF-8 + - en_DK.UTF-8 # We must generate this to use it for the 24h clock + tags: [localization] + + +- name: Force system-wide locale and 24h clock + ansible.builtin.command: update-locale LANG=en_US.UTF-8 LC_TIME=en_DK.UTF-8 + become: yes + changed_when: true + tags: [localization] + +- name: Flush handlers to apply DNS changes immediately + ansible.builtin.meta: flush_handlers + +- name: Wait for DNS to be functional + ansible.builtin.command: getent hosts google.com + register: dns_check + until: dns_check.rc == 0 + retries: 3 + delay: 5 + changed_when: false + tags: [identity, network] + +- name: Install baseline packages (Unified list) + ansible.builtin.apt: + name: "{{ common_packages }}" + state: present + update_cache: yes + cache_valid_time: 3600 + become: yes + tags: [packages] + +- name: Install fastfetch (Optional - may not be in legacy repos) + ansible.builtin.apt: + name: + - fastfetch + - btm + state: present + become: yes + ignore_errors: yes + tags: [packages] + +- name: Configure needrestart for non-interactive automation + ansible.builtin.lineinfile: + path: /etc/needrestart/needrestart.conf + regexp: '^#?\$nrconf{restart}' + line: "$nrconf{restart} = 'a';" + become: yes + tags: [packages, config] + +- name: Ensure discovery services are enabled and running + ansible.builtin.service: + name: "{{ item }}" + state: started + enabled: yes + loop: + - avahi-daemon + - lldpd + become: yes + tags: [services] + +- name: Include maintenance tasks + ansible.builtin.include_tasks: maintenance.yml + tags: [maintenance] diff --git a/maintenance.yml b/maintenance.yml new file mode 100644 index 0000000..18b6fa9 --- /dev/null +++ b/maintenance.yml @@ -0,0 +1,51 @@ +--- + +- name: Managed Lab Maintenance + hosts: all_nodes + become: true + serial: 2 # Update 2 nodes at a time to reduce network/storage strain + + tasks: + - name: 1. Update all packages via Nala + ansible.builtin.apt: + update_cache: yes + upgrade: dist + autoremove: yes + register: apt_res + + - name: 2. Check if a reboot is required + ansible.builtin.stat: + path: /var/run/reboot-required + register: reboot_required_file + + - name: 3. Conditional Reboot (Skip Physical Hosts for now) + when: + - reboot_required_file.stat.exists + - inventory_hostname not in groups['physical_iron'] # Handle physical hosts in a separate play + ansible.builtin.reboot: + msg: "Rebooting {{ inventory_hostname }} after updates" + reboot_timeout: 600 + +- name: Final Tier - Proxmox Host Maintenance + hosts: physical_iron + become: true + serial: 1 # Reboot physical hosts sequentially to avoid complete cluster downtime + + tasks: + - name: Check if Host needs reboot + ansible.builtin.stat: + path: /var/run/reboot-required + register: host_reboot + + - name: Proxmox Host Reboot Block + when: host_reboot.stat.exists + block: + - name: Graceful shutdown of all VMs/LXCs + ansible.builtin.shell: pvesh create /nodes/localhost/stopall + failed_when: false + + - name: Reboot the Host + ansible.builtin.reboot: + msg: "Host maintenance reboot" + reboot_timeout: 900 + diff --git a/playbooks/deploy_monitoring_lxc.yml b/playbooks/deploy_monitoring_lxc.yml new file mode 100644 index 0000000..1e946bb --- /dev/null +++ b/playbooks/deploy_monitoring_lxc.yml @@ -0,0 +1,32 @@ +--- +- name: Infrastructure - Deploy Monitoring Container + hosts: lxc_hosts + become: true + + pre_tasks: + - name: Ensure Host has LXC Python bindings + apt: + name: python3-lxc + state: present + update_cache: yes + + tasks: + - name: Provision Debian 13 LXC + community.general.lxc_container: + name: monitoring-srv + template: debian + state: started + template_options: --release trixie + container_config: + - "lxc.net.0.type = veth" + - "lxc.net.0.link = lxcbr0" # Adjust to your bridge name + - "lxc.start.auto = 1" + + - name: Wait for Network + pause: + seconds: 10 + + - name: Prepare Container for Ansible + shell: | + lxc-attach -n monitoring-srv -- apt-get update + lxc-attach -n monitoring-srv -- apt-get install -y python3 openssh-server diff --git a/push_passwords.yml b/push_passwords.yml new file mode 100644 index 0000000..3bdbf16 --- /dev/null +++ b/push_passwords.yml @@ -0,0 +1,19 @@ +--- +- name: Synchronize Host Passwords + hosts: all + become: yes + tasks: + - name: Ensure root password is set from Vault + ansible.builtin.user: + name: root + # This takes the text from your vault and hashes it on your Mac + password: "{{ vault_root_password | password_hash('sha512') }}" + shell: /bin/bash + + - name: Ensure volker password is set from Vault + ansible.builtin.user: + name: volker + password: "{{ vault_root_password | password_hash('sha512') }}" + shell: /bin/bash + groups: sudo + append: yes diff --git a/reboot.yml b/reboot.yml new file mode 100644 index 0000000..d8f2fa0 --- /dev/null +++ b/reboot.yml @@ -0,0 +1,44 @@ +--- +- name: Managed Reboot of Lab Infrastructure + hosts: all_nodes + become: true + gather_facts: true + serial: 3 # Reboots one host at a time to maintain availability + + tasks: + - name: Check if reboot is actually required + ansible.builtin.stat: + path: /var/run/reboot-required + register: reboot_required_file + + - name: Reboot block + when: reboot_required_file.stat.exists + block: + - name: Handle Proxmox Guests (Endor specific) + when: inventory_hostname == 'endor' + shell: | + # Gracefully stop all running VMs/CTs that aren't set to autostart + # or simply rely on Proxmox's built-in shutdown service. + # This is a safety check. + pvesh create /nodes/localhost/stopall + register: stop_all_guests + failed_when: false + + - name: Reboot the machine + ansible.builtin.reboot: + msg: "Reboot initiated by Ansible for kernel updates" + connect_timeout: 5 + reboot_timeout: 600 + pre_reboot_delay: 10 + post_reboot_delay: 30 + test_command: uptime + + - name: Confirm uptime + ansible.builtin.debug: + msg: "Host {{ inventory_hostname }} is back up and running." + + - name: No reboot needed + ansible.builtin.debug: + msg: "Host {{ inventory_hostname }} does not require a reboot." + when: not reboot_required_file.stat.exists + diff --git a/rescue_password.yml b/rescue_password.yml new file mode 100644 index 0000000..ce0f544 --- /dev/null +++ b/rescue_password.yml @@ -0,0 +1,16 @@ +--- +- name: Emergency Password Reset + hosts: all + become: yes + tasks: + - name: Force reset root password to something known + ansible.builtin.user: + name: root + # Replace 'TemporaryPassword123' with your desired plain text password + password: "{{ 'xxx' | password_hash('sha512', 'mycustomsalt') }}" + shell: /bin/bash + + - name: Force reset your main user password + ansible.builtin.user: + name: volker + password: "{{ 'xxx' | password_hash('sha512', 'mycustomsalt') }}" diff --git a/roles/backup_server/handlers/main.yml b/roles/backup_server/handlers/main.yml new file mode 100644 index 0000000..6013d78 --- /dev/null +++ b/roles/backup_server/handlers/main.yml @@ -0,0 +1,3 @@ +- name: Update Initramfs + ansible.builtin.command: update-initramfs -u + become: yes diff --git a/roles/backup_server/tasks/main.yml b/roles/backup_server/tasks/main.yml new file mode 100644 index 0000000..1d85729 --- /dev/null +++ b/roles/backup_server/tasks/main.yml @@ -0,0 +1,102 @@ +--- +- name: Install matching kernel headers and ZFS tools + apt: + name: + - "linux-headers-{{ ansible_kernel }}" + - zfs-dkms + - zfsutils-linux + state: present + update_cache: yes + become: yes + +- name: Check if ZFS pool already exists + command: zpool list pbs_pool + register: zpool_check + failed_when: false + changed_when: false + +#- name: Create ZFS RAID10 Pool +# shell: | +# zpool create -f pbs_pool \ +# mirror \ +# ata-TOSHIBA_MG08ACA14TE_61K0A1N5FVJG \ +# ata-TOSHIBA_MG08ACA14TE_61K0A1TKFVJG \ +# mirror \ +# ata-TOSHIBA_MG08ACA14TE_71X0A01QFVJG \ +# ata-TOSHIBA_MG08ACA14TE_71X0A02VFVJG +# args: +# chdir: /dev/disk/by-id +# become: yes +# when: zpool_check.rc != 0 + +#- name: Set ZFS properties for the pool +# zfs: +# name: pbs_pool +# state: present +# extra_zfs_properties: +# compression: lz4 +# atime: off +# xattr: sa +# become: yes +# +#- name: Create dedicated PBS dataset +# zfs: +# name: pbs_pool/datastore1 +# state: present +# become: yes + +#- name: Limit ZFS ARC cache to 2GB +# copy: +# dest: /etc/modprobe.d/zfs.conf +# content: "options zfs zfs_arc_max=2147483648" +# become: yes +# notify: Update Initramfs + + +#### PBS [ProxMoxBackupServer] Starts here + +#### PBS [ProxMoxBackupServer] Starts here + +#### PBS [ProxMoxBackupServer] Starts here +# + +#### PBS [ProxMoxBackupServer] Starts here +#### PBS [ProxMoxBackupServer] for Trixie ARM64 + +- name: Create keyring directory + file: + path: /etc/apt/keyrings + state: directory + mode: '0755' + become: yes + +- name: Add PiPBS GPG key (Trixie compatible) + get_url: + url: https://dexogen.github.io/pipbs/gpg.key + dest: /etc/apt/keyrings/pipbs.asc + mode: '0644' + become: yes + +- name: Add PiPBS Trixie Repository + copy: + dest: /etc/apt/sources.list.d/pipbs.list + content: "deb [arch=arm64 signed-by=/etc/apt/keyrings/pipbs.asc] https://dexogen.github.io/pipbs/ trixie main" + become: yes + +- name: Install Proxmox Backup Server and ZFS tools + apt: + name: + - zfs-initramfs + - proxmox-backup-server + state: present + update_cache: yes + become: yes + +- name: Ensure PBS has ownership of the datastore + file: + path: /pbs_pool/datastore1 + owner: backup + group: backup + mode: '0770' + state: directory + become: yes diff --git a/roles/common/files/00aptproxy b/roles/common/files/00aptproxy new file mode 100644 index 0000000..c51b2a2 --- /dev/null +++ b/roles/common/files/00aptproxy @@ -0,0 +1 @@ +Acquire::http::Proxy-Auto-Detect "/usr/local/bin/apt-proxy-detect.sh"; diff --git a/roles/common/files/fix_fucked_keys.sh b/roles/common/files/fix_fucked_keys.sh new file mode 100644 index 0000000..9ac870c --- /dev/null +++ b/roles/common/files/fix_fucked_keys.sh @@ -0,0 +1,11 @@ +#!/bin/bash +sudo rm -vrf /var/cache/apt/archives/* +sudo rm /etc/apt/apt.conf.d/00aptproxy +#pt-get update -o Acquire::http::No-Cache=True +sudo apt-get update -o Acquire::http::No-Cache=True +sudo apt-get clean +apt-key adv --refresh-keys --keyserver keyserver.ubuntu.com +gpg --keyserver keyserver.ubuntu.com --recv-keys 0E98404D386FA1D9 +gpg --export --armor 0E98404D386FA1D9 | sudo apt-key add - +sudo apt update +#used this to be distributed via Ansible to remove the Apt cacher and unfuck ssome fucked up apt keys diff --git a/roles/common/files/sudoer_volker b/roles/common/files/sudoer_volker new file mode 100644 index 0000000..fba25c8 --- /dev/null +++ b/roles/common/files/sudoer_volker @@ -0,0 +1 @@ +volker ALL=(ALL) NOPASSWD: ALL diff --git a/roles/common/handlers/main.yml b/roles/common/handlers/main.yml new file mode 100644 index 0000000..c547e6a --- /dev/null +++ b/roles/common/handlers/main.yml @@ -0,0 +1,11 @@ +- name: Restart systemd-resolved + ansible.builtin.service: # Changed from 'systemd' to 'service' for compatibility + name: systemd-resolved + state: restarted + ignore_errors: yes # <--- Add this line + + +- name: Reload NetworkManager + systemd: + name: NetworkManager + state: reloaded diff --git a/roles/common/tasks/main.yml b/roles/common/tasks/main.yml new file mode 100644 index 0000000..ed6b3be --- /dev/null +++ b/roles/common/tasks/main.yml @@ -0,0 +1,300 @@ +--- +- name: Ensure global variables are loaded explicitly + ansible.builtin.include_vars: + file: "{{ playbook_dir }}/group_vars/all.yml" + tags: [always] + +- name: Ensure Proxmox GPG key is present (for Raspberry Pi/PBS) + ansible.builtin.get_url: + url: https://enterprise.proxmox.com/debian/proxmox-release-trixie.gpg + dest: /etc/apt/trusted.gpg.d/proxmox-release-trixie.gpg + mode: '0644' + become: yes + when: ansible_distribution == 'Debian' + tags: [setup] + +- name: Set hostname + ansible.builtin.hostname: + name: "{{ inventory_hostname }}" + become: yes + tags: [identity] + +- name: Update /etc/hosts for FQDN resolution + ansible.builtin.lineinfile: + path: /etc/hosts + regexp: '^127\.0\.1\.1' + line: "127.0.1.1 {{ inventory_hostname }}.{{ domain_name }} {{ inventory_hostname }}" + become: yes + tags: [identity] + +- name: Check for NetworkManager + ansible.builtin.command: systemctl is-active NetworkManager + register: nm_status + failed_when: false + changed_when: false + tags: [identity, network] + +- name: Configure NetworkManager Search Domain (Raspberry Pi/mDNS Style) + when: + - nm_status.rc == 0 + - ansible_virtualization_type != 'lxc' + tags: [identity, network] + block: + - name: Get active connection name + ansible.builtin.shell: "nmcli -t -f NAME connection show --active | head -n 1" + register: active_conn + changed_when: false + - name: Apply search domain via nmcli + ansible.builtin.command: "nmcli connection modify '{{ active_conn.stdout }}' ipv4.dns-search '{{ domain_name }}'" + when: active_conn.stdout != "" + notify: Reload NetworkManager + +- name: Configure systemd-resolved Search Domain (Vanilla Debian Style) + ansible.builtin.ini_file: + path: /etc/systemd/resolved.conf + section: Resolve + option: Domains + value: "{{ domain_name }}" + become: yes + notify: Restart systemd-resolved + when: + - nm_status.rc != 0 + - ansible_virtualization_type != 'lxc' + tags: [identity, network] + +- name: Ensure the terminal is always functional + ansible.builtin.lineinfile: + path: /etc/profile + line: 'export TERM=xterm-256color' + state: present + become: yes + +- name: Set system timezone + community.general.timezone: + name: Europe/Berlin + become: yes + tags: [localization] + +- name: Generate required locales + ansible.builtin.locale_gen: + name: "{{ item }}" + state: present + become: yes + loop: + - en_US.UTF-8 + - en_DK.UTF-8 + tags: [localization] + +- name: Force system-wide locale and 24h clock + ansible.builtin.command: update-locale LANG=en_US.UTF-8 LC_TIME=en_DK.UTF-8 + become: yes + changed_when: true + tags: [localization] + +- name: Flush handlers to apply DNS changes immediately + ansible.builtin.meta: flush_handlers + +- name: Wait for DNS to be functional + ansible.builtin.command: getent hosts google.com + register: dns_check + until: dns_check.rc == 0 + retries: 3 + delay: 5 + changed_when: false + when: ansible_virtualization_type != 'lxc' + tags: [identity, network] + +# --- REINE PACKET-TASKS OHNE SECURITY --- + +- name: Install baseline packages (Unified list from group_vars) + ansible.builtin.apt: + name: "{{ item }}" + state: present + update_cache: yes + cache_valid_time: 3600 + loop: "{{ common_packages }}" + when: not (item == 'sudo' and 'yunohost_servers' in group_names) + become: yes + ignore_errors: yes + tags: [packages, common] + +- name: Install modern packages like fastfetch (Debian 13+ only) + ansible.builtin.apt: + name: "{{ modern_os_packages | default(['fastfetch']) }}" + state: present + become: yes + when: + - ansible_os_family == "Debian" + - ansible_distribution_major_version | int >= 13 + ignore_errors: yes + tags: [packages, common] + +- name: Install QEMU Guest Agent (VMs only - NOT on LXC or Physical Iron) + ansible.builtin.apt: + name: qemu-guest-agent + state: present + become: yes + when: + - "'proxmox_vms' in group_names" + - "'lxc_containers' not in group_names" + - "'physical_iron' not in group_names" + tags: [packages, proxmox] + +# --- SYSTEM-EINSTELLUNGEN & DIENSTE --- + +- name: Configure needrestart for non-interactive automation + ansible.builtin.lineinfile: + path: /etc/needrestart/needrestart.conf + regexp: '^#?\$nrconf{restart}' + line: "$nrconf{restart} = 'a';" + become: yes + tags: [packages, config] + +- name: Ensure discovery services are enabled and running + ansible.builtin.service: + name: "{{ item }}" + state: started + enabled: yes + loop: + - avahi-daemon + - lldpd + become: yes + tags: [services] + +- name: Include maintenance tasks + ansible.builtin.include_tasks: maintenance.yml + tags: [maintenance] + +- name: Ensure console getty is running (for Proxmox WebUI access) + ansible.builtin.systemd: + name: getty@tty1.service + state: started + enabled: yes + become: yes + tags: [services, setup] + +- name: Ensure Node Exporter is running for monitoring + ansible.builtin.systemd: + name: prometheus-node-exporter + state: started + enabled: yes + become: yes + tags: [monitoring, services] + +- name: Fix Vim mouse behavior for easy copy-paste + ansible.builtin.copy: + dest: /etc/vim/vimrc.local + content: | + set mouse= + syntax on + set number + owner: root + group: root + mode: '0644' + become: yes + +# --- GHOSTTY TERMINFO SHIZZLE --- + +- name: Create Ghostty terminfo source file on remote + ansible.builtin.copy: + content: | + {% raw %} + xterm-ghostty|ghostty|Ghostty, + am, bce, ccc, hs, km, mc5i, mir, msgr, npc, xenl, AX, Su, Tc, XT, fullkbd, + colors#256, cols#80, it#8, lines#24, pairs#32767, + acsc=++\,\,--..00``aaffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~, + bel=^G, blink=\E[5m, bold=\E[1m, cbt=\E[Z, civis=\E[?25l, + clear=\E[H\E[2J, cnorm=\E[?12l\E[?25h, cr=^M, + csr=\E[%i%p1%d;%p2%dr, cub=\E[%p1%dD, cub1=^H, + cud=\E[%p1%dB, cud1=^J, cuf=\E[%p1%dC, cuf1=\E[C, + cup=\E[%i%p1%d;%p2%dH, cuu=\E[%p1%dA, cuu1=\E[A, + cvvis=\E[?12;25h, dch=\E[%p1%dP, dch1=\E[P, dim=\E[2m, + dl=\E[%p1%dM, dl1=\E[M, dsl=\E]2;\007, ech=\E[%p1%dX, + ed=\E[J, el=\E[K, el1=\E[1K, flash=\E[?5h$<100/>\E[?5l, + fsl=^G, home=\E[H, hpa=\E[%i%p1%dG, ht=^I, hts=\EH, + ich=\E[%p1%d@, ich1=\E[@, il=\E[%p1%dL, il1=\E[L, ind=^J, + indn=\E[%p1%dS, + initc=\E]4;%p1%d;rgb\:%p2%{255}%*%{1000}%/%2.2X/%p3%{255}%*%{1000}%/%2.2X/%p4%{255}%*%{1000}%/%2.2X\E\\, + invis=\E[8m, kDC=\E[3;2~, kEND=\E[1;2F, kHOM=\E[1;2H, + kIC=\E[2;2~, kLFT=\E[1;2D, kNXT=\E[6;2~, kPRV=\E[5;2~, + kRIT=\E[1;2C, kbs=\177, kcbt=\E[Z, kcub1=\EOD, kcud1=\EOB, + kcuf1=\EOC, kcuu1=\EOA, kdch1=\E[3~, kend=\EOF, kent=\EOM, + kf1=\EOP, kf10=\E[21~, kf11=\E[23~, kf12=\E[24~, + kf13=\E[1;2P, kf14=\E[1;2Q, kf15=\E[1;2R, kf16=\E[1;2S, + kf17=\E[15;2~, kf18=\E[17;2~, kf19=\E[18;2~, kf2=\EOQ, + kf20=\E[19;2~, kf21=\E[20;2~, kf22=\E[21;2~, + kf23=\E[23;2~, kf24=\E[24;2~, kf25=\E[1;5P, kf26=\E[1;5Q, + kf27=\E[1;5R, kf28=\E[1;5S, kf29=\E[15;5~, kf3=\EOR, + kf30=\E[17;5~, kf31=\E[18;5~, kf32=\E[19;5~, + kf33=\E[20;5~, kf34=\E[21;5~, kf35=\E[23;5~, + kf36=\E[24;5~, kf37=\E[1;6P, kf38=\E[1;6Q, kf39=\E[1;6R, + kf4=\EOS, kf40=\E[1;6S, kf41=\E[15;6~, kf42=\E[17;6~, + kf43=\E[18;6~, kf44=\E[19;6~, kf45=\E[20;6~, + kf46=\E[21;6~, kf47=\E[23;6~, kf48=\E[24;6~, + kf49=\E[1;3P, kf5=\E[15~, kf50=\E[1;3Q, kf51=\E[1;3R, + kf52=\E[1;3S, kf53=\E[15;3~, kf54=\E[17;3~, + kf55=\E[18;3~, kf56=\E[19;3~, kf57=\E[20;3~, + kf58=\E[21;3~, kf59=\E[23;3~, kf6=\E[17~, kf60=\E[24;3~, + kf61=\E[1;4P, kf62=\E[1;4Q, kf63=\E[1;4R, kf7=\E[18~, + kf8=\E[19~, kf9=\E[20~, khome=\EOH, kich1=\E[2~, + kind=\E[1;2B, kmous=\E[<, knp=\E[6~, kpp=\E[5~, + kri=\E[1;2A, oc=\E]104\007, op=\E[39;49m, rc=\E8, + rep=%p1%c\E[%p2%{1}%-%db, rev=\E[7m, ri=\EM, + rin=\E[%p1%dT, ritm=\E[23m, rmacs=\E(B, rmam=\E[?7l, + rmcup=\E[?1049l, rmir=\E[4l, rmkx=\E[?1l\E>, rmso=\E[27m, + rmul=\E[24m, rs1=\E]\E\\\Ec, sc=\E7, + setab=\E[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e48;5;%p1%d%;m, + setaf=\E[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m, + sgr=%?%p9%t\E(0%e\E(B%;\E[0%?%p6%t;1%;%?%p5%t;2%;%?%p2%t;4%;%?%p1%p3%|%t;7%;%?%p4%t;5%;%?%p7%t;8%;m, + sgr0=\E(B\E[m, sitm=\E[3m, smacs=\E(0, smam=\E[?7h, + smcup=\E[?1049h, smir=\E[4h, smkx=\E[?1h\E=, smso=\E[7m, + smul=\E[4m, tbc=\E[3g, tsl=\E]2;, u6=\E[%i%d;%dR, u7=\E[6n, + u8=\E[?%[;0123456789]c, u9=\E[c, vpa=\E[%i%p1%dd, + BD=\E[?2004l, BE=\E[?2004h, Clmg=\E[s, + Cmg=\E[%i%p1%d;%p2%ds, Dsmg=\E[?69l, E3=\E[3J, + Enmg=\E[?69h, Ms=\E]52;%p1%s;%p2%s\007, PE=\E[201~, + PS=\E[200~, RV=\E[>c, Se=\E[2 q, + Setulc=\E[58\:2\:\:%p1%{65536}%/%d\:%p1%{256}%/%{255}%&%d\:%p1%{255}%&%d%;m, + Smulx=\E[4\:%p1%dm, Ss=\E[%p1%d q, + Sync=\E[?2026%?%p1%{1}%-%tl%eh%;, + XM=\E[?1006;1000%?%p1%{1}%=%th%el%;, XR=\E[>0q, + fd=\E[?1004l, fe=\E[?1004h, kDC3=\E[3;3~, kDC4=\E[3;4~, + kDC5=\E[3;5~, kDC6=\E[3;6~, kDC7=\E[3;7~, kDN=\E[1;2B, + kDN3=\E[1;3B, kDN4=\E[1;4B, kDN5=\E[1;5B, kDN6=\E[1;6B, + kDN7=\E[1;7B, kEND3=\E[1;3F, kEND4=\E[1;4F, + kEND5=\E[1;5F, kEND6=\E[1;6F, kEND7=\E[1;7F, + kHOM3=\E[1;3H, kHOM4=\E[1;4H, kHOM5=\E[1;5H, + kHOM6=\E[1;6H, kHOM7=\E[1;7H, kIC3=\E[2;3~, kIC4=\E[2;4~, + kIC5=\E[2;5~, kIC6=\E[2;6~, kIC7=\E[2;7~, kLFT3=\E[1;3D, + kLFT4=\E[1;4D, kLFT5=\E[1;5D, kLFT6=\E[1;6D, + kLFT7=\E[1;7D, kNXT3=\E[6;3~, kNXT4=\E[6;4~, + kNXT5=\E[6;5~, kNXT6=\E[6;6~, kNXT7=\E[6;7~, + kPRV3=\E[5;3~, kPRV4=\E[5;4~, kPRV5=\E[5;5~, + kPRV6=\E[5;6~, kPRV7=\E[5;7~, kRIT3=\E[1;3C, + kRIT4=\E[1;4C, kRIT5=\E[1;5C, kRIT6=\E[1;6C, + kRIT7=\E[1;7C, kUP=\E[1;2A, kUP3=\E[1;3A, kUP4=\E[1;4A, + kUP5=\E[1;5A, kUP6=\E[1;6A, kUP7=\E[1;7A, kxIN=\E[I, + kxOUT=\E[O, rmxx=\E[29m, rv=\E\\[[0-9]+;[0-9]+;[0-9]+c, + setrgbb=\E[48\:2\:%p1%d\:%p2%d\:%p3%dm, + setrgbf=\E[38\:2\:%p1%d\:%p2%d\:%p3%dm, smxx=\E[9m, + xm=\E[<%i%p3%d;%p1%d;%p2%d;%?%p4%tM%em%;, + xr=\EP>\\|[ -~]+a\E\\, + {% endraw %} + dest: /tmp/xterm-ghostty + mode: '0644' + ignore_errors: yes + tags: [common, terminal] + +- name: Optimize terminfo for Ghostty terminal + ansible.builtin.command: tic -x /tmp/xterm-ghostty + become: yes + changed_when: false + ignore_errors: yes + tags: [common, terminal] + +- name: Clean up temporary Ghostty terminfo file + ansible.builtin.file: + path: /tmp/xterm-ghostty + state: absent + ignore_errors: yes + tags: [common, terminal] diff --git a/roles/common/tasks/main.yml-back1 b/roles/common/tasks/main.yml-back1 new file mode 100644 index 0000000..28cdb9b --- /dev/null +++ b/roles/common/tasks/main.yml-back1 @@ -0,0 +1,78 @@ +- name: Install base packages + package: + name: [vim, git, curl, avahi-daemon] + state: present + +- name: Set hostname + hostname: + name: "{{ inventory_hostname }}" + +- name: Update /etc/hosts for FQDN resolution + lineinfile: + path: /etc/hosts + regexp: '^127\.0\.1\.1' + line: "127.0.1.1 {{ inventory_hostname }}.{{ domain_name }} {{ inventory_hostname }}" + +- name: Check for NetworkManager + command: systemctl is-active NetworkManager + register: nm_status + ignore_errors: yes + changed_when: false + +- name: Configure NetworkManager Search Domain (Raspberry Pi Style) + block: + - name: Get active connection name + shell: "nmcli -t -f NAME connection show --active | head -n 1" + register: active_conn + changed_when: false + + - name: Apply search domain via nmcli + command: "nmcli connection modify '{{ active_conn.stdout }}' ipv4.dns-search '{{ domain_name }}'" + when: active_conn.stdout != "" + notify: Reload NetworkManager + when: nm_status.rc == 0 + +- name: Configure systemd-resolved Search Domain (Vanilla Debian Style) + ini_file: + path: /etc/systemd/resolved.conf + section: Resolve + option: Domains + value: "{{ domain_name }}" + notify: Restart systemd-resolved + when: nm_status.rc != 0 +- name: Flush handlers to apply DNS changes immediately + meta: flush_handlers + +- name: Wait for DNS to be functional + command: getent hosts google.com + register: dns_check + until: dns_check.rc == 0 + retries: 3 + delay: 5 + +- name: Install merged baseline packages + apt: + name: "{{ common_packages }}" + state: present + update_cache: yes + cache_valid_time: 3600 + become: yes + +- name: Configure needrestart for non-interactive automation + lineinfile: + path: /etc/needrestart/needrestart.conf + regexp: '^#?\$nrconf{restart}' + line: "$nrconf{restart} = 'a';" + become: yes + +- name: Ensure discovery services are enabled and running + service: + name: "{{ item }}" + state: started + enabled: yes + loop: + - avahi-daemon + - lldpd + become: yes +- name: Include maintenance tasks + include_tasks: maintenance.yml diff --git a/roles/common/tasks/main.yml-back2 b/roles/common/tasks/main.yml-back2 new file mode 100644 index 0000000..32eb461 --- /dev/null +++ b/roles/common/tasks/main.yml-back2 @@ -0,0 +1,200 @@ +--- + +# FIX: InfluxData GPG Key Rotation (Required for Debian Trixie/sqv) +- name: InfluxData GPG Key Repair + become: true + tags: [maintenance, setup] + block: + - name: Remove known bad/expired Influx list files + ansible.builtin.file: + path: "/etc/apt/sources.list.d/{{ item }}" + state: absent + loop: + - repos_influxdata_com_debian.list + - influxdb.list + + - name: Download the 2026-valid InfluxData archive key + ansible.builtin.get_url: + url: https://repos.influxdata.com/influxdata-archive.key + dest: /tmp/influxdata-archive.key + mode: '0644' + + - name: Dearmor key for sqv (Sequoia-PGP) compatibility + ansible.builtin.shell: | + cat /tmp/influxdata-archive.key | gpg --dearmor > /usr/share/keyrings/influxdata-archive.gpg + args: + creates: /usr/share/keyrings/influxdata-archive.gpg + + - name: Write clean InfluxData source list with signed-by flag + ansible.builtin.copy: + dest: /etc/apt/sources.list.d/influxdata.list + content: "deb [signed-by=/usr/share/keyrings/influxdata-archive.gpg] https://repos.influxdata.com/debian stable main" + mode: '0644' + + +- name: Ensure Proxmox GPG key is present (for Raspberry Pi/PBS) + ansible.builtin.get_url: + url: https://enterprise.proxmox.com/debian/proxmox-release-trixie.gpg + dest: /etc/apt/trusted.gpg.d/proxmox-release-trixie.gpg + mode: '0644' + become: yes + when: ansible_distribution == 'Debian' + tags: [setup] + +- name: Set hostname + ansible.builtin.hostname: + name: "{{ inventory_hostname }}" + become: yes + tags: [identity] + +- name: Update /etc/hosts for FQDN resolution + ansible.builtin.lineinfile: + path: /etc/hosts + regexp: '^127\.0\.1\.1' + line: "127.0.1.1 {{ inventory_hostname }}.{{ domain_name }} {{ inventory_hostname }}" + become: yes + tags: [identity] + +- name: Check for NetworkManager + ansible.builtin.command: systemctl is-active NetworkManager + register: nm_status + failed_when: false + changed_when: false + tags: [identity, network] + +- name: Configure NetworkManager Search Domain (Raspberry Pi/mDNS Style) + when: nm_status.rc == 0 + tags: [identity, network] + block: + - name: Get active connection name + ansible.builtin.shell: "nmcli -t -f NAME connection show --active | head -n 1" + register: active_conn + changed_when: false + + - name: Apply search domain via nmcli + ansible.builtin.command: "nmcli connection modify '{{ active_conn.stdout }}' ipv4.dns-search '{{ domain_name }}'" + when: active_conn.stdout != "" + notify: Reload NetworkManager + +- name: Configure systemd-resolved Search Domain (Vanilla Debian Style) + ansible.builtin.ini_file: + path: /etc/systemd/resolved.conf + section: Resolve + option: Domains + value: "{{ domain_name }}" + become: yes + notify: Restart systemd-resolved + when: nm_status.rc != 0 + tags: [identity, network] + +- name: Ensure the terminal is always functional + ansible.builtin.lineinfile: + path: /etc/profile + line: 'export TERM=xterm-256color' + state: present + become: yes + +- name: Set system timezone + community.general.timezone: + name: Europe/Berlin + become: yes + tags: [localization] + +- name: Generate required locales + ansible.builtin.locale_gen: + name: "{{ item }}" + state: present + become: yes + loop: + - en_US.UTF-8 + - en_DK.UTF-8 # Required for the 24h clock format + tags: [localization] + +- name: Force system-wide locale and 24h clock + ansible.builtin.command: update-locale LANG=en_US.UTF-8 LC_TIME=en_DK.UTF-8 + become: yes + changed_when: true + tags: [localization] + +- name: Flush handlers to apply DNS changes immediately + ansible.builtin.meta: flush_handlers + +- name: Wait for DNS to be functional + ansible.builtin.command: getent hosts google.com + register: dns_check + until: dns_check.rc == 0 + retries: 3 + delay: 5 + changed_when: false + tags: [identity, network] + +- name: Install baseline packages (Unified list) + ansible.builtin.apt: + name: "{{ common_packages }}" + state: present + update_cache: yes + cache_valid_time: 3600 + become: yes + tags: [packages] + +- name: Install fastfetch (Optional - may not be in legacy repos) + ansible.builtin.apt: + name: + - fastfetch + - btm + state: present + become: yes + ignore_errors: yes + tags: [packages] + +- name: Configure needrestart for non-interactive automation + ansible.builtin.lineinfile: + path: /etc/needrestart/needrestart.conf + regexp: '^#?\$nrconf{restart}' + line: "$nrconf{restart} = 'a';" + become: yes + tags: [packages, config] + +- name: Ensure discovery services are enabled and running + ansible.builtin.service: + name: "{{ item }}" + state: started + enabled: yes + loop: + - avahi-daemon + - lldpd + become: yes + tags: [services] + +- name: Include maintenance tasks + ansible.builtin.include_tasks: maintenance.yml + tags: [maintenance] + +- name: Ensure console getty is running (for Proxmox WebUI access) + ansible.builtin.systemd: + name: getty@tty1.service + state: started + enabled: yes + become: yes + tags: [services, setup] + +- name: Ensure Node Exporter is running for monitoring + ansible.builtin.systemd: + name: prometheus-node-exporter + state: started + enabled: yes + become: yes + tags: [monitoring, services] + + +- name: Fix Vim mouse behavior for easy copy-paste + ansible.builtin.copy: + dest: /etc/vim/vimrc.local + content: | + set mouse= + syntax on + set number + owner: root + group: root + mode: '0644' + become: yes diff --git a/roles/common/tasks/main.yml-back3 b/roles/common/tasks/main.yml-back3 new file mode 100644 index 0000000..6249f99 --- /dev/null +++ b/roles/common/tasks/main.yml-back3 @@ -0,0 +1,290 @@ + --- +- name: Ensure Proxmox GPG key is present (for Raspberry Pi/PBS) + ansible.builtin.get_url: + url: https://enterprise.proxmox.com/debian/proxmox-release-trixie.gpg + dest: /etc/apt/trusted.gpg.d/proxmox-release-trixie.gpg + mode: '0644' + become: yes + when: ansible_distribution == 'Debian' + tags: [setup] + +- name: Set hostname + ansible.builtin.hostname: + name: "{{ inventory_hostname }}" + become: yes + tags: [identity] + +- name: Update /etc/hosts for FQDN resolution + ansible.builtin.lineinfile: + path: /etc/hosts + regexp: '^127\.0\.1\.1' + line: "127.0.1.1 {{ inventory_hostname }}.{{ domain_name }} {{ inventory_hostname }}" + become: yes + tags: [identity] + +- name: Check for NetworkManager + ansible.builtin.command: systemctl is-active NetworkManager + register: nm_status + failed_when: false + changed_when: false + tags: [identity, network] + +- name: Configure NetworkManager Search Domain (Raspberry Pi/mDNS Style) + when: + - nm_status.rc == 0 + - ansible_virtualization_type != 'lxc' # <-- NEU: Überspringe LXC + tags: [identity, network] + block: + - name: Get active connection name + ansible.builtin.shell: "nmcli -t -f NAME connection show --active | head -n 1" + register: active_conn + changed_when: false + - name: Apply search domain via nmcli + ansible.builtin.command: "nmcli connection modify '{{ active_conn.stdout }}' ipv4.dns-search '{{ domain_name }}'" + when: active_conn.stdout != "" + notify: Reload NetworkManager + +- name: Configure systemd-resolved Search Domain (Vanilla Debian Style) + ansible.builtin.ini_file: + path: /etc/systemd/resolved.conf + section: Resolve + option: Domains + value: "{{ domain_name }}" + become: yes + notify: Restart systemd-resolved + when: + - nm_status.rc != 0 + - ansible_virtualization_type != 'lxc' # <-- NEU: Überspringe LXC + tags: [identity, network] + +- name: Ensure the terminal is always functional + ansible.builtin.lineinfile: + path: /etc/profile + line: 'export TERM=xterm-256color' + state: present + become: yes + +- name: Set system timezone + community.general.timezone: + name: Europe/Berlin + become: yes + tags: [localization] + +- name: Generate required locales + ansible.builtin.locale_gen: + name: "{{ item }}" + state: present + become: yes + loop: + - en_US.UTF-8 + - en_DK.UTF-8 # Required for the 24h clock format + tags: [localization] + +- name: Force system-wide locale and 24h clock + ansible.builtin.command: update-locale LANG=en_US.UTF-8 LC_TIME=en_DK.UTF-8 + become: yes + changed_when: true + tags: [localization] + +- name: Flush handlers to apply DNS changes immediately + ansible.builtin.meta: flush_handlers + +- name: Wait for DNS to be functional + ansible.builtin.command: getent hosts google.com + register: dns_check + until: dns_check.rc == 0 + retries: 3 + delay: 5 + changed_when: false + when: ansible_virtualization_type != 'lxc' # <-- NEU: Überspringe LXC + tags: [identity, network] + +# --- REINE PACKET-TASKS OHNE SECURITY --- + +- name: Install baseline packages (Unified list from group_vars) + ansible.builtin.apt: + name: "{{ common_packages }}" + state: present + update_cache: yes + cache_valid_time: 3600 + become: yes + tags: [packages] + +- name: Install modern packages like fastfetch (Debian 13+ only) + ansible.builtin.apt: + name: "{{ modern_os_packages | default(['fastfetch']) }}" + state: present + become: yes + when: + - ansible_os_family == "Debian" + - ansible_distribution_major_version | int >= 13 + tags: [packages] + +- name: Install QEMU Guest Agent (VMs only - NOT on LXC or Physical Iron) + ansible.builtin.apt: + name: qemu-guest-agent + state: present + become: yes + when: + - "'proxmox_vms' in group_names" + - "'lxc_containers' not in group_names" + - "'physical_iron' not in group_names" + tags: [packages, proxmox] + +# --- SYSTEM-EINSTELLUNGEN & DIENSTE --- + +- name: Configure needrestart for non-interactive automation + ansible.builtin.lineinfile: + path: /etc/needrestart/needrestart.conf + regexp: '^#?\$nrconf{restart}' + line: "$nrconf{restart} = 'a';" + become: yes + tags: [packages, config] + +- name: Ensure discovery services are enabled and running + ansible.builtin.service: + name: "{{ item }}" + state: started + enabled: yes + loop: + - avahi-daemon + - lldpd + become: yes + tags: [services] + +- name: Include maintenance tasks + ansible.builtin.include_tasks: maintenance.yml + tags: [maintenance] + +- name: Ensure console getty is running (for Proxmox WebUI access) + ansible.builtin.systemd: + name: getty@tty1.service + state: started + enabled: yes + become: yes + tags: [services, setup] + +- name: Ensure Node Exporter is running for monitoring + ansible.builtin.systemd: + name: prometheus-node-exporter + state: started + enabled: yes + become: yes + tags: [monitoring, services] + +- name: Fix Vim mouse behavior for easy copy-paste + ansible.builtin.copy: + dest: /etc/vim/vimrc.local + content: | + set mouse= + syntax on + set number + owner: root + group: root + mode: '0644' + become: yes +### ghosty shit shizzle + +- name: Create Ghostty terminfo source file on remote + ansible.builtin.copy: + content: | + {% raw %} + xterm-ghostty|ghostty|Ghostty, + am, bce, ccc, hs, km, mc5i, mir, msgr, npc, xenl, AX, Su, Tc, XT, fullkbd, + colors#256, cols#80, it#8, lines#24, pairs#32767, + acsc=++\,\,--..00``aaffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~, + bel=^G, blink=\E[5m, bold=\E[1m, cbt=\E[Z, civis=\E[?25l, + clear=\E[H\E[2J, cnorm=\E[?12l\E[?25h, cr=^M, + csr=\E[%i%p1%d;%p2%dr, cub=\E[%p1%dD, cub1=^H, + cud=\E[%p1%dB, cud1=^J, cuf=\E[%p1%dC, cuf1=\E[C, + cup=\E[%i%p1%d;%p2%dH, cuu=\E[%p1%dA, cuu1=\E[A, + cvvis=\E[?12;25h, dch=\E[%p1%dP, dch1=\E[P, dim=\E[2m, + dl=\E[%p1%dM, dl1=\E[M, dsl=\E]2;\007, ech=\E[%p1%dX, + ed=\E[J, el=\E[K, el1=\E[1K, flash=\E[?5h$<100/>\E[?5l, + fsl=^G, home=\E[H, hpa=\E[%i%p1%dG, ht=^I, hts=\EH, + ich=\E[%p1%d@, ich1=\E[@, il=\E[%p1%dL, il1=\E[L, ind=^J, + indn=\E[%p1%dS, + initc=\E]4;%p1%d;rgb\:%p2%{255}%*%{1000}%/%2.2X/%p3%{255}%*%{1000}%/%2.2X/%p4%{255}%*%{1000}%/%2.2X\E\\, + invis=\E[8m, kDC=\E[3;2~, kEND=\E[1;2F, kHOM=\E[1;2H, + kIC=\E[2;2~, kLFT=\E[1;2D, kNXT=\E[6;2~, kPRV=\E[5;2~, + kRIT=\E[1;2C, kbs=\177, kcbt=\E[Z, kcub1=\EOD, kcud1=\EOB, + kcuf1=\EOC, kcuu1=\EOA, kdch1=\E[3~, kend=\EOF, kent=\EOM, + kf1=\EOP, kf10=\E[21~, kf11=\E[23~, kf12=\E[24~, + kf13=\E[1;2P, kf14=\E[1;2Q, kf15=\E[1;2R, kf16=\E[1;2S, + kf17=\E[15;2~, kf18=\E[17;2~, kf19=\E[18;2~, kf2=\EOQ, + kf20=\E[19;2~, kf21=\E[20;2~, kf22=\E[21;2~, + kf23=\E[23;2~, kf24=\E[24;2~, kf25=\E[1;5P, kf26=\E[1;5Q, + kf27=\E[1;5R, kf28=\E[1;5S, kf29=\E[15;5~, kf3=\EOR, + kf30=\E[17;5~, kf31=\E[18;5~, kf32=\E[19;5~, + kf33=\E[20;5~, kf34=\E[21;5~, kf35=\E[23;5~, + kf36=\E[24;5~, kf37=\E[1;6P, kf38=\E[1;6Q, kf39=\E[1;6R, + kf4=\EOS, kf40=\E[1;6S, kf41=\E[15;6~, kf42=\E[17;6~, + kf43=\E[18;6~, kf44=\E[19;6~, kf45=\E[20;6~, + kf46=\E[21;6~, kf47=\E[23;6~, kf48=\E[24;6~, + kf49=\E[1;3P, kf5=\E[15~, kf50=\E[1;3Q, kf51=\E[1;3R, + kf52=\E[1;3S, kf53=\E[15;3~, kf54=\E[17;3~, + kf55=\E[18;3~, kf56=\E[19;3~, kf57=\E[20;3~, + kf58=\E[21;3~, kf59=\E[23;3~, kf6=\E[17~, kf60=\E[24;3~, + kf61=\E[1;4P, kf62=\E[1;4Q, kf63=\E[1;4R, kf7=\E[18~, + kf8=\E[19~, kf9=\E[20~, khome=\EOH, kich1=\E[2~, + kind=\E[1;2B, kmous=\E[<, knp=\E[6~, kpp=\E[5~, + kri=\E[1;2A, oc=\E]104\007, op=\E[39;49m, rc=\E8, + rep=%p1%c\E[%p2%{1}%-%db, rev=\E[7m, ri=\EM, + rin=\E[%p1%dT, ritm=\E[23m, rmacs=\E(B, rmam=\E[?7l, + rmcup=\E[?1049l, rmir=\E[4l, rmkx=\E[?1l\E>, rmso=\E[27m, + rmul=\E[24m, rs1=\E]\E\\\Ec, sc=\E7, + setab=\E[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e48;5;%p1%d%;m, + setaf=\E[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m, + sgr=%?%p9%t\E(0%e\E(B%;\E[0%?%p6%t;1%;%?%p5%t;2%;%?%p2%t;4%;%?%p1%p3%|%t;7%;%?%p4%t;5%;%?%p7%t;8%;m, + sgr0=\E(B\E[m, sitm=\E[3m, smacs=\E(0, smam=\E[?7h, + smcup=\E[?1049h, smir=\E[4h, smkx=\E[?1h\E=, smso=\E[7m, + smul=\E[4m, tbc=\E[3g, tsl=\E]2;, u6=\E[%i%d;%dR, u7=\E[6n, + u8=\E[?%[;0123456789]c, u9=\E[c, vpa=\E[%i%p1%dd, + BD=\E[?2004l, BE=\E[?2004h, Clmg=\E[s, + Cmg=\E[%i%p1%d;%p2%ds, Dsmg=\E[?69l, E3=\E[3J, + Enmg=\E[?69h, Ms=\E]52;%p1%s;%p2%s\007, PE=\E[201~, + PS=\E[200~, RV=\E[>c, Se=\E[2 q, + Setulc=\E[58\:2\:\:%p1%{65536}%/%d\:%p1%{256}%/%{255}%&%d\:%p1%{255}%&%d%;m, + Smulx=\E[4\:%p1%dm, Ss=\E[%p1%d q, + Sync=\E[?2026%?%p1%{1}%-%tl%eh%;, + XM=\E[?1006;1000%?%p1%{1}%=%th%el%;, XR=\E[>0q, + fd=\E[?1004l, fe=\E[?1004h, kDC3=\E[3;3~, kDC4=\E[3;4~, + kDC5=\E[3;5~, kDC6=\E[3;6~, kDC7=\E[3;7~, kDN=\E[1;2B, + kDN3=\E[1;3B, kDN4=\E[1;4B, kDN5=\E[1;5B, kDN6=\E[1;6B, + kDN7=\E[1;7B, kEND3=\E[1;3F, kEND4=\E[1;4F, + kEND5=\E[1;5F, kEND6=\E[1;6F, kEND7=\E[1;7F, + kHOM3=\E[1;3H, kHOM4=\E[1;4H, kHOM5=\E[1;5H, + kHOM6=\E[1;6H, kHOM7=\E[1;7H, kIC3=\E[2;3~, kIC4=\E[2;4~, + kIC5=\E[2;5~, kIC6=\E[2;6~, kIC7=\E[2;7~, kLFT3=\E[1;3D, + kLFT4=\E[1;4D, kLFT5=\E[1;5D, kLFT6=\E[1;6D, + kLFT7=\E[1;7D, kNXT3=\E[6;3~, kNXT4=\E[6;4~, + kNXT5=\E[6;5~, kNXT6=\E[6;6~, kNXT7=\E[6;7~, + kPRV3=\E[5;3~, kPRV4=\E[5;4~, kPRV5=\E[5;5~, + kPRV6=\E[5;6~, kPRV7=\E[5;7~, kRIT3=\E[1;3C, + kRIT4=\E[1;4C, kRIT5=\E[1;5C, kRIT6=\E[1;6C, + kRIT7=\E[1;7C, kUP=\E[1;2A, kUP3=\E[1;3A, kUP4=\E[1;4A, + kUP5=\E[1;5A, kUP6=\E[1;6A, kUP7=\E[1;7A, kxIN=\E[I, + kxOUT=\E[O, rmxx=\E[29m, rv=\E\\[[0-9]+;[0-9]+;[0-9]+c, + setrgbb=\E[48\:2\:%p1%d\:%p2%d\:%p3%dm, + setrgbf=\E[38\:2\:%p1%d\:%p2%d\:%p3%dm, smxx=\E[9m, + xm=\E[<%i%p3%d;%p1%d;%p2%d;%?%p4%tM%em%;, + xr=\EP>\\|[ -~]+a\E\\, + {% endraw %} + dest: /tmp/xterm-ghostty + mode: '0644' + ignore_errors: yes + tags: [common, terminal] + +- name: Optimize terminfo for Ghostty terminal + ansible.builtin.command: tic -x /tmp/xterm-ghostty + become: yes + changed_when: false + ignore_errors: yes + tags: [common, terminal] + +- name: Clean up temporary Ghostty terminfo file + ansible.builtin.file: + path: /tmp/xterm-ghostty + state: absent + ignore_errors: yes + tags: [common, terminal] diff --git a/roles/common/tasks/maintenance.yml b/roles/common/tasks/maintenance.yml new file mode 100644 index 0000000..b9a2bc2 --- /dev/null +++ b/roles/common/tasks/maintenance.yml @@ -0,0 +1,22 @@ +--- +- name: Update and upgrade apt packages + become: true + ansible.builtin.apt: + update_cache: yes + upgrade: dist + autoremove: yes + purge: yes + tags: [maintenance, upgrade] + +- name: Check if a reboot is required + become: true + ansible.builtin.stat: + path: /var/run/reboot-required + register: reboot_required_file + tags: [maintenance] + +- name: Notify about pending reboot + ansible.builtin.debug: + msg: "Host {{ inventory_hostname }} requires a reboot." + when: reboot_required_file.stat.exists + tags: [maintenance] diff --git a/roles/fileserver/handlers/main.yml b/roles/fileserver/handlers/main.yml new file mode 100644 index 0000000..8c65570 --- /dev/null +++ b/roles/fileserver/handlers/main.yml @@ -0,0 +1,4 @@ +- name: Restart Samba + ansible.builtin.service: + name: smbd + state: restarted diff --git a/roles/fileserver/tasks/main.yml b/roles/fileserver/tasks/main.yml new file mode 100644 index 0000000..b5922af --- /dev/null +++ b/roles/fileserver/tasks/main.yml @@ -0,0 +1,47 @@ +- name: Install Samba packages + ansible.builtin.apt: + name: + - samba + - samba-common-bin + - smbclient + state: present + update_cache: yes + become: yes + +- name: Ensure Samba shared directories exist + ansible.builtin.file: + path: "{{ item.path }}" + state: directory + loop: "{{ samba_shares }}" + become: yes + +- name: Deploy Samba configuration from template + ansible.builtin.template: + src: smb.conf.template + dest: /etc/samba/smb.conf + owner: root + group: root + mode: '0644' + become: yes + notify: Restart Samba + + +#- name: Ensure Samba shared directories exist +# ansible.builtin.file: +# path: "{{ item.path }}" +# state: directory +# loop: "{{ samba_shares }}" +# owner: "{{ item.force_user | default('volker') }}" +# group: "{{ item.group | default('volker') }}" +# mode: "{{ item.mode | default('0775') }}" +# loop: "{{ samba_shares }}" +# ignore_errors: yes # <-- Das fängt den chown-Fehler bei externen Mounts ab + +#- name: Ensure Samba services are started and enabled +# ansible.builtin.service: +# name: "{{ item }}" +# state: started +# enabled: yes +# loop: +# - smbd +# - nmbd diff --git a/roles/fileserver/tasks/main.yml-bak1 b/roles/fileserver/tasks/main.yml-bak1 new file mode 100644 index 0000000..38eb165 --- /dev/null +++ b/roles/fileserver/tasks/main.yml-bak1 @@ -0,0 +1,27 @@ +--- +- name: Install and Configure Samba + hosts: samba_servers + become: yes + tasks: +- name: Install Samba + package: + name: samba + state: present +- name: Ensure NFS utilities are installed. + apt: + name: + - nfs-common + - nfs-kernel-server + state: present +- name: Configure smb.conf + template: + src: smb.conf.template + dest: /etc/samba/smb.conf + notify: restart samba + + # handlers: + # - name: restart samba + # service: + # name: smbd + # state: restarted + # state: present diff --git a/roles/fileserver/templates/smb.conf.template b/roles/fileserver/templates/smb.conf.template new file mode 100644 index 0000000..6d578ee --- /dev/null +++ b/roles/fileserver/templates/smb.conf.template @@ -0,0 +1,40 @@ +[global] + workgroup = WORKGROUP + netbios name = {{ inventory_hostname }} + server string = %h server (Samba, Ubuntu) + log file = /var/log/samba/log.%m + max log size = 1000 + logging = file + panic action = /usr/share/samba/panic-action %d + server role = standalone server + obey pam restrictions = yes + unix password sync = yes + passwd program = /usr/bin/passwd %u + passwd chat = *Enter\snew\s*\spassword:* %n\n *Retype\snew\s*\spassword:* %n\n *password\supdated\ssuccessfully* . + pam password change = yes + map to guest = bad user + usershare allow guests = yes +# --- macOS Optimization (Fruit) --- + vfs objects = fruit streams_xattr recycle + fruit:model = MacPro7,1@ECOLOR=226,226,224 + fruit:metadata = stream + fruit:veto_appledouble = no + fruit:posix_rename = yes + +# --- Recycle Bin Logic --- + recycle:touch = yes + recycle:keeptree = yes + recycle:versions = yes + +# Dynamic Shares Loop +{% for share in samba_shares %} +[{{ share.name }}] + path = {{ share.path }} + browseable = {{ share.browseable | default('yes') }} + read only = {{ share.read_only | default('no') }} + guest ok = {{ share.guest_ok | default('yes') }} + {% if share.force_user is defined %} + force user = {{ share.force_user }} + {% endif %} +{% endfor %} + diff --git a/roles/monitoring/handlers/main.yml b/roles/monitoring/handlers/main.yml new file mode 100644 index 0000000..6faa637 --- /dev/null +++ b/roles/monitoring/handlers/main.yml @@ -0,0 +1,5 @@ +--- +- name: Restart Prometheus + ansible.builtin.systemd: + name: prometheus + state: restarted diff --git a/roles/monitoring/tasks/main.yml b/roles/monitoring/tasks/main.yml new file mode 100644 index 0000000..a387195 --- /dev/null +++ b/roles/monitoring/tasks/main.yml @@ -0,0 +1,85 @@ +--- +# 1. This part runs on EVERY node +- name: Install Node Exporter (Agent) + ansible.builtin.apt: + name: prometheus-node-exporter + state: present + +- name: Ensure Node Exporter is running + ansible.builtin.systemd: + name: prometheus-node-exporter + state: started + enabled: yes + +# 2. This part ONLY runs on the monitor node +- name: Install Monitoring Server Stack + when: inventory_hostname == 'monitor' + block: + - name: Add Grafana GPG key + ansible.builtin.get_url: + url: https://apt.grafana.com/gpg.key + dest: /usr/share/keyrings/grafana.gpg + mode: '0644' + + - name: Add Grafana Repo + ansible.builtin.apt_repository: + repo: "deb [signed-by=/usr/share/keyrings/grafana.gpg] https://apt.grafana.com stable main" + state: present + - name: Ensure prometheus system user exists + ansible.builtin.user: + name: prometheus + shell: /bin/false + system: yes + create_home: no + when: inventory_hostname == 'monitor' + + - name: Ensure prometheus data directory has correct permissions + ansible.builtin.file: + path: /var/lib/prometheus + state: directory + owner: prometheus + group: prometheus + mode: '0755' + when: inventory_hostname == 'monitor' + + + - name: Install Server Packages + ansible.builtin.apt: + name: + - influxdb + - grafana + - prometheus # The server engine + state: present + update_cache: yes + + - name: Deploy Prometheus configuration from template + ansible.builtin.template: + src: prometheus.yml.j2 + dest: /etc/prometheus/prometheus.yml + owner: prometheus + group: prometheus + mode: '0644' + notify: Restart Prometheus + + - name: Ensure Server Services are running + ansible.builtin.systemd: + name: "{{ item }}" + state: started + enabled: yes + loop: + - influxdb + - grafana-server + - prometheus + + - name: Configure InfluxDB UDP listener for Proxmox + ansible.builtin.blockinfile: + path: /etc/influxdb/influxdb.conf + insertafter: '\[\[udp\]\]' + block: | + enabled = true + bind-address = ":8089" + database = "proxmox" + batch-size = 1000 + batch-timeout = "1s" + when: inventory_hostname == 'monitor' + notify: Restart Influxdb diff --git a/roles/monitoring/templates/prometheus.yml.j2 b/roles/monitoring/templates/prometheus.yml.j2 new file mode 100644 index 0000000..de211b7 --- /dev/null +++ b/roles/monitoring/templates/prometheus.yml.j2 @@ -0,0 +1,14 @@ +global: + scrape_interval: 15s + +scrape_configs: + - job_name: 'prometheus' + static_configs: + - targets: ['localhost:9090'] + + - job_name: 'lab_nodes' + static_configs: + - targets: +{% for host in groups['all_nodes'] %} + - '{{ hostvars[host].ansible_host }}:9100' +{% endfor %} diff --git a/roles/reverse_proxy/handlers/main.yml b/roles/reverse_proxy/handlers/main.yml new file mode 100644 index 0000000..dc03190 --- /dev/null +++ b/roles/reverse_proxy/handlers/main.yml @@ -0,0 +1,6 @@ +--- +- name: Restart Caddy + ansible.builtin.systemd: + name: caddy + state: restarted + become: yes diff --git a/roles/reverse_proxy/tasks/main.yml b/roles/reverse_proxy/tasks/main.yml new file mode 100644 index 0000000..afa2e72 --- /dev/null +++ b/roles/reverse_proxy/tasks/main.yml @@ -0,0 +1,30 @@ +--- +- name: Ensure old Cloudsmith repository artifact is removed + ansible.builtin.file: + path: /etc/apt/sources.list.d/caddy-stable.list + state: absent + become: yes + +- name: Install Caddy server package from official Debian repositories + ansible.builtin.apt: + name: caddy + state: present + update_cache: yes + become: yes + +- name: Deploy Caddyfile configuration from template + ansible.builtin.template: + src: Caddyfile.j2 + dest: /etc/caddy/Caddyfile + owner: caddy + group: caddy + mode: '0644' + become: yes + notify: Restart Caddy + +- name: Ensure Caddy service is enabled and running + ansible.builtin.systemd: + name: caddy + state: started + enabled: yes + become: yes diff --git a/roles/reverse_proxy/templates/Caddyfile.j2 b/roles/reverse_proxy/templates/Caddyfile.j2 new file mode 100644 index 0000000..74947df --- /dev/null +++ b/roles/reverse_proxy/templates/Caddyfile.j2 @@ -0,0 +1,146 @@ +# --- Yunohost: bumb --- +gh120.de, *.gh120.de { + reverse_proxy 192.168.112.46:443 { + transport http { + tls_insecure_skip_verify + } + } +} + +# --- Yunohost: rohan --- +wks20.de, *.wks20.de { + reverse_proxy 192.168.112.42:443 { + transport http { + tls_insecure_skip_verify + } + } +} + + +# ============================================================================== +# SUBDOMAINS FÜR GH120.DE (YunoHost 'bumb' - 192.168.112.46) +# ============================================================================== + +ha.gh120.de { + reverse_proxy https://192.168.112.46 { + transport http { + tls_insecure_skip_verify + } + header_up Web-Socket-Allowed true + } +} + +nc.gh120.de { + reverse_proxy https://192.168.112.46 { + transport http { + tls_insecure_skip_verify + } + } +} + +img.gh120.de { + request_body { + max_size 10GB + } + reverse_proxy https://192.168.112.46 { + transport http { + tls_insecure_skip_verify + } + } +} + +docs.gh120.de { + reverse_proxy https://192.168.112.46 { + transport http { + tls_insecure_skip_verify + } + } +} + +paper.gh120.de { + reverse_proxy https://192.168.112.46 { + transport http { + tls_insecure_skip_verify + } + } +} + + +# ============================================================================== +# SUBDOMAINS FÜR WKS20.DE (YunoHost 'rohan' - 192.168.112.42) +# ============================================================================== + +links.wks20.de { + reverse_proxy https://192.168.112.42 { + transport http { + tls_insecure_skip_verify + } + } +} + +mantis.wks20.de { + reverse_proxy https://192.168.112.42 { + transport http { + tls_insecure_skip_verify + } + } +} + +nc.wks20.de { + reverse_proxy https://192.168.112.42 { + transport http { + tls_insecure_skip_verify + } + } +} + +pics.wks20.de { + request_body { + max_size 10GB + } + reverse_proxy https://192.168.112.42 { + transport http { + tls_insecure_skip_verify + } + } +} + +roundc.wks20.de { + reverse_proxy https://192.168.112.42 { + transport http { + tls_insecure_skip_verify + } + } +} + +tea.wks20.de { + reverse_proxy https://192.168.112.42 { + transport http { + tls_insecure_skip_verify + } + } +} + +warden.wks20.de { + reverse_proxy https://192.168.112.42 { + transport http { + tls_insecure_skip_verify + } + header_up Web-Socket-Allowed true + } +} + +wiki.wks20.de { + reverse_proxy https://192.168.112.42 { + transport http { + tls_insecure_skip_verify + } + } +} + + + +# --- Future Optional (Auskommentiert) --- +# jellyfin.gh120.de { +# reverse_proxy 192.168.123.114:8096 +# diff --git a/roles/security/files/authorized_keys_volker b/roles/security/files/authorized_keys_volker new file mode 100644 index 0000000..59fba66 --- /dev/null +++ b/roles/security/files/authorized_keys_volker @@ -0,0 +1,5 @@ +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCqKm6tSG73CudRxZkUnR/hcwKQnvSfkQM/Gq1gR6wswu4kcthHZ+YCxzRFIJmTR1+C0UXy8yRVtwprz31plFbHvU3Om913MGaN1oadunYOkKD8OmAtCtht9H+5wC5HtjwuhNf/MH1K727ecNUSH10DYovzXkOD6byJukfkvbU6CVKxWAI6W9PXTLOPRyUoy3TX0GEBascayneqHBFfPGpICnR76X9Ydi2avfgmNiGtTMzKkn1mNqm3a4eHCfde8XUBtqlxdMnO/pMlgMh14XoBSD5T+U3OqIUvMOiU3ZKlcq4W46wtPX1Im6iqfgFutwT1YqQ8UNY06urO41nH6d5rVfSA1BS7Fonho2xK5lQ3aqapn2+o9goXTIQ1avoOHyWS0j+W8m5BEL8Prvr+eqjTCivh5g4rKVe2SebKzZU89oZSEkV9Mj69qhS1g3LnyJds+oskl04CdRXrn5KSyxXP9X4m0EYYfbzWMAPRZ6SsltAOw9w4hwZtwIKSl2+bMQAqQmRojDof4FgK+DCQfdcThhrmknGtGiL1v3tJuCmmiikoKis5qOVBmVJOhJaSOTKSIhx3oTVVfCgzlEnGE0M7gUk1+Qh30p4TahsbyfcWg5v3+0vdIVgAWIdW0Kp0s9R0mU4qKeIuZ9ejHCmaGcQe2ZolQZc5UrTwMBb1PaqPQQ== key von macbook fuer rogueone +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFhNTFIBVTfsFDiO5oKdTWxOkk9jrpnqYma6DFNkCROq strider-mackbook-2023-ed +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQC+5jrJHgRNSsZICWTRFppyVyyn1SfnboEa4/bwCd9yad34e0f3CRu5EGlVzKUZAar7D1EWxjeFEeJF1hmaY0iJGbnmzf2BT8FHIhiJqa/EyiKlrVY+rHsvkzP26XOe8xlZdh5MAEsKt4/6jnvWN8H+pctvQzOfynh8+9HdgU/df7M7YKrFd9sSToFx0dZfI+3eF0OfLrjYp2fKGVK/SiiyUBJE96h39IK13grMxlwQ2vv3p4zSu6ADINJipa1sedu8earq0t4dsxvy/0F7wwbfkMgek0Q0eN/gT31pM/m1NXpc7Qk1E2M8YcaFIUAbYchqoZT8wsn4/MxjbY835226RCIOPrEL+CmKzF904S3zUqIU2BJ42IGGBtCtM9eoRS3BMkYFLKY4vEH0bDTu9KSwBdLdc/1JYQZi5NPZSW0rH1OeKntJACmUczCK2NXAJraGm374eT/JRJkSQxFLolKZRo6duhAdkPcvGZeGTMSgcLguZ7ayZuz3Q730JqMtVV0jKpXbRjAM5kBqflc31580xgrG6J6gG/cTh9XvC4VF/vP8yP44HGODNtJeiTVBdowltsFA+xUPspJa8fFysCcSL0dmKjr+wlfMZgjiuEAJ3Ejm9m7VsVjeeWdlfRXVDUIrInsEYz+9lADrZvSom9cZGksuP581m3h4ncnLyFU9uw== key von macbook fuer goldeneye +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDX9hQGGErj6YUhq5KN934JLZdD4R8lqFlNOSbcY4vWFZp7F/l9zntGaozbzY9X+0WH2qLubrcdWXpWXf3mJPw/gjd+1DAHn/1BkWjgOccmiaM5CQc1SXLs5wZIzhgXuzg+OwGry7XXtAOGdjjAB+c0cDC6bz5o53Y2hiprG5+Y7AuAa7rJxs6AT+EM/gzWsuwofzdEbnnEeQn874gBXOb3IS4GNZL5NNcb1lqocnkmhsQnTXJIGbqkBtzWmWwcS5/GGWhaqFz+Ugv2VUcstgrz7JvtGA5WPr3hCiB+y4QRBiKHrYy/zjWn+ESGk7cYjnhiHdIlRJXeVLkWJlHIr4hN1ajuetx4wS6pg2molZxEwZfTzhDxMHWocVNUHm1UZMAxxQ3VpEq6nvrUM7ppVQicl1R+zgHEeHa9fRUSLq/fBaIg5y4VZCXK7p61O6ms6pK0QoNFcGaSZ9bqYoY0ouPxfNPTMAw5yLu1pFmFC/9+MEB1d/66mdG5x8UdLma2qGRChcVKr1gLqzIEtx69x/0hFKUne9KssInxy+BC55tjpkmbb3euAeuzRIKYtUHz/9XbEUEpjvofnXawtz2FEEddtI/eCtBc65nPP21f/or1ngT6I7gC+Ha9brvK/AmlM3OOx6tvUg1StRwQj9qFdT5FpFbN+cuWnf2/LWf8A5ik7w== key von macbook fuer LXC-Container +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIATdXmHXS8dGIsVa5zmAtjkWRMka/CNcIEeiFX8vru1 sentinel-automation diff --git a/roles/security/tasks/main.yml b/roles/security/tasks/main.yml new file mode 100644 index 0000000..e8e3427 --- /dev/null +++ b/roles/security/tasks/main.yml @@ -0,0 +1,60 @@ +--- +- name: Ensure the administrative user exists + ansible.builtin.user: + name: volker + shell: /bin/bash + groups: sudo + append: yes + become: yes # Added this to prevent permission denied errors + tags: [security, always] + +- name: Allow root SSH login + ansible.builtin.lineinfile: + path: /etc/ssh/sshd_config + regexp: '^#?PermitRootLogin' + line: 'PermitRootLogin yes' + become: yes + notify: Restart SSH + tags: [security, ssh] + +- name: Apply global user security policy + ansible.builtin.user: + name: "{{ item.name }}" + password: "{{ vault_root_password | password_hash('sha512') }}" + shell: /bin/bash + groups: "{{ item.groups | default(omit) }}" + become: yes # <--- Added this for safety + loop: + - { name: 'root' } + - { name: 'volker', groups: 'sudo' } + +#- name: Sync passwords for administrative users +# ansible.builtin.user: +# name: "{{ item }}" +# password: "{{ root_password_hash }}" +# become: yes +# loop: +# - root +# - volker +# tags: [security] + +- name: Ensure SSH keys are synchronized for both users + ansible.posix.authorized_key: + user: "{{ item }}" + state: present + key: "{{ lookup('file', 'authorized_keys_volker') }}" + become: yes + loop: + - root + - volker + tags: [security, ssh] + +- name: Passwordless sudo for volker + ansible.builtin.copy: + content: "volker ALL=(ALL) NOPASSWD:ALL" + dest: /etc/sudoers.d/volker + owner: root + group: root + mode: '0440' + validate: /usr/sbin/visudo -cf %s + become: yes diff --git a/roles/upgrade_trixie/tasks/main.yml b/roles/upgrade_trixie/tasks/main.yml new file mode 100644 index 0000000..f8a8c4b --- /dev/null +++ b/roles/upgrade_trixie/tasks/main.yml @@ -0,0 +1,107 @@ +--- +- name: Get distribution version + setup: + filter: ansible_distribution* +- name: Skip if not Debian 12 + meta: end_host + when: ansible_distribution != 'Debian' or ansible_distribution_major_version != '12' +- name: apt clean + apt: + clean: yes + become: yes +- name: Get filesystem facts + setup: + filter: ansible_mounts +- name: Fail if free space on / is below 5 GiB + ansible.builtin.assert: + that: + - item.size_available > (5 * 1024 * 1024 * 1024) + fail_msg: "Free disk space on {{ item.mount }} is below 5 GiB" + loop: "{{ ansible_mounts }}" + when: item.mount == "/" +- name: All apt packages up to date + apt: + upgrade: dist + update_cache: yes + become: yes +- name: apt autoremove + apt: + autoremove: yes + become: yes +- name: apt clean + apt: + clean: yes + become: yes +- name: Check if reboot required + ansible.builtin.stat: + path: /run/reboot-required + get_checksum: no + register: reboot_required_file +- name: Reboot if required + ansible.builtin.reboot: + msg: "Reboot initiated by Ansible" + connect_timeout: 5 + reboot_timeout: 600 + pre_reboot_delay: 0 + post_reboot_delay: 60 + test_command: whoami + when: reboot_required_file.stat.exists + become: true +- name: Switch OS from bookworm to trixie + ansible.builtin.replace: + path: /etc/apt/sources.list + regexp: 'bookworm' + replace: 'trixie' + become: yes +- name: Find all 3rd-party repos + ansible.builtin.find: + paths: /etc/apt/sources.list.d + patterns: '*' + recurse: no + register: third_party_repos +- name: Switch 3rd-party repos from bookworm to trixie + ansible.builtin.replace: + path: "{{ item.path }}" + regexp: 'bookworm' + replace: 'trixie' + loop: "{{ third_party_repos.files }}" + loop_control: + label: "{{ item.path }}" + become: yes +- name: Use apt to move to trixie + apt: + upgrade: dist + update_cache: yes + become: yes +- name: Get distribution version + setup: + filter: ansible_distribution* +- name: Fail if not Debian 13 + assert: + that: + - ansible_distribution_major_version == '13' + fail_msg: "Upgrade to Debian 13 failed" +- name: apt autoremove + apt: + autoremove: yes + become: yes +- name: apt clean + apt: + clean: yes + become: yes +- name: Reboot on trixie + ansible.builtin.reboot: + msg: "Reboot initiated by Ansible" + connect_timeout: 5 + reboot_timeout: 600 + pre_reboot_delay: 0 + post_reboot_delay: 60 + test_command: whoami + become: yes +- name: Modernize apt sources + ansible.builtin.command: + cmd: apt -y modernize-sources + become: yes +- name: Pause for 5 minutes for staggered upgrades + pause: + minutes: 5 diff --git a/roles/vim/files/.vimrc b/roles/vim/files/.vimrc new file mode 100644 index 0000000..f3cb92c --- /dev/null +++ b/roles/vim/files/.vimrc @@ -0,0 +1,27 @@ +" Basic Quality of Life +set nocompatible +filetype plugin indent on +syntax on +set number +set relativenumber " Great for jumping lines in code +set mouse=a +set clipboard=unnamedplus + +" Ghostty / Modern Terminal Compatibility +if exists('+termguicolors') + let &t_8f = "\[38;2;%lu;%lu;%lum" + let &t_8b = "\[48;2;%lu;%lu;%lum" + set termguicolors +endif + +" Search and UI +set hlsearch +set incsearch +set ignorecase +set smartcase +set wildmenu + +" Tab Settings (Standardized for the Lab) +set tabstop=4 +set shiftwidth=4 +set expandtab diff --git a/roles/vim/tasks/main.yml b/roles/vim/tasks/main.yml new file mode 100644 index 0000000..3827135 --- /dev/null +++ b/roles/vim/tasks/main.yml @@ -0,0 +1,14 @@ +- name: Install Vim + ansible.builtin.apt: + name: vim + state: present + +- name: Configure Vim for root + include_tasks: setup_user.yml + vars: + v_user: root + +- name: Configure Vim for volker + include_tasks: setup_user.yml + vars: + v_user: volker diff --git a/roles/vim/tasks/setup_user.yml b/roles/vim/tasks/setup_user.yml new file mode 100644 index 0000000..6852878 --- /dev/null +++ b/roles/vim/tasks/setup_user.yml @@ -0,0 +1,27 @@ +- name: Define home path + set_fact: + v_home: "{{ '/root' if v_user == 'root' else '/home/' + v_user }}" + +- name: Create .vim directories + file: + path: "{{ v_home }}/.vim/autoload" + state: directory + owner: "{{ v_user }}" + mode: '0755' + +- name: Install vim-plug + get_url: + url: https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim + dest: "{{ v_home }}/.vim/autoload/plug.vim" + owner: "{{ v_user }}" + +- name: Deploy .vimrc from template + template: + src: vimrc.j2 + dest: "{{ v_home }}/.vimrc" + owner: "{{ v_user }}" + +- name: Run PlugInstall + become_user: "{{ v_user }}" + command: vim +PlugInstall +qall + changed_when: false diff --git a/roles/vim/templates/vimrc.j2 b/roles/vim/templates/vimrc.j2 new file mode 100644 index 0000000..cab6db6 --- /dev/null +++ b/roles/vim/templates/vimrc.j2 @@ -0,0 +1,49 @@ +" --- Basic Quality of Life --- +set nocompatible +filetype plugin indent on +syntax on +set number +set relativenumber +set mouse=r +set clipboard=unnamedplus + +" --- Plugin Management (vim-plug) --- +call plug#begin('~/.vim/plugged') +Plug 'ojroques/vim-oscyank' +call plug#end() + +" --- Ghostty / Modern Terminal Compatibility --- +if (has("termguicolors")) + " Fix for some older vim versions in modern terms + let &t_8f = "\[38;2;%lu;%lu;%lum" + let &t_8b = "\[48;2;%lu;%lu;%lum" + set termguicolors +endif + +" --- Smart OSC52 Yanking (Works with Ghostty) --- +" This allows copying to your Mac clipboard over SSH +if has('autocmd') + autocmd TextYankPost * if v:event.operator is 'y' && v:event.regname is '' | execute 'OSCYankReg "' | endif +endif + +" --- UI and Search --- +set hlsearch +set incsearch +set ignorecase +set smartcase +set wildmenu + +" --- Tab Settings (Standardized for the Lab) --- +set tabstop=4 +set shiftwidth=4 +set expandtab + +" --- User Specific Logic --- +{% if v_user == 'root' %} +" Visual warning that you are editing as ROOT +hi StatusLine ctermbg=red ctermfg=white +hi StatusLineNC ctermbg=red ctermfg=gray +{% endif %} + +" Add user identity to status line +set statusline=%f\ %h%m%r%=USER:\ {{ v_user }}\ %p%% diff --git a/site.yml b/site.yml new file mode 100644 index 0000000..75e9e98 --- /dev/null +++ b/site.yml @@ -0,0 +1,42 @@ +#- name: Provision All Nodes +# hosts: all_nodes +# become: yes +# roles: +# - role: common # Identity, mDNS, Base packages +# - role: security # SSH Keys +# - role: vim # The multi-user Ghostty setup + + +# TIER 1: All nodes get the exporter so they can be "seen" +- name: Provision All Nodes + hosts: all_nodes + become: true + roles: + - common # This should install prometheus-node-exporter + - security + - vim + - monitoring +## TIER 2: ONLY the monitor node gets the heavy stack +#- name: Setup Monitoring Central +# hosts: monitor +# become: true +# roles: +# - monitoring # This installs Grafana, InfluxDB, and the Prometheus Server + + +# Setup the Fileserver (The part we just built) +- name: Setup File Storage + hosts: smb_servers # Use a group name here + tags: fileserver + roles: + - fileserver + +- name: Setup Pi Backup Storage + hosts: goldeneye # <--- Only runs on your Pi + roles: + - backup_server + +- name: Provision Reverse Proxy Server + hosts: reverse_proxies + roles: + - reverse_proxy diff --git a/tasks/reboot_logic.yml b/tasks/reboot_logic.yml new file mode 100644 index 0000000..0d23525 --- /dev/null +++ b/tasks/reboot_logic.yml @@ -0,0 +1,26 @@ +--- +- name: Check if reboot is required + ansible.builtin.stat: + path: /var/run/reboot-required + register: reboot_required_file + +- name: Perform Reboot Block + when: reboot_required_file.stat.exists + block: + - name: Handle Proxmox Guests (Endor only) + when: inventory_hostname == 'endor' + ansible.builtin.shell: "pvesh create /nodes/localhost/stopall" + failed_when: false + + - name: Reboot the machine + ansible.builtin.reboot: + msg: "Reboot initiated by Ansible for updates" + reboot_timeout: 600 + post_reboot_delay: 30 + + - name: Wait for Node Exporter to respond + ansible.builtin.wait_for: + port: 9100 + host: "{{ ansible_host }}" + delay: 10 + timeout: 300 diff --git a/templates/telegraf.conf.j2 b/templates/telegraf.conf.j2 new file mode 100644 index 0000000..9dfb705 --- /dev/null +++ b/templates/telegraf.conf.j2 @@ -0,0 +1,35 @@ +[agent] + interval = "10s" + round_interval = true + metric_batch_size = 1000 + metric_buffer_limit = 10000 + collection_jitter = "0s" + flush_interval = "10s" + hostname = "{{ inventory_hostname }}" + +[[outputs.influxdb]] + urls = ["http://192.168.123.101:8086"] # Your InfluxDB IP + database = "proxmox" + +[[inputs.cpu]] + percpu = true + totalcpu = true + collect_cpu_time = false + report_active = false +[[inputs.mem]] +[[inputs.disk]] + ignore_fs = ["tmpfs", "devtmpfs", "devfs", "iso9660", "overlay", "aufs", "squashfs"] +[[inputs.system]] +[[inputs.temp]] # This is the magic for the Raspberry Pi temperature + +[[inputs.zfs]] + ## ZFS pool metrics (This is what we need for the bar) + poolMetrics = true + ## Dataset metrics (Optional: for individual LXC/VM disks) + datasetMetrics = true + +# Keep your other inputs too +[[inputs.cpu]] +[[inputs.mem]] +[[inputs.disk]] +[[inputs.system]] diff --git a/unifi_secrets.yml b/unifi_secrets.yml new file mode 100644 index 0000000..65dcf29 --- /dev/null +++ b/unifi_secrets.yml @@ -0,0 +1,9 @@ +$ANSIBLE_VAULT;1.1;AES256 +64336435353835363662616666663737643962323663353663313265656231366466623739386265 +3132633630373533316139316163363966333564653639640a303163353039666231336434373366 +37623438363065633539353964613264653635613365343438326435303934393866336639373932 +3336663165663338620a383536363061636230313136396364626164623431303837366462346334 +66376266306336383666313966353930326261623361393639343033346262326336623662386662 +61353063366531333765626438636133613635613361386665373438303931616131353561626436 +35343334626462653430643662306537393333646233623632343934303366636635343166663665 +64663436333666333734 diff --git a/update_all.yml b/update_all.yml new file mode 100644 index 0000000..8d29c4d --- /dev/null +++ b/update_all.yml @@ -0,0 +1,31 @@ +--- +- name: Update and Upgrade All Nodes + hosts: all_nodes + gather_facts: yes + become: yes + + tasks: + - name: Run apt update and apt upgrade + ansible.builtin.apt: + upgrade: dist + update_cache: yes + autoremove: yes + autoclean: yes + when: ansible_os_family == "Debian" + + - name: Check if a reboot is required + ansible.builtin.stat: + path: /var/run/reboot-required + register: reboot_required_file + + - name: Reboot the server if required (VMs only) + ansible.builtin.reboot: + msg: "Reboot initiated by Ansible due to kernel updates" + connect_timeout: 5 + reboot_timeout: 300 + pre_reboot_delay: 0 + post_reboot_delay: 30 + test_command: whoami + when: + - reboot_required_file.stat.exists + - "'physical_iron' not in group_names" # Verhindert, dass Proxmox-Nodes ungeplant neustarten