odoo19_install_debian13.sh 13 KB

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