#!/bin/bash ################################################################################ # Простая установка/обновление/удаление Odoo 19 на Debian 13 # - автоматический выбор свежего архива odoo_19.0+e.*.tar.gz # - распаковка clean-enterprise-19.0.zip (если есть) # - PostgreSQL 16 из официального репозитория (кластер создаётся автоматически) # - wkhtmltopdf с проверкой и установкой шрифтов для кириллицы # - venv, systemd, конфиг в /etc/odoo/ #------------------------------------------------------------------------------- # Сделайте скрипт исполняемым: chmod +x odoo19_install_debian13.sh # Использование: sudo ./odoo_install.sh {install|update|uninstall} ################################################################################ set -e # ------------------------- ПЕРЕМЕННЫЕ ------------------------- OE_USER="odoo" OE_HOME="/opt/$OE_USER" OE_HOME_EXT="$OE_HOME/${OE_USER}-server" OE_VENV="$OE_HOME/venv" OE_CONFIG_DIR="/etc/$OE_USER" OE_CONFIG_FILE="$OE_CONFIG_DIR/${OE_USER}-server.conf" OE_SERVER="${OE_USER}-server" OE_VERSION="19.0" OE_PORT="8069" OE_SUPERADMIN="admin" GENERATE_RANDOM_PASSWORD="True" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" ODOO_ARCHIVE=$(ls -t "$SCRIPT_DIR"/odoo_19.0+e.*.tar.gz 2>/dev/null | head -n1) CUSTOM_ARCHIVE=$(ls -t "$SCRIPT_DIR"/clean-enterprise-19.0.zip 2>/dev/null | head -n1) if [[ -z "$ODOO_ARCHIVE" ]]; then echo "ОШИБКА: Не найден архив odoo_19.0+e.*.tar.gz в $SCRIPT_DIR" exit 1 fi echo "Используется архив: $ODOO_ARCHIVE" if [[ -n "$CUSTOM_ARCHIVE" ]]; then echo "Найден архив кастомных модулей: $CUSTOM_ARCHIVE" fi # ------------------------- ФУНКЦИИ ------------------------- log_info() { echo -e "\n[INFO] $*"; } log_error() { echo -e "\n[ERROR] $*" >&2; } check_root() { if [[ $EUID -ne 0 ]]; then log_error "Скрипт должен запускаться от root (sudo)." exit 1 fi } generate_password() { tr -dc 'a-zA-Z0-9' < /dev/urandom | fold -w 16 | head -n 1 } install_wkhtmltopdf() { log_info "Установка wkhtmltopdf и шрифтов для корректной генерации PDF" # 1. Шрифты критически важны для кириллицы в отчётах Odoo apt-get install -y xfonts-base xfonts-75dpi fontconfig # Проверяем, не установлен ли уже wkhtmltopdf (на случай повторного запуска) if command -v wkhtmltopdf &>/dev/null; then log_info "wkhtmltopdf уже установлен: $(wkhtmltopdf --version)" return 0 fi # 2. Скачиваем совместимый пакет от Debian 12 (Bookworm) local WKHTML_URL="https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6.1-3/wkhtmltox_0.12.6.1-3.bookworm_amd64.deb" log_info "Загрузка wkhtmltopdf..." wget -q -O /tmp/wkhtmltox.deb "$WKHTML_URL" # 3. Устанавливаем. apt автоматически разрешит зависимости для Debian 13 if apt-get install -y /tmp/wkhtmltox.deb; then log_info "wkhtmltopdf успешно установлен: $(wkhtmltopdf --version)" rm -f /tmp/wkhtmltox.deb # Создаем симлинки на всякий случай, если Odoo ищет их в /usr/bin ln -sf /usr/local/bin/wkhtmltopdf /usr/bin/wkhtmltopdf 2>/dev/null || true ln -sf /usr/local/bin/wkhtmltoimage /usr/bin/wkhtmltoimage 2>/dev/null || true else log_error "Не удалось установить wkhtmltopdf. Проверьте вывод apt выше." exit 1 fi } create_odoo_user_and_dirs() { log_info "Создание пользователя $OE_USER и каталогов" # Пользователь odoo НЕ добавляется в sudo в целях безопасности adduser --system --quiet --shell=/bin/bash --home=$OE_HOME --gecos 'ODOO' --group $OE_USER mkdir -p /var/log/$OE_USER mkdir -p $OE_HOME_EXT mkdir -p $OE_HOME/custom-addons mkdir -p $OE_CONFIG_DIR } extract_odoo() { log_info "Распаковка $ODOO_ARCHIVE в $OE_HOME_EXT" rm -rf "$OE_HOME_EXT"/* tar -C "$OE_HOME_EXT" -xzf "$ODOO_ARCHIVE" --strip-components=1 if [[ ! -d "$OE_HOME_EXT/odoo" || ! -f "$OE_HOME_EXT/odoo/__main__.py" ]]; then log_error "Структура архива неверна: нет odoo/__main__.py" exit 1 fi } extract_custom() { if [[ -n "$CUSTOM_ARCHIVE" && -f "$CUSTOM_ARCHIVE" ]]; then log_info "Распаковка $CUSTOM_ARCHIVE в $OE_HOME/custom-addons" if ! unzip -qo "$CUSTOM_ARCHIVE" -d "$OE_HOME/custom-addons"; then log_error "Ошибка при распаковке $CUSTOM_ARCHIVE. Проверьте целостность архива." exit 1 fi if [[ -d "$OE_HOME/custom-addons/clean-enterprise-19.0" ]]; then if [[ -d "$OE_HOME/custom-addons/clean-enterprise-19.0/clean_enterprise" ]]; then mv "$OE_HOME/custom-addons/clean-enterprise-19.0/clean_enterprise" "$OE_HOME/custom-addons/" fi rm -rf "$OE_HOME/custom-addons/clean-enterprise-19.0" fi else log_info "Файл кастомных модулей не найден, пропускаем." fi } setup_venv() { log_info "Создание venv в $OE_VENV" if [[ -d "$OE_VENV" ]]; then rm -rf "$OE_VENV" fi su - $OE_USER -c "python3 -m venv $OE_VENV" log_info "Установка зависимостей Python и odoo" su - $OE_USER -s /bin/bash < "$OE_CONFIG_FILE" < "/etc/systemd/system/${OE_SERVER}.service" < /etc/apt/sources.list.d/pgdg.list apt-get update apt-get install -y postgresql-16 postgresql-client-16 postgresql-server-dev-16 if ! pg_isready -q; then log_info "PostgreSQL не отвечает, пробуем запустить кластер" pg_ctlcluster 16 main start || { log_info "Не удалось запустить, создаём кластер вручную" su - postgres -c "pg_createcluster 16 main --start --locale C.UTF-8" } fi # Оставляем права суперпользователя (-s) для управления базами su - postgres -c "createuser -s $OE_USER" 2>/dev/null || true # 3. wkhtmltopdf install_wkhtmltopdf # 4. Глобальные пакеты npm npm install -g less less-plugin-clean-css rtlcss # 5. Пользователь и каталоги create_odoo_user_and_dirs # 6. Распаковка архивов extract_odoo extract_custom # 7. Права chown -R $OE_USER:$OE_USER "$OE_HOME" chown -R $OE_USER:$OE_USER "/var/log/$OE_USER" # 8. Виртуальное окружение setup_venv # 9. Конфиг и сервис create_config create_service echo "-----------------------------------------------------------" echo "УСТАНОВКА ЗАВЕРШЕНА" echo "-----------------------------------------------------------" echo "Веб-интерфейс: http://$(hostname -I | awk '{print $1}'):$OE_PORT" echo "Мастер-пароль: $OE_SUPERADMIN" echo "Конфиг: $OE_CONFIG_FILE" echo "Логи: /var/log/${OE_USER}/${OE_SERVER}.log" echo "Управление: systemctl {start|stop|restart|status} ${OE_SERVER}" echo "-----------------------------------------------------------" } do_update() { log_info "=== ОБНОВЛЕНИЕ Odoo $OE_VERSION ===" systemctl stop "${OE_SERVER}" || true ODOO_ARCHIVE=$(ls -t "$SCRIPT_DIR"/odoo_19.0+e.*.tar.gz 2>/dev/null | head -n1) if [[ -z "$ODOO_ARCHIVE" ]]; then log_error "Архив не найден для обновления!" exit 1 fi CUSTOM_ARCHIVE=$(ls -t "$SCRIPT_DIR"/clean-enterprise-19.0.zip 2>/dev/null | head -n1) extract_odoo extract_custom chown -R $OE_USER:$OE_USER "$OE_HOME" su - $OE_USER -s /bin/bash </dev/null || true systemctl disable "${OE_SERVER}" 2>/dev/null || true rm -f "/etc/systemd/system/${OE_SERVER}.service" systemctl daemon-reload rm -f "$OE_CONFIG_FILE" rmdir "$OE_CONFIG_DIR" 2>/dev/null || true rm -rf "$OE_HOME" rm -rf "/var/log/$OE_USER" userdel -r "$OE_USER" 2>/dev/null || true read -p "Удалить пользователя PostgreSQL 'odoo' и его базы? (y/N): " del_pg if [[ "$del_pg" =~ ^[Yy]$ ]]; then if id "postgres" &>/dev/null; then dbs=$(sudo -Hiu postgres psql -tAc "SELECT datname FROM pg_database WHERE datdba = (SELECT oid FROM pg_roles WHERE rolname='$OE_USER')") for db in $dbs; do db=$(echo "$db" | xargs) [[ -z "$db" ]] && continue sudo -u postgres dropdb "$db" 2>/dev/null || true done sudo -u postgres dropuser --if-exists "$OE_USER" 2>/dev/null || true log_info "Пользователь PostgreSQL и его базы удалены" fi fi read -p "Удалить PostgreSQL полностью? (ВНИМАНИЕ: это удалит ВСЕ базы на сервере) (y/N): " del_pg_all if [[ "$del_pg_all" =~ ^[Yy]$ ]]; then read -p "Вы абсолютно уверены? Это действие необратимо! (y/N): " confirm_all if [[ "$confirm_all" =~ ^[Yy]$ ]]; then apt-get purge -y postgresql-16 postgresql-client-16 postgresql-server-dev-16 rm -rf /var/lib/postgresql /var/log/postgresql log_info "Пакеты PostgreSQL и данные удалены. Системный пользователь 'postgres' сохранен для стабильности ОС." else log_info "Отмена полного удаления PostgreSQL." fi fi log_info "Удаление завершено" } # ------------------------- MAIN ------------------------- check_root if [[ $# -eq 0 ]]; then echo "Использование: $0 {install|update|uninstall}" exit 1 fi case "$1" in install) do_install ;; update) do_update ;; uninstall) do_uninstall ;; *) echo "Неверный параметр: $1"; exit 1 ;; esac exit 0