From f4b2e2d5f54b71d567e7e55a068f72b37eee0d97 Mon Sep 17 00:00:00 2001 From: Nj Subedi Date: Thu, 5 Jan 2023 02:07:24 +0545 Subject: [PATCH] cleanup and documentation --- CloudronManifest.json | 6 +- Dockerfile | 39 ++++----- README.md | 56 +++++++------ mysql_custom.cnf | 6 +- start.sh | 188 ++++++++++++++++-------------------------- 5 files changed, 127 insertions(+), 168 deletions(-) diff --git a/CloudronManifest.json b/CloudronManifest.json index fe13a12..14189fa 100644 --- a/CloudronManifest.json +++ b/CloudronManifest.json @@ -13,13 +13,15 @@ "changelog": "file://manifest/CHANGELOG.md", "postInstallMessage": "file://manifest/POSTINSTALL.md", "healthCheckPath": "/", + "configurePath": "/app/", "httpPort": 8888, "memoryLimit": 4294967296, "multiDomain": true, "addons": { "localstorage": {}, - "recvmail": {}, - "sendmail": { "supportsDisplayName": true }, + "sendmail": { + "supportsDisplayName": true + }, "ldap": {}, "redis": { "noPassword": true diff --git a/Dockerfile b/Dockerfile index 46f7526..2bdf0d7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,12 +1,5 @@ FROM cloudron/base:4.0.0@sha256:31b195ed0662bdb06a6e8a5ddbedb6f191ce92e8bee04c03fb02dd4e9d0286df -# Create all necessary directories - -RUN mkdir -p /app/code /app/data/{frappe-bench,mariadb} \ - && chown -R cloudron:cloudron /app/code /app/data - -WORKDIR /app/code/frappe-bench - # Remove unnecessary database and php packages (takes some time) # install mariadb (10.6 default), python (3.10 default) and required python3 packages RUN apt-get remove -y --purge mongodb-* postgresql-* *mysql* *mariadb* \ @@ -21,41 +14,39 @@ RUN apt-get remove -y --purge mongodb-* postgresql-* *mysql* *mariadb* \ mariadb-server mariadb-backup\ && pip3 install frappe-bench -ARG FRAPPE_VERSION=v14.21.0 +ENV FRAPPE_VERSION=v14.21.1 ERPNEXT_VERSION=v14.12.0 -RUN chown -R 1000:1000 /app/code +RUN mkdir -p /app/code/frappe-bench /app/pkg && \ + chown -R 1000:1000 /app/code + +WORKDIR /app/code/frappe-bench # Initialize frappe-bench, whatever it means. -RUN /usr/local/bin/gosu cloudron:cloudron bench init --verbose \ +RUN gosu cloudron:cloudron bench init --verbose \ --frappe-branch ${FRAPPE_VERSION} \ --skip-redis-config-generation \ --ignore-exist \ --python /usr/bin/python3 \ /app/code/frappe-bench -# [1]This is a standard procedure for Cloudron to move existing "data" somewhere else, -# and put a symlink to /app/data from the original location; on first run, we copy -# files from -orig to /app/data/, which in turn points to the actual files. -# anyone who has packaged an app would know this practice. - # Move the folders that frappe would pollute with writes at runtime. -RUN mkdir -p /app/data/frappe \ - && mv /app/code/frappe-bench/sites /app/code/frappe-bench/sites-orig \ +RUN mkdir -p /app/pkg/frappe-bench-orig \ + && mv /app/code/frappe-bench/sites /app/pkg/frappe-bench-orig/sites \ && ln -sf /app/data/frappe/sites /app/code/frappe-bench/sites \ \ - && mv /app/code/frappe-bench/env /app/code/frappe-bench/env-orig \ + && mv /app/code/frappe-bench/env /app/pkg/frappe-bench-orig/env \ && ln -sf /app/data/frappe/env /app/code/frappe-bench/env \ \ - && mv /app/code/frappe-bench/config /app/code/frappe-bench/config-orig \ + && mv /app/code/frappe-bench/config /app/pkg/frappe-bench-orig/config \ && ln -sf /app/data/frappe/config /app/code/frappe-bench/config \ \ - && mv /app/code/frappe-bench/apps /app/code/frappe-bench/apps-orig \ + && mv /app/code/frappe-bench/apps /app/pkg/frappe-bench-orig/apps \ && ln -sf /app/data/frappe/apps /app/code/frappe-bench/apps \ \ - && mv /app/code/frappe-bench/logs /app/code/frappe-bench/logs-orig \ + && mv /app/code/frappe-bench/logs /app/pkg/frappe-bench-orig/logs \ && ln -sf /run/frappe/logs /app/code/frappe-bench/logs \ \ - && mv /app/code/frappe-bench/patches.txt /app/code/frappe-bench/patches-orig.txt \ + && mv /app/code/frappe-bench/patches.txt /app/pkg/frappe-bench-orig/patches.txt \ && ln -sf /app/data/frappe/patches.txt /app/code/frappe-bench/patches.txt @@ -82,7 +73,7 @@ RUN sudo mysqld_safe & \ COPY supervisor/ /etc/supervisor/ -RUN mkdir -p /run/supervisor/{logs} \ +RUN mkdir -p /run/supervisor/logs \ && sudo ln -s /run/supervisor/logs/supervisord.log /var/log/supervisor/supervisord.log \ \ && rm /etc/nginx/sites-enabled/* \ @@ -94,6 +85,4 @@ RUN ln -sf /run/.yarnrc /home/cloudron/.yarnrc COPY nginx.conf setup-ldap.sh start.sh /app/pkg/ -ENV ERPNEXT_VERSION=v14.11.1 - CMD [ "/app/pkg/start.sh" ] \ No newline at end of file diff --git a/README.md b/README.md index 5069b17..ab18d99 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,7 @@ Refer to the [Cloudron Docs](https://docs.cloudron.io/packaging/cli) for more in Please refer to `docker-run.sh` file for some commands handy for you to test this setup. ## Logging in + Look for credentials in the file `-credentials.txt` from the file manager.sd ## LDAP Connection [WIP] @@ -37,46 +38,52 @@ LDAP Group sync or custom group mapping could also be possible, but I haven't tr For now, look at the `/app/pkg/setup-ldap.sh` and make necessary changes. Run the command to add LDAP settings. The script is configured to use your cloudron's LDAP addon. -- add : adds LDAP settings to the site -- disable: disables LDAP settings (required before deleting) -- delete: deletes the LDAP settings for the site +- `/app/pkg/setup-ldap.sh add` : adds LDAP settings to the site +- `/app/pkg/setup-ldap.sh disable`: disables LDAP settings (required before deleting) +- `/app/pkg/setup-ldap.sh delete`: deletes the LDAP settings for the site ## Installing Apps -You can install new frappe apps. To install the apps, simply follow these steps, and restart the app. -Also refer to the [Official Documentation](https://frappeframework.com/docs/v14/user/en/bench/bench-commands#add-apps) +You can install new frappe apps. To install the apps, simply follow these steps. ```shell # Make sure you are in the /app/code/frappe-bench directory. cd /app/code/frappe-bench +gosu cloudron bench get-app +gosu cloudron bench install-app +gosu cloudron bench restart -gosu cloudron bench get-app --branch +# EXAMPLE 1: install the hrms app +gosu cloudron bench get-app hrms gosu cloudron bench install-app hrms +gosu cloudron bench restart -# Example: install the hrms app for HR Management +# EXAMPLE 2: install a specific version of the hrms gosu cloudron bench get-app --branch v1.0.0 hrms gosu cloudron bench install-app hrms +gosu cloudron bench restart + +# EXAMPLE 3: install a specific version of the frappedesk +gosu cloudron bench get-app --branch develop frappedesk +gosu cloudron bench install-app frappedesk +gosu cloudron bench restart ``` -Note: Restart the app using the Restart button on top of the terminal, or simply run `supervisorctl restart all` to -ensure the apps are properly configured. +Also refer to the [Official Documentation](https://frappeframework.com/docs/v14/user/en/bench/bench-commands#add-apps) -## Updating ErpNext +## Updating Apps ### Important Notes -- **MAKE SURE TO BACKUP BEFORE TRYING TO UPDATE. IF THE UPDATE FAILS, THE APP MAY STOP RESPONDING, AND YOU MAY LOSE - DATA.** - -- **Run the `git` and `bench` commands with `gosu cloudron` as the user `cloudron` instead of the root user.**' - -- **Put the app in Recovery Mode from the dashboard before running updates and turn it off later.** +- MAKE SURE TO TAKE A BACKUP USING CLOUDRON BEFORE TRYING TO UPDATE. +- IF THE UPDATE FAILS, THE APP MAY STOP RESPONDING, AND YOU MAY LOSE DATA. ```shell # Put the app in maintenance mode gosu cloudron bench set-maintenance-mode on + # Run the update commands # Turn off maintenance mode gosu cloudron bench set-maintenance-mode off @@ -84,26 +91,27 @@ ensure the apps are properly configured. ### 1. Update with Cloudron CLI -You can update this package normally by pulling the latest version of this repository, then running `cloudron update` +You can update this package normally by pulling the latest version of this repository, then running `cloudron build` and `cloudron update --app your-app-domain`. This is the safest way to update the app. **After updating, make sure to run `gosu cloudron bench migrate` from the terminal while the app is running.** ### 2. Automatic updates with bench -Set the application to Recovery Mode. Then update normally. Refer to -the [Official Documentation](https://frappeframework.com/docs/v14/user/en/production-setup#updating) +You don't need to update this cloudron package. You can update Frappe, ErpNext and other apps from the cloudron +dashboard itself. ```shell - # switch frappe and erpnext app version to version-14 + # switch frappe and erpnext app branch to version-14 or any other branch. gosu cloudron bench switch-to-branch version-14 frappe erpnext #if you have more apps, switch to the respective versions for those apps as well - # gosu cloudron bench switch-to-branch version-xxx app1 app2 app3 ... - - # update frappe and all apps, then run migration - gosu cloudron bench update + # gosu cloudron bench switch-to-branch v1.0.0 hrms + # gosu cloudron bench switch-to-branch develop frappedesk + # etc... + # update frappe and all apps, then run migration. Note: backups are handled by cloudron (if you have set it up) + gosu cloudron bench update --reset --no-backup ``` You can also run each steps one at a time as needed. diff --git a/mysql_custom.cnf b/mysql_custom.cnf index 8debd29..e03e1da 100644 --- a/mysql_custom.cnf +++ b/mysql_custom.cnf @@ -9,4 +9,8 @@ innodb_use_native_aio=0 character-set-client-handshake=FALSE character-set-server=utf8mb4 collation-server=utf8mb4_unicode_ci -max_allowed_packet=107374182 \ No newline at end of file +max_allowed_packet=107374182 + +# these settings did not work while put in config, so they should be passed as runtime parameters to mysqld_safe +# --character-set-server +# --collation-server \ No newline at end of file diff --git a/start.sh b/start.sh index f29a93d..bb2b1b4 100755 --- a/start.sh +++ b/start.sh @@ -1,134 +1,96 @@ #!/bin/bash set -eu pipefail -echo ">>>> Creating directories" -mkdir -p /run/nginx /run/supervisor/logs /run/mariadb /run/frappe -chown -R cloudron:cloudron /run/nginx -chown -R cloudron:cloudron /run/supervisor/ +echo ">>>> Ensure runtime directories" +mkdir -p /run/nginx && chown -R cloudron:cloudron /run/nginx/ +mkdir -p /run/supervisor/logs && chown -R cloudron:cloudron /run/supervisor/ +mkdir -p /app/data/frappe/{env,config,sites,apps,logs} +mkdir -p /run/frappe/logs +mkdir -p /app/data/mariadb +mkdir -p /run/mysqld/logs -if [[ ! -f /run/.yarnrc ]]; then - touch /run/.yarnrc && chown cloudron:cloudron /run/.yarnrc -fi +# Yarn -cd /app/code/frappe-bench +echo ">>>> Ensure yarn can run properly" +touch /run/.yarnrc && chown cloudron:cloudron /run/.yarnrc -# I've split the first-run checks in multiple places because it takes a lot of time -# to copy from /app/code/frappe-bench/-orig to /app/data/frappe/ and then -# chown recursively. During development we can delete the .docker/app/data/mariadb folder -# without waiting for .docker/app/data/frapee folder to perform "first-run" again. +# Frappe Bench -# check for frappe framework files -# copy frappe bench, then chown to cloudron (takes a while) +echo ">>>> Ensure frappe-bench directory is initialized." if [[ ! -f /app/data/frappe/.initialized ]]; then - echo ">>>> firstrun: setup /app/data/{config,sites,apps,logs}" - mkdir -p /app/data/frappe/{env,config,sites,apps,logs} - cp -R /app/code/frappe-bench/env-orig/* /app/data/frappe/env/ - cp -R /app/code/frappe-bench/config-orig/* /app/data/frappe/config/ - cp -R /app/code/frappe-bench/sites-orig/* /app/data/frappe/sites/ - cp -R /app/code/frappe-bench/apps-orig/* /app/data/frappe/apps/ - cp -R /app/code/frappe-bench/logs-orig/* /app/data/frappe/logs/ - - chown -R cloudron:cloudron /app/data/frappe - + cp -R /app/pkg/frappe-bench-orig/env/* /app/data/frappe/env/ + cp -R /app/pkg/frappe-bench-orig/config/* /app/data/frappe/config/ + cp -R /app/pkg/frappe-bench-orig/sites/* /app/data/frappe/sites/ + cp -R /app/pkg/frappe-bench-orig/apps/* /app/data/frappe/apps/ + cp -n /app/pkg/frappe-bench-orig/patches.txt /app/data/frappe/patches.txt + cp -R /app/pkg/frappe-bench-orig/logs/* /run/frappe/logs/ touch /app/data/frappe/.initialized - echo ">>>> Done frappe setup" -fi - -if [[ ! -f /app/data/frappe/patches.txt ]]; then - cp /app/code/frappe-bench/patches-orig.txt /app/data/frappe/patches.txt - chown cloudron:cloudron /app/data/frappe/patches.txt -fi - -# Check for log folders (takes no time) -if [[ ! -d /run/frappe/logs ]]; then - echo ">>>> firstrun: setup /run/frappe/logs" - - mkdir -p /run/frappe/logs - cp -R /app/code/frappe-bench/logs-orig/* /run/frappe/logs/ - echo ">>>> Done frappe logs setup" fi +chown -R cloudron:cloudron /app/data/frappe chown -R cloudron:cloudron /run/frappe/logs -# Check if db setup is complete (takes no time) -if [[ ! -f /app/data/mariadb/.initialized ]]; then - - echo ">>>> firstrun: setup /app/data/mariadb" +# Mariadb - mkdir -p /app/data/mariadb +echo ">>>> Ensure mariadb is initialized." +if [[ ! -f /app/data/mariadb/.initialized ]]; then cp -R /var/lib/mysql-orig/* /app/data/mariadb/ - chown -R mysql:mysql /app/data/mariadb - touch /app/data/mariadb/.initialized fi chown -R mysql:mysql /app/data/mariadb -echo ">>>> Done /app/data/mariadb setup" - -echo ">>>> Setup /run/mysqld/logs" -if [[ ! -d /run/mysqld/logs ]]; then - mkdir -p /run/mysqld/logs -## sometimes /var/log/mysql-orig/* doesn't exist, and cp failed; can't find a cause, so skipping on the logs part now. -# cp -R /var/log/mysql-orig/* /run/mysqld/logs -fi chown -R mysql:mysql /run/mysqld/logs -echo ">>>> Done setup /run/mysqld/logs" - -## Setup mariadb -echo ">>>> Running mysqld_safe..." -mkdir -p /app/data/tmp && chown mysql:mysql /app/data/tmp +# Mariadb hardening -# NOTE: --character-set-server and --collation-server options don't work in config file. *SIGH* -/usr/local/bin/gosu mysql:mysql mysqld_safe \ - --skip-syslog \ - --character-set-server=utf8mb4 \ - --collation-server=utf8mb4_unicode_ci & +echo ">>>> Ensuring default root password for mariadb is changed." +gosu mysql:mysql mysqld_safe --skip-syslog --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci & sleep 5 - -# Wait until mysql process is listening +# Wait until mysql process is listening... tail -f /app/data/mariadb/*.err | sed '/ready for connections/ q' -echo ">>>> Success. Daemon mysqld listening." - if [[ ! -f /app/data/mariadb/.root_password ]]; then - echo ">>>> Changing password for database root user..." DB_ROOT_PWD=$(openssl rand -hex 32) - echo -n "$DB_ROOT_PWD" >>/app/data/mariadb/.root_password + echo -n "$DB_ROOT_PWD" >>/app/data/mariadb/.root_password.txt + echo ">>>> Changed password for database root user. See mariadb/.root_password.txt file." mysql -uroot -proot -e "SET PASSWORD FOR 'root'@'localhost' = PASSWORD('${DB_ROOT_PWD}');" mysql -uroot -proot -e "FLUSH PRIVILEGES;" echo "Done." + + touch /app/data/mariadb/.root_password fi -## Set common redis configuration. -REDIS_URL="redis://${CLOUDRON_REDIS_HOST}:${CLOUDRON_REDIS_PORT}" -## Using sed because `bench config set-common-config -c redis_cache "redis://$CLOUDRON_REDIS_HOST"` didn't work. -sed -i "s|\"redis_cache\": \".*\"|\"redis_cache\": \"$REDIS_URL\"|" /app/data/frappe/sites/common_site_config.json -sed -i "s|\"redis_queue\": \".*\"|\"redis_queue\": \"$REDIS_URL\"|" /app/data/frappe/sites/common_site_config.json -sed -i "s|\"redis_socketio\": \".*\"|\"redis_socketio\": \"$REDIS_URL\"|" /app/data/frappe/sites/common_site_config.json +# Redis -############# ################## -DEFAULT_SITE=${CLOUDRON_APP_DOMAIN:-'cloudron.local'} +gosu cloudron:cloudron bench set-redis-cache-host "${CLOUDRON_REDIS_HOST}:${CLOUDRON_REDIS_PORT}" +gosu cloudron:cloudron bench set-redis-queue-host "${CLOUDRON_REDIS_HOST}:${CLOUDRON_REDIS_PORT}" +gosu cloudron:cloudron bench set-redis-socketio-host "${CLOUDRON_REDIS_HOST}:${CLOUDRON_REDIS_PORT}" -if [[ ! -f "/app/data/frappe/sites/${DEFAULT_SITE}/.initialized" ]]; then +# Default Site - echo ">>>> Creating default site with hostname: ${DEFAULT_SITE} ..." +echo ">>>> Ensuring default site exists" - echo 'frappe' >/app/data/frappe/sites/apps.txt +DEFAULT_SITE=${CLOUDRON_APP_DOMAIN:-'cloudron.local'} +if [[ ! -f "/app/data/frappe/sites/${DEFAULT_SITE}/.initialized" ]]; then + + echo ">>>> Default site not found. Creating ${DEFAULT_SITE} ..." echo ">>>> Generating passwords..." - DB_ROOT_PWD=$(>>> Running bench new-site..." + echo ">>>> Running bench new-site command ..." - # Get and Install ErpNext app by default, as it cannot be installed after the initial setup of frappe website is complete. + # Make sure frappe is installed by default on this site. + echo 'frappe' >/app/data/frappe/sites/apps.txt + + # Fetch erpnext app (erpnext is not fetched in docker image to reduce size) gosu cloudron bench get-app --branch ${ERPNEXT_VERSION} --resolve-deps erpnext - /usr/local/bin/gosu cloudron:cloudron bench new-site \ - --verbose \ + gosu cloudron:cloudron bench new-site \ --force \ --db-name "${DB_NAME}" \ --db-password "${DB_PWD}" \ @@ -137,42 +99,36 @@ if [[ ! -f "/app/data/frappe/sites/${DEFAULT_SITE}/.initialized" ]]; then --admin-password "${SITE_PWD}" "${DEFAULT_SITE}" \ --install-app erpnext - echo "Website Username: Administrator / Website Password: ${SITE_PWD}" >"/app/data/${DEFAULT_SITE}-credential.txt" - - echo "Database Username: ${DB_NAME} / Database Password: ${DB_PWD}" >>"/app/data/${DEFAULT_SITE}-credential.txt" - - /usr/local/bin/gosu cloudron:cloudron bench use "${DEFAULT_SITE}" + # Save Login credentials for future use. User may change it if needed. + echo -e "Admin Login: \n Username: Administrator\n Password: ${SITE_PWD} " >"$CREDENTIALS_FILE" + echo -e "\n\n################\n\nSee ${DEFAULT_SITE}-credential.txt file for username/password.\n\n################\n" - echo ">>>> enable scheduler for ${DEFAULT_SITE}..." - /usr/local/bin/gosu cloudron:cloudron bench scheduler enable - ############# ################## - echo ">>>> setting nginx port to 8888 for site ${DEFAULT_SITE}" - bench set-nginx-port ${DEFAULT_SITE} 8888 + gosu cloudron:cloudron bench setup add-domain --site "${DEFAULT_SITE}" "${DEFAULT_SITE}" - echo ">>>> bench setup nginx" - /usr/local/bin/gosu cloudron:cloudron bench setup nginx --yes --logging none + touch "/app/data/frappe/sites/${DEFAULT_SITE}/.initialized" +else + echo ">>>> Site ${DEFAULT_SITE} already setup." +fi +gosu cloudron:cloudron bench use "${DEFAULT_SITE}" +gosu cloudron:cloudron bench scheduler enable +gosu cloudron:cloudron bench set-config allow_reads_during_maintenance 1 +gosu cloudron:cloudron bench set-config nginx_port 8888 - sed -i 's|proxy_set_header X-Forwarded-Proto $scheme;|proxy_set_header X-Forwarded-Proto https; # patched for cloudron|g' /app/data/frappe/config/nginx.conf - echo ">>>> Done nginx setup" - ############# ################## +# Nginx - ############# ################## - echo ">>>> bench setup supervisor" +echo ">>>> Setup nginx config." +gosu cloudron:cloudron bench setup nginx --yes --logging none +# Make nginx work with Cloudron reverse proxy. +sed -i 's|proxy_set_header X-Forwarded-Proto $scheme;|proxy_set_header X-Forwarded-Proto https;|g' /app/data/frappe/config/nginx.conf - /usr/local/bin/gosu cloudron:cloudron bench setup supervisor --skip-redis --yes - sed -i "s,/app/code/frappe-bench/logs/,/run/frappe/logs/,g" /app/data/frappe/config/supervisor.conf +# Supervisord +echo ">>>> Setup supervisor config." - echo ">>>> Done supervisor setup" - ############# ################## +gosu cloudron:cloudron bench setup supervisor --skip-redis --yes +# Change log path for all programs to a writable directory +sed -i "s,/app/code/frappe-bench/logs/,/run/frappe/logs/,g" /app/data/frappe/config/supervisor.conf - touch "/app/data/frappe/sites/${DEFAULT_SITE}/.initialized" -else - echo ">>>> Site ${DEFAULT_SITE} already setup." -fi -############# ################## +# Starting supervisord -## Starting supervisord echo ">>>> All done. Starting nginx & supervisord..." -echo ">>>> To setup LDAP, open the web terminal and run /app/code/setup-ldap.sh" - -/usr/local/bin/gosu cloudron:cloudron /usr/bin/supervisord --configuration /etc/supervisor/supervisord.conf --nodaemon -i frappe +gosu cloudron:cloudron /usr/bin/supervisord --configuration /etc/supervisor/supervisord.conf --nodaemon -i frappe