Compare commits
No commits in common. "69e9a76dcd908ebff423e8c21dfc81e6b3bc7a86" and "375fddaab08a9d1bf8a892f3e9b53d284de28a04" have entirely different histories.
69e9a76dcd
...
375fddaab0
6 changed files with 0 additions and 157 deletions
|
|
@ -1,30 +0,0 @@
|
|||
# Ansible
|
||||
|
||||
Run from David's Linux PC over SSH — nothing is installed on the managed hosts.
|
||||
Run all commands from inside this `ansible/` directory so `ansible.cfg` is picked up.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- `sudo pacman -S ansible`
|
||||
- One SSH key per client device (`~/.ssh/id_ed25519_homelab`), copied to each host with `ssh-copy-id`.
|
||||
- A `~/.ssh/config` entry per host (`User`, `IdentityFile`, `IdentitiesOnly yes`). The inventory
|
||||
only lists host names, so these must match the `Host` lines exactly.
|
||||
|
||||
## Hosts
|
||||
|
||||
| Group | Host | Notes |
|
||||
|---|---|---|
|
||||
| `octoprint` | `octopi.home.staffenberger.at` | RPi4, IoT VLAN — the learning guinea pig |
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
ansible octoprint -m ping # connectivity check
|
||||
ansible-playbook playbooks/update.yml --list-hosts # which hosts would this touch?
|
||||
ansible-playbook playbooks/update.yml --check --diff # dry run
|
||||
ansible-playbook playbooks/update.yml # apt upgrade + reboot if required
|
||||
ansible-playbook playbooks/octoprint.yml --check --diff # dry run of the Pi's configuration
|
||||
ansible-playbook playbooks/octoprint.yml # apply the Pi's configuration (after changes or a fresh flash)
|
||||
```
|
||||
|
||||
Add `-K` if a play fails with "Missing sudo password".
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
[defaults]
|
||||
inventory = inventory.yml
|
||||
# Use whatever Python the target has without printing a discovery warning each run
|
||||
interpreter_python = auto_silent
|
||||
# Opt in to the future default now: facts only via ansible_facts['...'], not ansible_* vars
|
||||
inject_facts_as_vars = False
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
# Host names match the `Host` entries in ~/.ssh/config, which supply the user
|
||||
# and key — so no connection details (or secrets) live in this repo.
|
||||
all:
|
||||
children:
|
||||
octoprint:
|
||||
hosts:
|
||||
octopi.home.staffenberger.at:
|
||||
|
|
@ -1,63 +0,0 @@
|
|||
# OS-level configuration of the OctoPrint Pi, on top of a stock OctoPi image.
|
||||
# OctoPrint's own settings/plugins/profiles come from its Backup & Restore zip,
|
||||
# not from here (OctoPrint rewrites its own config.yaml) — see docs/todo.md.
|
||||
- name: Configure the OctoPrint Pi
|
||||
hosts: octoprint
|
||||
become: true
|
||||
vars:
|
||||
timezone: Europe/Vienna
|
||||
|
||||
tasks:
|
||||
- name: Set the timezone
|
||||
community.general.timezone:
|
||||
name: "{{ timezone }}"
|
||||
|
||||
# ModemManager probes new serial devices for modems — a printer on /dev/ttyACM0
|
||||
# is one, and the probing can disturb the connection. There's no modem here.
|
||||
- name: Disable and mask ModemManager
|
||||
ansible.builtin.systemd_service:
|
||||
name: ModemManager
|
||||
state: stopped
|
||||
enabled: false
|
||||
masked: true
|
||||
|
||||
- name: Disable the Bluetooth services
|
||||
ansible.builtin.systemd_service:
|
||||
name: "{{ item }}"
|
||||
state: stopped
|
||||
enabled: false
|
||||
loop:
|
||||
- bluetooth
|
||||
- hciuart
|
||||
|
||||
- name: Turn off the Bluetooth hardware (applies after reboot)
|
||||
ansible.builtin.lineinfile:
|
||||
path: /boot/firmware/config.txt
|
||||
regexp: '^dtoverlay=disable-bt$'
|
||||
line: dtoverlay=disable-bt
|
||||
insertafter: '^\[all\]$'
|
||||
notify: Reboot
|
||||
|
||||
# Key login only. sshd uses the first value it reads, and files in
|
||||
# sshd_config.d are read (alphabetically) before the main sshd_config.
|
||||
- name: Disable SSH password login
|
||||
ansible.builtin.copy:
|
||||
dest: /etc/ssh/sshd_config.d/10-no-passwords.conf
|
||||
content: |
|
||||
# Managed by Ansible (Infrastructure repo) — key login only
|
||||
PasswordAuthentication no
|
||||
KbdInteractiveAuthentication no
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0644"
|
||||
validate: /usr/sbin/sshd -t -f %s
|
||||
notify: Restart ssh
|
||||
|
||||
handlers:
|
||||
- name: Restart ssh
|
||||
ansible.builtin.systemd_service:
|
||||
name: ssh
|
||||
state: restarted
|
||||
|
||||
- name: Reboot
|
||||
ansible.builtin.reboot:
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
# Upgrade all apt packages and reboot only if the upgrade asks for it.
|
||||
# Don't run against the OctoPrint Pi while a print is running — a reboot kills it.
|
||||
# OctoPrint itself lives in its own Python venv and is updated from its web UI, not apt.
|
||||
- name: Update Debian-based hosts
|
||||
hosts: octoprint
|
||||
become: true
|
||||
tasks:
|
||||
- name: Upgrade all packages
|
||||
ansible.builtin.apt:
|
||||
update_cache: true
|
||||
upgrade: dist
|
||||
autoremove: true
|
||||
|
||||
# Raspberry Pi OS doesn't create /var/run/reboot-required after kernel updates,
|
||||
# so compare the running kernel (from facts, gathered before the upgrade) with the
|
||||
# newest installed kernel of the same flavour (e.g. rpi-v8).
|
||||
- name: Find the newest installed kernel of the running flavour
|
||||
ansible.builtin.shell: |
|
||||
set -o pipefail
|
||||
ls /lib/modules | grep -- '-{{ ansible_facts['kernel'] | regex_replace("^[^-]*-", "") }}$' | sort -V | tail -n 1
|
||||
args:
|
||||
executable: /bin/bash
|
||||
register: newest_kernel
|
||||
changed_when: false
|
||||
check_mode: false # read-only, so safe to run in --check mode too
|
||||
|
||||
- name: Check whether a package asked for a reboot
|
||||
ansible.builtin.stat:
|
||||
path: /var/run/reboot-required
|
||||
register: reboot_flag
|
||||
|
||||
- name: Reboot if needed
|
||||
ansible.builtin.reboot:
|
||||
when: reboot_flag.stat.exists or newest_kernel.stdout != ansible_facts['kernel']
|
||||
17
docs/todo.md
17
docs/todo.md
|
|
@ -28,23 +28,6 @@ Living checklist. See [status.md](status.md) for the full decisions/context behi
|
|||
|
||||
- [ ] **Real (non-self-signed) certificate for the NAS's own DSM access** — not crucial, DSM's cert warning is just cosmetic for local access. Leaning toward **`mkcert`** (local CA, install its root cert as trusted on your own devices once, zero external credentials/services involved) over Let's Encrypt DNS-01 through INWX — the latter would need either a scoped INWX API key (check if INWX offers one) or `acme.sh`'s manual mode (no credentials, but manual renewal every ~90 days); full INWX account credentials handed to a script was correctly ruled out as too broad a permission grant for this.
|
||||
|
||||
## Ansible — learning, started 2026-09-27
|
||||
|
||||
Setup lives in [`../ansible/`](../ansible/README.md). OctoPrint Pi is the guinea pig; the NUC is the real goal (status.md: Ansible from David's PC, no footprint on the server).
|
||||
|
||||
- [x] SSH key auth to the Pi: one key per *client device* (`id_ed25519_homelab`), not per server; `~/.ssh/config` entry with `IdentitiesOnly yes`.
|
||||
- [x] `ansible octoprint -m ping` works; `update.yml` run for real on 2026-09-27 (248 packages, kernel → 6.12.109). Gotchas: David's sudo needs a password → run with `-K`; Raspberry Pi OS does **not** create `/var/run/reboot-required` after kernel updates, so the playbook compares the running kernel with the newest installed one of the same flavour.
|
||||
- [ ] **Audit the Pi's hand-made changes** so a rebuild can reproduce them: `apt-mark showmanual`, enabled services, crontabs, `/boot/firmware/config.txt`, installed OctoPrint plugins. **Removed by hand 2026-09-27** (one-off cleanups don't belong in the config playbook — it describes what *should* be there, and an "ensure absent" task would fight future experiments): **Docker** (installed Sep 2026 for a Spoolman test, Spoolman already gone — packages, `docker.list` repo + `docker.asc` key, `/var/lib/docker`, `/var/lib/containerd`, `docker` group) and **nginx** (only the default site, never listening — `haproxy` holds 80/443 and fronts OctoPrint on `127.0.0.1:5000`). Rule going forward: experiment by hand, then either add it to the playbook or remove it; spool-manager-type services belong on the NUC anyway. The Pi 4 (**1 GB RAM**) boots the 32-bit `rpi-v7` kernel instead of the Bookworm default (64-bit `v8` kernel, 32-bit userland) — `config.txt` has an explicit `arm_64bit=0`, which appears to come with the OctoPi image (apt history shows the Pi is essentially a stock OctoPi flash, not years of in-place upgrades). **Decided: leave it.** With 1 GB there's no RAM to gain, and 32-bit userland uses slightly less memory; switching only the kernel isn't worth it before the rebuild. For the rebuild: a **32-bit** OctoPi image is fine on this Pi, using whatever kernel it boots by default. Still wanted from the audit: `config.txt`, enabled services, apt history.
|
||||
- [x] First *configuration* playbook `playbooks/octoprint.yml` (run 2026-09-27; verified: password SSH refused, timezone set, no Bluetooth device): timezone, ModemManager masked (probes the printer's serial port), Bluetooth off (services + `dtoverlay=disable-bt`), SSH password login off. Wi-Fi stays on — the Pi is on the IoT **Wi-Fi** now, no longer on the cable. nginx removal checked: webcam uses MJPEG (`webcamd`), not the HLS stream (`ffmpeg_hls`, which needed nginx).
|
||||
- [ ] **Rebuild procedure** (document once tested): flash current 32-bit OctoPi with Raspberry Pi Imager's OS customisation — hostname, user `david`, IoT Wi-Fi, SSH **public-key only** with `id_ed25519_homelab.pub` (Wi-Fi password stays out of the repo) → `ansible-playbook playbooks/octoprint.yml -K` → restore the OctoPrint backup. Test on a spare SD card.
|
||||
- [ ] **Automated OctoPrint backups** (deferred — basics first). Rebuild plan: flash card → run playbook → restore OctoPrint backup; OctoPrint's own state (settings, plugins, profiles) comes from its Backup & Restore zip, not Ansible (OctoPrint rewrites its own `config.yaml`, so templating it would fight the UI). Plan:
|
||||
1. Ansible deploys a nightly timer on the Pi running the backup CLI (`octoprint plugins backup:backup` — verify syntax/exclude flags first), excluding uploads/timelapses, keeping the last few. Alternative: the "Backup Scheduler" plugin, but that's UI config outside the repo.
|
||||
2. Off-device copy must be **pulled** — the `IoT → !IoT` ACL means the Pi can't push to the NAS (keep it that way). Interim: `update.yml` takes a backup and fetches it to David's PC before upgrading. Later: nightly pull from the NUC (Servers → IoT allowed) with a **dedicated key restricted via `rrsync`** to read-only access to the backup folder.
|
||||
3. Backup zips contain user hashes + API keys — store outside this repo (decide location, e.g. NAS share).
|
||||
- [ ] Split into roles (`common`, `updates`) + `group_vars`; `ansible-vault` for any secrets (e.g. OctoPrint API key for a "skip while printing" check).
|
||||
- [ ] Add the two personal Linux machines (`community.general.pacman` for Arch-based ones — not fully unattended, Arch updates occasionally need manual steps).
|
||||
- [ ] Provision the NUC with it (common role + Docker + Compose stacks).
|
||||
|
||||
## Backlog / lower priority
|
||||
|
||||
- [ ] **Change the Omada Controller auto-backup from daily to weekly** — daily is deliberate for now because so much config is changing; revisit once the switch/AP/VLAN work has settled and changes become infrequent.
|
||||
|
|
|
|||
Loading…
Reference in a new issue