odoo19_install_debian13.sh 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424
  1. #!/bin/bash
  2. ################################################################################
  3. # Простая установка/обновление/удаление Odoo 19 на Debian 13 (Trixie)
  4. # - автоматический выбор свежего архива odoo_19.0+e.*.tar.gz
  5. # - распаковка clean-enterprise-19.0.zip (с запросом при обновлении)
  6. # - PostgreSQL 16 с надёжным созданием/запуском кластера
  7. # - wkhtmltopdf (установка через gdebi для автоматического разрешения зависимостей)
  8. # - venv с корректными правами (chown -R)
  9. # - фиксированная версия PyPDF2==2.12.1 для совместимости с Odoo
  10. # - установка openpyxl для работы с Excel
  11. # - обновление только баз, принадлежащих пользователю odoo
  12. # - автоматическая ежедневная ротация логов через logrotate
  13. #-------------------------------------------------------------------------------
  14. # Сделайте скрипт исполняемым: chmod +x odoo19_install_debian13.sh
  15. # Использование: sudo ./odoo19_install_debian13.sh {install|update|uninstall}
  16. ################################################################################
  17. set -e
  18. # ------------------------- ПЕРЕМЕННЫЕ -------------------------
  19. OE_USER="odoo"
  20. OE_HOME="/opt/$OE_USER"
  21. OE_HOME_EXT="$OE_HOME/${OE_USER}-server"
  22. OE_VENV="$OE_HOME/venv"
  23. OE_CONFIG_DIR="/etc/$OE_USER"
  24. OE_CONFIG_FILE="$OE_CONFIG_DIR/${OE_USER}-server.conf"
  25. OE_SERVER="${OE_USER}-server"
  26. OE_VERSION="19.0"
  27. OE_PORT="8069"
  28. OE_SUPERADMIN="admin"
  29. GENERATE_RANDOM_PASSWORD="True"
  30. UPDATE_MODE="False"
  31. SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
  32. ODOO_ARCHIVE=$(ls -t "$SCRIPT_DIR"/odoo_19.0+e.*.tar.gz 2>/dev/null | head -n1)
  33. CUSTOM_ARCHIVE=$(ls -t "$SCRIPT_DIR"/clean-enterprise-19.0.zip 2>/dev/null | head -n1)
  34. WKHTMLTOX_URL="https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6.1-3/wkhtmltox_0.12.6.1-3.bookworm_amd64.deb"
  35. if [[ -z "$ODOO_ARCHIVE" ]]; then
  36. echo "ОШИБКА: Не найден архив odoo_19.0+e.*.tar.gz в $SCRIPT_DIR"
  37. exit 1
  38. fi
  39. echo "Используется архив: $ODOO_ARCHIVE"
  40. if [[ -n "$CUSTOM_ARCHIVE" ]]; then
  41. echo "Найден архив кастомных модулей: $CUSTOM_ARCHIVE"
  42. fi
  43. # ------------------------- ФУНКЦИИ -------------------------
  44. log_info() { echo -e "\n[INFO] $*"; }
  45. log_error() { echo -e "\n[ERROR] $*" >&2; }
  46. check_root() {
  47. if [[ $EUID -ne 0 ]]; then
  48. log_error "Скрипт должен запускаться от root (sudo)."
  49. exit 1
  50. fi
  51. }
  52. generate_password() {
  53. tr -dc 'a-zA-Z0-9' < /dev/urandom | fold -w 20 | head -n 1
  54. }
  55. install_wkhtmltopdf() {
  56. log_info "Установка wkhtmltopdf"
  57. wget -q "$WKHTMLTOX_URL" -O /tmp/wkhtmltox.deb
  58. # Используем gdebi для автоматической установки зависимостей
  59. gdebi -n /tmp/wkhtmltox.deb
  60. rm -f /tmp/wkhtmltox.deb
  61. ln -sf /usr/local/bin/wkhtmltopdf /usr/bin/wkhtmltopdf
  62. ln -sf /usr/local/bin/wkhtmltoimage /usr/bin/wkhtmltoimage
  63. log_info "wkhtmltopdf установлен"
  64. }
  65. create_odoo_user_and_dirs() {
  66. log_info "Создание пользователя $OE_USER и каталогов"
  67. adduser --system --quiet --shell=/bin/bash --home=$OE_HOME --gecos 'ODOO' --group $OE_USER
  68. adduser $OE_USER sudo
  69. mkdir -p /var/log/$OE_USER
  70. mkdir -p $OE_HOME_EXT
  71. mkdir -p $OE_HOME/custom-addons
  72. mkdir -p $OE_CONFIG_DIR
  73. }
  74. extract_odoo() {
  75. log_info "Распаковка $ODOO_ARCHIVE в $OE_HOME_EXT"
  76. rm -rf $OE_HOME_EXT/*
  77. tar -C $OE_HOME_EXT -xzf "$ODOO_ARCHIVE" --strip-components=1
  78. if [[ ! -d "$OE_HOME_EXT/odoo" || ! -f "$OE_HOME_EXT/odoo/__main__.py" ]]; then
  79. log_error "Структура архива неверна: нет odoo/__main__.py"
  80. exit 1
  81. fi
  82. }
  83. extract_custom() {
  84. if [[ -n "$CUSTOM_ARCHIVE" && -f "$CUSTOM_ARCHIVE" ]]; then
  85. if [[ "$UPDATE_MODE" == "True" ]] && [[ -d "$OE_HOME/custom-addons/clean_enterprise" ]]; then
  86. read -p "Обновить кастомные модули (папка clean_enterprise уже существует)? (y/N): " confirm
  87. if [[ ! "$confirm" =~ ^[Yy]$ ]]; then
  88. log_info "Пропускаем обновление кастомных модулей."
  89. return
  90. fi
  91. rm -rf "$OE_HOME/custom-addons/clean_enterprise"
  92. fi
  93. log_info "Распаковка $CUSTOM_ARCHIVE в $OE_HOME/custom-addons"
  94. unzip -qo "$CUSTOM_ARCHIVE" -d $OE_HOME/custom-addons
  95. if [[ -d "$OE_HOME/custom-addons/clean-enterprise-19.0" ]]; then
  96. if [[ -d "$OE_HOME/custom-addons/clean-enterprise-19.0/clean_enterprise" ]]; then
  97. mv "$OE_HOME/custom-addons/clean-enterprise-19.0/clean_enterprise" "$OE_HOME/custom-addons/"
  98. fi
  99. rm -rf "$OE_HOME/custom-addons/clean-enterprise-19.0"
  100. fi
  101. else
  102. log_info "Файл $CUSTOM_ARCHIVE не найден, пропускаем."
  103. fi
  104. }
  105. setup_venv() {
  106. log_info "Создание venv в $OE_VENV"
  107. if [[ -d "$OE_VENV" ]]; then
  108. rm -rf $OE_VENV
  109. fi
  110. su - $OE_USER -c "python3 -m venv $OE_VENV"
  111. # Убедимся, что все файлы venv принадлежат пользователю odoo
  112. chown -R $OE_USER:$OE_USER $OE_VENV
  113. log_info "Установка зависимостей Python и odoo"
  114. su - $OE_USER -s /bin/bash <<EOF
  115. source $OE_VENV/bin/activate
  116. pip install --upgrade pip wheel setuptools
  117. pip install -r $OE_HOME_EXT/requirements.txt
  118. pip install num2words ofxparse dbfread ebaysdk firebase_admin pyOpenSSL phonenumbers google_auth PyPDF2==2.12.1 psycopg2-binary pdfminer.six openpyxl
  119. pip install -e $OE_HOME_EXT/
  120. deactivate
  121. EOF
  122. # Ещё раз убеждаемся, что после установки права не нарушились
  123. chown -R $OE_USER:$OE_USER $OE_VENV
  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 "Пароль администратора: $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. setup_logrotate() {
  166. log_info "Настройка logrotate для /var/log/${OE_USER}/${OE_SERVER}.log"
  167. cat > /etc/logrotate.d/${OE_SERVER} <<EOF
  168. /var/log/${OE_USER}/${OE_SERVER}.log {
  169. daily
  170. rotate 7
  171. compress
  172. missingok
  173. notifempty
  174. create 0640 ${OE_USER} ${OE_USER}
  175. postrotate
  176. systemctl reload ${OE_SERVER} > /dev/null 2>&1 || true
  177. endscript
  178. }
  179. EOF
  180. log_info "logrotate настроен: ежедневная ротация, хранение 7 дней, сжатие."
  181. }
  182. update_databases() {
  183. log_info "Обновление модулей во всех базах данных пользователя $OE_USER"
  184. OE_DBS=$(sudo -Hiu postgres psql -tAc "SELECT datname FROM pg_database WHERE datdba = (SELECT oid FROM pg_roles WHERE rolname='$OE_USER')")
  185. if [[ -n "$OE_DBS" ]]; then
  186. for db in $OE_DBS; do
  187. log_info "Обновление базы: $db"
  188. 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"
  189. done
  190. else
  191. log_info "Нет баз данных, принадлежащих пользователю $OE_USER, для обновления."
  192. fi
  193. }
  194. # ------------------------- РЕЖИМЫ -------------------------
  195. do_install() {
  196. log_info "=== УСТАНОВКА Odoo $OE_VERSION на Debian 13 (Trixie) ==="
  197. # 0. Настройка репозитория PostgreSQL ДО первого apt-get update
  198. log_info "Настройка репозитория PostgreSQL 16"
  199. rm -f /usr/share/keyrings/postgresql-archive-keyring.gpg
  200. rm -f /etc/apt/sources.list.d/pgdg.list
  201. wget -q -O- https://www.postgresql.org/media/keys/ACCC4CF8.asc | gpg --dearmor -o /usr/share/keyrings/postgresql-archive-keyring.gpg
  202. if [[ ! -s /usr/share/keyrings/postgresql-archive-keyring.gpg ]]; then
  203. log_error "Не удалось загрузить ключ репозитория PostgreSQL"
  204. exit 1
  205. fi
  206. 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
  207. # 1. Обновление системы
  208. apt-get update
  209. apt-get upgrade -y
  210. # 2. Базовые пакеты
  211. apt-get install -y git python3 python3-pip build-essential wget \
  212. python3-dev python3-venv python3-wheel python3-cffi \
  213. libssl-dev libffi-dev libxml2-dev libxslt1-dev \
  214. libzip-dev libldap2-dev libsasl2-dev libpq-dev \
  215. libjpeg-dev zlib1g-dev libpng-dev \
  216. nodejs npm gdebi-core curl unzip logrotate
  217. # 3. PostgreSQL 16
  218. log_info "Установка PostgreSQL 16"
  219. if ! id "postgres" &>/dev/null; then
  220. log_info "Создание системного пользователя postgres"
  221. adduser --system --quiet --shell=/bin/bash --home=/var/lib/postgresql --group postgres
  222. fi
  223. apt-get install -y postgresql-16 postgresql-client-16 postgresql-server-dev-16
  224. # Убедимся, что кластер существует и запущен
  225. if ! pg_isready -q; then
  226. log_info "PostgreSQL не отвечает, пробуем запустить кластер"
  227. if pg_ctlcluster 16 main start 2>/dev/null; then
  228. log_info "Кластер 16/main запущен"
  229. else
  230. log_info "Не удалось запустить кластер, пробуем создать"
  231. su - postgres -c "pg_createcluster 16 main --start --locale C.UTF-8" 2>/dev/null || {
  232. log_info "Создание не удалось, возможно кластер уже есть, пробуем запустить"
  233. pg_ctlcluster 16 main start || {
  234. log_error "Не удалось запустить или создать кластер"
  235. exit 1
  236. }
  237. }
  238. fi
  239. else
  240. log_info "PostgreSQL уже работает"
  241. fi
  242. # Создаём пользователя odoo в PostgreSQL
  243. su - postgres -c "createuser -s $OE_USER" 2>/dev/null || true
  244. # 4. wkhtmltopdf
  245. install_wkhtmltopdf
  246. # 5. Глобальные пакеты npm
  247. npm install -g less less-plugin-clean-css rtlcss
  248. # 6. Пользователь и каталоги
  249. create_odoo_user_and_dirs
  250. # 7. Распаковка архивов
  251. extract_odoo
  252. extract_custom
  253. # 8. Права
  254. chown -R $OE_USER:$OE_USER $OE_HOME
  255. chown -R $OE_USER:$OE_USER /var/log/$OE_USER
  256. # 9. Виртуальное окружение
  257. setup_venv
  258. # 10. Конфиг и сервис
  259. create_config
  260. create_service
  261. # 11. Настройка logrotate
  262. setup_logrotate
  263. echo "-----------------------------------------------------------"
  264. echo "УСТАНОВКА ЗАВЕРШЕНА"
  265. echo "Веб-интерфейс: http://$(hostname -I | awk '{print $1}'):$OE_PORT"
  266. echo "Мастер-пароль: $OE_SUPERADMIN"
  267. echo "Конфиг: $OE_CONFIG_FILE"
  268. echo "Логи: /var/log/${OE_USER}/${OE_SERVER}.log (ротация ежедневная, 7 дней)"
  269. echo "Управление: systemctl {start|stop|restart|status} ${OE_SERVER}"
  270. echo "-----------------------------------------------------------"
  271. }
  272. do_update() {
  273. log_info "=== ОБНОВЛЕНИЕ Odoo $OE_VERSION ==="
  274. UPDATE_MODE="True"
  275. systemctl stop ${OE_SERVER} || true
  276. ODOO_ARCHIVE=$(ls -t "$SCRIPT_DIR"/odoo_19.0+e.*.tar.gz 2>/dev/null | head -n1)
  277. if [[ -z "$ODOO_ARCHIVE" ]]; then
  278. log_error "Архив не найден для обновления!"
  279. exit 1
  280. fi
  281. CUSTOM_ARCHIVE=$(ls -t "$SCRIPT_DIR"/clean-enterprise-19.0.zip 2>/dev/null | head -n1)
  282. extract_odoo
  283. extract_custom
  284. chown -R $OE_USER:$OE_USER $OE_HOME
  285. su - $OE_USER -s /bin/bash <<EOF
  286. source $OE_VENV/bin/activate
  287. pip install --upgrade pip wheel setuptools
  288. pip install -r $OE_HOME_EXT/requirements.txt
  289. pip install -e $OE_HOME_EXT/
  290. deactivate
  291. EOF
  292. update_databases
  293. systemctl start ${OE_SERVER}
  294. log_info "Обновление завершено"
  295. }
  296. do_uninstall() {
  297. log_info "=== УДАЛЕНИЕ Odoo ==="
  298. read -p "Вы уверены? (y/N): " confirm
  299. if [[ ! "$confirm" =~ ^[Yy]$ ]]; then
  300. log_info "Отмена"
  301. exit 0
  302. fi
  303. # 1. Остановка и удаление сервиса
  304. systemctl stop ${OE_SERVER} 2>/dev/null || true
  305. systemctl disable ${OE_SERVER} 2>/dev/null || true
  306. rm -f /etc/systemd/system/${OE_SERVER}.service
  307. systemctl daemon-reload
  308. # 2. Удаление конфига и каталогов Odoo
  309. rm -f $OE_CONFIG_FILE
  310. rmdir $OE_CONFIG_DIR 2>/dev/null || true
  311. rm -rf $OE_HOME
  312. rm -rf /var/log/$OE_USER
  313. # 3. Удаление пользователя odoo
  314. userdel -r $OE_USER 2>/dev/null || true
  315. # 4. Удаление ключа репозитория PostgreSQL и файла источника
  316. rm -f /usr/share/keyrings/postgresql-archive-keyring.gpg
  317. rm -f /etc/apt/sources.list.d/pgdg.list
  318. # 5. Удаление wkhtmltopdf и симлинков
  319. log_info "Удаление wkhtmltopdf"
  320. apt-get purge -y wkhtmltox 2>/dev/null || true
  321. rm -f /usr/bin/wkhtmltopdf /usr/bin/wkhtmltoimage
  322. log_info "wkhtmltopdf и симлинки удалены"
  323. # 6. Удаление настройки logrotate
  324. rm -f /etc/logrotate.d/${OE_SERVER}
  325. log_info "Настройка logrotate удалена"
  326. # 7. (Опционально) Удаление глобальных npm-пакетов
  327. # npm uninstall -g less less-plugin-clean-css rtlcss
  328. # 8. Удаление пользователя PostgreSQL и баз
  329. read -p "Удалить пользователя PostgreSQL 'odoo' и его базы? (y/N): " del_pg
  330. if [[ "$del_pg" =~ ^[Yy]$ ]]; then
  331. if id "postgres" &>/dev/null; then
  332. dbs=$(sudo -Hiu postgres psql -tAc "SELECT datname FROM pg_database WHERE datdba = (SELECT oid FROM pg_roles WHERE rolname='$OE_USER')")
  333. for db in $dbs; do
  334. sudo -u postgres dropdb "$db" 2>/dev/null || true
  335. done
  336. sudo -u postgres dropuser --if-exists $OE_USER 2>/dev/null || true
  337. log_info "Пользователь PostgreSQL удалён"
  338. fi
  339. fi
  340. # 9. Удаление PostgreSQL полностью (опционально)
  341. read -p "Удалить PostgreSQL полностью? (y/N): " del_pg_all
  342. if [[ "$del_pg_all" =~ ^[Yy]$ ]]; then
  343. apt-get purge -y postgresql-16 postgresql-client-16 postgresql-server-dev-16
  344. rm -rf /var/lib/postgresql /var/log/postgresql
  345. userdel -r postgres 2>/dev/null || true
  346. groupdel postgres 2>/dev/null || true
  347. log_info "PostgreSQL удалён"
  348. fi
  349. log_info "Удаление завершено"
  350. }
  351. # ------------------------- MAIN -------------------------
  352. check_root
  353. if [[ $# -eq 0 ]]; then
  354. echo "Использование: $0 {install|update|uninstall}"
  355. exit 1
  356. fi
  357. case "$1" in
  358. install) do_install ;;
  359. update) do_update ;;
  360. uninstall) do_uninstall ;;
  361. *) echo "Неверный параметр: $1"; exit 1 ;;
  362. esac
  363. exit 0