| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393 |
- #!/bin/bash
- ################################################################################
- # Простая установка/обновление/удаление Odoo 19 на Debian 13 (Trixie)
- # - автоматический выбор свежего архива odoo_19.0+e.*.tar.gz
- # - распаковка clean-enterprise-19.0.zip (с запросом при обновлении)
- # - PostgreSQL 16 с надёжным созданием/запуском кластера
- # - wkhtmltopdf (нативная сборка для Bookworm/Trixie)
- # - venv, systemd, конфиг в /etc/odoo/
- # - обновление только баз, принадлежащих пользователю odoo
- #-------------------------------------------------------------------------------
- # Сделайте скрипт исполняемым: chmod +x odoo19_install_debian13.sh
- # Использование: sudo ./odoo19_install_debian13.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"
- UPDATE_MODE="False" # флаг для режима обновления
- 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)
- WKHTMLTOX_URL="https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6.1-3/wkhtmltox_0.12.6.1-3.bookworm_amd64.deb"
- 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 20 | head -n 1
- }
- install_wkhtmltopdf() {
- log_info "Установка wkhtmltopdf"
- wget -q "$WKHTMLTOX_URL" -O /tmp/wkhtmltox.deb
- dpkg -i /tmp/wkhtmltox.deb || apt-get install -f -y >/dev/null 2>&1
- rm -f /tmp/wkhtmltox.deb
- ln -sf /usr/local/bin/wkhtmltopdf /usr/bin/wkhtmltopdf
- ln -sf /usr/local/bin/wkhtmltoimage /usr/bin/wkhtmltoimage
- log_info "wkhtmltopdf установлен"
- }
- create_odoo_user_and_dirs() {
- log_info "Создание пользователя $OE_USER и каталогов"
- adduser --system --quiet --shell=/bin/bash --home=$OE_HOME --gecos 'ODOO' --group $OE_USER
- adduser $OE_USER sudo
- 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
- # Если это обновление и папка уже существует, спрашиваем
- if [[ "$UPDATE_MODE" == "True" ]] && [[ -d "$OE_HOME/custom-addons/clean_enterprise" ]]; then
- read -p "Обновить кастомные модули (папка clean_enterprise уже существует)? (y/N): " confirm
- if [[ ! "$confirm" =~ ^[Yy]$ ]]; then
- log_info "Пропускаем обновление кастомных модулей."
- return
- fi
- # Если подтвердили, удаляем папку
- rm -rf "$OE_HOME/custom-addons/clean_enterprise"
- fi
- log_info "Распаковка $CUSTOM_ARCHIVE в $OE_HOME/custom-addons"
- unzip -qo "$CUSTOM_ARCHIVE" -d $OE_HOME/custom-addons
- 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 "Файл $CUSTOM_ARCHIVE не найден, пропускаем."
- 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 <<EOF
- source $OE_VENV/bin/activate
- pip install --upgrade pip wheel setuptools
- pip install -r $OE_HOME_EXT/requirements.txt
- pip install num2words ofxparse dbfread ebaysdk firebase_admin pyOpenSSL phonenumbers google_auth PyPDF2 psycopg2-binary pdfminer.six
- pip install -e $OE_HOME_EXT/
- deactivate
- EOF
- }
- create_config() {
- log_info "Создание конфига $OE_CONFIG_FILE"
- if [[ "$GENERATE_RANDOM_PASSWORD" == "True" ]]; then
- OE_SUPERADMIN=$(generate_password)
- log_info "Пароль администратора: $OE_SUPERADMIN"
- fi
- cat > $OE_CONFIG_FILE <<EOF
- [options]
- admin_passwd = ${OE_SUPERADMIN}
- http_port = ${OE_PORT}
- logfile = /var/log/${OE_USER}/${OE_SERVER}.log
- addons_path = ${OE_HOME_EXT}/odoo/addons,${OE_HOME}/custom-addons
- limit_time_real = 1200
- EOF
- chown $OE_USER:$OE_USER $OE_CONFIG_FILE
- chmod 640 $OE_CONFIG_FILE
- }
- create_service() {
- log_info "Создание systemd сервиса"
- cat > /etc/systemd/system/${OE_SERVER}.service <<EOF
- [Unit]
- Description=Odoo $OE_VERSION Server
- Requires=postgresql.service
- After=network.target postgresql.service
- [Service]
- Type=simple
- User=$OE_USER
- Group=$OE_USER
- Environment="PATH=$OE_VENV/bin:/usr/bin:/bin"
- ExecStart=$OE_VENV/bin/python3 -m odoo -c $OE_CONFIG_FILE
- Restart=always
- RestartSec=10
- StandardOutput=journal+console
- [Install]
- WantedBy=multi-user.target
- EOF
- systemctl daemon-reload
- systemctl enable --now ${OE_SERVER}
- sleep 3
- }
- update_databases() {
- log_info "Обновление модулей во всех базах данных пользователя $OE_USER"
- # Выбираем только те базы, владельцем которых является пользователь odoo
- OE_DBS=$(sudo -Hiu postgres psql -tAc "SELECT datname FROM pg_database WHERE datdba = (SELECT oid FROM pg_roles WHERE rolname='$OE_USER')")
- if [[ -n "$OE_DBS" ]]; then
- for db in $OE_DBS; do
- log_info "Обновление базы: $db"
- su - $OE_USER -s /bin/bash -c "source $OE_VENV/bin/activate && python3 -m odoo -c $OE_CONFIG_FILE --update all --stop-after-init -d $db"
- done
- else
- log_info "Нет баз данных, принадлежащих пользователю $OE_USER, для обновления."
- fi
- }
- # ------------------------- РЕЖИМЫ -------------------------
- do_install() {
- log_info "=== УСТАНОВКА Odoo $OE_VERSION на Debian 13 (Trixie) ==="
- # 0. Настройка репозитория PostgreSQL ДО первого apt-get update
- log_info "Настройка репозитория PostgreSQL 16"
- rm -f /usr/share/keyrings/postgresql-archive-keyring.gpg
- rm -f /etc/apt/sources.list.d/pgdg.list
- wget -q -O- https://www.postgresql.org/media/keys/ACCC4CF8.asc | gpg --dearmor -o /usr/share/keyrings/postgresql-archive-keyring.gpg
- if [[ ! -s /usr/share/keyrings/postgresql-archive-keyring.gpg ]]; then
- log_error "Не удалось загрузить ключ репозитория PostgreSQL"
- exit 1
- fi
- echo "deb [signed-by=/usr/share/keyrings/postgresql-archive-keyring.gpg] http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list
- # 1. Обновление системы
- apt-get update
- apt-get upgrade -y
- # 2. Базовые пакеты
- apt-get install -y git python3 python3-pip build-essential wget \
- python3-dev python3-venv python3-wheel python3-cffi \
- libssl-dev libffi-dev libxml2-dev libxslt1-dev \
- libzip-dev libldap2-dev libsasl2-dev libpq-dev \
- libjpeg-dev zlib1g-dev libpng-dev \
- nodejs npm gdebi-core curl unzip
- # 3. PostgreSQL 16 (установка, кластер уже не требует добавления репозитория)
- log_info "Установка PostgreSQL 16"
- # Убедимся, что системный пользователь postgres существует
- if ! id "postgres" &>/dev/null; then
- log_info "Создание системного пользователя postgres"
- adduser --system --quiet --shell=/bin/bash --home=/var/lib/postgresql --group postgres
- fi
- apt-get install -y postgresql-16 postgresql-client-16 postgresql-server-dev-16
- # Убедимся, что кластер существует и запущен
- if ! pg_isready -q; then
- log_info "PostgreSQL не отвечает, пробуем запустить кластер"
- if pg_ctlcluster 16 main start 2>/dev/null; then
- log_info "Кластер 16/main запущен"
- else
- log_info "Не удалось запустить кластер, пробуем создать"
- su - postgres -c "pg_createcluster 16 main --start --locale C.UTF-8" 2>/dev/null || {
- log_info "Создание не удалось, возможно кластер уже есть, пробуем запустить"
- pg_ctlcluster 16 main start || {
- log_error "Не удалось запустить или создать кластер"
- exit 1
- }
- }
- fi
- else
- log_info "PostgreSQL уже работает"
- fi
- # Создаём пользователя odoo в PostgreSQL
- su - postgres -c "createuser -s $OE_USER" 2>/dev/null || true
- # 4. wkhtmltopdf
- install_wkhtmltopdf
- # 5. Глобальные пакеты npm
- npm install -g less less-plugin-clean-css rtlcss
- # 6. Пользователь и каталоги
- create_odoo_user_and_dirs
- # 7. Распаковка архивов
- extract_odoo
- extract_custom
- # 8. Права
- chown -R $OE_USER:$OE_USER $OE_HOME
- chown -R $OE_USER:$OE_USER /var/log/$OE_USER
- # 9. Виртуальное окружение
- setup_venv
- # 10. Конфиг и сервис
- create_config
- create_service
- 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 ==="
- UPDATE_MODE="True"
- 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 <<EOF
- source $OE_VENV/bin/activate
- pip install --upgrade pip wheel setuptools
- pip install -r $OE_HOME_EXT/requirements.txt
- pip install -e $OE_HOME_EXT/
- deactivate
- EOF
- update_databases
- systemctl start ${OE_SERVER}
- log_info "Обновление завершено"
- }
- do_uninstall() {
- log_info "=== УДАЛЕНИЕ Odoo ==="
- read -p "Вы уверены? (y/N): " confirm
- if [[ ! "$confirm" =~ ^[Yy]$ ]]; then
- log_info "Отмена"
- exit 0
- fi
- # 1. Остановка и удаление сервиса
- systemctl stop ${OE_SERVER} 2>/dev/null || true
- systemctl disable ${OE_SERVER} 2>/dev/null || true
- rm -f /etc/systemd/system/${OE_SERVER}.service
- systemctl daemon-reload
- # 2. Удаление конфига и каталогов Odoo
- rm -f $OE_CONFIG_FILE
- rmdir $OE_CONFIG_DIR 2>/dev/null || true
- rm -rf $OE_HOME
- rm -rf /var/log/$OE_USER
- # 3. Удаление пользователя odoo
- userdel -r $OE_USER 2>/dev/null || true
- # 4. Удаление ключа репозитория PostgreSQL и файла источника
- rm -f /usr/share/keyrings/postgresql-archive-keyring.gpg
- rm -f /etc/apt/sources.list.d/pgdg.list
- # 5. Удаление wkhtmltopdf и симлинков
- log_info "Удаление wkhtmltopdf"
- apt-get purge -y wkhtmltox 2>/dev/null || true
- rm -f /usr/bin/wkhtmltopdf /usr/bin/wkhtmltoimage
- log_info "wkhtmltopdf и симлинки удалены"
- # 6. (Опционально) Удаление глобальных npm-пакетов
- # npm uninstall -g less less-plugin-clean-css rtlcss
- # 7. Удаление пользователя PostgreSQL и баз
- 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
- 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
- # 8. Удаление PostgreSQL полностью (опционально)
- read -p "Удалить PostgreSQL полностью? (y/N): " del_pg_all
- if [[ "$del_pg_all" =~ ^[Yy]$ ]]; then
- apt-get purge -y postgresql-16 postgresql-client-16 postgresql-server-dev-16
- rm -rf /var/lib/postgresql /var/log/postgresql
- userdel -r postgres 2>/dev/null || true
- groupdel postgres 2>/dev/null || true
- log_info "PostgreSQL удалён"
- 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
|