Browse Source

init mvp

14.0
Nj Subedi 2 years ago
commit
75533b7e3f
  1. 3
      .dockerignore
  2. 6
      .gitignore
  3. 31
      CloudronManifest.json
  4. 36
      Dockerfile
  5. 21
      LICENSE
  6. 26
      README.md
  7. 1
      dev-scripts/README.md
  8. 11
      dev-scripts/build-push-install.sh
  9. 11
      dev-scripts/docker-run-openldap.sh
  10. 25
      dev-scripts/docker-run-postgres.sh
  11. 11
      dev-scripts/docker-run.sh
  12. 30
      dev-scripts/simulate-cloudron.sh
  13. 2
      manifest/CHANGELOG.md
  14. 12
      manifest/DESCRIPTION.md
  15. 6
      manifest/POSTINSTALL.md
  16. BIN
      manifest/logo.png
  17. 87
      nginx.conf
  18. 3
      odoo.conf.sample
  19. 138
      start.sh

3
.dockerignore

@ -0,0 +1,3 @@
.dockerignore
.docker
dev-scripts/

6
.gitignore

@ -0,0 +1,6 @@
*.tar.gz
.DS_Store
.env
.docker/
.idea/
*.iml

31
CloudronManifest.json

@ -0,0 +1,31 @@
{
"manifestVersion": 2,
"id": "com.odoo.cloudronapp",
"website": "https://www.odoo.com",
"contactEmail": "support@odoo.com",
"title": "Odoo",
"author": "Odoo authors",
"tagline": "Open Source ERP and CRM",
"version": "15.0",
"icon": "manifest/logo.png",
"description": "file://manifest/DESCRIPTION.md",
"changelog": "file://manifest/CHANGELOG.md",
"postInstallMessage": "file://manifest/POSTINSTALL.md",
"healthCheckPath": "/",
"httpPort": 80,
"memoryLimit": 2684354560,
"addons": {
"localstorage": {},
"postgresql": {},
"sendmail": {},
"ldap": {}
},
"tags": [
"auth"
],
"optionalSso": true,
"mediaLinks": [],
"forumUrl": "https://forum.cloudron.io/",
"documentationUrl": "https://docs.cloudron.io/"
}

36
Dockerfile

@ -0,0 +1,36 @@
FROM cloudron/base:3.2.0@sha256:ba1d566164a67c266782545ea9809dc611c4152e27686fd14060332dd88263ea
# Reference: https://github.com/odoo/docker/blob/master/15.0/Dockerfile
RUN mkdir -p /app/code /app/pkg /app/data
WORKDIR /app/code
RUN apt-get update && \
apt-get install -y \
python3-dev libxml2-dev libxslt1-dev libldap2-dev libsasl2-dev \
libtiff5-dev libjpeg8-dev libopenjp2-7-dev zlib1g-dev libfreetype6-dev \
liblcms2-dev libwebp-dev libharfbuzz-dev libfribidi-dev libxcb1-dev libpq-dev
RUN curl -o wkhtmltox.deb -sSL https://github.com/wkhtmltopdf/wkhtmltopdf/releases/download/0.12.5/wkhtmltox_0.12.5-1.focal_amd64.deb && \
echo 'ae4e85641f004a2097621787bf4381e962fb91e1 wkhtmltox.deb' | sha1sum -c - && \
apt-get install -y --no-install-recommends ./wkhtmltox.deb && \
rm -f ./wkhtmltox.deb && \
rm -rf /var/lib/apt/lists/* /var/cache/apt
RUN npm install -g rtlcss
# Install Odoo
ENV ODOO_VERSION 15.0
RUN curl -L https://github.com/odoo/odoo/archive/refs/heads/$ODOO_VERSION.tar.gz | tar zx --strip-components 1 -C /app/code && \
pip3 install wheel && \
pip3 install -r requirements.txt
RUN rm -rf /var/log/nginx && mkdir /run/nginx && ln -s /run/nginx /var/log/nginx
# Copy entrypoint script and Odoo configuration file
ADD start.sh odoo.conf.sample nginx.conf /app/pkg/
RUN mkdir -p /app/data/odoo/filestore /app/data/odoo/addons && \
chown -R cloudron:cloudron /app/data
CMD [ "/app/pkg/start.sh" ]

21
LICENSE

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2022 Nj Subedi
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

26
README.md

@ -0,0 +1,26 @@
## What
Run [Odoo](https://www.odoo.com/) on [Cloudron](https://cloudron.io). For more information see DESCRIPTION.md
## Why
Because Odoo works almost out of the box in any system that has Postgres and some disk space for data storage.
## Build and Install
- Install Cloudron CLI on your machine: `npm install -g cloudron-cli`.
- Install Docker, and make sure you can push to docker hub, or install the docker registry app in your own Cloudron.
- Log in to your Cloudron using cloudron cli: `cloudron login <my.yourdomain.tld>`.
- Build and publish the docker image: `cloudron build`.
- If you're using your own docker registry, name the image properly,
like `docker.example-cloudron.tld/john_doe/cloudron-odoo`.
- Log in to Docker Hub and mark the image as public, if necessary.
- Install the app `cloudron install -l <auth.yourdomain.tld>`
- Look at the logs to see if everything is going as planned.
Refer to the [Cloudron Docs](https://docs.cloudron.io/packaging/cli) for more information.
## Third-party Intellectual Properties
All third-party product names, company names, and their logos belong to their respective owners, and may be their
trademarks or registered trademarks.

1
dev-scripts/README.md

@ -0,0 +1 @@
Scripts inside this folder are only used as reference during development, and have no use or effect in the docker image or containers.

11
dev-scripts/build-push-install.sh

@ -0,0 +1,11 @@
#!/bin/sh
VERSION=15.0
DOMAIN='<domain in cloudron to install this app>'
AUTHOR='<your name>'
docker build -t $AUTHOR/cloudron-odoo:$VERSION ./ && docker push $AUTHOR/cloudron-odoo:$VERSION
cloudron install --image $AUTHOR/cloudron-odoo:$VERSION -l $DOMAIN
cloudron logs -f --app $DOMAIN

11
dev-scripts/docker-run-openldap.sh

@ -0,0 +1,11 @@
#!/bin/bash -e
# Run OpenLDAP & phpLDAPadmin on the network named localnet
# Create a network, if not exists: `docker network create localnet`
docker run --name ldap-service --hostname ldap-service --network localnet --detach osixia/openldap:1.1.8
docker run -p 8091:443 --name phpldapadmin-service --hostname phpldapadmin-service --network localnet --env PHPLDAPADMIN_LDAP_HOSTS=ldap-service --detach osixia/phpldapadmin:0.9.0
echo "Go to: https://localhost:8091"
echo "Login DN: cn=admin,dc=example,dc=org"
echo "Password: admin"

25
dev-scripts/docker-run-postgres.sh

@ -0,0 +1,25 @@
#!/bin/sh
# Run `postgres` container named `postgres` in docker network `localnet`
# Create a network, if not exists: `docker network create localnet`
docker run --name postgres -d -p 5432:5432 --network localnet \
-e POSTGRES_USER=odoo_user \
-e POSTGRES_PASSWORD=odoo_password \
-e POSTGRES_DB=odoo \
postgres:latest
# Login to pg cli
PGPASSWORD=postgres psql -h 127.0.0.1 -U postgres -p 5432
# Create user called 'odoo_user'
CREATE ROLE odoo_user with LOGIN
\password odoo_user
# Enter a password, such as: odoo_password, which is an extremely bad password btw.
# Recreate database quickly.
drop database odoo;
create database odoo with encoding 'utf-8' owner odoo_user;
# Try logging in as odoo_user
PGPASSWORD=odoo_password psql -h 172.17.0.1 -p 5432 -U odoo_user -d odoo

11
dev-scripts/docker-run.sh

@ -0,0 +1,11 @@
#!/bin/sh
docker rm -f odoo_container && rm -rf ./.docker/* && mkdir -p ./.docker/run/nginx ./.docker/run/odoo ./.docker/app/data ./.docker/tmp && \
BUILDKIT_PROGRESS=plain docker build -t odoo_custom . && docker run --read-only \
-v "$(pwd)"/.docker/app/data:/app/data:rw \
-v "$(pwd)"/.docker/tmp:/tmp:rw \
-v "$(pwd)"/.docker/run:/run:rw \
-p 8000:8000 \
--network localnet \
--name odoo_container \
odoo_custom

30
dev-scripts/simulate-cloudron.sh

@ -0,0 +1,30 @@
if [[ -z "${CLOUDRON+x}" ]]; then
echo "Not Cloudron. Setting testing vars..."
export CLOUDRON_POSTGRESQL_PORT=5432
export CLOUDRON_POSTGRESQL_HOST=172.17.0.1
export CLOUDRON_POSTGRESQL_DATABASE=odoo
export CLOUDRON_POSTGRESQL_USERNAME=odoo_user
export CLOUDRON_POSTGRESQL_PASSWORD=odoo_password
export CLOUDRON_APP_DOMAIN=odoo.localhost
export CLOUDRON_APP_ORIGIN=https://odoo.localhost
export CLOUDRON_MAIL_SMTP_SERVER='localhost'
export CLOUDRON_MAIL_SMTP_PORT='25'
export CLOUDRON_MAIL_SMTP_USERNAME='username'
export CLOUDRON_MAIL_SMTP_PASSWORD='password'
export CLOUDRON_MAIL_FROM='from@localhost'
export CLOUDRON_MAIL_IMAP_SERVER='localhost'
export CLOUDRON_MAIL_IMAP_PORT='25'
export CLOUDRON_MAIL_IMAP_USERNAME='username'
export CLOUDRON_MAIL_IMAP_PASSWORD='password'
export CLOUDRON_LDAP_SERVER='172.18.0.1'
export CLOUDRON_LDAP_PORT='3002'
export CLOUDRON_LDAP_URL='ldap://172.18.0.1:3002'
export CLOUDRON_LDAP_USERS_BASE_DN='ou=users,dc=cloudron'
export CLOUDRON_LDAP_GROUPS_BASE_DN='ou=groups,dc=cloudron'
export CLOUDRON_LDAP_BIND_DN='cn=app_id,ou=apps,dc=cloudron'
export CLOUDRON_LDAP_BIND_PASSWORD='example_bind_password'
fi

2
manifest/CHANGELOG.md

@ -0,0 +1,2 @@
v15.0
First release of Odoo 15.0.

12
manifest/DESCRIPTION.md

@ -0,0 +1,12 @@
Run Odoo on Cloudron.
Features
---
- Uses Cloudron LDAP for user federation
- Uses Cloudron SMTP for sending emails
- Uses Cloudron IMAP for incoming emails
- Hardened to disable database selection, debug mode, etc.
- Supports custom addons installed at `/app/data/extra-addons`
- Supports customization using `/app/data/odoo.conf`
- Supports long-polling actions like chat using custom `/run/nginx/nginx.conf` file

6
manifest/POSTINSTALL.md

@ -0,0 +1,6 @@
Log in with the default credentials and change your password immediately by clicking on the profile
(**Administrator**) button in the top right corner of the screen.
Email : `admin`
Password: `admin`

BIN
manifest/logo.png

After

Width: 256  |  Height: 256  |  Size: 7.8 KiB

87
nginx.conf

@ -0,0 +1,87 @@
# Based on https://git.cloudron.io/cloudron/taiga-app/-/raw/master/nginx.conf
daemon off;
worker_processes auto;
pid /run/nginx/nginx.pid;
error_log stderr;
events {
worker_connections 768;
}
http {
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
include /etc/nginx/mime.types;
default_type application/octet-stream;
client_body_temp_path /run/nginx/client_body;
proxy_temp_path /run/nginx/proxy_temp;
fastcgi_temp_path /run/nginx/fastcgi_temp;
scgi_temp_path /run/nginx/scgi_temp;
uwsgi_temp_path /run/nginx/uwsgi_temp;
##
# Logging Settings
##
access_log /dev/stdout;
##
# Gzip Settings
##
gzip on;
gzip_disable "msie6";
##
# Virtual Host Configs
##
#odoo server
upstream odoo {
server 127.0.0.1:8069;
}
upstream odoo-lp {
server 127.0.0.1:8072;
}
server {
listen 8000;
server_name __REPLACE_WITH_CLOUDRON_APP_DOMAIN__;
proxy_read_timeout 720s;
proxy_connect_timeout 720s;
proxy_send_timeout 720s;
large_client_header_buffers 4 32k;
client_max_body_size 50M;
charset utf-8;
# Add Headers for odoo proxy mode
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Scheme $scheme;
proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $host;
# Redirect longpoll requests to odoo longpolling port
location /longpolling {
proxy_pass http://odoo-lp;
}
# Redirect requests to odoo backend server
location / {
proxy_redirect off;
proxy_pass http://odoo;
}
# common gzip
gzip_types text/css text/scss text/plain text/xml application/xml application/json application/javascript;
gzip on;
}
}

3
odoo.conf.sample

@ -0,0 +1,3 @@
[options]
addons_path = /app/code/addons,/app/data/extra-addons
data_dir = /app/data/odoo

138
start.sh

@ -0,0 +1,138 @@
#!/bin/bash
set -eu pipefail
export LANG="C.UTF-8"
export ODOO_RC="/app/data/odoo.conf"
pg_cli() {
PGPASSWORD=$CLOUDRON_POSTGRESQL_PASSWORD psql \
-h $CLOUDRON_POSTGRESQL_HOST \
-p $CLOUDRON_POSTGRESQL_PORT \
-U $CLOUDRON_POSTGRESQL_USERNAME \
-d $CLOUDRON_POSTGRESQL_DATABASE -c "$1"
}
# Create required directories if they don't exist
mkdir -p /app/data/extra-addons /app/data/odoo /run/odoo /run/nginx
chown -R cloudron:cloudron /run
# Check for First Run
if [[ ! -f /app/data/odoo.conf ]]; then
echo "First run. Initializing DB..."
# Initialize the database, and exit.
/usr/local/bin/gosu cloudron:cloudron /app/code/odoo-bin -i base,auth_ldap,fetchmail --without-demo all --data-dir /app/data/odoo --logfile /run/odoo/runtime.log -d $CLOUDRON_POSTGRESQL_DATABASE --db_host $CLOUDRON_POSTGRESQL_HOST --db_user $CLOUDRON_POSTGRESQL_USERNAME --db_pass $CLOUDRON_POSTGRESQL_PASSWORD --stop-after-init
echo "Initialized successfully."
echo "Copying default configuration file to /app/data/odoo.conf..."
cp /app/pkg/odoo.conf.sample /app/data/odoo.conf
echo "Adding required tables/relations for mail settings."
pg_cli "INSERT INTO public.res_config_settings (create_uid, create_date, write_uid, write_date, company_id, user_default_rights, external_email_server_default, module_base_import, module_google_calendar, module_microsoft_calendar, module_mail_plugin, module_google_drive, module_google_spreadsheet, module_auth_oauth, module_auth_ldap, module_base_gengo, module_account_inter_company_rules, module_pad, module_voip, module_web_unsplash, module_partner_autocomplete, module_base_geolocalize, module_google_recaptcha, group_multi_currency, show_effect, profiling_enabled_until, module_product_images, unsplash_access_key, fail_counter, alias_domain, restrict_template_rendering, use_twilio_rtc_servers, twilio_account_sid, twilio_account_token, auth_signup_reset_password, auth_signup_uninvited, auth_signup_template_user_id) VALUES (2, 'NOW()', 2, 'NOW()', 1, false, true, true, false, false, false, false, false, false, true, false, false, false, false, true, true, false, false, false, true, NULL, false, NULL, 0, '$CLOUDRON_APP_DOMAIN', false, false, NULL, NULL, false, 'b2c', 5) ON CONFLICT (id) DO NOTHING;"
pg_cli "INSERT INTO public.ir_config_parameter (key, value, create_uid, create_date, write_uid, write_date) VALUES ('base_setup.default_external_email_server', 'True', 2, 'NOW()', 2, 'NOW()');"
pg_cli "INSERT INTO public.ir_config_parameter (key, value, create_uid, create_date, write_uid, write_date) VALUES ('mail.catchall.domain', '$CLOUDRON_APP_DOMAIN', 2, 'NOW()', 2, 'NOW()');"
echo "First run complete."
fi
# These values should be re-set to make Odoo work as expcected.
echo "Ensuring proper [options] in /app/data/odoo.conf ..."
# Custom paths
crudini --set /app/data/odoo.conf 'options' addons_path "/app/code/addons,/app/data/extra-addons"
crudini --set /app/data/odoo.conf 'options' data_dir "/app/data/odoo"
# Logging
crudini --set /app/data/odoo.conf 'options' logfile "/run/odoo.log"
crudini --set /app/data/odoo.conf 'options' logrotate 'False'
crudini --set /app/data/odoo.conf 'options' log_db 'False'
crudini --set /app/data/odoo.conf 'options' syslog 'False'
# Http Server
crudini --set /app/data/odoo.conf 'options' proxy_mode "True"
crudini --set /app/data/odoo.conf 'options' secure 'False'
crudini --set /app/data/odoo.conf 'options' interface '127.0.0.1'
crudini --set /app/data/odoo.conf 'options' port '8069'
crudini --set /app/data/odoo.conf 'options' longpolling_port '8072'
# Securing Odoo
crudini --set /app/data/odoo.conf 'options' list_db "False"
crudini --set /app/data/odoo.conf 'options' test_enable "False"
crudini --set /app/data/odoo.conf 'options' test_file "False"
crudini --set /app/data/odoo.conf 'options' test_report_directory "False"
crudini --set /app/data/odoo.conf 'options' without_demo "all"
crudini --set /app/data/odoo.conf 'options' debug_mode "False"
#TODO Disable debug mode
# DB
crudini --set /app/data/odoo.conf 'options' db_host "$CLOUDRON_POSTGRESQL_HOST"
crudini --set /app/data/odoo.conf 'options' db_port "$CLOUDRON_POSTGRESQL_PORT"
crudini --set /app/data/odoo.conf 'options' db_user "$CLOUDRON_POSTGRESQL_USERNAME"
crudini --set /app/data/odoo.conf 'options' db_password "$CLOUDRON_POSTGRESQL_PASSWORD"
crudini --set /app/data/odoo.conf 'options' db_name "$CLOUDRON_POSTGRESQL_DATABASE"
crudini --set /app/data/odoo.conf 'options' db_filter "^$CLOUDRON_POSTGRESQL_DATABASE.*$"
crudini --set /app/data/odoo.conf 'options' db_sslmode 'False'
# IMAP Configuration
if [[ -z "${CLOUDRON_MAIL_SMTP_SERVER+x}" ]]; then
echo "IMAP is disabled. Removing values from config."
pg_cli "DELETE FROM public.fetchmail_server WHERE id = 1 AND company = 1"
else
echo "IMAP is enabled. Adding values to config."
pg_cli "INSERT INTO public.fetchmail_server (id, name, active, state, server, port, server_type, is_ssl, attach, original, date, \"user\", password, object_id, priority, configuration, script, create_uid, create_date, write_uid, write_date) VALUES (1, 'Cloudron IMAP Service', true, 'done', '$CLOUDRON_MAIL_IMAP_SERVER', $CLOUDRON_MAIL_IMAP_PORT, 'imap', false, true, false, NULL, '$CLOUDRON_MAIL_IMAP_USERNAME', '$CLOUDRON_MAIL_IMAP_PASSWORD', 151, 5, NULL, '/mail/static/scripts/odoo-mailgate.py', 2, 'NOW()', 2, 'NOW()') ON CONFLICT (id) DO NOTHING;"
fi
# SMTP Configuration
if [[ -z "${CLOUDRON_MAIL_SMTP_SERVER+x}" ]]; then
echo "SMTP is disabled. Removing values from config."
pg_cli "DELETE FROM public.ir_mail_server WHERE id = 1 AND company = 1"
else
echo "SMTP is enabled. Adding values to config."
pg_cli "INSERT INTO public.ir_mail_server (id, name, from_filter, smtp_host, smtp_port, smtp_authentication, smtp_user, smtp_pass, smtp_encryption, smtp_ssl_certificate, smtp_ssl_private_key, smtp_debug, sequence, active, create_uid, create_date, write_uid, write_date) VALUES (1, 'Cloudron SMTP Service', NULL, '$CLOUDRON_MAIL_SMTP_SERVER', $CLOUDRON_MAIL_SMTP_PORT, 'login', '$CLOUDRON_MAIL_SMTP_USERNAME', '$CLOUDRON_MAIL_SMTP_PASSWORD', 'none', NULL, NULL, false, 10, true, 2, 'NOW()', 2, 'NOW()') ON CONFLICT (id) DO NOTHING;"
fi
# LDAP Configuration
if [[ -z "${CLOUDRON_LDAP_SERVER+x}" ]]; then
echo "LDAP is disabled. Removing values from config."
pg_cli "DELETE FROM public.res_company_ldap WHERE id = 1 AND company = 1"
else
echo "LDAP is enabled. Adding values to config."
pg_cli "INSERT INTO public.res_company_ldap (id, sequence, company, ldap_server, ldap_server_port, ldap_binddn, ldap_password, ldap_filter, ldap_base, \"user\", create_user, ldap_tls, create_uid, create_date, write_uid, write_date) VALUES (1, 10, 1, '$CLOUDRON_LDAP_SERVER', $CLOUDRON_LDAP_PORT, '$CLOUDRON_LDAP_BIND_DN', '$CLOUDRON_LDAP_BIND_PASSWORD', '(objectclass=user)', '$CLOUDRON_LDAP_USERS_BASE_DN', NULL, true, false, 2, 'NOW()', 2, 'NOW()') ON CONFLICT (id) DO NOTHING;;"
fi
# Start nginx process
sed -e "s,__REPLACE_WITH_CLOUDRON_APP_DOMAIN__,${CLOUDRON_APP_DOMAIN}," /app/pkg/nginx.conf >/run/nginx/nginx.conf
chown -R cloudron:cloudron /app/data
echo "=> Start nginx"
nginx -c /run/nginx/nginx.conf &
# Done nginx
echo "Resource allocation (hard limit: 100% of available memory; soft limit: 80%)"
if [[ -f /sys/fs/cgroup/memory/memory.memsw.limit_in_bytes ]]; then
memory_limit_hard=$(($(cat /sys/fs/cgroup/memory/memory.memsw.limit_in_bytes)))
memory_limit_soft=$((memory_limit_hard * 4 / 5))
else
memory_limit_hard=2684354560
memory_limit_soft=2147483648 # (memory_limit_hard * 4 / 5)
fi
worker_count=$((memory_limit_hard / 1024 / 1024 / 150)) # 1 worker for 150M
worker_count=$((worker_count > 8 ? 8 : worker_count)) # max of 8
worker_count=$((worker_count < 1 ? 1 : worker_count)) # min of 1
echo "Memory limits - hard limit: $memory_limit_hard bytes, soft limit: $memory_limit_soft bytes"
crudini --set /app/data/odoo.conf 'options' limit_memory_hard $memory_limit_hard
crudini --set /app/data/odoo.conf 'options' limit_memory_soft $memory_limit_soft
crudini --set /app/data/odoo.conf 'options' workers $worker_count
echo "Done. Starting server with $worker_count workers.."
chown -R cloudron:cloudron /app/data/
/usr/local/bin/gosu cloudron:cloudron /app/code/odoo-bin -c /app/data/odoo.conf
Loading…
Cancel
Save