Merge pull request #274 from outis1one/claude/ionos-script-integration-x32ofw
Fix ensure_coturn_user leaving callers in the wrong directory
This commit is contained in:
@@ -33,28 +33,107 @@ 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).
|
||||
The PAT is stripped from the stored remote URL after cloning.
|
||||
|
||||
**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).
|
||||
<details>
|
||||
<summary><b>Cloud provider install-script / user-data field (IONOS, DigitalOcean, Hetzner, ...)</b></summary>
|
||||
|
||||
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.)
|
||||
`cloud-init.sh`, or paste its contents (below) 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.
|
||||
the script if you've provisioned a separate sudo user instead.
|
||||
|
||||
```bash
|
||||
#!/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 whole file's contents into the provider's install-script /
|
||||
# user-data field (or use an "import from file" option if it has one).
|
||||
# User-data fields run the content you give them directly — they don't fetch
|
||||
# a URL — so paste the script itself, not a link to it.
|
||||
#
|
||||
# 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."
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
## Usage
|
||||
|
||||
|
||||
+14
-1
@@ -810,7 +810,20 @@ ensure_coturn_user() {
|
||||
if [ ! -d "$DOCKER_DIR/coturn" ]; then
|
||||
if declare -F install_coturn >/dev/null 2>&1; then
|
||||
log_info "No shared coturn (TURN/STUN) server yet — setting one up for $_consumer..."
|
||||
install_coturn || { log_warning "coturn setup failed — $_consumer will run without TURN."; return 1; }
|
||||
# install_coturn cd's into $DOCKER_DIR/coturn and never cd's back —
|
||||
# the caller (e.g. asterisk.sh, already cd'd into its own install
|
||||
# directory) would otherwise return here with the wrong cwd and go
|
||||
# on to write ITS docker-compose.yml/.env into coturn's directory
|
||||
# instead of its own. Confirmed live: this clobbered coturn's
|
||||
# compose file and left the consumer's own directory without one,
|
||||
# so its later `docker compose up --build` failed with "Dockerfile:
|
||||
# no such file or directory" (no Dockerfile in coturn's directory).
|
||||
local _caller_pwd
|
||||
_caller_pwd="$(pwd)"
|
||||
install_coturn
|
||||
local _coturn_rc=$?
|
||||
cd "$_caller_pwd" || true
|
||||
[ "$_coturn_rc" -ne 0 ] && { log_warning "coturn setup failed — $_consumer will run without TURN."; return 1; }
|
||||
else
|
||||
log_warning "services/coturn.sh not loaded — $_consumer will run without TURN."
|
||||
log_warning "Run: sudo ./setup.sh coturn"
|
||||
|
||||
Reference in New Issue
Block a user