Initial Lab Setup

This commit is contained in:
2026-07-06 16:45:51 +02:00
commit 05184d778d
52 changed files with 2526 additions and 0 deletions
+3
View File
@@ -0,0 +1,3 @@
- name: Update Initramfs
ansible.builtin.command: update-initramfs -u
become: yes
+102
View File
@@ -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
+1
View File
@@ -0,0 +1 @@
Acquire::http::Proxy-Auto-Detect "/usr/local/bin/apt-proxy-detect.sh";
+11
View File
@@ -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
+1
View File
@@ -0,0 +1 @@
volker ALL=(ALL) NOPASSWD: ALL
+11
View File
@@ -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
+300
View File
@@ -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]
+78
View File
@@ -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
+200
View File
@@ -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
+290
View File
@@ -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]
+22
View File
@@ -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]
+4
View File
@@ -0,0 +1,4 @@
- name: Restart Samba
ansible.builtin.service:
name: smbd
state: restarted
+47
View File
@@ -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
+27
View File
@@ -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
@@ -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 %}
+5
View File
@@ -0,0 +1,5 @@
---
- name: Restart Prometheus
ansible.builtin.systemd:
name: prometheus
state: restarted
+85
View File
@@ -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
@@ -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 %}
+6
View File
@@ -0,0 +1,6 @@
---
- name: Restart Caddy
ansible.builtin.systemd:
name: caddy
state: restarted
become: yes
+30
View File
@@ -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
+146
View File
@@ -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
#
@@ -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
+60
View File
@@ -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
+107
View File
@@ -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
+27
View File
@@ -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 = "\<Esc>[38;2;%lu;%lu;%lum"
let &t_8b = "\<Esc>[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
+14
View File
@@ -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
+27
View File
@@ -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
+49
View File
@@ -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 = "\<Esc>[38;2;%lu;%lu;%lum"
let &t_8b = "\<Esc>[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%%