Curling localhost without X-Forwarded-Proto always yields http:// URLs even when trustProxies is correct behind Caddy.
123 lines
4.0 KiB
Bash
Executable File
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}"
|