Files
automations/cloud-init
57_Wolve 7faa9098de feat: unified launcher, multi-OS hardening, login alerts & auto-updates
Restructure around a single entry point (automations.sh) with a Gum wizard and
a self-extracting bundle for repo-less installs. Add scripts/oslib.sh so the
provisioning scripts (setup-host, harden-ssh, harden-jumphost, sshuser) run on
Alpine/Debian/Alma; seed root keys from globals/.

- ntfy SSH-login alerts (user, source IP, key, region, jump target) via pam_exec
- daily auto-updates with AUTO_REBOOT=idle (reboots only when no SSH active) and
  opt-in Alpine stable-branch upgrades
- generic + per-deployment cloud-init; Gitea release workflow on tag
- README/LICENSE/.gitignore/.gitattributes (force LF); repo URLs -> Gitea
2026-06-12 14:56:02 -05:00
..

cloud-init/

Generic, distro-agnostic cloud-init templates for standing up a base host or a bastion from scratch. They run on Alpine, Debian, or Alma — the runcmd prelude detects the package manager and installs bash/git/curl before invoking the scripts.

Template What it does
base.yml Hostname (per the schema) + shared MOTD + seed root keys from globals/ + SSH hardening (harden-ssh.sh).
jumphost.yml Same base, but bastion hardening (harden-jumphost.sh) with an ssh-admins/ssh-jumpers split and a ProxyJump whitelist.

These are for the host itself. To stand up a Docker stack on a host, use the per-deployment cloud-init.yml under deployments/<name>/ instead (those clone the repo and run the stack's deploy.sh).

Usage

  1. Copy the template, fill in REPO_URL, HOST (<svc>-<n>, e.g. sto-1), and the other values at the top of the runcmd block.
  2. Paste it as the instance's user-data when creating the VM.
  3. On first boot the host names itself, installs the MOTD, seeds admin keys from globals/, and hardens SSH.

Hostnames follow ../globals/Network Domain Name Schema.md; our VMs skip the region code and use srvno.de as the base.

The harden scripts print a generated root private key to stdout, which lands in the cloud provider's serial/console log. Capture it there, or rely on the keys seeded from globals/authorized_keys (or SSH_KEYS_URL) and ignore it.