diff --git a/README.rst b/README.rst index c68e98f..0d03ba7 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,5 @@ Odoo - From ERP to CRM, eCommerce to CMS -======================================== +========================================== `Odoo`_ is an all-in-one business management suite of mobile-friendly web apps that integrates everything you need to grow your business: CRM, @@ -7,75 +7,60 @@ website content management, project management, human resources, accounting, invoicing and more. Odoo apps integrate seamlessly to provide a full-featured open source ERP, but can also be used stand-alone. Python programmers can develop their own app modules, or -choose from an array of free open source such as those provided by OCA_; +choose from an array of free open source such as those provided by `OCA`_; or paid commercial ones. This appliance includes all the standard features in `TurnKey Core`_: - Odoo configurations for TurnKey v18.x: - - Odoo v16 installed from debian backports apt repo (v18.x). - - Includes modules from base install of Odoo. + - **Odoo v18** installed from official Odoo 18.0 nightly apt + repository. + - Includes modules from base install of Odoo. -- **Security note**: As of 18.0, due to using the debian backports repo - Updates to Odoo **ARE NOT** configured to install automatically. +- **Security note**: Updates to Odoo are available via standard + ``apt-get upgrade`` from the Odoo nightly repository. - SSL support out of the box. - `Adminer`_ administration frontend for PostgreSQL (listening on port 12322 - uses SSL). - Webmin modules for configuring Apache2, PostgreSQL and Postfix. +- Custom addons directory at ``/opt/odoo/custom-addons``. +- WebSocket support for Odoo 18 live chat and notifications. -**To create a new Odoo Databse (i.e. site)** +**To create a new Odoo Database (i.e. site)** To create a new Odoo DB, the Odoo config file needs to be edited and the Odoo service restarted. Overview of process: -1. Edit /etc/odoo/odoo - - change value of "db_name" from "TurnkeylinuxExample" to your desired DB +1. Edit /etc/odoo/odoo.conf + + * change value of "db_name" from "TurnkeylinuxExample" to your desired DB name -2. Restart odoo.service -3. Reload Odoo login screen in your browser and you should be good to go -Webmin steps: -1. - - Browse to 'Tools' >> 'FileManager' - - Navigate to '/etc/odoo' and edit the 'odoo.conf' file - - Edit as per step 1 above - - Save changes -2. - - Navigate to 'System' >> 'Bootup and Shutdown' - - Find the "odoo.service" in the list and select it via the checkbox - - Scroll to the bottom and select 'Restart' -3. - - As per step 3 above - -CLI steps: -1. - - Edit /etc/odoo/odoo as per step 1 -2. - - Restart odoo.service:: - - systemctl restart odoo -3. - - As per step 3 above +2. Restart odoo.service:: + + systemctl restart odoo + +3. Reload Odoo login screen in your browser and you should be good to go **Notice for special Odoo Localization** In case you run a L10n Odoo Localization you will need other PIP Packages and Libs installed on your system, please check your localization support on -OCA_. +`OCA`_. Credentials *(passwords set at first boot)* -------------------------------------------- +-------------------------------------------- **Note**: the Odoo password set at firstboot applies to both the Odoo -admin account (example app) AND the masterpassword - however these can be +admin account (example app) AND the masterpassword - however these can be changed individually after firstboot. -- Webmin, SSH: username **root** -- PostgreSQL, Adminer: username **postgres** -- Odoo Master Account: **admin** +- Webmin, SSH: username **root** +- PostgreSQL, Adminer: username **postgres** +- Odoo Master Account: **admin** .. _Odoo: https://www.odoo.com/ .. _TurnKey Core: https://www.turnkeylinux.org/core diff --git a/changelog b/changelog index 37dd4e1..1a176df 100644 --- a/changelog +++ b/changelog @@ -1,3 +1,32 @@ +turnkey-odoo-19.0 (1) turnkey; urgency=low + + * Upgraded Odoo to v18 from official Odoo 18.0 nightly apt repository + (previously v16 from Debian backports). + + * Python 3.11 (Debian Bookworm native) meets Odoo 18 requirement of + Python 3.10+. + + * PostgreSQL 15 (Debian Bookworm native) meets Odoo 18 requirement. + + * Added /opt/odoo/custom-addons directory for custom/OCA modules. + + * Updated odoo.conf with Odoo 18 optimized defaults (workers, memory + limits, proxy_mode, gevent_port for WebSocket). + + * Added Apache WebSocket proxy support (mod_proxy_wstunnel) for Odoo 18 + live chat, discuss, and real-time notifications. + + * Updated inithook for Odoo 18 compatibility (pbkdf2_sha512 hashing). + + * Installed rtlcss via npm for right-to-left language support. + + * Installed wkhtmltopdf 0.12.6 for PDF report generation. + + * Note: Please refer to turnkey-core's changelog for changes common to + all appliances. + + -- Marcos Méndez Mon, 16 Mar 2026 04:00:54 -0300 + turnkey-odoo-18.0 (1) turnkey; urgency=low * Install Odoo v16.x from Debian backports (bookworm-backports) apt diff --git a/conf.d/main b/conf.d/main index 74d377a..ad887bc 100755 --- a/conf.d/main +++ b/conf.d/main @@ -1,87 +1,106 @@ #!/bin/bash -ex - -# Set variables -# - -DB_USER=odoo -DB_PASS=$(mcookie) +# TurnKey Odoo 18 — Main Configuration Script + +SRC=/usr/local/src + +# ----------------------------------------------- +# 1. Add Odoo 18 official nightly repository +# ----------------------------------------------- +wget -qO - https://nightly.odoo.com/odoo.key \ + | gpg --dearmor -o /usr/share/keyrings/odoo-archive-keyring.gpg + +echo 'deb [signed-by=/usr/share/keyrings/odoo-archive-keyring.gpg] https://nightly.odoo.com/18.0/nightly/deb/ ./' \ + > /etc/apt/sources.list.d/odoo.list + +apt-get update +DEBIAN_FRONTEND=noninteractive apt-get install -y odoo + +# ----------------------------------------------- +# 2. Install wkhtmltopdf (patched QT version) +# ----------------------------------------------- +if ! wkhtmltopdf --version 2>/dev/null | grep -q "0.12.6"; then + WKHTMLTOPDF_DEB="wkhtmltox_0.12.6.1-2.bookworm_amd64.deb" + WKHTMLTOPDF_URL="https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6.1-2" + cd /tmp + wget "${WKHTMLTOPDF_URL}/${WKHTMLTOPDF_DEB}" || true + if [ -f "${WKHTMLTOPDF_DEB}" ]; then + dpkg -i "${WKHTMLTOPDF_DEB}" || apt-get install -f -y + rm -f "${WKHTMLTOPDF_DEB}" + fi + cd - +fi + +# ----------------------------------------------- +# 3. Install rtlcss (for right-to-left languages) +# ----------------------------------------------- +npm install -g rtlcss + +# ----------------------------------------------- +# 4. Stop Odoo for initial configuration +# ----------------------------------------------- +systemctl stop odoo || true + +# ----------------------------------------------- +# 5. Create custom addons directory +# ----------------------------------------------- +mkdir -p /opt/odoo/custom-addons +chown odoo:odoo /opt/odoo/custom-addons + +mkdir -p /var/log/odoo +chown odoo:odoo /var/log/odoo + +# ----------------------------------------------- +# 6. Configure Apache proxy for Odoo 18 +# ----------------------------------------------- +# Enable required Apache modules +a2enmod proxy proxy_http proxy_wstunnel rewrite headers ssl + +# ----------------------------------------------- +# 7. Configure PostgreSQL and create example DB +# ----------------------------------------------- DB_NAME="TurnkeylinuxExample" -# We will use a random password for now. Reset during inithook -ODOO_ADMIN_PASSWORD=$(mcookie) - -# User name that Odoo will run under -SERVICE_USER=$DB_USER - -CONF=/etc/odoo/odoo.conf - -# Create database role for odoo -# ******************************************* - -# Start postgresql server systemctl start postgresql -# Create db user -su postgres -c "createuser --superuser --createdb --no-createrole $DB_USER" - -# Set db user password -su postgres -c "psql postgres" << EOF -alter user $DB_USER with encrypted password '$DB_PASS'; -EOF -su postgres -c "psql postgres" << EOF -create database "$DB_NAME" owner $DB_USER; -EOF - -# Set password/name in config file -sed -i "s|db_password =.*|db_password = $DB_PASS|" $CONF -sed -i "s|db_host =.*|db_host = localhost|" $CONF -echo "db_name = $DB_NAME" >> $CONF - -# Stop postgresql server -systemctl stop postgresql - -# Set admin password to random value for now -sed -i "s|admin_passwd =.*|admin_passwd = $ODOO_ADMIN_PASSWORD|" $CONF -chown odoo:odoo $CONF - -# Add and disable service user -usermod -L $SERVICE_USER - -# Enable needed modules -a2enmod proxy_http headers rewrite - -# Configure sites -a2dissite 000-default -a2ensite odoo.conf - -# Populate database -systemctl start postgresql -systemctl start apache2 +su - postgres -c "createdb -O odoo ${DB_NAME}" || true -su odoo -g odoo -s '/bin/bash' -c 'odoo -i base \ - --stop-after-init --db_host=localhost \ - -d '"\"$DB_NAME\""' \ - -r '"\"$DB_USER\""' \ - -w '"\"$DB_PASS\""' \ - -s -c '"\"$CONF\"" +su - odoo -s /bin/bash -c \ + "odoo --database=${DB_NAME} \ + --init=base \ + --without-demo=all \ + --stop-after-init \ + --config=/etc/odoo/odoo.conf" || true -# enable and start odoo -systemctl enable odoo +# ----------------------------------------------- +# 8. Start services and set master password +# ----------------------------------------------- systemctl start odoo -while [[ "$(curl -Lk http://localhost)" = *"Unavailable"* ]]; do - sleep 1 +CURL="curl -s -k -L --max-time 5" +URL="http://127.0.0.1:8069" +MAX_TRIES=60 +COUNT=0 + +echo "Waiting for Odoo to start..." +while [ $COUNT -lt $MAX_TRIES ]; do + if $CURL $URL/web/login 2>/dev/null | grep -q "login"; then + echo "Odoo is ready." + break + fi + COUNT=$((COUNT + 1)) + sleep 2 done -URL="https://127.0.0.1/web" -CURL="curl --insecure -c /tmp/cookie -b /tmp/cookie" +if [ $COUNT -ge $MAX_TRIES ]; then + echo "WARNING: Odoo may not have started within expected time" +fi -$CURL $URL/login -sleep 1 -$CURL $URL/database/manager -sleep 1 -$CURL $URL/database/change_password --data-raw "master_pwd=admin&master_pwd_new=${ODOO_ADMIN_PASSWORD}" +ODOO_ADMIN_PASSWORD="${ODOO_ADMIN_PASSWORD:-admin}" +$CURL $URL/database/change_password \ + --data-raw "master_pwd=admin&master_pwd_new=${ODOO_ADMIN_PASSWORD}" || true +# ----------------------------------------------- +# 9. Stop for appliance packaging +# ----------------------------------------------- systemctl stop odoo systemctl stop postgresql -systemctl stop apache2 diff --git a/overlay/etc/apache2/sites-available/odoo.conf b/overlay/etc/apache2/sites-available/odoo.conf index e1cbb55..4d36003 100644 --- a/overlay/etc/apache2/sites-available/odoo.conf +++ b/overlay/etc/apache2/sites-available/odoo.conf @@ -1,34 +1,32 @@ -ServerName localhost - - - RewriteEngine on - ReWriteCond %{SERVER_PORT} !^443$ - RewriteRule ^/(.*) https://%{HTTP_HOST}/$1 [NC,R=301,L] - - - SSLEngine on ServerAdmin webmaster@localhost - ProxyRequests Off + SSLEngine on - - Order deny,allow - Allow from all - - - ProxyVia On + # Proxy headers + RequestHeader set X-Forwarded-Proto "https" + RequestHeader set X-Forwarded-Port "443" - # Needed for real time message / chat feature (longpolling) - ProxyPass /longpolling/poll http://127.0.0.1:8072/longpolling/poll/ timeout=200 - ProxyPass /longpolling/poll/ http://127.0.0.1:8072/longpolling/poll/ timeout=200 - ProxyPassReverse /longpolling/poll/ http://127.0.0.1:8072/longpolling/poll/ + ProxyRequests Off + ProxyPreserveHost On + + # WebSocket support (Odoo 18 live chat, discuss, notifications) + ProxyPass /websocket ws://127.0.0.1:8072/websocket + ProxyPassReverse /websocket ws://127.0.0.1:8072/websocket - ProxyPass / http://127.0.0.1:8069/ timeout=200 + # Standard HTTP proxy + ProxyPass / http://127.0.0.1:8069/ ProxyPassReverse / http://127.0.0.1:8069/ - RequestHeader set "X-Forwarded-Proto" "https" + ProxyTimeout 600 + TimeOut 600 + + ErrorLog ${APACHE_LOG_DIR}/odoo-error.log + CustomLog ${APACHE_LOG_DIR}/odoo-access.log combined + - # Fix IE problem (http error 408/409) - SetEnv proxy-nokeepalive 1 + + ServerAdmin webmaster@localhost + RewriteEngine On + RewriteRule ^(.*)$ https://%{HTTP_HOST}$1 [R=301,L] diff --git a/overlay/etc/odoo/odoo.conf b/overlay/etc/odoo/odoo.conf new file mode 100644 index 0000000..92c5cce --- /dev/null +++ b/overlay/etc/odoo/odoo.conf @@ -0,0 +1,30 @@ +[options] +admin_passwd = admin +db_host = False +db_port = False +db_user = odoo +db_password = False +db_name = TurnkeylinuxExample + +addons_path = /usr/lib/python3/dist-packages/odoo/addons,/opt/odoo/custom-addons + +proxy_mode = True +list_db = True + +logfile = /var/log/odoo/odoo-server.log +log_level = info +logrotate = True + +workers = 2 +max_cron_threads = 1 +limit_memory_hard = 2684354560 +limit_memory_soft = 2147483648 +limit_time_cpu = 60 +limit_time_real = 120 +limit_request = 8192 + +xmlrpc_port = 8069 +gevent_port = 8072 + +data_dir = /var/lib/odoo/.local/share/Odoo +csv_internal_sep = , diff --git a/overlay/usr/lib/inithooks/bin/odoo.py b/overlay/usr/lib/inithooks/bin/odoo.py index 76cbf67..fa371b3 100755 --- a/overlay/usr/lib/inithooks/bin/odoo.py +++ b/overlay/usr/lib/inithooks/bin/odoo.py @@ -1,23 +1,18 @@ #!/usr/bin/python3 +"""Set Odoo 18 admin password and master password -"""Set Odoo Admin Password Option: - --pass= unless provided, will ask interactively + --pass= unless provided, will ask interactively """ -import re import sys import getopt - -import crypt -import random -import hashlib -import configparser - import subprocess -from libinithooks.dialog_wrapper import Dialog -from pgsqlconf import PostgreSQL + from passlib.context import CryptContext +from dialog_wrapper import Dialog +from pgsqlconf import PostgreSQL + def usage(s=None): if s: @@ -26,6 +21,7 @@ def usage(s=None): print(__doc__, file=sys.stderr) sys.exit(1) + def main(): try: opts, args = getopt.gnu_getopt(sys.argv[1:], "h", @@ -40,38 +36,39 @@ def main(): elif opt == '--pass': password = val - if not password: d = Dialog('TurnKey Linux - First boot configuration') password = d.get_password( - "Odoo Database Managment & example 'admin' Password", - "Enter new password for Odoo Database Management - create/delete/manage Odoo DBs. " - "This password will also login to 'admin' account of default/example Odoo.", + "Odoo Database Management & example 'admin' Password", + "Enter new password for Odoo Database Management " + "- create/delete/manage Odoo DBs. " + "This password will also login to 'admin' account " + "of default/example Odoo.", blacklist=['\\', '/']) processed_password = CryptContext(['pbkdf2_sha512']).hash(password) default_db = 'TurnkeylinuxExample' default_db_exists = True + try: p = PostgreSQL(default_db) p.execute("UPDATE res_users SET password='{}' WHERE id=2".format( processed_password).encode('utf8')) except subprocess.CalledProcessError as e: default_db_exists = False - print(f"Default DB ({default_db}) not found - skipping setting passsword for that") + print(f"Default DB ({default_db}) not found " + "- skipping setting password for that") - sys.path.insert(0, '/usr/lib/python3/dist-packages') - import odoo - odoo.tools.config.parse_config(['--config=/etc/odoo/odoo.conf']) - odoo.tools.config.set_admin_password(password) - odoo.tools.config.save() + conf_file = '/etc/odoo/odoo.conf' + subprocess.run([ + 'sed', '-i', + 's|^admin_passwd.*|admin_passwd = {}|'.format(password), + conf_file + ], check=True) - # restart odoo to apply updated password - subprocess.run(['systemctl', 'restart', 'odoo']) + subprocess.run(['systemctl', 'restart', 'odoo'], check=True) - if not default_db_exists: - sys.exit(1) if __name__ == "__main__": main() diff --git a/plan/main b/plan/main index db0e703..950dec0 100644 --- a/plan/main +++ b/plan/main @@ -1,13 +1,56 @@ -#include -#include +# TurnKey Odoo 18 - Package Plan +# Odoo 18 installed via official nightly apt repo in conf.d/main -odoo-16 -xfonts-75dpi -wkhtmltopdf -python3-psycogreen +postgresql +postgresql-client -adduser -postgresql-client -python3 +# Python3 dependencies for Odoo 18 +python3-babel +python3-chardet +python3-dateutil +python3-decorator +python3-docutils +python3-feedparser +python3-gevent +python3-greenlet +python3-html2text +python3-idna +python3-jinja2 +python3-libsass +python3-lxml +python3-mako +python3-markupsafe +python3-num2words +python3-ofxparse +python3-openssl +python3-passlib +python3-pil +python3-polib +python3-psutil +python3-psycopg2 +python3-pydot +python3-pypdf2 +python3-qrcode +python3-reportlab +python3-requests +python3-stdnum +python3-tz +python3-vobject +python3-werkzeug +python3-xlrd +python3-xlsxwriter +python3-xlwt +python3-zeep -python3-passlib /* Needed to set admin password */ +# System dependencies +node-less +nodejs +npm +libldap2-dev +libsasl2-dev +libpq-dev +libxml2-dev +libxslt1-dev + +# Adminer for PostgreSQL management +adminer