diff --git a/install-from-image.sh b/install-from-image.sh new file mode 100755 index 0000000..ea8d7db --- /dev/null +++ b/install-from-image.sh @@ -0,0 +1,151 @@ +#!/usr/bin/env bash +set -Eeuo pipefail + +APP_NAME="corp-address-book" +CONTAINER_NAME="corporate-address-book" +INSTALL_DIR="/opt/corp-address-book" +IMAGE_NAME="corp-address-book:latest" +IMAGE_URL="https://git.h0melab.ru/fabritsky/corp-address-book/raw/branch/docker-image/corp-address-book-latest.tar.gz" +IMAGE_ARCHIVE="${INSTALL_DIR}/corp-address-book-latest.tar.gz" +HOST_PORT="8180" +CONTAINER_PORT="3000" +ENV_CREATED="false" +GENERATED_ADMIN_PASSWORD="" + +log() { + printf '\n[%s] %s\n' "$(date +'%H:%M:%S')" "$*" +} + +die() { + printf '\nERROR: %s\n' "$*" >&2 + exit 1 +} + +need_root() { + if [ "${EUID:-$(id -u)}" -ne 0 ]; then + die "Run this installer as root, for example: curl -fsSL ... | sudo bash" + fi +} + +install_base_packages() { + log "Installing required packages" + export DEBIAN_FRONTEND=noninteractive + apt-get update + apt-get install -y ca-certificates curl gnupg openssl +} + +install_docker_if_needed() { + if command -v docker >/dev/null 2>&1; then + log "Docker is already installed" + else + log "Installing Docker Engine" + install -m 0755 -d /etc/apt/keyrings + curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg + chmod a+r /etc/apt/keyrings/docker.gpg + + . /etc/os-release + arch="$(dpkg --print-architecture)" + codename="${VERSION_CODENAME:-}" + [ -n "$codename" ] || die "Cannot determine Ubuntu codename." + + printf 'deb [arch=%s signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu %s stable\n' "$arch" "$codename" \ + > /etc/apt/sources.list.d/docker.list + + export DEBIAN_FRONTEND=noninteractive + apt-get update + apt-get install -y docker-ce docker-ce-cli containerd.io + fi + + systemctl enable --now docker +} + +prepare_env_and_data() { + log "Preparing persistent files" + mkdir -p "${INSTALL_DIR}/data" + + if [ ! -f "${INSTALL_DIR}/.env" ]; then + jwt_secret="$(openssl rand -hex 32 2>/dev/null || date +%s%N)" + admin_password="$(openssl rand -base64 24 2>/dev/null | tr -d '\n' || date +%s%N)" + GENERATED_ADMIN_PASSWORD="$admin_password" + ENV_CREATED="true" + + umask 077 + cat > "${INSTALL_DIR}/.env" </dev/null 2>&1; then + die "Loaded archive did not provide ${IMAGE_NAME}." + fi +} + +replace_container() { + log "Starting ${CONTAINER_NAME} on port ${HOST_PORT}" + + if docker container inspect "$CONTAINER_NAME" >/dev/null 2>&1; then + docker stop "$CONTAINER_NAME" >/dev/null + docker rm "$CONTAINER_NAME" >/dev/null + fi + + docker run -d \ + --name "$CONTAINER_NAME" \ + --restart unless-stopped \ + --env-file "${INSTALL_DIR}/.env" \ + -p "${HOST_PORT}:${CONTAINER_PORT}" \ + -v "${INSTALL_DIR}/data:/app/data" \ + "$IMAGE_NAME" >/dev/null + + sleep 5 + if ! curl -fsSI "http://127.0.0.1:${HOST_PORT}/" >/dev/null; then + docker logs --tail=80 "$CONTAINER_NAME" || true + die "Health check failed on http://127.0.0.1:${HOST_PORT}/." + fi +} + +print_result() { + server_ip="$(hostname -I 2>/dev/null | awk '{print $1}')" + [ -n "${server_ip:-}" ] || server_ip="SERVER_IP" + + log "Installation completed" + printf 'URL: http://%s:%s/\n' "$server_ip" "$HOST_PORT" + printf 'Admin login: admin\n' + if [ "$ENV_CREATED" = "true" ]; then + printf 'Admin password: %s\n' "$GENERATED_ADMIN_PASSWORD" + else + printf 'Admin password: unchanged; read it from %s/.env on the server.\n' "$INSTALL_DIR" + fi +} + +main() { + need_root + install_base_packages + install_docker_if_needed + prepare_env_and_data + download_and_load_image + replace_container + print_result +} + +main "$@"