Merge pull request #271 from outis1one/claude/ionos-script-integration-x32ofw

Add cloud-init.sh for provider install-script/user-data fields
This commit is contained in:
Outis
2026-08-09 22:33:42 -04:00
committed by GitHub
2 changed files with 92 additions and 0 deletions
+21
View File
@@ -33,6 +33,27 @@ the wizard — the USB can be unplugged once setup starts.
sudo bash bootstrap.sh --pat ghp_xxxxxxxxxxxxxxxxxxxx
```
Use a fine-grained read-only PAT scoped to just this repo (Contents: Read).
**Cloud provider install-script / user-data field (IONOS, DigitalOcean,
Hetzner, ...):** these run as root with no terminal attached while the
image is still being provisioned, so `bootstrap.sh`'s interactive hand-off
doesn't apply yet. Use `cloud-init.sh` instead — it's a plain cloud-init
user-data shell script (starts with `#!/bin/bash`, no `#cloud-config` YAML).
IONOS's server-creation screen has a **User Data** box under "Scripts" with
a **Script Type** choice of *Cloud Config* or *Shell Script* — pick
**Shell Script**, then either click **Import from file** and select
`cloud-init.sh`, or paste its contents directly. User-data fields run the
script's own content; they don't fetch a URL, so paste/import the file
itself rather than a link to it. (DigitalOcean/Hetzner's plain "User data"
textbox works the same way — paste the script contents in directly.)
It clones the repo in the background during provisioning and installs a
one-shot login hook. The provider boots Ubuntu 24.04, this runs unattended,
and by the time you SSH in the whiptail service menu is already waiting for
you — same experience as `bootstrap.sh`, just already started. Assumes a
root login (the default for all three providers above); see the comments in
`cloud-init.sh` if you've provisioned a separate sudo user instead.
The PAT is stripped from the stored remote URL after cloning.
## Usage
Executable
+71
View File
@@ -0,0 +1,71 @@
#!/bin/bash
# cloud-init.sh — payload for a cloud provider's "install script" / user-data
# field (IONOS Cloud Server image deploy, DigitalOcean droplet user-data,
# Hetzner Cloud user-data, etc). The provider runs this as root, unattended,
# with no TTY, while the box is still being provisioned — before you have
# ever logged in.
#
# It deliberately does NOT run the interactive wizard itself (there's no
# terminal for whiptail to talk to yet). Instead it does two things:
#
# 1. Clones this repo to /root/ubuntu-post-install (pulls if already there).
# 2. Installs a one-shot /etc/profile.d hook that launches setup.sh —
# the normal whiptail service menu — the first time you actually log
# in over SSH, then deletes itself so it never fires again.
#
# End result: the provider boots Ubuntu 24.04, this runs in the background,
# and by the time you SSH in the checklist menu is sitting there waiting —
# the same experience as running bootstrap.sh by hand, just already started.
#
# Usage: paste this file's raw URL into the provider's install-script /
# user-data field, e.g.
# https://raw.githubusercontent.com/outis1one/ubuntu-post-install/main/cloud-init.sh
#
# Assumes the provider logs you in as root (the default for IONOS Cloud
# Server, DigitalOcean droplets, and Hetzner Cloud server images). If you've
# provisioned a separate non-root sudo user instead, the hook won't reach
# you automatically — SSH in and run:
# sudo bash /root/ubuntu-post-install/setup.sh
set -euo pipefail
if [ "$(id -u)" -ne 0 ]; then
echo "cloud-init.sh must run as root — that's how provider install-script hooks already run it." >&2
exit 1
fi
REPO_URL="https://github.com/outis1one/ubuntu-post-install.git"
DEST="/root/ubuntu-post-install"
MARKER="/root/.ubuntu-post-install-pending"
HOOK="/etc/profile.d/99-ubuntu-post-install.sh"
export DEBIAN_FRONTEND=noninteractive
command -v git >/dev/null 2>&1 || { apt-get update -qq && apt-get install -y git; }
if [ -d "$DEST/.git" ]; then
git -C "$DEST" pull --ff-only || true
else
git clone "$REPO_URL" "$DEST"
fi
touch "$MARKER"
# POSIX sh, not bash — /etc/profile.d/*.sh gets sourced by whatever shell
# the login uses, not necessarily bash.
cat > "$HOOK" << 'EOF'
# Installed by cloud-init.sh — launches the ubuntu-post-install wizard on
# the first interactive login, then removes itself so it never fires again.
MARKER="/root/.ubuntu-post-install-pending"
HOOK="/etc/profile.d/99-ubuntu-post-install.sh"
DEST="/root/ubuntu-post-install"
if [ -f "$MARKER" ] && [ -t 0 ] && [ "$(id -u)" -eq 0 ] && [ -f "$DEST/setup.sh" ]; then
rm -f "$MARKER" "$HOOK"
echo ""
echo "ubuntu-post-install: launching the setup wizard..."
echo ""
bash "$DEST/setup.sh"
fi
EOF
chmod 644 "$HOOK"
echo "cloud-init.sh: repo cloned to $DEST — the setup wizard will launch on first login."