Files
ben 2b126ee4e6
CI / test (push) Successful in 24s
CI / build-and-push (push) Successful in 18s
CI / deploy (push) Successful in 13s
Fix deploy asset check to use forwarded HTTPS headers.
Curling localhost without X-Forwarded-Proto always yields http:// URLs even when trustProxies is correct behind Caddy.
2026-08-12 23:32:14 +02:00

123 lines
4.0 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
usage() {
cat <<'EOF'
Deploy a pre-built APP_IMAGE to one or more AndyTranscribe directories.
Environment:
APP_IMAGE Required. e.g. gitea.z00.nu/ben/andytranscribe:abc1234
DEPLOY_PATHS Comma-separated instance directories (default: current directory)
DEPLOY_SHA Optional git SHA to hard-reset each directory to (CI sets this)
GIT_PULL When 1 (default) and DEPLOY_SHA is empty, run git pull --ff-only
Usage:
APP_IMAGE=gitea.z00.nu/ben/andytranscribe:tag DEPLOY_PATHS=$HOME/andyTranscibe ./scripts/deploy-production.sh
EOF
}
IMAGE="${APP_IMAGE:-${1:-}}"
if [[ -z "${IMAGE}" ]]; then
usage >&2
exit 1
fi
PATHS_CSV="${DEPLOY_PATHS:-${2:-.}}"
GIT_PULL="${GIT_PULL:-1}"
DEPLOY_SHA="${DEPLOY_SHA:-}"
IFS=',' read -r -a DIRS <<< "${PATHS_CSV}"
for dir in "${DIRS[@]}"; do
dir="${dir#"${dir%%[![:space:]]*}"}"
dir="${dir%"${dir##*[![:space:]]}"}"
if [[ ! -d "${dir}" ]]; then
echo "Missing instance directory: ${dir}" >&2
exit 1
fi
name="$(basename "${dir}")"
echo "==> Deploying ${IMAGE} in ${dir}"
(
cd "${dir}"
if git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
if [[ -n "${DEPLOY_SHA}" ]]; then
git fetch --force origin "${DEPLOY_SHA}"
git checkout --force --detach "${DEPLOY_SHA}"
git reset --hard "${DEPLOY_SHA}"
# Drop local edits/hot-patches; keep runtime data and secrets.
git clean -fd \
--exclude=database/ \
--exclude=storage/ \
--exclude=.env \
--exclude=.env.*
elif [[ "${GIT_PULL}" == "1" ]]; then
git pull --ff-only
fi
fi
export APP_IMAGE="${IMAGE}"
export COMPOSE_PROJECT_NAME="${COMPOSE_PROJECT_NAME:-${name,,}}"
compose_files=(-f docker-compose.yml)
if [[ -f compose.z00.yaml ]]; then
compose_files+=(-f compose.z00.yaml)
fi
if grep -q '^APP_IMAGE=' .env 2>/dev/null; then
sed -i "s|^APP_IMAGE=.*|APP_IMAGE=${IMAGE}|" .env
else
printf '\nAPP_IMAGE=%s\n' "${IMAGE}" >> .env
fi
docker compose "${compose_files[@]}" pull app queue reverb
docker compose "${compose_files[@]}" up -d --remove-orphans
docker compose "${compose_files[@]}" ps
app_port="$(awk -F= '/^APP_HOST_PORT=/ {print $2; exit}' .env 2>/dev/null || true)"
app_port="${app_port:-18080}"
health_url="http://127.0.0.1:${app_port}/up"
echo "waiting for ${health_url}"
ok=0
for _ in $(seq 1 45); do
if curl -fsS "${health_url}" >/dev/null 2>&1; then
echo "healthy"
ok=1
break
fi
sleep 2
done
if [[ "${ok}" -ne 1 ]]; then
echo "ERROR: health check failed for ${name}" >&2
exit 1
fi
# Hit /login as the public HTTPS edge would (trustProxies needs forwarded proto).
app_url="$(awk -F= '/^APP_URL=/ {print $2; exit}' .env 2>/dev/null || true)"
app_url="${app_url:-https://transcribe.z00.nu}"
public_host="$(python3 - <<PY
from urllib.parse import urlparse
print(urlparse("${app_url}").hostname or "transcribe.z00.nu")
PY
)"
asset_scheme="$(
curl -fsS \
-H "X-Forwarded-Proto: https" \
-H "X-Forwarded-Host: ${public_host}" \
-H "X-Forwarded-Port: 443" \
"http://127.0.0.1:${app_port}/login" \
| grep -oE 'https?://[^"'\'' ]+\.css' \
| head -1 || true
)"
if [[ "${asset_scheme}" == http://* ]]; then
echo "ERROR: login page still emits http:// asset URLs (${asset_scheme})" >&2
exit 1
fi
echo "asset check ok: ${asset_scheme:-no absolute css url (relative/ok)}"
)
done
echo "Deploy complete: ${IMAGE}"