Ctrl K
ComunidadGuías…

site/public/install.sh

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
#!/usr/bin/env bash
# Fresh, loopback-only quickstart using the verified Docker Hub release.
set +x
set -euo pipefail

fail() { printf 'Feedbacks: %s\n' "$*" >&2; exit 1; }

progress() { printf '\n[%s/7] %s\n' "$1" "$2"; }

download() {
  curl --fail --silent --show-error --location --connect-timeout 10 --max-time 90 \
    --retry 2 --retry-delay 1 --proto '=https' --proto-redir '=https' "$@"
}

read_release() {
  local key value
  version= image= checksum= revision=
  while IFS='=' read -r key value || [[ -n "$key" ]]; do
    case "$key" in
      version) [[ -z "$version" ]] || fail 'Duplicate release version.'; version=$value ;;
      image) [[ -z "$image" ]] || fail 'Duplicate release image.'; image=$value ;;
      compose_sha256) [[ -z "$checksum" ]] || fail 'Duplicate Compose checksum.'; checksum=$value ;;
      compose_revision) [[ -z "$revision" ]] || fail 'Duplicate Compose revision.'; revision=$value ;;
      *) fail 'Invalid stable release metadata. No containers were started.' ;;
    esac
  done < "$directory/release.txt"
  [[ "$version" =~ ^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$ ]] || fail 'Invalid stable version.'
  [[ "$image" =~ ^softinator/feedbacks@sha256:[a-f0-9]{64}$ ]] || fail 'Invalid release image.'
  [[ "$checksum" =~ ^[a-f0-9]{64}$ && "$revision" =~ ^[a-f0-9]{40}$ ]] || fail 'Invalid Compose release pin.'
}

management_commands() {
  printf 'Stop:   cd %q && docker compose --project-name %q stop\n' "$directory" "$project"
  printf 'Start:  cd %q && docker compose --project-name %q up -d --wait\n' "$directory" "$project"
  printf 'Status: cd %q && docker compose --project-name %q ps\n' "$directory" "$project"
  printf 'Logs:   cd %q && docker compose --project-name %q logs -f --tail=50\n' "$directory" "$project"
}

setup_stopped() {
  local directory=$feedbacks_setup_directory project=$feedbacks_setup_project
  printf '\nSetup stopped. Files and volumes are preserved in %s.\n' "$directory" >&2
  if [[ -n "${project:-}" && -f "$directory/.env" ]]; then management_commands >&2; fi
}

compose() {
  env -u FEEDBACKS_IMAGE -u APP_ORIGIN -u POSTGRES_PASSWORD -u ORGANIZATION_ID \
    -u FEEDBACKS_PORT -u COMPOSE_PROJECT_NAME \
    docker compose --project-name "$project" --project-directory "$directory" \
      --env-file "$directory/.env" -f "$directory/compose.yaml" "$@"
}

main() {
  local directory="$PWD/feedbacks-server" port=3000 project= image checksum actual version revision
  local database_password owner_password random_id organization_id origin
  while [[ $# -gt 0 ]]; do
    case "$1" in
      --help)
        printf 'Usage: bash install.sh [--directory NEW_DIRECTORY] [--port 3000]\n'
        printf 'Requires Docker Compose v2, curl and OpenSSL. Starts on localhost with persistent database and image volumes.\n'
        return ;;
      --directory|--port)
        [[ $# -ge 2 && -n "$2" ]] || fail 'Missing option value. Use --help.'
        if [[ "$1" == --directory ]]; then directory=$2; else port=$2; fi
        shift 2 ;;
      *) fail 'Unknown option. Use --help.' ;;
    esac
  done
  [[ "$port" =~ ^[1-9][0-9]{3,4}$ && "$port" -ge 1024 && "$port" -le 65535 ]] || fail 'Use a port from 1024 to 65535.'
  [[ "$directory" == /* ]] || directory="$PWD/$directory"
  [[ ! -e "$directory" && ! -L "$directory" ]] || fail "Existing path preserved: $directory. Choose a new directory; this is not an upgrade command."
  for tool in docker curl openssl; do command -v "$tool" >/dev/null || fail "Install $tool first."; done
  progress 1 'Checking Docker and the requested local port…'
  if (: < /dev/tcp/127.0.0.1/"$port") 2>/dev/null; then
    fail "Port $port is already in use. Nothing was installed. Retry with --port 3300 --directory feedbacks-3300 (or choose another free port)."
  fi
  docker compose version >/dev/null || fail 'Docker Compose v2 is required.'
  docker info >/dev/null 2>&1 || fail 'Start Docker and check your Docker access first.'

  umask 077
  mkdir -m 700 "$directory" || fail 'Could not create the installation directory.'
  feedbacks_setup_directory=$directory
  feedbacks_setup_project=
  trap setup_stopped EXIT
  printf '*\n' > "$directory/.gitignore"
  progress 2 'Finding the latest verified stable release…'
  download --max-filesize 4096 https://feedbacks.softinator.ai/quickstart-stable.txt --output "$directory/release.txt"
  read_release
  printf 'Selected Feedbacks %s (verified image digest).\n' "$version"
  progress 3 'Downloading and verifying the Compose configuration…'
  download "https://raw.githubusercontent.com/Softinator-TechLabs/feedbacks-oss/$revision/site/public/compose.quickstart.yaml" \
    --output "$directory/compose.yaml.download"

  actual=$(openssl dgst -sha256 "$directory/compose.yaml.download")
  [[ ${actual##* } == "$checksum" ]] || fail 'Compose checksum did not match. No containers were started.'
  mv "$directory/compose.yaml.download" "$directory/compose.yaml"
  progress 4 'Creating private login and persistent-volume configuration…'
  database_password=$(openssl rand -hex 32)
  owner_password=$(openssl rand -hex 24)
  random_id=$(openssl rand -hex 16)
  organization_id="${random_id:0:8}-${random_id:8:4}-4${random_id:13:3}-8${random_id:17:3}-${random_id:20:12}"
  project="feedbacks-${random_id:0:12}"
  feedbacks_setup_project=$project
  origin="http://localhost:$port"
  {
    printf 'COMPOSE_PROJECT_NAME=%s\n' "$project"
    printf 'FEEDBACKS_IMAGE=%s\n' "$image"
    printf 'FEEDBACKS_PORT=%s\nAPP_ORIGIN=%s\n' "$port" "$origin"
    printf 'POSTGRES_PASSWORD=%s\nORGANIZATION_ID=%s\n' "$database_password" "$organization_id"
  } > "$directory/.env"
  printf '%s' "$owner_password" > "$directory/owner-password"
  chmod 600 "$directory/.env" "$directory/owner-password"
  compose config --quiet
  progress 5 'Pulling images from Docker Hub (the first download can take several minutes)…'
  compose pull
  progress 6 'Starting PostgreSQL and Feedbacks; waiting for health checks…'
  compose up -d --wait --wait-timeout 180
  progress 7 'Creating the owner account and checking readiness…'
  printf '%s' "$owner_password" | compose exec -T -e [email protected] \
    -e BOOTSTRAP_NAME=Owner app node dist/cli/bootstrap.js
  compose exec -T app node -e \
    "fetch('http://127.0.0.1:3000/readyz').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"
  trap - EXIT
  printf '\nFeedbacks is running.\nURL: %s\nEmail: [email protected]\n' "$origin"
  if [[ -t 1 ]]; then printf 'Password: %s\n' "$owner_password"; fi
  printf 'Password saved privately: %s/owner-password\n' "$directory"
  printf 'Database and screenshots use persistent Docker volumes. No S3 account is needed.\n'
  management_commands
  printf 'For shared HTTPS hosting: https://feedbacks.softinator.ai/docs/guide/self-host#bring-the-server-online\n'
  unset owner_password database_password
}

# Run only after the complete downloaded script has been parsed.
main "$@"