146 lines
4.6 KiB
Bash
Executable File
146 lines
4.6 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
# Run as root from host. This script pipes certificate material through the
|
|
# `code` user into the Prosody container via podman exec.
|
|
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
|
STACK_ENV="${STACK_ENV:-$ROOT_DIR/stack.env}"
|
|
if [[ -f "$STACK_ENV" ]]; then
|
|
set -a
|
|
. "$STACK_ENV"
|
|
set +a
|
|
fi
|
|
STACK_ID="${GIA_STACK_ID:-${STACK_ID:-}}"
|
|
STACK_ID="$(echo "$STACK_ID" | tr -cs 'a-zA-Z0-9._-' '-' | sed 's/^-*//; s/-*$//')"
|
|
|
|
if [[ -n "$STACK_ID" ]]; then
|
|
PROSODY_CONTAINER_DEFAULT="prosody_gia_${STACK_ID}"
|
|
else
|
|
PROSODY_CONTAINER_DEFAULT="prosody_gia"
|
|
fi
|
|
PROSODY_CONTAINER="${PROSODY_CONTAINER:-$PROSODY_CONTAINER_DEFAULT}"
|
|
MANAGE_SCRIPT="${MANAGE_SCRIPT:-$ROOT_DIR/utilities/prosody/manage_prosody_container.sh}"
|
|
ACME_BASE_DIR="${ACME_BASE_DIR:-/root/.acme.sh}"
|
|
CERT_NAME="${CERT_NAME:-${ACME_CERT_NAME:-}}"
|
|
|
|
FULLCHAIN_PATH="${FULLCHAIN_PATH:-}"
|
|
KEY_PATH="${KEY_PATH:-}"
|
|
CERT_PATH_IN_CONTAINER="${CERT_PATH_IN_CONTAINER:-/etc/prosody/certs/cert.pem}"
|
|
CONTAINER_WAIT_SECONDS="${CONTAINER_WAIT_SECONDS:-15}"
|
|
|
|
resolve_cert_paths() {
|
|
local cert_dir=""
|
|
local expected_key=""
|
|
if [[ -n "$CERT_NAME" ]]; then
|
|
cert_dir="$ACME_BASE_DIR/$CERT_NAME"
|
|
if [[ -r "$cert_dir/fullchain.cer" ]]; then
|
|
expected_key="$cert_dir/${CERT_NAME}.key"
|
|
if [[ -r "$expected_key" ]]; then
|
|
FULLCHAIN_PATH="$cert_dir/fullchain.cer"
|
|
KEY_PATH="$expected_key"
|
|
return 0
|
|
fi
|
|
KEY_PATH="$(find "$cert_dir" -maxdepth 1 -type f -name '*.key' | head -n1 || true)"
|
|
if [[ -n "$KEY_PATH" && -r "$KEY_PATH" ]]; then
|
|
FULLCHAIN_PATH="$cert_dir/fullchain.cer"
|
|
return 0
|
|
fi
|
|
fi
|
|
echo "Requested CERT_NAME '$CERT_NAME' does not provide readable fullchain/key under $cert_dir" >&2
|
|
return 1
|
|
fi
|
|
cert_dir="$(find "$ACME_BASE_DIR" -mindepth 1 -maxdepth 1 -type d \
|
|
-exec test -r '{}/fullchain.cer' ';' -printf '%T@ %p\n' \
|
|
| sort -nr \
|
|
| awk 'NR==1 {print $2}' || true)"
|
|
if [[ -z "$cert_dir" ]]; then
|
|
echo "No readable ACME certificate directories with fullchain.cer found under $ACME_BASE_DIR" >&2
|
|
return 1
|
|
fi
|
|
FULLCHAIN_PATH="$cert_dir/fullchain.cer"
|
|
KEY_PATH="$(find "$cert_dir" -maxdepth 1 -type f -name '*.key' | head -n1 || true)"
|
|
if [[ -z "$KEY_PATH" || ! -r "$KEY_PATH" ]]; then
|
|
echo "No readable key file (*.key) found in $cert_dir" >&2
|
|
return 1
|
|
fi
|
|
return 0
|
|
}
|
|
|
|
code_podman() {
|
|
su -s /bin/sh code -c "podman $*"
|
|
}
|
|
|
|
container_exists() {
|
|
code_podman "container exists '$PROSODY_CONTAINER'"
|
|
}
|
|
|
|
container_is_running() {
|
|
[[ "$(code_podman "inspect '$PROSODY_CONTAINER' --format '{{.State.Running}}'" 2>/dev/null || true)" == "true" ]]
|
|
}
|
|
|
|
ensure_running_container() {
|
|
if ! container_exists; then
|
|
echo "Prosody container '$PROSODY_CONTAINER' not found for user 'code'; attempting startup..." >&2
|
|
su -s /bin/sh code -c "cd '$ROOT_DIR/utilities/prosody' && '$MANAGE_SCRIPT' up"
|
|
fi
|
|
if ! container_exists; then
|
|
echo "Failed to create/start Prosody container: $PROSODY_CONTAINER" >&2
|
|
exit 1
|
|
fi
|
|
if ! container_is_running; then
|
|
code_podman "start '$PROSODY_CONTAINER'" >/dev/null 2>&1 || true
|
|
fi
|
|
local i=0
|
|
while (( i < CONTAINER_WAIT_SECONDS )); do
|
|
if container_is_running; then
|
|
return 0
|
|
fi
|
|
sleep 1
|
|
i=$((i + 1))
|
|
done
|
|
echo "Prosody container exists but is not running: $PROSODY_CONTAINER" >&2
|
|
code_podman "inspect '$PROSODY_CONTAINER' --format 'status={{.State.Status}} exit={{.State.ExitCode}} error={{.State.Error}}'" >&2 || true
|
|
echo "Recent Prosody logs:" >&2
|
|
code_podman "logs --tail 120 '$PROSODY_CONTAINER'" >&2 || true
|
|
exit 1
|
|
}
|
|
|
|
if [[ "$(id -u)" -ne 0 ]]; then
|
|
echo "This script must run as root." >&2
|
|
exit 1
|
|
fi
|
|
|
|
if [[ -z "$FULLCHAIN_PATH" || -z "$KEY_PATH" ]]; then
|
|
resolve_cert_paths
|
|
fi
|
|
|
|
if [[ ! -r "$FULLCHAIN_PATH" ]]; then
|
|
echo "Missing or unreadable fullchain: $FULLCHAIN_PATH" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if [[ ! -r "$KEY_PATH" ]]; then
|
|
echo "Missing or unreadable key: $KEY_PATH" >&2
|
|
exit 1
|
|
fi
|
|
|
|
ensure_running_container
|
|
|
|
cat "$FULLCHAIN_PATH" "$KEY_PATH" \
|
|
| sed '/^$/d' \
|
|
| su -s /bin/sh code -c "podman exec --user 0 -i '$PROSODY_CONTAINER' sh -lc 'cat > \"$CERT_PATH_IN_CONTAINER\"'"
|
|
|
|
su -s /bin/sh code -c "podman exec --user 0 '$PROSODY_CONTAINER' sh -lc '
|
|
set -e
|
|
chown prosody:prosody \"$CERT_PATH_IN_CONTAINER\"
|
|
chmod 0600 \"$CERT_PATH_IN_CONTAINER\"
|
|
if prosodyctl reload >/dev/null 2>&1; then
|
|
exit 0
|
|
fi
|
|
# In foreground/container mode prosodyctl may report \"Prosody is not running\"
|
|
# despite PID 1 being the active prosody process. HUP PID 1 as reload fallback.
|
|
kill -HUP 1
|
|
'"
|
|
|
|
echo "Prosody certificate updated and reloaded in container: $PROSODY_CONTAINER"
|