odoo19_install_debian13.sh 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  1. #!/bin/bash
  2. ################################################################################
  3. # Простая установка/обновление/удаление Odoo 19 на Debian 13
  4. # - автоматический выбор свежего архива odoo_19.0+e.*.tar.gz
  5. # - распаковка clean-enterprise-19.0.zip (если есть)
  6. # - PostgreSQL 16 из официального репозитория (кластер создаётся автоматически)
  7. # - wkhtmltopdf с проверкой и установкой шрифтов для кириллицы
  8. # - venv, systemd, конфиг в /etc/odoo/
  9. #-------------------------------------------------------------------------------
  10. # Сделайте скрипт исполняемым: chmod +x odoo19_install_debian13.sh
  11. # Использование: sudo ./odoo_install.sh {install|update|uninstall}
  12. ################################################################################
  13. set -e
  14. # ------------------------- ПЕРЕМЕННЫЕ -------------------------
  15. OE_USER="odoo"
  16. OE_HOME="/opt/$OE_USER"
  17. OE_HOME_EXT="$OE_HOME/${OE_USER}-server"
  18. OE_VENV="$OE_HOME/venv"
  19. OE_CONFIG_DIR="/etc/$OE_USER"
  20. OE_CONFIG_FILE="$OE_CONFIG_DIR/${OE_USER}-server.conf"
  21. OE_SERVER="${OE_USER}-server"
  22. OE_VERSION="19.0"
  23. OE_PORT="8069"
  24. OE_SUPERADMIN="admin"
  25. GENERATE_RANDOM_PASSWORD="True"
  26. SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
  27. ODOO_ARCHIVE=$(ls -t "$SCRIPT_DIR"/odoo_19.0+e.*.tar.gz 2>/dev/null | head -n1)
  28. CUSTOM_ARCHIVE=$(ls -t "$SCRIPT_DIR"/clean-enterprise-19.0.zip 2>/dev/null | head -n1)
  29. if [[ -z "$ODOO_ARCHIVE" ]]; then
  30. echo "ОШИБКА: Не найден архив odoo_19.0+e.*.tar.gz в $SCRIPT_DIR"
  31. exit 1
  32. fi
  33. echo "Используется архив: $ODOO_ARCHIVE"
  34. if [[ -n "$CUSTOM_ARCHIVE" ]]; then
  35. echo "Найден архив кастомных модулей: $CUSTOM_ARCHIVE"
  36. fi
  37. # ------------------------- ФУНКЦИИ -------------------------
  38. log_info() { echo -e "\n[INFO] $*"; }
  39. log_error() { echo -e "\n[ERROR] $*" >&2; }
  40. check_root() {
  41. if [[ $EUID -ne 0 ]]; then
  42. log_error "Скрипт должен запускаться от root (sudo)."
  43. exit 1
  44. fi
  45. }
  46. generate_password() {
  47. tr -dc 'a-zA-Z0-9' < /dev/urandom | fold -w 16 | head -n 1
  48. }
  49. install_wkhtmltopdf() {
  50. log_info "Установка wkhtmltopdf и шрифтов для корректной генерации PDF"
  51. # 1. Шрифты критически важны для кириллицы в отчётах Odoo
  52. apt-get install -y xfonts-base xfonts-75dpi fontconfig
  53. # Проверяем, не установлен ли уже wkhtmltopdf (на случай повторного запуска)
  54. if command -v wkhtmltopdf &>/dev/null; then
  55. log_info "wkhtmltopdf уже установлен: $(wkhtmltopdf --version)"
  56. return 0
  57. fi
  58. # 2. Скачиваем совместимый пакет от Debian 12 (Bookworm)
  59. local WKHTML_URL="https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6.1-3/wkhtmltox_0.12.6.1-3.bookworm_amd64.deb"
  60. log_info "Загрузка wkhtmltopdf..."
  61. wget -q -O /tmp/wkhtmltox.deb "$WKHTML_URL"
  62. # 3. Устанавливаем. apt автоматически разрешит зависимости для Debian 13
  63. if apt-get install -y /tmp/wkhtmltox.deb; then
  64. log_info "wkhtmltopdf успешно установлен: $(wkhtmltopdf --version)"
  65. rm -f /tmp/wkhtmltox.deb
  66. # Создаем симлинки на всякий случай, если Odoo ищет их в /usr/bin
  67. ln -sf /usr/local/bin/wkhtmltopdf /usr/bin/wkhtmltopdf 2>/dev/null || true
  68. ln -sf /usr/local/bin/wkhtmltoimage /usr/bin/wkhtmltoimage 2>/dev/null || true
  69. else
  70. log_error "Не удалось установить wkhtmltopdf. Проверьте вывод apt выше."
  71. exit 1
  72. fi
  73. }
  74. create_odoo_user_and_dirs() {
  75. log_info "Создание пользователя $OE_USER и каталогов"
  76. # Пользователь odoo НЕ добавляется в sudo в целях безопасности
  77. adduser --system --quiet --shell=/bin/bash --home=$OE_HOME --gecos 'ODOO' --group $OE_USER
  78. mkdir -p /var/log/$OE_USER
  79. mkdir -p $OE_HOME_EXT
  80. mkdir -p $OE_HOME/custom-addons
  81. mkdir -p $OE_CONFIG_DIR
  82. }
  83. extract_odoo() {
  84. log_info "Распаковка $ODOO_ARCHIVE в $OE_HOME_EXT"
  85. rm -rf "$OE_HOME_EXT"/*
  86. tar -C "$OE_HOME_EXT" -xzf "$ODOO_ARCHIVE" --strip-components=1
  87. if [[ ! -d "$OE_HOME_EXT/odoo" || ! -f "$OE_HOME_EXT/odoo/__main__.py" ]]; then
  88. log_error "Структура архива неверна: нет odoo/__main__.py"
  89. exit 1
  90. fi
  91. }
  92. extract_custom() {
  93. if [[ -n "$CUSTOM_ARCHIVE" && -f "$CUSTOM_ARCHIVE" ]]; then
  94. log_info "Распаковка $CUSTOM_ARCHIVE в $OE_HOME/custom-addons"
  95. if ! unzip -qo "$CUSTOM_ARCHIVE" -d "$OE_HOME/custom-addons"; then
  96. log_error "Ошибка при распаковке $CUSTOM_ARCHIVE. Проверьте целостность архива."
  97. exit 1
  98. fi
  99. if [[ -d "$OE_HOME/custom-addons/clean-enterprise-19.0" ]]; then
  100. if [[ -d "$OE_HOME/custom-addons/clean-enterprise-19.0/clean_enterprise" ]]; then
  101. mv "$OE_HOME/custom-addons/clean-enterprise-19.0/clean_enterprise" "$OE_HOME/custom-addons/"
  102. fi
  103. rm -rf "$OE_HOME/custom-addons/clean-enterprise-19.0"
  104. fi
  105. else
  106. log_info "Файл кастомных модулей не найден, пропускаем."
  107. fi
  108. }
  109. setup_venv() {
  110. log_info "Создание venv в $OE_VENV"
  111. if [[ -d "$OE_VENV" ]]; then
  112. rm -rf "$OE_VENV"
  113. fi
  114. su - $OE_USER -c "python3 -m venv $OE_VENV"
  115. log_info "Установка зависимостей Python и odoo"
  116. su - $OE_USER -s /bin/bash <<EOF
  117. source $OE_VENV/bin/activate
  118. pip install --upgrade pip wheel setuptools
  119. pip install -r $OE_HOME_EXT/requirements.txt
  120. pip install num2words ofxparse dbfread ebaysdk firebase_admin pyOpenSSL phonenumbers google_auth PyPDF2 psycopg2-binary pdfminer.six
  121. pip install -e $OE_HOME_EXT/
  122. deactivate
  123. EOF
  124. }
  125. create_config() {
  126. log_info "Создание конфига $OE_CONFIG_FILE"
  127. if [[ "$GENERATE_RANDOM_PASSWORD" == "True" ]]; then
  128. OE_SUPERADMIN=$(generate_password)
  129. log_info "Пароль администратора (master password): $OE_SUPERADMIN"
  130. fi
  131. cat > "$OE_CONFIG_FILE" <<EOF
  132. [options]
  133. admin_passwd = ${OE_SUPERADMIN}
  134. http_port = ${OE_PORT}
  135. logfile = /var/log/${OE_USER}/${OE_SERVER}.log
  136. addons_path = ${OE_HOME_EXT}/odoo/addons,${OE_HOME}/custom-addons
  137. limit_time_real = 1200
  138. EOF
  139. chown $OE_USER:$OE_USER "$OE_CONFIG_FILE"
  140. chmod 640 "$OE_CONFIG_FILE"
  141. }
  142. create_service() {
  143. log_info "Создание systemd сервиса"
  144. cat > "/etc/systemd/system/${OE_SERVER}.service" <<EOF
  145. [Unit]
  146. Description=Odoo $OE_VERSION Server
  147. Requires=postgresql.service
  148. After=network.target postgresql.service
  149. [Service]
  150. Type=simple
  151. User=$OE_USER
  152. Group=$OE_USER
  153. Environment="PATH=$OE_VENV/bin:/usr/bin:/bin"
  154. ExecStart=$OE_VENV/bin/python3 -m odoo -c $OE_CONFIG_FILE
  155. Restart=always
  156. RestartSec=10
  157. StandardOutput=journal+console
  158. [Install]
  159. WantedBy=multi-user.target
  160. EOF
  161. systemctl daemon-reload
  162. systemctl enable --now "${OE_SERVER}"
  163. sleep 3
  164. }
  165. update_databases() {
  166. log_info "Обновление модулей в базах данных Odoo"
  167. # Исправлено: убран дубликат 'template0', добавлена фильтрация по владельцу
  168. OE_DBS=$(sudo -Hiu postgres psql -tAc "SELECT datname FROM pg_database WHERE datdba = (SELECT oid FROM pg_roles WHERE rolname='$OE_USER') AND datname NOT IN ('postgres', 'template0', 'template1');")
  169. if [[ -n "$OE_DBS" ]]; then
  170. for db in $OE_DBS; do
  171. db=$(echo "$db" | xargs)
  172. [[ -z "$db" ]] && continue
  173. log_info "Обновление базы: $db"
  174. 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"
  175. done
  176. else
  177. log_info "Нет баз данных Odoo для обновления."
  178. fi
  179. }
  180. # ------------------------- РЕЖИМЫ -------------------------
  181. do_install() {
  182. log_info "=== УСТАНОВКА Odoo $OE_VERSION ==="
  183. # 1. Базовые пакеты
  184. apt-get update
  185. log_info "Внимание: будет выполнено обновление всех пакетов системы (apt-get upgrade)."
  186. read -p "Продолжить обновление системы? (Y/n): " confirm_upgrade
  187. if [[ ! "$confirm_upgrade" =~ ^[Nn]$ ]]; then
  188. apt-get upgrade -y
  189. else
  190. log_info "Обновление системы пропущено."
  191. fi
  192. apt-get install -y git python3 python3-pip build-essential wget \
  193. python3-dev python3-venv python3-wheel python3-cffi \
  194. libssl-dev libffi-dev libxml2-dev libxslt1-dev \
  195. libzip-dev libldap2-dev libsasl2-dev libpq-dev \
  196. libjpeg-dev zlib1g-dev libpng-dev \
  197. nodejs npm gdebi-core curl unzip
  198. # 2. PostgreSQL 16
  199. log_info "Установка PostgreSQL 16"
  200. curl -fsSL https://www.postgresql.org/media/keys/ACCC4CF8.asc | gpg --dearmor -o /usr/share/keyrings/postgresql-archive-keyring.gpg
  201. 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
  202. apt-get update
  203. apt-get install -y postgresql-16 postgresql-client-16 postgresql-server-dev-16
  204. if ! pg_isready -q; then
  205. log_info "PostgreSQL не отвечает, пробуем запустить кластер"
  206. pg_ctlcluster 16 main start || {
  207. log_info "Не удалось запустить, создаём кластер вручную"
  208. su - postgres -c "pg_createcluster 16 main --start --locale C.UTF-8"
  209. }
  210. fi
  211. # Оставляем права суперпользователя (-s) для управления базами
  212. su - postgres -c "createuser -s $OE_USER" 2>/dev/null || true
  213. # 3. wkhtmltopdf
  214. install_wkhtmltopdf
  215. # 4. Глобальные пакеты npm
  216. npm install -g less less-plugin-clean-css rtlcss
  217. # 5. Пользователь и каталоги
  218. create_odoo_user_and_dirs
  219. # 6. Распаковка архивов
  220. extract_odoo
  221. extract_custom
  222. # 7. Права
  223. chown -R $OE_USER:$OE_USER "$OE_HOME"
  224. chown -R $OE_USER:$OE_USER "/var/log/$OE_USER"
  225. # 8. Виртуальное окружение
  226. setup_venv
  227. # 9. Конфиг и сервис
  228. create_config
  229. create_service
  230. echo "-----------------------------------------------------------"
  231. echo "УСТАНОВКА ЗАВЕРШЕНА"
  232. echo "-----------------------------------------------------------"
  233. echo "Веб-интерфейс: http://$(hostname -I | awk '{print $1}'):$OE_PORT"
  234. echo "Мастер-пароль: $OE_SUPERADMIN"
  235. echo "Конфиг: $OE_CONFIG_FILE"
  236. echo "Логи: /var/log/${OE_USER}/${OE_SERVER}.log"
  237. echo "Управление: systemctl {start|stop|restart|status} ${OE_SERVER}"
  238. echo "-----------------------------------------------------------"
  239. }
  240. do_update() {
  241. log_info "=== ОБНОВЛЕНИЕ Odoo $OE_VERSION ==="
  242. systemctl stop "${OE_SERVER}" || true
  243. ODOO_ARCHIVE=$(ls -t "$SCRIPT_DIR"/odoo_19.0+e.*.tar.gz 2>/dev/null | head -n1)
  244. if [[ -z "$ODOO_ARCHIVE" ]]; then
  245. log_error "Архив не найден для обновления!"
  246. exit 1
  247. fi
  248. CUSTOM_ARCHIVE=$(ls -t "$SCRIPT_DIR"/clean-enterprise-19.0.zip 2>/dev/null | head -n1)
  249. extract_odoo
  250. extract_custom
  251. chown -R $OE_USER:$OE_USER "$OE_HOME"
  252. su - $OE_USER -s /bin/bash <<EOF
  253. source $OE_VENV/bin/activate
  254. pip install --upgrade pip wheel setuptools
  255. pip install -r $OE_HOME_EXT/requirements.txt
  256. pip install -e $OE_HOME_EXT/
  257. deactivate
  258. EOF
  259. update_databases
  260. systemctl start "${OE_SERVER}"
  261. log_info "Обновление завершено"
  262. }
  263. do_uninstall() {
  264. log_info "=== УДАЛЕНИЕ Odoo ==="
  265. read -p "Вы уверены? (y/N): " confirm
  266. if [[ ! "$confirm" =~ ^[Yy]$ ]]; then
  267. log_info "Отмена"
  268. exit 0
  269. fi
  270. systemctl stop "${OE_SERVER}" 2>/dev/null || true
  271. systemctl disable "${OE_SERVER}" 2>/dev/null || true
  272. rm -f "/etc/systemd/system/${OE_SERVER}.service"
  273. systemctl daemon-reload
  274. rm -f "$OE_CONFIG_FILE"
  275. rmdir "$OE_CONFIG_DIR" 2>/dev/null || true
  276. rm -rf "$OE_HOME"
  277. rm -rf "/var/log/$OE_USER"
  278. userdel -r "$OE_USER" 2>/dev/null || true
  279. read -p "Удалить пользователя PostgreSQL 'odoo' и его базы? (y/N): " del_pg
  280. if [[ "$del_pg" =~ ^[Yy]$ ]]; then
  281. if id "postgres" &>/dev/null; then
  282. dbs=$(sudo -Hiu postgres psql -tAc "SELECT datname FROM pg_database WHERE datdba = (SELECT oid FROM pg_roles WHERE rolname='$OE_USER')")
  283. for db in $dbs; do
  284. db=$(echo "$db" | xargs)
  285. [[ -z "$db" ]] && continue
  286. sudo -u postgres dropdb "$db" 2>/dev/null || true
  287. done
  288. sudo -u postgres dropuser --if-exists "$OE_USER" 2>/dev/null || true
  289. log_info "Пользователь PostgreSQL и его базы удалены"
  290. fi
  291. fi
  292. read -p "Удалить PostgreSQL полностью? (ВНИМАНИЕ: это удалит ВСЕ базы на сервере) (y/N): " del_pg_all
  293. if [[ "$del_pg_all" =~ ^[Yy]$ ]]; then
  294. read -p "Вы абсолютно уверены? Это действие необратимо! (y/N): " confirm_all
  295. if [[ "$confirm_all" =~ ^[Yy]$ ]]; then
  296. apt-get purge -y postgresql-16 postgresql-client-16 postgresql-server-dev-16
  297. rm -rf /var/lib/postgresql /var/log/postgresql
  298. log_info "Пакеты PostgreSQL и данные удалены. Системный пользователь 'postgres' сохранен для стабильности ОС."
  299. else
  300. log_info "Отмена полного удаления PostgreSQL."
  301. fi
  302. fi
  303. log_info "Удаление завершено"
  304. }
  305. # ------------------------- MAIN -------------------------
  306. check_root
  307. if [[ $# -eq 0 ]]; then
  308. echo "Использование: $0 {install|update|uninstall}"
  309. exit 1
  310. fi
  311. case "$1" in
  312. install) do_install ;;
  313. update) do_update ;;
  314. uninstall) do_uninstall ;;
  315. *) echo "Неверный параметр: $1"; exit 1 ;;
  316. esac
  317. exit 0