Initial VPS operations handbook

This commit is contained in:
windyboy
2026-08-03 12:26:42 +08:00
commit b73125e5bc
97 changed files with 3641 additions and 0 deletions
+73
View File
@@ -0,0 +1,73 @@
---
# Read-only control-plane audit. This play intentionally contains no package,
# file, service, container, or configuration mutation tasks.
- name: Audit managed VPS hosts without changes
hosts: managed
gather_facts: true
become: false
any_errors_fatal: false
tasks:
- name: Verify Docker Compose command is available
ansible.builtin.command:
argv:
- docker
- compose
- version
changed_when: false
- name: Inspect configured Compose project
ansible.builtin.command:
argv:
- docker
- compose
- --project-directory
- "{{ compose_project_dir }}"
- ps
- --all
register: audit_compose_ps
changed_when: false
failed_when: false
- name: Inspect failed systemd units
ansible.builtin.command:
argv:
- systemctl
- --failed
- --no-legend
- --no-pager
register: audit_failed_units
changed_when: false
failed_when: false
- name: Inspect filesystem capacity
ansible.builtin.command:
argv:
- df
- -P
- -x
- tmpfs
- -x
- devtmpfs
register: audit_filesystems
changed_when: false
- name: Inspect active listeners
ansible.builtin.command:
argv:
- ss
- -lntup
register: audit_listeners
changed_when: false
failed_when: false
- name: Report sanitized audit summary
ansible.builtin.debug:
msg:
host: "{{ inventory_hostname }}"
profile: "{{ healthcheck_profile }}"
os: "{{ ansible_distribution }} {{ ansible_distribution_version }}"
kernel: "{{ ansible_kernel }}"
compose_rc: "{{ audit_compose_ps.rc }}"
failed_units: "{{ audit_failed_units.stdout_lines | default([]) }}"
filesystem_lines: "{{ audit_filesystems.stdout_lines | default([]) }}"
listener_lines: "{{ audit_listeners.stdout_lines | default([]) }}"
+9
View File
@@ -0,0 +1,9 @@
---
# Baseline starts audit-only. Opt-in variables are deliberately false by default.
- name: Apply controlled common baseline
hosts: managed
become: true
gather_facts: false
roles:
- role: baseline
tags: [baseline, audit]
+9
View File
@@ -0,0 +1,9 @@
---
# Requires a target-local root-owned SMTP config; no credentials are passed here.
- name: Deploy health email alert integration
hosts: managed
become: true
gather_facts: false
roles:
- role: email_alert
tags: [healthcheck, email]
+8
View File
@@ -0,0 +1,8 @@
---
- name: Deploy daily local health checks
hosts: managed
become: true
gather_facts: false
roles:
- role: healthcheck
tags: [healthcheck, timers]
+9
View File
@@ -0,0 +1,9 @@
---
- name: Install or reconcile the single-node K3s server
hosts: k3s_servers
become: true
gather_facts: true
serial: 1
roles:
- role: k3s_server
tags: [k3s, matrix, mutating]
+30
View File
@@ -0,0 +1,30 @@
---
# Preview only. This playbook does not install updates, restart services, or
# change DNS/secrets. A separate, manually reviewed change is required to act.
- name: Preview pending maintenance without changes
hosts: managed
become: true
gather_facts: false
tasks:
- name: Check reboot requirement marker
ansible.builtin.stat:
path: /var/run/reboot-required
register: maintenance_reboot_marker
- name: Preview available package updates on Debian-family hosts
ansible.builtin.command:
argv:
- apt-get
- --just-print
- upgrade
register: maintenance_apt_preview
changed_when: false
failed_when: false
when: ansible_facts.os_family | default('Debian') == 'Debian'
- name: Report maintenance preview
ansible.builtin.debug:
msg:
host: "{{ inventory_hostname }}"
reboot_required: "{{ maintenance_reboot_marker.stat.exists }}"
package_preview: "{{ maintenance_apt_preview.stdout_lines | default([]) }}"
+8
View File
@@ -0,0 +1,8 @@
---
- name: Install local Matrix consistency backup jobs
hosts: matrix
become: true
gather_facts: false
roles:
- role: matrix_backup
tags: [matrix, backup, mutating]
+11
View File
@@ -0,0 +1,11 @@
---
- name: Reconcile Helm, cert-manager, and the Let's Encrypt issuer
hosts: k3s_servers
become: true
gather_facts: false
serial: 1
roles:
- role: helm_client
tags: [helm, matrix, mutating]
- role: cert_manager
tags: [cert_manager, matrix, mutating]
@@ -0,0 +1,9 @@
---
- name: Run the temporary Matrix HTTP-01 certificate smoke test
hosts: matrix
become: true
gather_facts: false
serial: 1
roles:
- role: matrix_certificate_smoke
tags: [matrix, certificates, smoke_test, mutating]
@@ -0,0 +1,8 @@
---
- name: Create non-secret Matrix Kubernetes foundation resources
hosts: matrix
become: true
gather_facts: false
roles:
- role: matrix_cluster_base
tags: [matrix, cluster_base, mutating]
@@ -0,0 +1,8 @@
---
- name: Install Matrix K3s local health checks
hosts: matrix
become: true
gather_facts: false
roles:
- role: matrix_healthcheck
tags: [matrix, healthcheck, timers]
+9
View File
@@ -0,0 +1,9 @@
---
# Read-only gate before a K3s or Matrix change.
- name: Validate Matrix K3s host readiness without changes
hosts: matrix
become: true
gather_facts: true
roles:
- role: k3s_preflight
tags: [matrix, preflight, read_only]
@@ -0,0 +1,8 @@
---
- name: Validate the pre-provisioned Matrix secret contract
hosts: matrix
become: true
gather_facts: false
roles:
- role: matrix_secret_contract
tags: [matrix, secrets, validation]
+99
View File
@@ -0,0 +1,99 @@
---
# Deploy the official ESS OCI chart on a K3s node.
# Pre-tasks create the non-secret values files on the target host.
# The matrix_stack role then validates and deploys the chart.
- name: Deploy the Matrix stack (ESS OCI chart)
hosts: matrix
become: true
gather_facts: false
serial: 1
pre_tasks:
- name: Ensure the ESS values directory exists
ansible.builtin.file:
path: /etc/ess
state: directory
owner: root
group: root
mode: "0700"
- name: Write hostnames values file
ansible.builtin.copy:
dest: /etc/ess/hostnames.yaml
owner: root
group: root
mode: "0600"
content: |
serverName: {{ matrix_server_name }}
elementWeb:
ingress:
host: {{ matrix_element_host }}
synapse:
ingress:
host: {{ matrix_synapse_host }}
matrixAuthenticationService:
ingress:
host: {{ matrix_mas_host }}
elementAdmin:
ingress:
host: {{ matrix_admin_host }}
matrixRTC:
ingress:
host: {{ matrix_rtc_host }}
- name: Write TLS values file
ansible.builtin.copy:
dest: /etc/ess/tls.yaml
owner: root
group: root
mode: "0600"
content: |
certManager:
clusterIssuer: letsencrypt-prod
ingress:
className: traefik
tlsEnabled: true
- name: Write single-node tuning values file
ansible.builtin.copy:
dest: /etc/ess/single-node.yaml
owner: root
group: root
mode: "0600"
content: |
# ESS single-node resource tuning for K3s
# Chart defaults are already single-node-friendly
postgres:
storage:
size: 20Gi
redis:
maxMemory: 128mb
matrixRTC:
enabled: false
- name: Verify values files are in place
ansible.builtin.stat:
path: "/etc/ess/{{ item }}"
loop:
- hostnames.yaml
- tls.yaml
- single-node.yaml
register: _values_check
- name: Assert all values files exist
ansible.builtin.assert:
that:
- item.stat.exists
- item.stat.isreg
- item.stat.pw_name == 'root'
loop: "{{ _values_check.results }}"
loop_control:
label: "{{ item.stat.path | default(item.item) }}"
roles:
- role: matrix_stack
tags: [matrix, stack, mutating]
+13
View File
@@ -0,0 +1,13 @@
---
# Intentionally targets only services with approved local dump/data sources.
# Set restic_enabled=true only after selecting a backend and provisioning the
# root-only repository config directly on each target.
- name: Deploy controlled Restic timers
hosts:
- vaultwarden
- powerdns
become: true
gather_facts: false
roles:
- role: restic
tags: [restic, backup]