Linux|实用工具|onlyoffice workspace使用docker快速部署(离线和定制化部署)

一、

什么是only office workspace

ONLYOFFICE协作空间,是Ascensio System SIA公司出品的,基于Web的,开源的,跨平台的,在线文档编辑和协作的解决方案

官网地址:ONLYOFFICE - 企业在线办公应用软件 | ONLYOFFICE

社区版only office下载地址:下载 ONLYOFFICE 产品的社区版本 | ONLYOFFICE

在线Office包含了最基本的办公三件套:文档编辑器、幻灯片编辑器和表格编辑器,额外还支持了pdf格式文件的创建和编辑功能,还有表单文件的创建编辑功能,并且,还提供了在线文档转换、在线文档预览、在线文档协作等功能。

最关键的是,多人在线实时协同办公功能,ONLYOFFICE协作空间创建一个个不同的虚拟房间,拉入不同的人进入虚拟房间就是一个团队一个team,每个人在团队中,可以创建自己的文档,也可以编辑其他人的文档,还可以查看其他人的文档,还可以和其他人分享自己的文档。

需要注意的是还有only office docspace,这个是和only office workspace相似的文档协助系统,但面向的用户侧重点不同,only office docspace是一个轻量化的系统,适用于敏捷开发的团队,而only office workspace是一个功能更多的,面向大中型企业所使用的在线文档系统,还拥有CRM、邮件等一体化管理。更有备份、存储、LDAP、SSO 等高级功能,是中小企业和开发者必备的在线文档系统利器

本文主要是介绍only office workspace和如何实现离线化快速安装部署,以及添加用户等等基本的业务操作介绍

二、

only office workspace组件介绍

only office workspace主要是由五个组件构成

  • 第一个组件是MySQL数据库,该组件作用是备份功能以及文档持久化

  • 第二个组件是elasticsearch,该组件的作用是提供文档检索,管理的功能

  • 第三个组件是DS也就是onlyoffice/documentserver

  • 该组件的作用是实现在线文档的编辑,查看文档的实际操作功能,特别需要注意的是该组件可以单独部署,但由于缺少CS组件,因此,无用户管理,此组件不依赖于其它组件,例如MySQL,elasticsearch

 ​​一、onlyoffice/documentserver的核心功能​

  1. ​在线文档编辑​
    • 支持主流办公格式:包括Microsoft Office(.docx.xlsx.pptx)、OpenDocument(.odt.ods.odp)及PDF、HTML等,确保与现有文件兼容

  2. ​实时协作编辑​
    • 多用户同步操作:多人同时编辑同一文档时,实时显示光标位置、文本修改及批注内容,通过WebSocket技术实现毫秒级同步。

    • 权限分级控制:支持按角色设置编辑、评论或只读权限,确保分工明确5。

  3. ​文档版本管理​
    • 自动保存历史版本:每次编辑生成快照,支持回溯至任意版本,避免误操作丢失数据

  • 第四个组件是CS也就是onlyoffice/communityserver

onlyoffice/communityserver(即ONLYOFFICE Community Server)是ONLYOFFICE Workspace的核心组件,负责整合并管理协作办公生态中的多类功能模块,实现企业级文档协作、项目管理、客户关系维护及通信的统一化处理。其核心作用可归纳为以下四大领域:


📁 ​​1. 文档集中化与协作管理​
  • ​实时协作编辑​​:与Document Server集成,实现多人同时编辑同一文档,实时显示他人光标位置,支持聊天讨论和批注功能

  • ​云存储集成​​:无缝对接Google Drive、Dropbox、OneDrive等主流云盘,实现跨平台文件同步与嵌入


📊 ​​2. 项目全周期管理​
  • ​甘特图与任务调度​​:可视化规划项目进度,设置里程碑、任务依赖关系及子任务分配

  • ​工时追踪与报告​​:记录任务耗时,自动生成项目进度报告,支持资源负载分析

  • ​自动化提醒​​:关联日历模块,自动推送任务截止提醒,减少进度延误


👥 ​​3. 客户关系管理(CRM)​
  • ​客户数据库​​:集中管理客户信息、联系人角色、交易历史及沟通记录,支持自定义字段扩展

  • ​销售流程自动化​​:

    • ​销售管道(Pipeline)​​:自定义销售阶段(如“潜在客户→成交”),拖拽更新商机状态

    • ​Web-to-Lead表单​​:官网表单自动捕获潜在客户信息,生成CRM线索

    • ​集成通信工具​​:关联邮件和通话记录(如Twilio),自动同步至客户时间线。

✉️ ​​4. 邮件聚合与团队协作​
  • ​统一收件箱​​:聚合多个邮箱账户(如QQ、Gmail),支持邮件收发、分类及搜索,避免多平台切换

  • ​团队协同工具​​:

    • ​日历共享​​:同步会议、演示日程,避免时间冲突

    • ​论坛/博客/投票​​:内置社区功能,支持内部知识分享与决策收集

    • ​即时通讯(需集成Talk组件)​​:支持群组聊天与文件传输,补充异步沟通场景

  • 第五个组件是onlyoffice/controlpanel,该组件是其它组件的后台管理组件,也就是平面管理组件

主要提供LDAP,SSO等等与其它外部系统交互的功能,该组件并不是特别的核心,但可以为整个系统锦上添花

总结一下这些组件,可以得出一个结论,关键核心组件是onlyoffice/documentserver和onlyoffice/communityserver,其它组件基本都是围绕这两个组件来实现的onlyoffice/documentserver这个组件可以单独部署,其它组件不可以

三、

only office workspace的部署方式

only office workspace主要是通过线上官网下载shell脚本,然后通过调整脚本参数来实现不同的部署,主要是RPM/APT也就是二进制部署和docker镜像部署这两种方式,本文主要介绍通过shell脚本,借助docker 快速实现离线化部署

workspace-install.sh下载地址:

https://download.onlyoffice.com/installworkspace-install.sh

该脚本内容如下:

#!/bin/bash

set -e

# (c) Copyright Ascensio System Limited 2010-2021
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and limitations under the License.
# You can contact Ascensio System SIA by email at sales@onlyoffice.com

PARAMETERS="";
DOCKER="";
HELP="false";

while [ "$1" != "" ]; do
        case $1 in

	-ls | --localscripts )
	        if [ "$2" == "true" ] || [ "$2" == false ]; then
			PARAMETERS="$PARAMETERS ${1}";
			LOCAL_SCRIPTS=$2
			shift
		fi
         ;;

	 "-?" | -h | --help )
	        HELP="true"
		DOCKER="true"
		PARAMETERS="$PARAMETERS -ht workspace-install.sh";
	 ;;

	esac
	PARAMETERS="$PARAMETERS ${1}";
	shift
done

PARAMETERS="$PARAMETERS -it WORKSPACE";

root_checking () {
	if [ ! $( id -u ) -eq 0 ]; then
		echo "To perform this action you must be logged in with root rights"
		exit 1;
	fi
}

command_exists () {
	type "$1" &> /dev/null;
}

install_curl () {
	if command_exists apt-get; then
		apt-get -y update
		apt-get -y -q install curl
	elif command_exists yum; then
		yum -y install curl
	fi

	if ! command_exists curl; then
		echo "command curl not found"
		exit 1;
	fi
}

read_installation_method () {
	echo "Select 'Y' to install ONLYOFFICE using Docker (recommended). Select 'N' to install it using RPM/DEB packages.";
	echo "Please note, that in case you select RPM/DEB installation, you will need to manually install Mail Server and connect it to your ONLYOFFICE installation.";
	echo "See instructions in our Help Center: http://helpcenter.onlyoffice.com/server/docker/mail/connect-mail-server-to-community-server-via-portal-settings.aspx";
	read -p "Install with Docker [Y/N/C]? " choice
	case "$choice" in
		y|Y )
			DOCKER="true";
		;;

		n|N )
			DOCKER="false";
		;;

		c|C )
			exit 0;
		;;

		* )
			echo "Please, enter Y, N or C to cancel";
		;;
	esac

	if [ "$DOCKER" == "" ]; then
		read_installation_method;
	fi
}

root_checking

if ! command_exists curl ; then
	install_curl;
fi

if [ "$HELP" == "false" ]; then
	read_installation_method;
fi

if [ "$DOCKER" == "true" ]; then
	if [ "${LOCAL_SCRIPTS}" == "true" ]; then
		bash install.sh ${PARAMETERS}
	else
		curl -s -O http://download.onlyoffice.com/install/install.sh
		bash install.sh ${PARAMETERS}
		rm install.sh
	fi
else
	if [ -f /etc/redhat-release ] ; then
		DIST=$(cat /etc/redhat-release |sed s/\ release.*//);
		REV=$(cat /etc/redhat-release | sed s/.*release\ // | sed s/\ .*//);

		REV_PARTS=(${REV//\./ });
		REV=${REV_PARTS[0]};

		if [[ "${DIST}" == CentOS* ]] && [ ${REV} -lt 7 ]; then
			echo "CentOS 7 or later is required";
			exit 1;
		fi

		if [ "${LOCAL_SCRIPTS}" == "true" ]; then
			bash install-RedHat.sh ${PARAMETERS}
		else
			curl -s -O http://download.onlyoffice.com/install/install-RedHat.sh
			bash install-RedHat.sh ${PARAMETERS}
			rm install-RedHat.sh
		fi
	elif [ -f /etc/debian_version ] ; then
		if [ "${LOCAL_SCRIPTS}" == "true" ]; then
			bash install-Debian.sh ${PARAMETERS}
		else
			curl -s -O http://download.onlyoffice.com/install/install-Debian.sh
			bash install-Debian.sh ${PARAMETERS}
			rm install-Debian.sh
		fi
	else
		echo "Not supported OS";
		exit 1;
	fi
fi

可以看到,如果是docker方式部署安装only office workspace,那么跳转到curl -s -O http://download.onlyoffice.com/install/install.sh 这个命令下载名为install.sh的脚本,然后准备环境,并pull相关镜像后,启动所有相关服务

如果是redhat操作系统,那么跳转到curl -s -O http://download.onlyoffice.com/install/install-RedHat.sh这个命令下载名为install-RedHat.sh的脚本,并自动配置仓库然后开始rpm方式的安装,并最终启动所有相关服务

如果是debian操作系统,那么跳转到curl -s -O http://download.onlyoffice.com/install/install-Debian.sh这个命令下载名为install-Debian.sh的脚本,并自动配置仓库然后开始rpm方式的安装,并最终启动所有相关服务

install.sh脚本的内容(脚本非常长,小心查看):

#!/bin/bash

# (c) Copyright Ascensio System Limited 2010-2021
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and limitations under the License.
# You can contact Ascensio System SIA by email at sales@onlyoffice.com

DISK_REQUIREMENTS=40960;
MEMORY_REQUIREMENTS=8000;
CORE_REQUIREMENTS=4;

PRODUCT="onlyoffice";
BASE_DIR="/app/$PRODUCT";
NETWORK="$PRODUCT";
SWAPFILE="/${PRODUCT}_swapfile";
MACHINEKEY_PARAM=$(echo "${PRODUCT}_CORE_MACHINEKEY" | awk '{print toupper($0)}');

COMMUNITY_CONTAINER_NAME="onlyoffice-community-server";
DOCUMENT_CONTAINER_NAME="onlyoffice-document-server";
MAIL_CONTAINER_NAME="onlyoffice-mail-server";
CONTROLPANEL_CONTAINER_NAME="onlyoffice-control-panel";
ELASTICSEARCH_CONTAINER_NAME="onlyoffice-elasticsearch";
MYSQL_CONTAINER_NAME="onlyoffice-mysql-server";

COMMUNITY_IMAGE_NAME="onlyoffice/communityserver";
DOCUMENT_IMAGE_NAME="onlyoffice/documentserver-ee";
MAIL_IMAGE_NAME="onlyoffice/mailserver";
CONTROLPANEL_IMAGE_NAME="onlyoffice/controlpanel";
ELASTICSEARCH_IMAGE_NAME="onlyoffice/elasticsearch";
MYSQL_IMAGE_NAME="mysql";

COMMUNITY_VERSION="";
DOCUMENT_VERSION="";
MAIL_VERSION="";
CONTROLPANEL_VERSION="";
ELASTICSEARCH_VERSION="7.16.3";
MYSQL_VERSION="5.5";

DOCUMENT_SERVER_HOST="";

ELASTICSEARCH_PORT="9200";

MAIL_SERVER_API_HOST="";
MAIL_SERVER_DB_HOST="";
MAIL_IMAPSYNC_START_DATE="$(date +"%Y-%m-%dT%H:%M:%S")";

MAIL_DOMAIN_NAME="";

DIST="";
REV="";
KERNEL="";

UPDATE="false";

HUB="";
USERNAME="";
PASSWORD="";

INSTALL_COMMUNITY_SERVER="true";
INSTALL_DOCUMENT_SERVER="true";
INSTALL_MAIL_SERVER="true";
INSTALL_ELASTICSEARCH="true";
INSTALL_CONTROLPANEL="true";

USE_AS_EXTERNAL_SERVER="false";

PARTNER_DATA_FILE="";

INSTALLATION_TYPE="WORKSPACE_ENTERPRISE";

MAKESWAP="true";

RESTART_COMMUNITY_SERVER="false";
MOVE_COMMUNITY_SERVER_DATABASE="false";
ACTIVATE_COMMUNITY_SERVER_TRIAL="false";

MYSQL_PORT="3306";
MYSQL_DATABASE="$PRODUCT";
MYSQL_MAIL_DATABASE="${PRODUCT}_mailserver";
MYSQL_MAIL_ROOT_PASSWORD="Isadmin123";
MYSQL_MAIL_USER="mail_admin";
MYSQL_ROOT_USER="root";
MYSQL_ROOT_PASSWORD="my-secret-pw";
MYSQL_USER="${PRODUCT}_user";
MYSQL_PASSWORD="${PRODUCT}_pass";
MYSQL_HOST="";

HELP_TARGET="install.sh";

JWT_ENABLED="";
JWT_SECRET="";
CORE_MACHINEKEY="";

SKIP_HARDWARE_CHECK="false";
SKIP_VERSION_CHECK="false";
SKIP_DOMAIN_CHECK="false";

COMMUNITY_PORT=80;

while [ "$1" != "" ]; do
	case $1 in

		-ci | --communityimage )
			if [ "$2" != "" ]; then
				COMMUNITY_IMAGE_NAME=$2
				shift
			fi
		;;

		-di | --documentimage )
			if [ "$2" != "" ]; then
				DOCUMENT_IMAGE_NAME=$2
				shift
			fi
		;;

		-mi | --mailimage )
			if [ "$2" != "" ]; then
				MAIL_IMAGE_NAME=$2
				shift
			fi
		;;

		-cpi | --controlpanelimage )
			if [ "$2" != "" ]; then
				CONTROLPANEL_IMAGE_NAME=$2
				shift
			fi
		;;

		-mysqli | --mysqlimage )
			if [ "$2" != "" ]; then
				MYSQL_IMAGE_NAME=$2
				shift
			fi
		;;

		-dip | --documentserverip  )
			if [ "$2" != "" ]; then
				DOCUMENT_SERVER_HOST=$2
				shift
			fi
		;;

		-mip | --mailserverip  )
			if [ "$2" != "" ]; then
				MAIL_SERVER_API_HOST=$2
				shift
			fi
		;;

		-mdbip | --mailserverdbip  )
			if [ "$2" != "" ]; then
				MAIL_SERVER_DB_HOST=$2
				shift
			fi
		;;

		-cv | --communityversion )
			if [ "$2" != "" ]; then
				COMMUNITY_VERSION=$2
				shift
			fi
		;;

		-dv | --documentversion )
			if [ "$2" != "" ]; then
				DOCUMENT_VERSION=$2
				shift
			fi
		;;

		-mv | --mailversion )
			if [ "$2" != "" ]; then
				MAIL_VERSION=$2
				shift
			fi
		;;

		-cpv | --controlpanelversion )
			if [ "$2" != "" ]; then
				CONTROLPANEL_VERSION=$2
				shift
			fi
		;;

		-md | --maildomain )
			if [ "$2" != "" ]; then
				MAIL_DOMAIN_NAME=$2
				shift
			fi
		;;

		-u | --update )
			if [ "$2" != "" ]; then
				UPDATE=$2
				shift
			fi
		;;

		-hub | --hub )
			if [ "$2" != "" ]; then
				HUB=$2
				shift
			fi
		;;

		-un | --username )
			if [ "$2" != "" ]; then
				USERNAME=$2
				shift
			fi
		;;

		-p | --password )
			if [ "$2" != "" ]; then
				PASSWORD=$2
				shift
			fi
		;;

		-ics | --installcommunityserver )
			if [ "$2" != "" ]; then
				INSTALL_COMMUNITY_SERVER=$2
				shift
			fi
		;;

		-ids | --installdocumentserver )
			if [ "$2" != "" ]; then
				INSTALL_DOCUMENT_SERVER=$2
				shift
			fi
		;;

		-ims | --installmailserver )
			if [ "$2" != "" ]; then
				INSTALL_MAIL_SERVER=$2
				shift
			fi
		;;

		-icp | --installcontrolpanel )
			if [ "$2" != "" ]; then
				INSTALL_CONTROLPANEL=$2
				shift
			fi
		;;

		-es | --useasexternalserver )
			if [ "$2" != "" ]; then
				USE_AS_EXTERNAL_SERVER=$2
				shift
			fi
		;;

		-pdf | --partnerdatafile )
			if [ "$2" != "" ]; then
				PARTNER_DATA_FILE=$2
				shift
			fi
		;;

		-it | --installation_type )
			if [ "$2" != "" ]; then
				INSTALLATION_TYPE=$(echo "$2" | awk '{print toupper($0)}');
				shift
			fi
		;;

		-ms | --makeswap )
			if [ "$2" != "" ]; then
				MAKESWAP=$2
				shift
			fi
		;;

		-ht | --helptarget )
			if [ "$2" != "" ]; then
				HELP_TARGET=$2
				shift
			fi
		;;

		-mysqlprt | --mysqlport )
			if [ "$2" != "" ]; then
				MYSQL_PORT=$2
				shift
			fi
		;;

		-mysqld | --mysqldatabase )
			if [ "$2" != "" ]; then
				MYSQL_DATABASE=$2
				shift
			fi
		;;

		-mysqlmd | --mysqlmaildatabase )
			if [ "$2" != "" ]; then
				MYSQL_MAIL_DATABASE=$2
				shift
			fi
		;;

		-mysqlmp | --mysqlmailpassword )
			if [ "$2" != "" ]; then
				MYSQL_MAIL_ROOT_PASSWORD=$2
				shift
			fi
		;;

		-mysqlmu | --mysqlmailuser )
			if [ "$2" != "" ]; then
				MYSQL_MAIL_USER=$2
				shift
			fi
		;;

		-mysqlru | --mysqlrootuser )
			if [ "$2" != "" ]; then
				MYSQL_ROOT_USER=$2
				shift
			fi
		;;

		-mysqlrp | --mysqlrootpassword )
			if [ "$2" != "" ]; then
				MYSQL_ROOT_PASSWORD=$2
				shift
			fi
		;;

		-mysqlu | --mysqluser )
			if [ "$2" != "" ]; then
				MYSQL_USER=$2
				shift
			fi
		;;

		-mysqlp | --mysqlpassword )
			if [ "$2" != "" ]; then
				MYSQL_PASSWORD=$2
				shift
			fi
		;;

		-mysqlh | --mysqlhost )
			if [ "$2" != "" ]; then
				MYSQL_HOST=$2
				shift
			fi
		;;

		-skiphc | --skiphardwarecheck )
			if [ "$2" != "" ]; then
				SKIP_HARDWARE_CHECK=$2
				shift
			fi
		;;

		-skipvc | --skipversioncheck )
			if [ "$2" != "" ]; then
				SKIP_VERSION_CHECK=$2
				shift
			fi
		;;

		-skipdc | --skipdomaincheck )
			if [ "$2" != "" ]; then
				SKIP_DOMAIN_CHECK=$2
				shift
			fi
		;;

		-cp | --communityport )
			if [ "$2" != "" ]; then
				COMMUNITY_PORT=$2
				shift
			fi
		;;

		-mk | --machinekey )
			if [ "$2" != "" ]; then
				CORE_MACHINEKEY=$2
				shift
			fi
		;;

		-esi | --elasticsearchimage )
			if [ "$2" != "" ]; then
				ELASTICSEARCH_IMAGE_NAME=$2
				shift
			fi
		;;

		-esv | --elasticsearchversion )
			if [ "$2" != "" ]; then
				ELASTICSEARCH_VERSION=$2
				shift
			fi
		;;

		-esh | --elasticsearchhost  )
			if [ "$2" != "" ]; then
				ELASTICSEARCH_HOST=$2
				shift
			fi
		;;

		-ies | --installelasticsearch )
			if [ "$2" != "" ]; then
				INSTALL_ELASTICSEARCH=$2
				shift
			fi
		;;

		-esp | --elasticsearchport )
			if [ "$2" != "" ]; then
				ELASTICSEARCH_PORT=$2
				shift
			fi
		;;

		-je | --jwtenabled )
			if [ "$2" != "" ]; then
				JWT_ENABLED=$2
				shift
			fi
		;;
		
		-jh | --jwtheader )
			if [ "$2" != "" ]; then
				JWT_HEADER=$2
				shift
			fi
		;;

		-js | --jwtsecret )
			if [ "$2" != "" ]; then
				JWT_SECRET=$2
				shift
			fi
		;;

		-? | -h | --help )
			echo "  Usage: bash $HELP_TARGET [PARAMETER] [[PARAMETER], ...]"
			echo
			echo "    Parameters:"
			echo "      -ci, --communityimage             community image name or .tar.gz file path"
			echo "      -di, --documentimage              document image name or .tar.gz file path"
			echo "      -mi, --mailimage                  mail image name or .tar.gz file path"
			echo "      -esi, --elasticsearchimage        elasticsearch image name or .tar.gz file path"
			echo "      -cpi, --controlpanelimage         control panel image name or .tar.gz file path"
			echo "      -mysqli, --mysqlimage             mysql image name or .tar.gz file path"
			echo "      -cv, --communityversion           community version"
			echo "      -dv, --documentversion            document version"
			echo "      -dip, --documentserverip          document server ip"
			echo "      -esv, --elasticsearchversion      elasticsearch version"
			echo "      -esh, --elasticsearchhost         elasticsearch server host"
			echo "      -msp, --elasticsearchport         elasticsearch server port"
			echo "      -mv, --mailversion                mail version"
			echo "      -mip, --mailserverip              mail server ip"
			echo "      -mdbip, --mailserverdbip          mail server db ip"
			echo "      -cpv, --controlpanelversion       control panel version"
			echo "      -md, --maildomain                 mail domail name"
			echo "      -u, --update                      use to update existing components (true|false)"
			echo "      -hub, --hub                       dockerhub name"
			echo "      -un, --username                   dockerhub username"
			echo "      -p, --password                    dockerhub password"
			echo "      -ics, --installcommunityserver    install or update community server (true|false|pull)"
			echo "      -ids, --installdocumentserver     install or update document server (true|false|pull)"
			echo "      -ims, --installmailserver         install or update mail server (true|false|pull)"
			echo "      -ies, --installelasticsearch      install or update elasticsearch (true|false|pull)"
			echo "      -icp, --installcontrolpanel       install or update control panel (true|false|pull)"
			echo "      -es, --useasexternalserver        use as external server (true|false)"
			echo "      -pdf, --partnerdatafile           partner data file"
			echo "      -it, --installation_type          installation type (GROUPS|WORKSPACE|WORKSPACE_ENTERPRISE)"
			echo "      -ms, --makeswap                   make swap file (true|false)"
			echo "      -mysqlh, --mysqlhost              mysql server host"
			echo "      -mysqlprt, --mysqlport            mysql server port"
			echo "      -mysqlru, --mysqlrootuser         mysql server root user"
			echo "      -mysqlrp, --mysqlrootpassword     mysql server root password"
			echo "      -mysqld, --mysqldatabase          community server database name"
			echo "      -mysqlu, --mysqluser              community server database user"
			echo "      -mysqlp, --mysqlpassword          community server database password"
			echo "      -mysqlmd, --mysqlmaildatabase     mail server database name"
			echo "      -mysqlmu, --mysqlmailuser         mail server database user"
			echo "      -mysqlmp, --mysqlmailpassword     mail server database password"
			echo "      -skiphc, --skiphardwarecheck      skip hardware check (true|false)"
			echo "      -skipvc, --skipversioncheck       skip version check while update (true|false)"
			echo "      -skipdc, --skipdomaincheck        skip domain check when installing mail server (true|false)"
			echo "      -cp, --communityport              community port (default value 80)"
			echo "      -mk, --machinekey                 setting for core.machinekey"
			echo "      -je, --jwtenabled                 specifies the enabling the JWT validation (true|false)"
			echo "      -jh, --jwtheader                  defines the http header that will be used to send the JWT"
			echo "      -js, --jwtsecret                  defines the secret key to validate the JWT in the request"
			echo "      -?, -h, --help                    this help"
			echo
			echo "  Examples"
			echo "    Install all the solution components:"
			echo "      bash $HELP_TARGET -md yourdomain.com"
			echo
			echo "    Install all the components without Mail Server:"
			echo "      bash $HELP_TARGET -ims false"
			echo
			echo "    Install Document Server only. Skip the installation of Mail Server, Community Server and Control Panel:"
			echo "      bash $HELP_TARGET -ics false -ids true -icp false -ims false -es true"
			echo
			echo "    Install Mail Server only. Skip the installation of Document Server, Community Server and Control Panel:"
			echo "      bash $HELP_TARGET -ics false -ids false -icp false -ims true -md yourdomain.com -es true"
			echo
			echo "    Install Community Server with Control Panel and connect it with Document Server installed on a different machine which has the 192.168.3.202 IP address:"
			echo "      bash $HELP_TARGET -ics true -icp true -ids false -ims false -dip 192.168.3.202"
			echo
			echo "    Update all installed components. Stop the containers that need to be updated, remove them and run the latest versions of the corresponding components. The portal data should be picked up automatically:"
			echo "      bash $HELP_TARGET -u true"
			echo
			echo "    Update Document Server only to version 4.4.2.20 and skip the update for all other components:"
			echo "      bash $HELP_TARGET -u true -dv 4.4.2.20 -ics false -icp false -ims false"
			echo
			echo "    Update Community Server only to version 9.1.0.393 and skip the update for all other components:"
			echo "      bash $HELP_TARGET -u true -cv 9.1.0.393 -ids false -icp false -ims false"
			echo
			echo "    Update Mail Server only to version 1.6.27 and skip the update for all other components:"
			echo "      bash $HELP_TARGET -u true -mv 1.6.27 -ics false -ids false -icp false"
			echo
			echo "    Update Control Panel only to version 2.1.0.93 and skip the update for all other components:"
			echo "      bash $HELP_TARGET -u true -cpv 2.1.0.93 -ics false -ids false -ims false"
			echo
			exit 0
		;;

		* )
			echo "Unknown parameter $1" 1>&2
			exit 1
		;;
	esac
	shift
done



root_checking () {
	if [ ! $( id -u ) -eq 0 ]; then
		echo "To perform this action you must be logged in with root rights"
		exit 1;
	fi
}

command_exists () {
    type "$1" &> /dev/null;
}

file_exists () {
	if [ -z "$1" ]; then
		echo "file path is empty"
		exit 1;
	fi

	if [ -f "$1" ]; then
		return 0; #true
	else
		return 1; #false
	fi
}

install_curl () {
	if command_exists apt-get; then
		apt-get -y update
		apt-get -y -q install curl
	elif command_exists yum; then
		yum -y install curl
	fi

	if ! command_exists curl; then
		echo "command curl not found"
		exit 1;
	fi
}

install_jq () {
	if command_exists apt-get; then
		apt-get -y update
		apt-get -y -q install jq
	elif command_exists yum; then
		rpm -ivh https://dl.fedoraproject.org/pub/epel/epel-release-latest-$REV.noarch.rpm || true
		yum -y install jq
	fi

	if ! command_exists jq; then
		echo "command jq not found"
		exit 1;
	fi
}

install_netstat () {
	if command_exists apt-get; then
		apt-get -y update
		apt-get -y -q install net-tools
	elif command_exists yum; then
		yum -y install net-tools
	fi

	if ! command_exists netstat; then
		echo "command netstat not found"
		exit 1;
	fi
}

to_lowercase () {
	echo "$1" | awk '{print tolower($0)}'
}

trim () {
	echo -e "$1" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//'
}

get_os_info () {
	OS=`to_lowercase \`uname\``

	if [ "${OS}" == "windowsnt" ]; then
		echo "Not supported OS";
		exit 1;
	elif [ "${OS}" == "darwin" ]; then
		echo "Not supported OS";
		exit 1;
	else
		OS=`uname`

		if [ "${OS}" == "SunOS" ] ; then
			echo "Not supported OS";
			exit 1;
		elif [ "${OS}" == "AIX" ] ; then
			echo "Not supported OS";
			exit 1;
		elif [ "${OS}" == "Linux" ] ; then
			MACH=`uname -m`

			if [ "${MACH}" != "x86_64" ]; then
				echo "Currently only supports 64bit OS's";
				exit 1;
			fi

			KERNEL=`uname -r`

			if [ -f /etc/redhat-release ] ; then
				CONTAINS=$(cat /etc/redhat-release | { grep -sw release || true; });
				if [[ -n ${CONTAINS} ]]; then
					DIST=`cat /etc/redhat-release |sed s/\ release.*//`
					REV=`cat /etc/redhat-release | grep -oP '(?<=release )\d+'`
				else
					DIST=`cat /etc/os-release | grep -sw 'ID' | awk -F=  '{ print $2 }' | sed -e 's/^"//' -e 's/"$//'`
					REV=`cat /etc/os-release | grep -sw 'VERSION_ID' | awk -F=  '{ print $2 }' | sed -e 's/^"//' -e 's/"$//'`
				fi
			elif [ -f /etc/SuSE-release ] ; then
				REV=`cat /etc/os-release  | grep '^VERSION_ID' | awk -F=  '{ print $2 }' |  sed -e 's/^"//'  -e 's/"$//'`
				DIST='SuSe'
			elif [ -f /etc/debian_version ] ; then
				REV=`cat /etc/debian_version`
				DIST='Debian'
				if [ -f /etc/lsb-release ] ; then
					DIST=`cat /etc/lsb-release | grep '^DISTRIB_ID' | awk -F=  '{ print $2 }'`
					REV=`cat /etc/lsb-release | grep '^DISTRIB_RELEASE' | awk -F=  '{ print $2 }'`
				elif [ -f /etc/lsb_release ] || [ -f /usr/bin/lsb_release ] ; then
					DIST=`lsb_release -a 2>&1 | grep 'Distributor ID:' | awk -F ":" '{print $2 }'`
					REV=`lsb_release -a 2>&1 | grep 'Release:' | awk -F ":" '{print $2 }'`
				fi
			elif [ -f /etc/os-release ] ; then
				DIST=`cat /etc/os-release | grep -sw 'ID' | awk -F=  '{ print $2 }' | sed -e 's/^"//' -e 's/"$//'`
				REV=`cat /etc/os-release | grep -sw 'VERSION_ID' | awk -F=  '{ print $2 }' | sed -e 's/^"//' -e 's/"$//'`
			fi
		fi

		DIST=$(trim "$DIST");
		REV=$(trim $REV);
	fi
}

check_os_info () {
	if [[ -z ${KERNEL} || -z ${DIST} || -z ${REV} ]]; then
		echo "$KERNEL, $DIST, $REV";
		echo "Not supported OS";
		exit 1;
	fi
}

check_kernel () {
	MIN_NUM_ARR=(3 10 0);
	CUR_NUM_ARR=();

	CUR_STR_ARR=$(echo $KERNEL | grep -Po "[0-9]+\.[0-9]+\.[0-9]+" | tr "." " ");
	for CUR_STR_ITEM in $CUR_STR_ARR
	do
		CUR_NUM_ARR=(${CUR_NUM_ARR[@]} $CUR_STR_ITEM)
	done

	INDEX=0;

	while [[ $INDEX -lt 3 ]]; do
		if [ ${CUR_NUM_ARR[INDEX]} -lt ${MIN_NUM_ARR[INDEX]} ]; then
			echo "Not supported OS Kernel"
			exit 1;
		elif [ ${CUR_NUM_ARR[INDEX]} -gt ${MIN_NUM_ARR[INDEX]} ]; then
			INDEX=3
		fi
		(( INDEX++ ))
	done
}

check_hardware () {
	AVAILABLE_DISK_SPACE=$(df -m /  | tail -1 | awk '{ print $4 }');

	if [ ${AVAILABLE_DISK_SPACE} -lt ${DISK_REQUIREMENTS} ]; then
		echo "Minimal requirements are not met: need at least $DISK_REQUIREMENTS MB of free HDD space"
		exit 1;
	fi

	TOTAL_MEMORY=$(free --mega | grep -oP '\d+' | head -n 1);

	if [ ${TOTAL_MEMORY} -lt ${MEMORY_REQUIREMENTS} ]; then
		echo "Minimal requirements are not met: need at least $MEMORY_REQUIREMENTS MB of RAM"
		exit 1;
	fi

	CPU_CORES_NUMBER=$(cat /proc/cpuinfo | grep processor | wc -l);

	if [ ${CPU_CORES_NUMBER} -lt ${CORE_REQUIREMENTS} ]; then
		echo "The system does not meet the minimal hardware requirements. CPU with at least $CORE_REQUIREMENTS cores is required"
		exit 1;
	fi
}

make_swap () {
	DISK_REQUIREMENTS=6144; #6Gb free space
	MEMORY_REQUIREMENTS=16000; #RAM ~16Gb

	AVAILABLE_DISK_SPACE=$(df -m /  | tail -1 | awk '{ print $4 }');
	TOTAL_MEMORY=$(free --mega | grep -oP '\d+' | head -n 1);
	EXIST=$(swapon -s | awk '{ print $1 }' | { grep -x ${SWAPFILE} || true; });

	if [[ -z $EXIST ]] && [ ${TOTAL_MEMORY} -lt ${MEMORY_REQUIREMENTS} ] && [ ${AVAILABLE_DISK_SPACE} -gt ${DISK_REQUIREMENTS} ]; then

		if [ "${DIST}" == "Ubuntu" ] || [ "${DIST}" == "Debian" ]; then
			fallocate -l 6G ${SWAPFILE}
		else
			dd if=/dev/zero of=${SWAPFILE} count=6144 bs=1MiB
		fi

		chmod 600 ${SWAPFILE}
		mkswap ${SWAPFILE}
		swapon ${SWAPFILE}
		echo "$SWAPFILE none swap sw 0 0" >> /etc/fstab
	fi
}

check_ports () {
	RESERVED_PORTS=(443 5222 25 143 587 4190 8081 3306);
	ARRAY_PORTS=();
	USED_PORTS="";

	if ! command_exists netstat; then
		install_netstat
	fi

	if [ "${COMMUNITY_PORT//[0-9]}" = "" ]; then
		for RESERVED_PORT in "${RESERVED_PORTS[@]}"
		do
			if [ "$RESERVED_PORT" -eq "$COMMUNITY_PORT" ] ; then
				echo "Community port $COMMUNITY_PORT is reserved. Select another port"
				exit 1;
			fi
		done
	else
		echo "Invalid community port $COMMUNITY_PORT"
		exit 1;
	fi

	if [ "$INSTALL_COMMUNITY_SERVER" == "true" ]; then
		ARRAY_PORTS=(${ARRAY_PORTS[@]} "$COMMUNITY_PORT" "443" "5222");
	elif [ "$INSTALL_DOCUMENT_SERVER" == "true" ]; then
		if [ "${USE_AS_EXTERNAL_SERVER}" == "true" ]; then
			ARRAY_PORTS=(${ARRAY_PORTS[@]} "$COMMUNITY_PORT" "443");
		fi
	fi

	if [ "$INSTALL_MAIL_SERVER" == "true" ]; then
		ARRAY_PORTS=(${ARRAY_PORTS[@]} "25" "143" "587", "465", "993", "995", "4190");

		if [ "${USE_AS_EXTERNAL_SERVER}" == "true" ]; then
			ARRAY_PORTS=(${ARRAY_PORTS[@]} "8081");

			if [[ -z ${MYSQL_HOST} ]]; then
				ARRAY_PORTS=(${ARRAY_PORTS[@]} "3306");
			fi
		fi
	fi

	for PORT in "${ARRAY_PORTS[@]}"
	do
		REGEXP=":$PORT$"
		CHECK_RESULT=$(netstat -lnt | awk '{print $4}' | { grep $REGEXP || true; })

		if [[ $CHECK_RESULT != "" ]]; then
			if [[ $USED_PORTS != "" ]]; then
				USED_PORTS="$USED_PORTS, $PORT"
			else
				USED_PORTS="$PORT"
			fi
		fi
	done

	if [[ $USED_PORTS != "" ]]; then
		echo "The following TCP Ports must be available: $USED_PORTS"
		exit 1;
	fi
}

check_docker_version () {
	CUR_FULL_VERSION=$(docker -v | cut -d ' ' -f3 | cut -d ',' -f1);
	CUR_VERSION=$(echo $CUR_FULL_VERSION | cut -d '-' -f1);
	CUR_EDITION=$(echo $CUR_FULL_VERSION | cut -d '-' -f2);

	if [ "${CUR_EDITION}" == "ce" ] || [ "${CUR_EDITION}" == "ee" ]; then
		return 0;
	fi

	if [ "${CUR_VERSION}" != "${CUR_EDITION}" ]; then
		echo "Unspecific docker version"
		exit 1;
	fi

	MIN_NUM_ARR=(1 10 0);
	CUR_NUM_ARR=();

	CUR_STR_ARR=$(echo $CUR_VERSION | grep -Po "[0-9]+\.[0-9]+\.[0-9]+" | tr "." " ");

	for CUR_STR_ITEM in $CUR_STR_ARR
	do
		CUR_NUM_ARR=(${CUR_NUM_ARR[@]} $CUR_STR_ITEM)
	done

	INDEX=0;

	while [[ $INDEX -lt 3 ]]; do
		if [ ${CUR_NUM_ARR[INDEX]} -lt ${MIN_NUM_ARR[INDEX]} ]; then
			echo "The outdated Docker version has been found. Please update to the latest version."
			exit 1;
		elif [ ${CUR_NUM_ARR[INDEX]} -gt ${MIN_NUM_ARR[INDEX]} ]; then
			return 0;
		fi
		(( INDEX++ ))
	done
}

install_docker_using_script () {
	if ! command_exists curl ; then
		install_curl;
	fi

	curl -fsSL https://get.docker.com -o get-docker.sh
	sh get-docker.sh
	rm get-docker.sh
}

install_docker () {

	if [ "${DIST}" == "Ubuntu" ] || [ "${DIST}" == "Debian" ] || [[ "${DIST}" == CentOS* ]] || [ "${DIST}" == "Fedora" ]; then

		install_docker_using_script
		systemctl start docker
		systemctl enable docker

	elif [ "${DIST}" == "Red Hat Enterprise Linux Server" ]; then

		echo ""
		echo "Your operating system does not allow Docker CE installation."
		echo "You can install Docker EE using the manual here - https://docs.docker.com/engine/installation/linux/rhel/"
		echo ""
		exit 1;

	elif [ "${DIST}" == "SuSe" ]; then

		echo ""
		echo "Your operating system does not allow Docker CE installation."
		echo "You can install Docker EE using the manual here - https://docs.docker.com/engine/installation/linux/suse/"
		echo ""
		exit 1;

	elif [ "${DIST}" == "altlinux" ]; then

		apt-get -y install docker-io
		chkconfig docker on
		service docker start
		systemctl enable docker

	else

		echo ""
		echo "Docker could not be installed automatically."
		echo "Please use this official instruction https://docs.docker.com/engine/installation/linux/other/ for its manual installation."
		echo ""
		exit 1;

	fi

	if ! command_exists docker ; then
		echo "error while installing docker"
		exit 1;
	fi
}

docker_login () {
	if [[ -n ${USERNAME} && -n ${PASSWORD}  ]]; then
		docker login ${HUB} --username ${USERNAME} --password ${PASSWORD}
	fi
}

make_directories () {
	mkdir -p "$BASE_DIR/setup";

	mkdir -p "$BASE_DIR/DocumentServer/data";
	mkdir -p "$BASE_DIR/DocumentServer/logs";
	mkdir -p "$BASE_DIR/DocumentServer/fonts";
	mkdir -p "$BASE_DIR/DocumentServer/forgotten";

	mkdir -p "$BASE_DIR/MailServer/data/certs";
	mkdir -p "$BASE_DIR/MailServer/logs";

	mkdir -p "$BASE_DIR/CommunityServer/data";
	mkdir -p "$BASE_DIR/CommunityServer/data/certs";
	mkdir -p "$BASE_DIR/CommunityServer/data/certs/tmp";
	mkdir -p "$BASE_DIR/CommunityServer/logs";

	mkdir -p "$BASE_DIR/ControlPanel/data";
	mkdir -p "$BASE_DIR/ControlPanel/logs";

	mkdir -p "$BASE_DIR/mysql/conf.d";
	mkdir -p "$BASE_DIR/mysql/data";
	mkdir -p "$BASE_DIR/mysql/initdb";
	mkdir -p "$BASE_DIR/mysql/logs";
	mkdir -p "$BASE_DIR/mysql/.private";
}

get_available_version () {
	if [[ -z "$1" ]]; then
		echo "image name is empty";
		exit 1;
	fi

	if ! command_exists curl ; then
		install_curl >/dev/null 2>&1
	fi

	if ! command_exists jq ; then
		install_jq >/dev/null 2>&1
	fi

	CREDENTIALS="";
	AUTH_HEADER="";
	TAGS_RESP="";

	if [[ -n ${HUB} ]]; then
		DOCKER_CONFIG="$HOME/.docker/config.json";

		if [[ -f "$DOCKER_CONFIG" ]]; then
			CREDENTIALS=$(jq -r '.auths."'$HUB'".auth' < "$DOCKER_CONFIG");
			if [ "$CREDENTIALS" == "null" ]; then
				CREDENTIALS="";
			fi
		fi

		if [[ -z ${CREDENTIALS} && -n ${USERNAME} && -n ${PASSWORD} ]]; then
			CREDENTIALS=$(echo -n "$USERNAME:$PASSWORD" | base64);
		fi

		if [[ -n ${CREDENTIALS} ]]; then
			AUTH_HEADER="Authorization: Basic $CREDENTIALS";
		fi

		REPO=$(echo $1 | sed "s/$HUB\///g");
		TAGS_RESP=$(curl -s -H "$AUTH_HEADER" -X GET https://$HUB/v2/$REPO/tags/list);
		TAGS_RESP=$(echo $TAGS_RESP | jq -r '.tags')
	else
		if [[ -n ${USERNAME} && -n ${PASSWORD} ]]; then
			CREDENTIALS="{\"username\":\"$USERNAME\",\"password\":\"$PASSWORD\"}";
		fi

		if [[ -n ${CREDENTIALS} ]]; then
			LOGIN_RESP=$(curl -s -H "Content-Type: application/json" -X POST -d "$CREDENTIALS" https://hub.docker.com/v2/users/login/);
			TOKEN=$(echo $LOGIN_RESP | jq -r '.token');
			AUTH_HEADER="Authorization: JWT $TOKEN";
			sleep 1;
		fi

		TAGS_RESP=$(curl -s -H "$AUTH_HEADER" -X GET https://hub.docker.com/v2/repositories/$1/tags/);
		TAGS_RESP=$(echo $TAGS_RESP | jq -r '.results[].name')
	fi

	VERSION_REGEX_1="[0-9]+\.[0-9]+\.[0-9]+"
	VERSION_REGEX_2="[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+"
	TAG_LIST=""

	for item in $TAGS_RESP
	do
		if [[ $item =~ $VERSION_REGEX_1 ]] || [[ $item =~ $VERSION_REGEX_2 ]]; then
			TAG_LIST="$item,$TAG_LIST"
		fi
	done

	LATEST_TAG=$(echo $TAG_LIST | tr ',' '\n' | sort -t. -k 1,1n -k 2,2n -k 3,3n -k 4,4n | awk '/./{line=$0} END{print line}');

	echo "$LATEST_TAG" | sed "s/\"//g"
}

get_current_image_name () {
	if [[ -z "$1" ]]; then
		echo "container name is empty";
		exit 1;
	fi

	CONTAINER_IMAGE=$(docker inspect --format='{{.Config.Image}}' $1)

	CONTAINER_IMAGE_PARTS=($(echo $CONTAINER_IMAGE | tr ":" "\n"))

	echo ${CONTAINER_IMAGE_PARTS[0]}
}

get_current_image_version () {
	if [[ -z "$1" ]]; then
		echo "container name is empty";
		exit 1;
	fi

	CONTAINER_IMAGE=$(docker inspect --format='{{.Config.Image}}' $1)

	CONTAINER_IMAGE_PARTS=($(echo $CONTAINER_IMAGE | tr ":" "\n"))

	echo ${CONTAINER_IMAGE_PARTS[1]}
}

check_bindings () {
	if [[ -z "$1" ]]; then
		echo "container id is empty";
		exit 1;
	fi

	binds=$(docker inspect --format='{{range $p,$conf:=.HostConfig.Binds}}{{$conf}};{{end}}' $1)
	volumes=$(docker inspect --format='{{range $p,$conf:=.Config.Volumes}}{{$p}};{{end}}' $1)
	arrBinds=$(echo $binds | tr ";" "\n")
	arrVolumes=$(echo $volumes | tr ";" "\n")
	bindsCorrect=1

	if [[ -n "$2" ]]; then
		exceptions=$(echo $2 | tr "," "\n")
		for ex in ${exceptions[@]}
		do
			arrVolumes=(${arrVolumes[@]/$ex})
		done
	fi

	for volume in $arrVolumes
	do
		bindExist=0
		for bind in $arrBinds
		do
			bind=($(echo $bind | tr ":" " "))
			if [ "${bind[1]}" == "${volume}" ]; then
				bindExist=1
			fi
		done
		if [ "$bindExist" == "0" ]; then
			bindsCorrect=0
			echo "${volume} not binded"
		fi
	done

	if [ "$bindsCorrect" == "0" ]; then
		exit 1;
	fi
}

change_mysql_credentials () {
	while ! docker exec -it ${MYSQL_CONTAINER_NAME} mysqladmin ping --silent; do
		echo "wait for $MYSQL_CONTAINER_NAME"
		sleep 5
	done

	docker exec -it ${MYSQL_CONTAINER_NAME} mysqladmin password "$MYSQL_ROOT_PASSWORD"

	docker exec -i ${MYSQL_CONTAINER_NAME} mysql -u ${MYSQL_ROOT_USER} -p${MYSQL_ROOT_PASSWORD} < ${BASE_DIR}/mysql/initdb/setup.sql
}

install_mysql_server () {
	MYSQL_SERVER_ID=$(get_container_id "$MYSQL_CONTAINER_NAME");

	RUN_MYSQL_SERVER="true";

	if [[ -n ${MYSQL_SERVER_ID} ]]; then
		RUN_MYSQL_SERVER="false";
		echo "ONLYOFFICE MYSQL SERVER is already installed."
		if [[ "$(awk -F. '{ printf("%d%03d%03d%03d", $1,$2,$3,$4); }' <<< $MYSQL_VERSION)" -lt "8000000000" ]]; then
			if ! grep -q "tls_version" ${BASE_DIR}/mysql/conf.d/${PRODUCT}.cnf; then
				echo "tls_version = TLSv1.2" >> ${BASE_DIR}/mysql/conf.d/${PRODUCT}.cnf 
				echo "" > $BASE_DIR/CommunityServer/data/.private/release_date
			else
				sed -i "s/tls_version.*/tls_version = TLSv1.2/" ${BASE_DIR}/mysql/conf.d/${PRODUCT}.cnf
			fi
		fi

		if file_exists "${BASE_DIR}/mysql/initdb/setup.sql"; then
			if grep -q "caching_sha2_password" ${BASE_DIR}/mysql/initdb/setup.sql; then
				sed -i 's/caching_sha2_password/mysql_native_password/g' ${BASE_DIR}/mysql/initdb/setup.sql
			elif ! grep -q "mysql_native_password" ${BASE_DIR}/mysql/initdb/setup.sql; then
				sed -i 's/IDENTIFIED BY/IDENTIFIED WITH mysql_native_password BY/g' ${BASE_DIR}/mysql/initdb/setup.sql
			fi
		fi

		docker restart ${MYSQL_SERVER_ID};
	fi

	if [ "$RUN_MYSQL_SERVER" == "true" ]; then

		if ! file_exists ${BASE_DIR}/mysql/conf.d/${PRODUCT}.cnf; then
			echo "[mysqld]
sql_mode = 'NO_ENGINE_SUBSTITUTION'
max_connections = 1000
max_allowed_packet = 1048576000
group_concat_max_len = 2048
log-error = /var/log/mysql/error.log" > ${BASE_DIR}/mysql/conf.d/${PRODUCT}.cnf
			[[ "$(awk -F. '{ printf("%d%03d%03d%03d", $1,$2,$3,$4); }' <<< $MYSQL_VERSION)" -lt "8000000000" ]] && echo "tls_version = TLSv1.2" >> ${BASE_DIR}/mysql/conf.d/${PRODUCT}.cnf
			chmod 0644 ${BASE_DIR}/mysql/conf.d/${PRODUCT}.cnf
		fi

		if ! file_exists ${BASE_DIR}/mysql/initdb/setup.sql; then
                        echo "CREATE USER '$MYSQL_USER'@'%' IDENTIFIED WITH mysql_native_password BY '$MYSQL_PASSWORD';
CREATE USER '$MYSQL_MAIL_USER'@'%' IDENTIFIED WITH mysql_native_password BY '$MYSQL_MAIL_ROOT_PASSWORD';
ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY '$MYSQL_ROOT_PASSWORD';
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '$MYSQL_ROOT_PASSWORD';
GRANT ALL PRIVILEGES ON *.* TO '$MYSQL_ROOT_USER'@'%';
GRANT ALL PRIVILEGES ON *.* TO '$MYSQL_USER'@'%';
GRANT ALL PRIVILEGES ON *.* TO '$MYSQL_MAIL_USER'@'%';
FLUSH PRIVILEGES;" > ${BASE_DIR}/mysql/initdb/setup.sql
        fi



		if ! file_exists ${BASE_DIR}/mysql/logs/error.log; then
			chown 999:999 ${BASE_DIR}/mysql/logs;
		fi


		if [ "$UPDATE" == "true" ]; then
			echo "copying $MYSQL_DATABASE database mysql files"
			cp -rf ${BASE_DIR}/CommunityServer/mysql/. ${BASE_DIR}/mysql/data
			MOVE_COMMUNITY_SERVER_DATABASE="true";
		fi

		args=();
		args+=(--name "$MYSQL_CONTAINER_NAME");

		if [ "${USE_AS_EXTERNAL_SERVER}" == "true" ]; then
			args+=(-p 3306:3306);
		fi

		args+=(-v "$BASE_DIR/mysql/conf.d:/etc/mysql/conf.d");
		args+=(-v "$BASE_DIR/mysql/data:/var/lib/mysql");
		args+=(-v "$BASE_DIR/mysql/initdb:/docker-entrypoint-initdb.d");
		args+=(-v "$BASE_DIR/mysql/logs:/var/log/mysql");
		args+=(-e "MYSQL_ROOT_PASSWORD=$MYSQL_ROOT_PASSWORD");
		args+=(-e "MYSQL_DATABASE=$MYSQL_DATABASE");
		args+=("$MYSQL_IMAGE_NAME:$MYSQL_VERSION");

		docker run --net ${NETWORK} -i -t -d --restart=always "${args[@]}";

		MYSQL_SERVER_ID=$(get_container_id "$MYSQL_CONTAINER_NAME");

		if [[ -z ${MYSQL_SERVER_ID} ]]; then
			echo "ONLYOFFICE MYSQL SERVER not installed."
			exit 1;
		fi

		if [ "$UPDATE" == "true" ]; then
			change_mysql_credentials
		fi
	fi
}

install_document_server () {
	DOCUMENT_SERVER_ID=$(get_container_id "$DOCUMENT_CONTAINER_NAME");

	RUN_DOCUMENT_SERVER="true";

	if [[ -n ${DOCUMENT_SERVER_ID} ]]; then
		if [ "$UPDATE" == "true" ]; then
			CURRENT_IMAGE_NAME=$(get_current_image_name "$DOCUMENT_CONTAINER_NAME");
			CURRENT_IMAGE_VERSION=$(get_current_image_version "$DOCUMENT_CONTAINER_NAME");

			if [ "$CURRENT_IMAGE_NAME" == "onlyoffice/documentserver" ]; then
				ACTIVATE_COMMUNITY_SERVER_TRIAL="true";
			fi

			if [ "$CURRENT_IMAGE_NAME" != "$DOCUMENT_IMAGE_NAME" ] || ([ "$CURRENT_IMAGE_VERSION" != "$DOCUMENT_VERSION" ] || [ "$SKIP_VERSION_CHECK" == "true" ]); then
				check_bindings $DOCUMENT_SERVER_ID "/etc/$PRODUCT,/var/lib/$PRODUCT,/var/lib/postgresql,/usr/share/fonts/truetype/custom,/var/lib/rabbitmq,/var/lib/redis";
				docker exec ${DOCUMENT_CONTAINER_NAME} bash /usr/bin/documentserver-prepare4shutdown.sh
				remove_container ${DOCUMENT_CONTAINER_NAME}
			else
				RUN_DOCUMENT_SERVER="false";
				echo "The latest version of ONLYOFFICE DOCUMENT SERVER is already installed."
				docker start ${DOCUMENT_SERVER_ID};
			fi
		else
			RUN_DOCUMENT_SERVER="false";
			echo "ONLYOFFICE DOCUMENT SERVER is already installed."
			docker start ${DOCUMENT_SERVER_ID};
		fi
	else
		RESTART_COMMUNITY_SERVER="true";
	fi

	if [ "$RUN_DOCUMENT_SERVER" == "true" ]; then
		args=();
		args+=(--name "$DOCUMENT_CONTAINER_NAME");

		if [ "${USE_AS_EXTERNAL_SERVER}" == "true" ]; then
			args+=(-p 80:80);
			args+=(-p 443:443);
		fi

		if [[ -n ${JWT_SECRET} ]]; then
			args+=(-e "JWT_ENABLED=$JWT_ENABLED");
			args+=(-e "JWT_HEADER=$JWT_HEADER");
			args+=(-e "JWT_SECRET=$JWT_SECRET");
		else
			args+=(-e "JWT_ENABLED=false");
		fi

		args+=(-v "$BASE_DIR/DocumentServer/data:/var/www/$PRODUCT/Data");
		args+=(-v "$BASE_DIR/DocumentServer/logs:/var/log/$PRODUCT");
		args+=(-v "$BASE_DIR/DocumentServer/fonts:/usr/share/fonts/truetype/custom");
		args+=(-v "$BASE_DIR/DocumentServer/forgotten:/var/lib/$PRODUCT/documentserver/App_Data/cache/files/forgotten");
		args+=("$DOCUMENT_IMAGE_NAME:$DOCUMENT_VERSION");

		docker run --net ${NETWORK} -i -t -d --restart=always "${args[@]}";

		DOCUMENT_SERVER_ID=$(get_container_id "$DOCUMENT_CONTAINER_NAME");

		if [[ -z ${DOCUMENT_SERVER_ID} ]]; then
			echo "ONLYOFFICE DOCUMENT SERVER not installed."
			exit 1;
		else
			COMMUNITY_SERVER_ID=$(get_container_id "$COMMUNITY_CONTAINER_NAME");

			if [[ -n ${COMMUNITY_SERVER_ID} ]]; then
				docker exec ${COMMUNITY_CONTAINER_NAME} chown -R ${PRODUCT}:${PRODUCT} /var/www/${PRODUCT}/DocumentServerData
			fi
		fi
	fi
}

install_mail_server () {
	MAIL_SERVER_ID=$(get_container_id "$MAIL_CONTAINER_NAME");
	MYSQL_SERVER_ID=$(get_container_id "$MYSQL_CONTAINER_NAME");
	HOSTNAME_IPS=$(hostname -i);
	IP_V4_REGEX="([0-9]{1,3}\.){3}[0-9]{1,3}";
	RUN_MAIL_SERVER="true";

	if [[ -n ${MAIL_SERVER_ID} ]]; then
		if [ "$UPDATE" == "true" ]; then
			CURRENT_IMAGE_NAME=$(get_current_image_name "$MAIL_CONTAINER_NAME");
			CURRENT_IMAGE_VERSION=$(get_current_image_version "$MAIL_CONTAINER_NAME");

			MOVE_DATABASE="false";
			if [[ -z ${MYSQL_HOST} ]] && [[ -n ${MYSQL_SERVER_ID} ]]; then
				EXIST_DATABASE=$(docker exec -i ${MYSQL_CONTAINER_NAME} mysql -s -N -u ${MYSQL_ROOT_USER} -p${MYSQL_ROOT_PASSWORD} -e "show databases;" 2>/dev/null | { grep -sw ${MYSQL_MAIL_DATABASE} || true; });
				if [[ -z ${EXIST_DATABASE} ]]; then
					MOVE_DATABASE="true";
				fi
			fi

			if [ "$CURRENT_IMAGE_NAME" != "$MAIL_IMAGE_NAME" ] || ([ "$CURRENT_IMAGE_VERSION" != "$MAIL_VERSION" ] || [ "$SKIP_VERSION_CHECK" == "true" ]) || [ "$MOVE_DATABASE" == "true" ]; then
				check_bindings $MAIL_SERVER_ID "/var/lib/mysql";
				MAIL_DOMAIN_NAME=$(docker exec $MAIL_SERVER_ID hostname -f);

				if [ "$MOVE_DATABASE" == "true" ]; then
					move_mail_server_database
				fi

				stop_mail_server_mysql
				remove_container ${MAIL_CONTAINER_NAME}
			else
				RUN_MAIL_SERVER="false";
				echo "The latest version of ONLYOFFICE MAIL SERVER is already installed."
				docker start ${MAIL_SERVER_ID};
			fi
		else
			RUN_MAIL_SERVER="false";
			echo "ONLYOFFICE MAIL SERVER is already installed."
			docker start ${MAIL_SERVER_ID};
		fi
	else
		RESTART_COMMUNITY_SERVER="true";
	fi

	if [ "$RUN_MAIL_SERVER" == "true" ]; then
		if [[ -n ${MAIL_DOMAIN_NAME} ]]; then
			args=();
			args+=(--name "$MAIL_CONTAINER_NAME");
			args+=(-p 25:25);
			args+=(-p 143:143);
			args+=(-p 587:587);
			args+=(-p 465:465);
			args+=(-p 993:993);
			args+=(-p 995:995);
			args+=(-p 4190:4190);

			MAIL_SERVER_ADDITIONAL_PORTS="";

			if [ "${USE_AS_EXTERNAL_SERVER}" == "true" ]; then
				args+=(-p 8081:8081);

				if [[ -z ${MYSQL_SERVER_ID} ]]; then
					args+=(-p 3306:3306);
				fi

				for ip in ${HOSTNAME_IPS}
				do
					if [[ $ip =~ $IP_V4_REGEX ]]; then
						args+=(--add-host="$MAIL_DOMAIN_NAME:$ip");
					fi
				done
			fi

			MYSQL_SERVER="";

			if [[ -n ${MYSQL_SERVER_ID} ]]; then
				MYSQL_SERVER="$MYSQL_CONTAINER_NAME";
			elif [[ -n ${MYSQL_HOST} ]]; then
				MYSQL_SERVER="$MYSQL_HOST";
			fi

			if [[ -n ${MYSQL_SERVER} ]]; then
				args+=(-e "MYSQL_SERVER=$MYSQL_SERVER");
				args+=(-e "MYSQL_SERVER_PORT=$MYSQL_PORT");
				args+=(-e "MYSQL_ROOT_USER=$MYSQL_ROOT_USER");
				args+=(-e "MYSQL_ROOT_PASSWD=$MYSQL_ROOT_PASSWORD");
				args+=(-e "MYSQL_SERVER_DB_NAME=$MYSQL_MAIL_DATABASE");
			fi

			args+=(-v "$BASE_DIR/MailServer/data:/var/vmail");
			args+=(-v "$BASE_DIR/MailServer/data/certs:/etc/pki/tls/mailserver");
			args+=(-v "$BASE_DIR/MailServer/logs:/var/log");
			args+=(-h "$MAIL_DOMAIN_NAME");
			args+=("$MAIL_IMAGE_NAME:$MAIL_VERSION");

			MAJOR_DOCKER_VERSION=$(docker -v | cut -d ' ' -f3 | cut -d ',' -f1 | cut -d '-' -f1 | cut -d '.' -f1);

			if [ ${MAJOR_DOCKER_VERSION} -ge 17 ]; then
				docker run --init --net ${NETWORK} --privileged -i -t -d --restart=always "${args[@]}";
			else
				docker run --net ${NETWORK} --privileged -i -t -d --restart=always "${args[@]}";
			fi

			MAIL_SERVER_ID=$(get_container_id "$MAIL_CONTAINER_NAME");

			if [[ -z ${MAIL_SERVER_ID} ]]; then
				echo "ONLYOFFICE MAIL SERVER not installed."
				exit 1;
			fi
		else
			echo "mail domain is not specified."
		fi
	fi
}

install_elasticsearch () {
	ELASTICSEARCH_ID=$(get_container_id "$ELASTICSEARCH_CONTAINER_NAME");
	RUN_ELASTICSEARCH="true";

	if [[ -n ${ELASTICSEARCH_ID} ]]; then
		ELASTICSEARCH_SERVER="$ELASTICSEARCH_CONTAINER_NAME";
		if [ "$UPDATE" == "true" ]; then
			CURRENT_IMAGE_NAME=$(get_current_image_name "$ELASTICSEARCH_CONTAINER_NAME");
			CURRENT_IMAGE_VERSION=$(get_current_image_version "$ELASTICSEARCH_CONTAINER_NAME");

			if [ "$CURRENT_IMAGE_NAME" != "$ELASTICSEARCH_IMAGE_NAME" ] || \
			   [ "$CURRENT_IMAGE_VERSION" != "$ELASTICSEARCH_VERSION" ] || \
			   [ "$SKIP_VERSION_CHECK" == "true" ]; then
				check_bindings $ELASTICSEARCH_ID "/usr/share/elasticsearch/data";
				remove_container ${ELASTICSEARCH_CONTAINER_NAME}
			else
				RUN_ELASTICSEARCH="false";
				echo "The latest version of ELASTICSEARCH is already installed."
				docker start ${ELASTICSEARCH_ID};
			fi
		else
			RUN_ELASTICSEARCH="false";
			echo "ELASTICSEARCH is already installed."
			docker start ${ELASTICSEARCH_ID};
		fi
	else
		RESTART_COMMUNITY_SERVER="true";
	fi

	if [ "$RUN_ELASTICSEARCH" == "true" ]; then
		args=();
		args+=(--name "$ELASTICSEARCH_CONTAINER_NAME");

		args+=(-e "discovery.type=single-node");
		args+=(-e "bootstrap.memory_lock=true");
		args+=(-e "ingest.geoip.downloader.enabled=false");
		
		MEMORY_REQUIREMENTS=12228; #RAM ~12Gb
		if [ ${TOTAL_MEMORY} -gt ${MEMORY_REQUIREMENTS} ]; then
			args+=(-e "ES_JAVA_OPTS=-Xms4g -Xmx4g -Dlog4j2.formatMsgNoLookups=true");
		else
			args+=(-e "ES_JAVA_OPTS=-Xms1g -Xmx1g -Dlog4j2.formatMsgNoLookups=true");
		fi

		args+=(-e "indices.fielddata.cache.size=30%");
		args+=(-e "indices.memory.index_buffer_size=30%");
		args+=(--ulimit "nofile=65535:65535");
		args+=(--ulimit "memlock=-1:-1");
		
		if [ "${USE_AS_EXTERNAL_SERVER}" == "true" ]; then
			args+=(-p 9200:9200);
			args+=(-p 9300:9300);
		fi

		args+=(-v "$BASE_DIR/elasticsearch/data:/usr/share/elasticsearch/data");
		args+=("$ELASTICSEARCH_IMAGE_NAME:$ELASTICSEARCH_VERSION");

		docker run --net ${NETWORK} -i -t -d --restart=always "${args[@]}";
		chown -R 1000:1000 $BASE_DIR/elasticsearch #fix AccessDeniedException[/usr/share/elasticsearch/data/nodes]
		ELASTICSEARCH_ID=$(get_container_id "$ELASTICSEARCH_CONTAINER_NAME");

		if [[ -n ${ELASTICSEARCH_ID} ]]; then
			ELASTICSEARCH_SERVER="$ELASTICSEARCH_CONTAINER_NAME";
		elif [[ -z ${ELASTICSEARCH_ID} ]]; then
			echo "ELASTICSEARCH not installed."
			exit 1;
		fi
	fi
}

install_controlpanel () {
	CONTROL_PANEL_ID=$(get_container_id "$CONTROLPANEL_CONTAINER_NAME");

	RUN_CONTROL_PANEL="true";

	if [[ -n ${CONTROL_PANEL_ID} ]]; then
		if [ "$UPDATE" == "true" ]; then
			CURRENT_IMAGE_NAME=$(get_current_image_name "$CONTROLPANEL_CONTAINER_NAME");
			CURRENT_IMAGE_VERSION=$(get_current_image_version "$CONTROLPANEL_CONTAINER_NAME");

			if [ "$CURRENT_IMAGE_NAME" != "$CONTROLPANEL_IMAGE_NAME" ] || ([ "$CURRENT_IMAGE_VERSION" != "$CONTROLPANEL_VERSION" ] || [ "$SKIP_VERSION_CHECK" == "true" ]); then
				check_bindings $CONTROL_PANEL_ID "/var/lib/mysql";
				remove_container ${CONTROLPANEL_CONTAINER_NAME}
			else
				RUN_CONTROL_PANEL="false";
				echo "The latest version of ONLYOFFICE CONTROL PANEL is already installed."
				docker start ${CONTROL_PANEL_ID};
			fi
		else
			RUN_CONTROL_PANEL="false";
			echo "ONLYOFFICE CONTROL PANEL is already installed."
			docker start ${CONTROL_PANEL_ID};
		fi
	else
		RESTART_COMMUNITY_SERVER="true";
	fi

	if [ "$RUN_CONTROL_PANEL" == "true" ]; then
		args=();
		args+=(--name "$CONTROLPANEL_CONTAINER_NAME");

		if [[ -n ${MAIL_SERVER_API_HOST} ]]; then
			args+=(-e "MAIL_SERVER_EXTERNAL=true");
		fi

		if [[ -n ${DOCUMENT_SERVER_HOST} ]]; then
			args+=(-e "DOCUMENT_SERVER_EXTERNAL=true");
		fi

		if [[ -n ${COMMUNITY_SERVER_HOST} ]]; then
			args+=(-e "COMMUNITY_SERVER_EXTERNAL=true");
		fi

		if [[ -n ${CORE_MACHINEKEY} ]]; then
			args+=(-e "$MACHINEKEY_PARAM=$CORE_MACHINEKEY");
		fi

		args+=(-v "/var/run/docker.sock:/var/run/docker.sock");
		args+=(-v "$BASE_DIR/CommunityServer/data:/app/$PRODUCT/CommunityServer/data");
		args+=(-v "$BASE_DIR/ControlPanel/data:/var/www/$PRODUCT/Data");
		args+=(-v "$BASE_DIR/ControlPanel/logs:/var/log/$PRODUCT");
		args+=("$CONTROLPANEL_IMAGE_NAME:$CONTROLPANEL_VERSION");

		docker run --net ${NETWORK} -i -t -d --restart=always "${args[@]}";

		CONTROL_PANEL_ID=$(get_container_id "$CONTROLPANEL_CONTAINER_NAME");

		if [[ -z ${CONTROL_PANEL_ID} ]]; then
			echo "ONLYOFFICE CONTROL PANEL not installed."
			exit 1;
		fi
	fi
}

install_community_server () {
	COMMUNITY_SERVER_ID=$(get_container_id "$COMMUNITY_CONTAINER_NAME");
	DOCUMENT_SERVER_ID=$(get_container_id "$DOCUMENT_CONTAINER_NAME");
	MAIL_SERVER_ID=$(get_container_id "$MAIL_CONTAINER_NAME");
	CONTROL_PANEL_ID=$(get_container_id "$CONTROLPANEL_CONTAINER_NAME");
	MYSQL_SERVER_ID=$(get_container_id "$MYSQL_CONTAINER_NAME");

	RUN_COMMUNITY_SERVER="true";

	if [[ -n ${COMMUNITY_SERVER_ID} ]]; then
		docker exec -d ${COMMUNITY_CONTAINER_NAME} bash -c "cp -rf /var/www/${PRODUCT}/WebStudio/App_Data/static/partnerdata /var/www/${PRODUCT}/Data/"

		if [ "$UPDATE" == "true" ]; then
			CURRENT_IMAGE_NAME=$(get_current_image_name "$COMMUNITY_CONTAINER_NAME");
			CURRENT_IMAGE_VERSION=$(get_current_image_version "$COMMUNITY_CONTAINER_NAME");

			if [ "$CURRENT_IMAGE_NAME" != "$COMMUNITY_IMAGE_NAME" ] || ([ "$CURRENT_IMAGE_VERSION" != "$COMMUNITY_VERSION" ] || [ "$SKIP_VERSION_CHECK" == "true" ]) || [ "$MOVE_COMMUNITY_SERVER_DATABASE" == "true" ]; then
				check_bindings $COMMUNITY_SERVER_ID "/var/lib/mysql";
				COMMUNITY_PORT=$(docker port $COMMUNITY_SERVER_ID 80 | sed 's/.*://' | head -n1)
				stop_community_server_mysql
				remove_container ${COMMUNITY_CONTAINER_NAME}
			else
				RUN_COMMUNITY_SERVER="false";

				if [ "$ACTIVATE_COMMUNITY_SERVER_TRIAL" == "true" ]; then
					docker restart ${COMMUNITY_CONTAINER_NAME}
				fi

				echo "The latest version of ONLYOFFICE COMMUNITY SERVER is already installed."
				docker start ${COMMUNITY_SERVER_ID};
			fi
		else
			if [ "$RESTART_COMMUNITY_SERVER" == "true" ]; then
				check_bindings $COMMUNITY_SERVER_ID "/var/lib/mysql";
				COMMUNITY_PORT=$(docker port $COMMUNITY_SERVER_ID 80 | sed 's/.*://' | head -n1)
				stop_community_server_mysql
				remove_container ${COMMUNITY_CONTAINER_NAME}
			else
				RUN_COMMUNITY_SERVER="false";
				echo "ONLYOFFICE COMMUNITY SERVER is already installed."
				docker start ${COMMUNITY_SERVER_ID};
			fi
		fi
	fi

	if [ "$RUN_COMMUNITY_SERVER" == "true" ]; then
		args=();
		args+=(--name "$COMMUNITY_CONTAINER_NAME");
		args+=(-p "$COMMUNITY_PORT:80");
		args+=(-p 443:443);
		args+=(-p 5222:5222);
		args+=(--cgroupns host);

		if [[ -n ${MAIL_SERVER_API_HOST} ]]; then
			args+=(-e "MAIL_SERVER_API_HOST=$MAIL_SERVER_API_HOST");

			if [[ -n ${MAIL_SERVER_DB_HOST} ]]; then
				args+=(-e "MAIL_SERVER_DB_HOST=$MAIL_SERVER_DB_HOST");
			else
				args+=(-e "MAIL_SERVER_DB_HOST=$MAIL_SERVER_API_HOST");
			fi
		fi

		if [[ -n ${MAIL_DOMAIN_NAME} ]]; then
			args+=(-e "MAIL_DOMAIN_NAME=$MAIL_DOMAIN_NAME");
		fi

		if [[ -n ${DOCUMENT_SERVER_HOST} ]]; then
			args+=(-e "DOCUMENT_SERVER_HOST=$DOCUMENT_SERVER_HOST");
		fi

		if [[ -n ${DOCUMENT_SERVER_ID} ]]; then
			args+=(-e "DOCUMENT_SERVER_PORT_80_TCP_ADDR=$DOCUMENT_CONTAINER_NAME");
		fi

		MYSQL_SERVER="";

		if [[ -n ${MYSQL_SERVER_ID} ]]; then
			MYSQL_SERVER="$MYSQL_CONTAINER_NAME";
		elif [[ -n ${MYSQL_HOST} ]]; then
			MYSQL_SERVER="$MYSQL_HOST";
		fi

		if [[ -n ${MYSQL_SERVER} ]]; then
			args+=(-e "MYSQL_SERVER_ROOT_PASSWORD=$MYSQL_ROOT_PASSWORD");
			args+=(-e "MYSQL_SERVER_DB_NAME=$MYSQL_DATABASE");
			args+=(-e "MYSQL_SERVER_HOST=$MYSQL_SERVER");
			args+=(-e "MYSQL_SERVER_USER=$MYSQL_USER");
			args+=(-e "MYSQL_SERVER_PASS=$MYSQL_PASSWORD");
		fi

		if [[ -n ${ELASTICSEARCH_SERVER} ]]; then
			args+=(-e "ELASTICSEARCH_SERVER_HOST=$ELASTICSEARCH_SERVER");
			args+=(-e "ELASTICSEARCH_SERVER_HTTPPORT=$ELASTICSEARCH_PORT");
		fi

		if [[ -n ${MAIL_SERVER_ID} ]]; then
			args+=(-e "MAIL_SERVER_API_HOST=$MAIL_CONTAINER_NAME");

			if [[ -n ${MYSQL_SERVER} ]]; then
				args+=(-e "MAIL_SERVER_DB_HOST=$MYSQL_SERVER");
				args+=(-e "MAIL_SERVER_DB_NAME=$MYSQL_MAIL_DATABASE");
				args+=(-e "MAIL_SERVER_DB_PORT=$MYSQL_PORT");
				args+=(-e "MAIL_SERVER_DB_USER=$MYSQL_ROOT_USER");
				args+=(-e "MAIL_SERVER_DB_PASS=$MYSQL_ROOT_PASSWORD");
			else
				args+=(-e "MAIL_SERVER_DB_HOST=$MAIL_CONTAINER_NAME");
			fi
		fi

		if [[ -n ${MAIL_IMAPSYNC_START_DATE} ]]; then
			args+=(-e "MAIL_IMAPSYNC_START_DATE=$MAIL_IMAPSYNC_START_DATE");
		fi

		if [[ -n ${CONTROL_PANEL_ID} ]]; then
			args+=(-e "CONTROL_PANEL_PORT_80_TCP=80");
			args+=(-e "CONTROL_PANEL_PORT_80_TCP_ADDR=$CONTROLPANEL_CONTAINER_NAME");
		fi

		if [[ -n ${JWT_SECRET} ]]; then
			args+=(-e "DOCUMENT_SERVER_JWT_ENABLED=$JWT_ENABLED");
			args+=(-e "DOCUMENT_SERVER_JWT_HEADER=$JWT_HEADER");
			args+=(-e "DOCUMENT_SERVER_JWT_SECRET=$JWT_SECRET");
		else
			args+=(-e "DOCUMENT_SERVER_JWT_ENABLED=false");
		fi

		if [[ -n ${CORE_MACHINEKEY} ]]; then
			args+=(-e "$MACHINEKEY_PARAM=$CORE_MACHINEKEY");
		fi

		args+=(-v "$BASE_DIR/CommunityServer/letsencrypt:/etc/letsencrypt");
		args+=(-v "/sys/fs/cgroup:/sys/fs/cgroup:rw");
		args+=(-v "$BASE_DIR/CommunityServer/data:/var/www/$PRODUCT/Data");
		args+=(-v "$BASE_DIR/CommunityServer/logs:/var/log/$PRODUCT");
		args+=(-v "$BASE_DIR/DocumentServer/data:/var/www/$PRODUCT/DocumentServerData");
		args+=("$COMMUNITY_IMAGE_NAME:$COMMUNITY_VERSION");

		docker run --net ${NETWORK} -itd  --privileged --restart=always "${args[@]}";

		COMMUNITY_SERVER_ID=$(get_container_id "$COMMUNITY_CONTAINER_NAME");

		if [[ -z ${COMMUNITY_SERVER_ID} ]]; then
			echo "ONLYOFFICE COMMUNITY SERVER not installed."
			exit 1;
		else
			docker exec -d ${COMMUNITY_CONTAINER_NAME} bash -c "[ -d /var/www/${PRODUCT}/Data/partnerdata ] && cp /var/www/${PRODUCT}/Data/partnerdata/* /var/www/${PRODUCT}/WebStudio/App_Data/static/partnerdata/ && rm -rf /var/www/${PRODUCT}/Data/partnerdata"
		fi
	fi
}

get_container_id () {
	CONTAINER_NAME=$1;

	if [[ -z ${CONTAINER_NAME} ]]; then
		echo "Empty container name"
		exit 1;
	fi

	CONTAINER_ID="";

	CONTAINER_EXIST=$(docker ps -aqf "name=$CONTAINER_NAME");

	if [[ -n ${CONTAINER_EXIST} ]]; then
		CONTAINER_ID=$(docker inspect --format='{{.Id}}' ${CONTAINER_NAME});
	fi

	echo "$CONTAINER_ID"
}

get_container_ip () {
	CONTAINER_NAME=$1;

	if [[ -z ${CONTAINER_NAME} ]]; then
		echo "Empty container name"
		exit 1;
	fi

	CONTAINER_IP="";

	CONTAINER_EXIST=$(docker ps -aqf "name=$CONTAINER_NAME");

	if [[ -n ${CONTAINER_EXIST} ]]; then
		CONTAINER_IP=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' ${CONTAINER_NAME});
	fi

	echo "$CONTAINER_IP"
}

get_random_str () {
	LENGTH=$1;

	if [[ -z ${LENGTH} ]]; then
		LENGTH=12;
	fi

	VALUE=$(cat /dev/urandom | tr -dc A-Za-z0-9 | head -c ${LENGTH});
	echo "$VALUE"
}

set_jwt_secret () {
	CURRENT_JWT_SECRET="";

	if [[ -z ${JWT_SECRET} ]]; then
		CURRENT_JWT_SECRET=$(get_container_env_parameter "$DOCUMENT_CONTAINER_NAME" "JWT_SECRET");

		if [[ -n ${CURRENT_JWT_SECRET} ]]; then
			JWT_SECRET="$CURRENT_JWT_SECRET";
		fi
	fi

	if [[ -z ${JWT_SECRET} ]]; then
		CURRENT_JWT_SECRET=$(get_container_env_parameter "$COMMUNITY_CONTAINER_NAME" "DOCUMENT_SERVER_JWT_SECRET");

		if [[ -n ${CURRENT_JWT_SECRET} ]]; then
			JWT_SECRET="$CURRENT_JWT_SECRET";
		fi
	fi

	if [[ -z ${JWT_SECRET} ]] && [[ "$USE_AS_EXTERNAL_SERVER" != "true" ]]; then
		JWT_SECRET=$(get_random_str 32);
		[ $JWT_ENABLED = "true" ] && JWT_MESSAGE='JWT is enabled by default. A random secret is generated automatically. Run the command "docker exec $(sudo docker ps -q) sudo documentserver-jwt-status.sh" to get information about JWT.'
	fi
}

set_jwt_header () {
	CURRENT_JWT_HEADER="";

	if [[ -z ${JWT_HEADER} ]]; then
		CURRENT_JWT_HEADER=$(get_container_env_parameter "$DOCUMENT_CONTAINER_NAME" "JWT_HEADER");

		if [[ -n ${CURRENT_JWT_HEADER} ]]; then
			JWT_HEADER="$CURRENT_JWT_HEADER";
		fi
	fi	
	
	if [[ -z ${JWT_HEADER} ]]; then
		CURRENT_JWT_HEADER=$(get_container_env_parameter "$COMMUNITY_CONTAINER_NAME" "DOCUMENT_SERVER_JWT_HEADER");

		if [[ -n ${CURRENT_JWT_HEADER} ]]; then
			JWT_HEADER="$CURRENT_JWT_HEADER";
		fi
	fi

	if [[ -z ${JWT_HEADER} ]]; then
		JWT_HEADER="AuthorizationJwt"
	fi
}


set_jwt_enabled () {
	CURRENT_JWT_ENABLED="";

	if [[ -z ${JWT_ENABLED} ]]; then
		CURRENT_JWT_ENABLED=$(get_container_env_parameter "$DOCUMENT_CONTAINER_NAME" "JWT_ENABLED");

		if [[ -n ${CURRENT_JWT_ENABLED} ]]; then
			JWT_ENABLED="$CURRENT_JWT_ENABLED";
		fi
	fi

	if [[ -z ${JWT_ENABLED} ]]; then
		CURRENT_JWT_ENABLED=$(get_container_env_parameter "$COMMUNITY_CONTAINER_NAME" "DOCUMENT_SERVER_JWT_ENABLED");

		if [[ -n ${CURRENT_JWT_ENABLED} ]]; then
			JWT_ENABLED="$CURRENT_JWT_ENABLED";
		fi
	fi

	if [[ -z ${JWT_ENABLED} ]]; then
		JWT_ENABLED="true"
	fi
}

set_core_machinekey () {
	CURRENT_CORE_MACHINEKEY="";

	if [[ -z ${CORE_MACHINEKEY} ]]; then
		if file_exists ${BASE_DIR}/CommunityServer/data/.private/machinekey; then
			CURRENT_CORE_MACHINEKEY=$(cat ${BASE_DIR}/CommunityServer/data/.private/machinekey);

			if [[ -n ${CURRENT_CORE_MACHINEKEY} ]]; then
				CORE_MACHINEKEY="$CURRENT_CORE_MACHINEKEY";
			fi
		fi
	fi

	if [[ -z ${CORE_MACHINEKEY} ]]; then
		CURRENT_CORE_MACHINEKEY=$(get_container_env_parameter "$CONTROLPANEL_CONTAINER_NAME" "$MACHINEKEY_PARAM");

		if [[ -n ${CURRENT_CORE_MACHINEKEY} ]]; then
			CORE_MACHINEKEY="$CURRENT_CORE_MACHINEKEY";
		fi
	fi

	if [[ -z ${CORE_MACHINEKEY} ]]; then
		CURRENT_CORE_MACHINEKEY=$(get_container_env_parameter "$COMMUNITY_CONTAINER_NAME" "$MACHINEKEY_PARAM");

		if [[ -n ${CURRENT_CORE_MACHINEKEY} ]]; then
			CORE_MACHINEKEY="$CURRENT_CORE_MACHINEKEY";
		fi
	fi

	if [[ -z ${CORE_MACHINEKEY} ]] && [[ "$UPDATE" != "true" ]] && [[ "$USE_AS_EXTERNAL_SERVER" != "true" ]]; then
		CORE_MACHINEKEY=$(get_random_str 12);
	fi
}

read_parameters () {
	COMMUNITY_SERVER_ID=$(get_container_id "$COMMUNITY_CONTAINER_NAME");
	MAIL_SERVER_ID=$(get_container_id "$MAIL_CONTAINER_NAME");
	PARAMETER_VALUE="";

	if [[ -n ${COMMUNITY_SERVER_ID} ]]; then
		PARAMETER_VALUE=$(get_container_env_parameter "$COMMUNITY_CONTAINER_NAME" "MYSQL_SERVER_HOST");
		if [[ -n ${PARAMETER_VALUE} ]]; then
			MYSQL_HOST="$PARAMETER_VALUE";
			if [ "$MYSQL_HOST" == "$MYSQL_CONTAINER_NAME" ]; then
				MYSQL_HOST="";
			fi
		fi

		PARAMETER_VALUE=$(get_container_env_parameter "$COMMUNITY_CONTAINER_NAME" "MYSQL_SERVER_ROOT_PASSWORD");
		if [[ -n ${PARAMETER_VALUE} ]]; then
			MYSQL_ROOT_PASSWORD="$PARAMETER_VALUE";
		fi

		PARAMETER_VALUE=$(get_container_env_parameter "$COMMUNITY_CONTAINER_NAME" "MYSQL_SERVER_DB_NAME");
		if [[ -n ${PARAMETER_VALUE} ]]; then
			MYSQL_DATABASE="$PARAMETER_VALUE";
		fi

		PARAMETER_VALUE=$(get_container_env_parameter "$COMMUNITY_CONTAINER_NAME" "MYSQL_SERVER_USER");
		if [[ -n ${PARAMETER_VALUE} ]]; then
			MYSQL_USER="$PARAMETER_VALUE";
		fi

		PARAMETER_VALUE=$(get_container_env_parameter "$COMMUNITY_CONTAINER_NAME" "MYSQL_SERVER_PASS");
		if [[ -n ${PARAMETER_VALUE} ]]; then
			MYSQL_PASSWORD="$PARAMETER_VALUE";
		fi

		PARAMETER_VALUE=$(get_container_env_parameter "$COMMUNITY_CONTAINER_NAME" "ELASTICSEARCH_SERVER_HOST");
		if [[ -n ${PARAMETER_VALUE} ]]; then
			ELASTICSEARCH_HOST="$PARAMETER_VALUE";
			if [ "$ELASTICSEARCH_HOST" == "$ELASTICSEARCH_CONTAINER_NAME" ]; then
				ELASTICSEARCH_HOST="";
			fi
		fi

		PARAMETER_VALUE=$(get_container_env_parameter "$COMMUNITY_CONTAINER_NAME" "ELASTICSEARCH_SERVER_HTTPPORT");
		if [[ -n ${PARAMETER_VALUE} ]]; then
			ELASTICSEARCH_PORT="$PARAMETER_VALUE";
		fi

		PARAMETER_VALUE=$(get_container_env_parameter "$COMMUNITY_CONTAINER_NAME" "MAIL_IMAPSYNC_START_DATE");
		if [[ -n ${PARAMETER_VALUE} ]]; then
			MAIL_IMAPSYNC_START_DATE="$PARAMETER_VALUE";
		fi
	fi

	if [[ -n ${MAIL_SERVER_ID} ]]; then
		PARAMETER_VALUE=$(get_container_env_parameter "$MAIL_CONTAINER_NAME" "MYSQL_SERVER");
		if [[ -n ${PARAMETER_VALUE} ]]; then
			MYSQL_HOST="$PARAMETER_VALUE";
			if [ "$MYSQL_HOST" == "$MYSQL_CONTAINER_NAME" ]; then
				MYSQL_HOST="";
			fi
		fi

		PARAMETER_VALUE=$(get_container_env_parameter "$MAIL_CONTAINER_NAME" "MYSQL_SERVER_PORT");
		if [[ -n ${PARAMETER_VALUE} ]]; then
			MYSQL_PORT="$PARAMETER_VALUE";
		fi

		PARAMETER_VALUE=$(get_container_env_parameter "$MAIL_CONTAINER_NAME" "MYSQL_ROOT_USER");
		if [[ -n ${PARAMETER_VALUE} ]]; then
			MYSQL_ROOT_USER="$PARAMETER_VALUE";
		fi

		PARAMETER_VALUE=$(get_container_env_parameter "$MAIL_CONTAINER_NAME" "MYSQL_ROOT_PASSWD");
		if [[ -n ${PARAMETER_VALUE} ]]; then
			MYSQL_ROOT_PASSWORD="$PARAMETER_VALUE";
		fi

		PARAMETER_VALUE=$(get_container_env_parameter "$MAIL_CONTAINER_NAME" "MYSQL_SERVER_DB_NAME");
		if [[ -n ${PARAMETER_VALUE} ]]; then
			MYSQL_MAIL_DATABASE="$PARAMETER_VALUE";
		fi
	fi
}

get_container_env_parameter () {
	CONTAINER_NAME=$1;
	PARAMETER_NAME=$2;
	VALUE="";

	if [[ -z ${CONTAINER_NAME} ]]; then
		echo "Empty container name"
		exit 1;
	fi

	if [[ -z ${PARAMETER_NAME} ]]; then
		echo "Empty parameter name"
		exit 1;
	fi

	if command_exists docker ; then
		CONTAINER_EXIST=$(docker ps -aqf "name=$CONTAINER_NAME");

		if [[ -n ${CONTAINER_EXIST} ]]; then
			VALUE=$(docker inspect --format='{{range .Config.Env}}{{println .}}{{end}}' ${CONTAINER_NAME} | grep "${PARAMETER_NAME}=" | sed 's/^.*=//');
		fi
	fi

	echo "$VALUE"
}

move_mail_server_database () {
	EXIST_DATABASE=$(docker exec -i ${MYSQL_CONTAINER_NAME} mysql -s -N -u ${MYSQL_ROOT_USER} -p${MYSQL_ROOT_PASSWORD} -e "show databases;" 2>/dev/null | { grep -sw ${MYSQL_MAIL_DATABASE} || true; });
	EXIST_MAIL_DATABASE=$(docker exec -itd ${MAIL_CONTAINER_NAME} mysql -s -N -u ${MYSQL_ROOT_USER} -p${MYSQL_MAIL_ROOT_PASSWORD} -e "show databases;" 2>/dev/null | { grep -sw ${MYSQL_MAIL_DATABASE} || true; })
	if [[ -n ${EXIST_DATABASE} ]]; then
		echo "$MYSQL_MAIL_DATABASE database already exist in $MYSQL_CONTAINER_NAME"
	elif [[ -z "${EXIST_MAIL_DATABASE}" ]]; then
		echo "$MYSQL_MAIL_DATABASE database does not exist in $MAIL_CONTAINER_NAME"
	else
		if ! docker exec -itd ${MAIL_CONTAINER_NAME} mysqladmin -u ${MYSQL_ROOT_USER} -p${MYSQL_MAIL_ROOT_PASSWORD} status; then
			echo "$MAIL_CONTAINER_NAME mysqld service not available."
			exit 1;
		fi
		echo "creating $MYSQL_MAIL_DATABASE database dump file"
		if ! docker exec -it ${MAIL_CONTAINER_NAME} mysqldump -u ${MYSQL_ROOT_USER} -p${MYSQL_MAIL_ROOT_PASSWORD} ${MYSQL_MAIL_DATABASE} > dump.sql; then
			echo "$MAIL_CONTAINER_NAME could not create $MYSQL_MAIL_DATABASE database dump file"
			exit 1;
		fi
		if ! docker exec -i ${MYSQL_CONTAINER_NAME} mysql -u ${MYSQL_ROOT_USER} -p${MYSQL_ROOT_PASSWORD} -e "CREATE DATABASE \`${MYSQL_MAIL_DATABASE}\`"; then
			echo "$MYSQL_CONTAINER_NAME could not create $MYSQL_MAIL_DATABASE database"
			exit 1;
		fi
		echo "restoring $MYSQL_MAIL_DATABASE database dump file"
		if ! docker exec -i ${MYSQL_CONTAINER_NAME} mysql -u ${MYSQL_ROOT_USER} -p${MYSQL_ROOT_PASSWORD} ${MYSQL_MAIL_DATABASE} < dump.sql; then
			echo "$MYSQL_CONTAINER_NAME could not restore $MYSQL_MAIL_DATABASE database dump file"
			exit 1;
		fi

		rm -f dump.sql
	fi
}

stop_mail_server_mysql () {
	if ! docker exec -it ${MAIL_CONTAINER_NAME} service mysqld stop; then
		echo "$MAIL_CONTAINER_NAME mysqld service could not be stopped correctly."
	fi
}

stop_community_server_mysql () {
	if ! docker exec -it ${COMMUNITY_CONTAINER_NAME} service god stop; then
			echo "$COMMUNITY_CONTAINER_NAME god service could not be stopped correctly."
	fi
	if ! docker exec -it ${COMMUNITY_CONTAINER_NAME} service mysql stop; then
		echo "$COMMUNITY_CONTAINER_NAME mysql service could not be stopped correctly."
	fi
}

remove_container () {
	CONTAINER_NAME=$1;

	if [[ -z ${CONTAINER_NAME} ]]; then
		echo "Empty container name"
		exit 1;
	fi

	echo "stop container:"
	docker stop ${CONTAINER_NAME};
	echo "remove container:"
	docker rm -f ${CONTAINER_NAME};

	sleep 10 #Hack for SuSe: exception "Error response from daemon: devmapper: Unknown device xxx"

	echo "check removed container: $CONTAINER_NAME"
	CONTAINER_ID=$(get_container_id "$CONTAINER_NAME");

	if [[ -n ${CONTAINER_ID} ]]; then
		echo "try again remove ${CONTAINER_NAME}"
		remove_container ${CONTAINER_NAME}
	fi
}

pull_mysql_server () {
	if file_exists ${BASE_DIR}/mysql/.private/$MYSQL_DATABASE.version; then
		MYSQL_VERSION=$(cat ${BASE_DIR}/mysql/.private/$MYSQL_DATABASE.version)	
	elif grep "Version:" ${BASE_DIR}/mysql/logs/error.log > /dev/null 2>&1 ; then
		MYSQL_VERSION=$(grep "Version:" ${BASE_DIR}/mysql/logs/error.log | grep -Po "'[0-99].[0-99]..*?'" | head -1 | tr -d \')
	fi

	echo $MYSQL_VERSION > ${BASE_DIR}/mysql/.private/$MYSQL_DATABASE.version

	if file_exists "${MYSQL_IMAGE_NAME}"; then
		docker load -i ${MYSQL_IMAGE_NAME}

		FILE_NAME=$(basename $MYSQL_IMAGE_NAME)
		TMP_STRING=${FILE_NAME//.tar.gz/ }
		TMP_ARRAY=(${TMP_STRING//_/ })
		MYSQL_IMAGE_NAME=${TMP_ARRAY[0]/-//}
		MYSQL_VERSION="${TMP_ARRAY[1]}"
	else
		if [[ -z ${MYSQL_VERSION} ]]; then
			MYSQL_VERSION=$(get_available_version "$MYSQL_IMAGE_NAME");
		fi

		pull_image ${MYSQL_IMAGE_NAME} ${MYSQL_VERSION}
	fi
}

pull_document_server () {
	if file_exists "${DOCUMENT_IMAGE_NAME}"; then
		docker load -i ${DOCUMENT_IMAGE_NAME}

		FILE_NAME=$(basename $DOCUMENT_IMAGE_NAME)
		TMP_STRING=${FILE_NAME//.tar.gz/ }
		TMP_ARRAY=(${TMP_STRING//-/ })
		DOCUMENT_IMAGE_NAME="${TMP_ARRAY[0]}/${TMP_ARRAY[1]}"
		DOCUMENT_VERSION="${TMP_ARRAY[2]}"
	else
		if [[ -z ${DOCUMENT_VERSION} ]]; then
			DOCUMENT_VERSION=$(get_available_version "$DOCUMENT_IMAGE_NAME");
		fi

		pull_image ${DOCUMENT_IMAGE_NAME} ${DOCUMENT_VERSION}
	fi
}

pull_mail_server () {
	if file_exists "${MAIL_IMAGE_NAME}"; then
		docker load -i ${MAIL_IMAGE_NAME}

		FILE_NAME=$(basename $MAIL_IMAGE_NAME)
		TMP_STRING=${FILE_NAME//.tar.gz/ }
		TMP_ARRAY=(${TMP_STRING//-/ })
		MAIL_IMAGE_NAME="${TMP_ARRAY[0]}/${TMP_ARRAY[1]}"
		MAIL_VERSION="${TMP_ARRAY[2]}"
	else
		if [[ -z ${MAIL_VERSION} ]]; then
			MAIL_VERSION=$(get_available_version "$MAIL_IMAGE_NAME");
		fi

		pull_image ${MAIL_IMAGE_NAME} ${MAIL_VERSION}
	fi
}

pull_elasticsearch () {
	if file_exists "${ELASTICSEARCH_IMAGE_NAME}"; then
		docker load -i ${ELASTICSEARCH_IMAGE_NAME}

		FILE_NAME=$(basename $ELASTICSEARCH_IMAGE_NAME)
		TMP_STRING=${FILE_NAME//.tar.gz/ }
		TMP_ARRAY=(${TMP_STRING//-/ })
		ELASTICSEARCH_IMAGE_NAME="${TMP_ARRAY[0]}/${TMP_ARRAY[1]}"
		ELASTICSEARCH_VERSION="${TMP_ARRAY[2]}"
	else
		if [[ -z ${ELASTICSEARCH_VERSION} ]]; then
			ELASTICSEARCH_VERSION=$(get_available_version "$ELASTICSEARCH_IMAGE_NAME");
		fi

		pull_image ${ELASTICSEARCH_IMAGE_NAME} ${ELASTICSEARCH_VERSION}
	fi
}

pull_controlpanel () {
	if file_exists "${CONTROLPANEL_IMAGE_NAME}"; then
		docker load -i ${CONTROLPANEL_IMAGE_NAME}

		FILE_NAME=$(basename $CONTROLPANEL_IMAGE_NAME)
		TMP_STRING=${FILE_NAME//.tar.gz/ }
		TMP_ARRAY=(${TMP_STRING//-/ })
		CONTROLPANEL_IMAGE_NAME="${TMP_ARRAY[0]}/${TMP_ARRAY[1]}"
		CONTROLPANEL_VERSION="${TMP_ARRAY[2]}"
	else
		if [[ -z ${CONTROLPANEL_VERSION} ]]; then
			CONTROLPANEL_VERSION=$(get_available_version "$CONTROLPANEL_IMAGE_NAME");
		fi

		pull_image ${CONTROLPANEL_IMAGE_NAME} ${CONTROLPANEL_VERSION}
	fi
}

pull_community_server () {
	if file_exists "${COMMUNITY_IMAGE_NAME}"; then
		docker load -i ${COMMUNITY_IMAGE_NAME}

		FILE_NAME=$(basename $COMMUNITY_IMAGE_NAME)
		TMP_STRING=${FILE_NAME//.tar.gz/ }
		TMP_ARRAY=(${TMP_STRING//_/ })
		COMMUNITY_IMAGE_NAME=${TMP_ARRAY[0]/-//}
		COMMUNITY_VERSION="${TMP_ARRAY[1]}"
	else
		if [[ -z ${COMMUNITY_VERSION} ]]; then
			COMMUNITY_VERSION=$(get_available_version "$COMMUNITY_IMAGE_NAME");
		fi

		pull_image ${COMMUNITY_IMAGE_NAME} ${COMMUNITY_VERSION}
	fi
}

pull_image () {
	IMAGE_NAME=$1;
	IMAGE_VERSION=$2;

	if [[ -z ${IMAGE_NAME} || -z ${IMAGE_VERSION} ]]; then
		echo "Docker pull argument exception: repository=$IMAGE_NAME, tag=$IMAGE_VERSION"
		exit 1;
	fi

	EXIST=$(docker images | grep "$IMAGE_NAME" | awk '{print $2;}' | { grep -x "$IMAGE_VERSION" || true; });
	COUNT=1;

	while [[ -z $EXIST && $COUNT -le 3 ]]; do
		docker pull ${IMAGE_NAME}:${IMAGE_VERSION}
		EXIST=$(docker images | grep "$IMAGE_NAME" | awk '{print $2;}' | { grep -x "$IMAGE_VERSION" || true; });
		(( COUNT++ ))
	done

	if [[ -z $EXIST ]]; then
		echo "Docker image $IMAGE_NAME:$IMAGE_VERSION not found"
		exit 1;
	fi
}

set_partner_data () {
	if [[ -n ${PARTNER_DATA_FILE} ]]; then
		curl -o ${BASE_DIR}/CommunityServer/data/json-data.txt ${PARTNER_DATA_FILE}
	fi
}

create_network () {
	EXIST=$(docker network ls | awk '{print $2;}' | { grep -x ${NETWORK} || true; });

	if [[ -z ${EXIST} ]]; then
		docker network create --driver bridge ${NETWORK}
	fi
}

set_installation_type_data () {
	if [ "$INSTALLATION_TYPE" == "GROUPS" ]; then
		INSTALL_DOCUMENT_SERVER="false";
		INSTALL_MAIL_SERVER="false";
		set_opensource_data
	elif [ "$INSTALLATION_TYPE" == "WORKSPACE" ]; then
		set_opensource_data
	fi
}

set_opensource_data () {
	COMMUNITY_IMAGE_NAME="onlyoffice/communityserver";
	DOCUMENT_IMAGE_NAME="onlyoffice/documentserver";
	MAIL_IMAGE_NAME="onlyoffice/mailserver";
	CONTROLPANEL_IMAGE_NAME="onlyoffice/controlpanel";

	HUB="";
	USERNAME="";
	PASSWORD="";
}

ping_host_port () {
	HOST=$1
	PORT=$2

	if [ -z "$HOST" ] || [ -z "$PORT" ]; then
		echo "mysql host or port is empty"
		exit 1;
	fi

	if command_exists nc ; then
		RESULT=`nc -z -v -w5 $HOST $PORT &> /dev/null; echo $?`
		if [ $RESULT != 0 ]; then
			echo "Error ping $HOST:$PORT"
			exit 1;
		fi
	fi
}

check_domain () {
	if ! command_exists dig ; then
		if command_exists apt-get; then
			apt-get -y update
			apt-get install -y dnsutils
		elif command_exists yum; then
			yum install bind-utils
		fi

		if ! command_exists dig; then
			echo "command dig not found"
			exit 1;
		fi

		if ! command_exists host; then
			echo "command host not found"
			exit 1;
		fi
	fi

	IP=$(dig +short myip.opendns.com @resolver1.opendns.com)
	RESULT=$(host $MAIL_DOMAIN_NAME | { grep $IP || true; })

	if [[ -z $IP ]]; then
		echo "Could not determine the external ip of the current server";
		RESULT=true;
	elif [[ -z ${RESULT} ]]; then
		echo "$MAIL_DOMAIN_NAME is not linked to the $IP address. Please check your A-record."
		exit 1;
	fi
}

check_vsyscall () {
	MIN_NUM_ARR=(4 18 0);
	CUR_NUM_ARR=();

	CUR_STR_ARR=$(echo $KERNEL | grep -Po "[0-9]+\.[0-9]+\.[0-9]+" | tr "." " ");
	for CUR_STR_ITEM in $CUR_STR_ARR
	do
		CUR_NUM_ARR=(${CUR_NUM_ARR[@]} $CUR_STR_ITEM)
	done

	INDEX=0;
	NEED_VSYSCALL_CHECK="true";

	while [[ $INDEX -lt 3 ]]; do
		if [ ${CUR_NUM_ARR[INDEX]} -lt ${MIN_NUM_ARR[INDEX]} ]; then
			NEED_VSYSCALL_CHECK="false";
			INDEX=3;
		elif [ ${CUR_NUM_ARR[INDEX]} -gt ${MIN_NUM_ARR[INDEX]} ]; then
			INDEX=3;
		fi
		(( INDEX++ ))
	done

	if [ "$NEED_VSYSCALL_CHECK" == "true" ]; then
		VSYSCALL_ENABLED=$(cat /proc/self/maps | egrep 'vsyscall');
		if [ -z "$VSYSCALL_ENABLED" ]; then
			echo "vsyscall is required for the Mail Server to work correctly"
			echo "Please use this instruction https://helpcenter.onlyoffice.com/server/docker/mail/enabling-vsyscall-on-debian.aspx"
			exit 1;
		fi
	fi
}

start_installation () {
	root_checking

	set_installation_type_data

	set_jwt_enabled
	set_jwt_header
	set_jwt_secret

	set_core_machinekey

	if [ "$UPDATE" == "true" ]; then
		read_parameters
	fi

	get_os_info

	check_os_info

	check_kernel

	if [ "$SKIP_HARDWARE_CHECK" != "true" ]; then
		check_hardware
	fi

	if [ "$UPDATE" != "true" ]; then
		check_ports
		MYSQL_VERSION="8.0.29";

		if [ "$INSTALL_MAIL_SERVER" == "true" ]; then
			if [[ -z ${MAIL_DOMAIN_NAME} ]]; then

				INSTALL_MAIL_SERVER_TEMP="";

				while [ "$INSTALL_MAIL_SERVER_TEMP" != "Y" ] && [ "$INSTALL_MAIL_SERVER_TEMP" != "N" ]; do
					read -p "Install ONLYOFFICE Mail Server [Y/N]?: " INSTALL_MAIL_SERVER_TEMP
					INSTALL_MAIL_SERVER_TEMP="$(echo $INSTALL_MAIL_SERVER_TEMP | tr '[:lower:]' '[:upper:]')";
				done

				if [ "$INSTALL_MAIL_SERVER_TEMP" = "Y" ]; then
					while [ -z "$MAIL_DOMAIN_NAME" ]; do
						read -p "Enter mail domain for ONLYOFFICE Mail Server: " MAIL_DOMAIN_NAME
					done
				fi
			fi

			if [[ -z ${MAIL_DOMAIN_NAME} ]]; then
				INSTALL_MAIL_SERVER="false";
			elif [ "$SKIP_DOMAIN_CHECK" != "true" ]; then
				check_domain
			fi

			if [ "$INSTALL_MAIL_SERVER" == "true" ] && [ "$DIST" == "Debian" ]; then
				check_vsyscall
			fi
		fi
	elif [[ -z $(get_container_id "$MAIL_CONTAINER_NAME") ]]; then
		INSTALL_MAIL_SERVER="false";
	fi

	if [ "$MAKESWAP" == "true" ]; then
		make_swap
	fi

	if command_exists docker ; then
		check_docker_version
		service docker start
	else
		install_docker
	fi

	docker_login

	make_directories

	set_partner_data

	create_network

	if [[ -z ${MYSQL_HOST} ]]; then
		if [ "$INSTALL_MAIL_SERVER" == "true" ] || [ "$INSTALL_COMMUNITY_SERVER" == "true" ]; then
			pull_mysql_server
			install_mysql_server
		elif [ "$INSTALL_MAIL_SERVER" == "pull" ] || [ "$INSTALL_COMMUNITY_SERVER" == "pull" ]; then
			pull_mysql_server
		fi
	else
		ping_host_port "$MYSQL_HOST" "$MYSQL_PORT"
	fi

	if [[ -z ${ELASTICSEARCH_HOST} ]]; then
		if [ "$INSTALL_ELASTICSEARCH" == "true" ]; then
			pull_elasticsearch
			install_elasticsearch
		elif [ "$INSTALL_ELASTICSEARCH" == "pull" ]; then
			pull_elasticsearch
		fi
	else
		ping_host_port "$ELASTICSEARCH_HOST" "$ELASTICSEARCH_PORT"
		ELASTICSEARCH_SERVER="$ELASTICSEARCH_HOST";
	fi

	if [ "$INSTALL_DOCUMENT_SERVER" == "true" ]; then
		pull_document_server
		install_document_server
	elif [ "$INSTALL_DOCUMENT_SERVER" == "pull" ]; then
		pull_document_server
	fi

	if [ "$INSTALL_MAIL_SERVER" == "true" ]; then
		pull_mail_server
		install_mail_server
	elif [ "$INSTALL_MAIL_SERVER" == "pull" ]; then
		pull_mail_server
	fi

	if [ "$INSTALL_CONTROLPANEL" == "true" ]; then
		pull_controlpanel
		install_controlpanel
	elif [ "$INSTALL_CONTROLPANEL" == "pull" ]; then
		pull_controlpanel
	fi

	if [ "$INSTALL_COMMUNITY_SERVER" == "true" ]; then
		pull_community_server
		install_community_server
	elif [ "$INSTALL_COMMUNITY_SERVER" == "pull" ]; then
		pull_community_server
	fi

	[ -n "$JWT_MESSAGE" ] && [ -n "$DOCUMENT_SERVER_ID" ] && JWT_MESSAGE=$(echo "$JWT_MESSAGE" | sed 's/$(sudo docker ps -q)/'"${DOCUMENT_SERVER_ID::12}"'/') && echo -e "\n$JWT_MESSAGE"
	echo ""
	echo "Thank you for installing ONLYOFFICE."
	echo "You can now configure your portal and add Mail Server to your installation (in case you skipped it earlier) using the Control Panel"
	echo "In case you have any questions contact us via http://support.onlyoffice.com or visit our forum at http://forum.onlyoffice.com"
	echo ""

	exit 0;
}

start_installation

workspace-install.sh这个脚本主要的作用是检测安装环境并根据脚本选择执行相应的自动化安装部署过程,下面介绍如何离线化快速安装only office workspace

四、

workspace的具体离线部署步骤

镜像离线包下载地址:

通过网盘分享的文件:workspace
链接: https://pan.baidu.com/s/1_jnE5cmIizBB7djTJi0Xkg?pwd=hvbn 提取码: hvbn 
--来自百度网盘超级会员v6的分享

相关脚本和所有镜像都在网盘内,onlyoffice-zong.tar 是所有镜像的压缩包方便传输,总共是五个镜像

搭建好docker环境后,导入上述五个镜像,即可开始执行workspace-install.sh,在执行此脚本前,还是需要先看看帮助(注意,这个帮助是install.sh这个脚本提供的,如果是bash workspace-install.sh -h,那么,install.sh这个脚本将会被删除):

root@centos14 ~]# bash install.sh -h
  Usage: bash install.sh [PARAMETER] [[PARAMETER], ...]

    Parameters:
      -ci, --communityimage             community image name or .tar.gz file path
      -di, --documentimage              document image name or .tar.gz file path
      -mi, --mailimage                  mail image name or .tar.gz file path
      -esi, --elasticsearchimage        elasticsearch image name or .tar.gz file path
      -cpi, --controlpanelimage         control panel image name or .tar.gz file path
      -mysqli, --mysqlimage             mysql image name or .tar.gz file path
      -cv, --communityversion           community version
      -dv, --documentversion            document version
      -dip, --documentserverip          document server ip
      -esv, --elasticsearchversion      elasticsearch version
      -esh, --elasticsearchhost         elasticsearch server host
      -msp, --elasticsearchport         elasticsearch server port
      -mv, --mailversion                mail version
      -mip, --mailserverip              mail server ip
      -mdbip, --mailserverdbip          mail server db ip
      -cpv, --controlpanelversion       control panel version
      -md, --maildomain                 mail domail name
      -u, --update                      use to update existing components (true|false)
      -hub, --hub                       dockerhub name
      -un, --username                   dockerhub username
      -p, --password                    dockerhub password
      -ics, --installcommunityserver    install or update community server (true|false|pull)
      -ids, --installdocumentserver     install or update document server (true|false|pull)
      -ims, --installmailserver         install or update mail server (true|false|pull)
      -ies, --installelasticsearch      install or update elasticsearch (true|false|pull)
      -icp, --installcontrolpanel       install or update control panel (true|false|pull)
      -es, --useasexternalserver        use as external server (true|false)
      -pdf, --partnerdatafile           partner data file
      -it, --installation_type          installation type (GROUPS|WORKSPACE|WORKSPACE_ENTERPRISE)
      -ms, --makeswap                   make swap file (true|false)
      -mysqlh, --mysqlhost              mysql server host
      -mysqlprt, --mysqlport            mysql server port
      -mysqlru, --mysqlrootuser         mysql server root user
      -mysqlrp, --mysqlrootpassword     mysql server root password
      -mysqld, --mysqldatabase          community server database name
      -mysqlu, --mysqluser              community server database user
      -mysqlp, --mysqlpassword          community server database password
      -mysqlmd, --mysqlmaildatabase     mail server database name
      -mysqlmu, --mysqlmailuser         mail server database user
      -mysqlmp, --mysqlmailpassword     mail server database password
      -skiphc, --skiphardwarecheck      skip hardware check (true|false)
      -skipvc, --skipversioncheck       skip version check while update (true|false)
      -skipdc, --skipdomaincheck        skip domain check when installing mail server (true|false)
      -cp, --communityport              community port (default value 80)
      -mk, --machinekey                 setting for core.machinekey
      -je, --jwtenabled                 specifies the enabling the JWT validation (true|false)
      -jh, --jwtheader                  defines the http header that will be used to send the JWT
      -js, --jwtsecret                  defines the secret key to validate the JWT in the request
      -?, -h, --help                    this help

  Examples
    Install all the solution components:
      bash install.sh -md yourdomain.com

    Install all the components without Mail Server:
      bash install.sh -ims false

    Install Document Server only. Skip the installation of Mail Server, Community Server and Control Panel:
      bash install.sh -ics false -ids true -icp false -ims false -es true

    Install Mail Server only. Skip the installation of Document Server, Community Server and Control Panel:
      bash install.sh -ics false -ids false -icp false -ims true -md yourdomain.com -es true

    Install Community Server with Control Panel and connect it with Document Server installed on a different machine which has the 192.168.3.202 IP address:
      bash install.sh -ics true -icp true -ids false -ims false -dip 192.168.3.202

    Update all installed components. Stop the containers that need to be updated, remove them and run the latest versions of the corresponding components. The portal data should be picked up automatically:
      bash install.sh -u true

    Update Document Server only to version 4.4.2.20 and skip the update for all other components:
      bash install.sh -u true -dv 4.4.2.20 -ics false -icp false -ims false

    Update Community Server only to version 9.1.0.393 and skip the update for all other components:
      bash install.sh -u true -cv 9.1.0.393 -ids false -icp false -ims false

    Update Mail Server only to version 1.6.27 and skip the update for all other components:
      bash install.sh -u true -mv 1.6.27 -ics false -ids false -icp false

    Update Control Panel only to version 2.1.0.93 and skip the update for all other components:
      bash install.sh -u true -cpv 2.1.0.93 -ics false -ids false -ims false

install.sh这个脚本的变量可以按需修改成如下:

DISK_REQUIREMENTS=20960;
MEMORY_REQUIREMENTS=4000;

DOCUMENT_IMAGE_NAME="onlyoffice/documentserver";

BASE_DIR="/opt3/$PRODUCT";



说明:onlyoffice/documentserver和onlyoffice/documentserver-ee一个是社区的镜像,一个是企业版的镜像,必须要改

DISK_REQUIREMENTS=20960;表示磁盘根目录的可用空间要求是2G,原来是需要5G

MEMORY_REQUIREMENTS=4000;表示需要内存是4G,原来是8G

BASE_DIR="/opt/$PRODUCT"; 如果要删除或者重新安装,先清除所有容器后,删除这个指定的目录,再次运行脚本即可,opt可以换成任意的目录,例如app,app1等等都可以

清除所有容器命令为:docker rm -f $(docker ps -aq)

结合上述帮助和现有镜像的版本,可以得出如下安装命令:

bash workspace-install.sh -dv 9.0.3.1 -cv 12.7.1.1942 -cpv 3.5.4.541 -esv 7.16.3 -cp 18080 -mysqli mysql_8.0.29.tar.gz -ims false

该命令注意是指定dv,cv,esv,cpv的版本,这些版本和现有的镜像版本是一一对应的关系(cv=community version,dv=document version,esv=elasticsearch version,cpv=control panel version),指定最终community的入口端口是18080,如果默认,是80端口,脚本执行的时候不提示mail server服务是否安装,直接忽略,还有一点必须强调,如果MySQL镜像没有docker load,或者其它镜像没有load,必须修改后缀为tar.gz 然后指定具体路径,

根据帮助命令,可以知道MySQL的端口,用户,密码等等都可以定制,如果需要的,比如,MySQL的密码设置为指定密码,-mysqlp 要设定的密码,加在上面的命令后面即可,cs的端口是18080,这个端口也可以随意更换,后面的示例是以18080端口演示的

安装日志如下(只要看到谢谢就表示安装成功完成了):

[root@centos14 ~]# bash workspace-install.sh -dv 9.0.3.1 -cv 12.7.1.1942 -cpv 3.5.4.541 -esv 7.16.3 -cp 18080 -mysqli mysql_8.0.29.tar.gz -ims false
Select 'Y' to install ONLYOFFICE using Docker (recommended). Select 'N' to install it using RPM/DEB packages.
Please note, that in case you select RPM/DEB installation, you will need to manually install Mail Server and connect it to your ONLYOFFICE installation.
See instructions in our Help Center: http://helpcenter.onlyoffice.com/server/docker/mail/connect-mail-server-to-community-server-via-portal-settings.aspx
Install with Docker [Y/N/C]? y
Redirecting to /bin/systemctl start docker.service
Loaded image: mysql:8.0.29
d35786c1e44ee0daa5cb23f8353fc24a505d6cc437f9bd7105918b9aca45e39f
4badf9013bd49ab4126ddd30bee00813e449774b0593224fa9a54e616c4a6e1e
cfe44b02916b1dc9b0a2e32dbb9bd0ddcbbf58408f2feead3fd0fea4c07966f4
85bafe7069ad931fb7cf29a235d1c0523ad010b28792293788be2912abc03aba
ecc564d4038b777ba8fbf35f617c3a5d4b6a8f797b6d16be620b2b2a838f9e7a

JWT is enabled by default. A random secret is generated automatically. Run the command "docker exec cfe44b02916b sudo documentserver-jwt-status.sh" to get information about JWT.

Thank you for installing ONLYOFFICE.
You can now configure your portal and add Mail Server to your installation (in case you skipped it earlier) using the Control Panel
In case you have any questions contact us via http://support.onlyoffice.com or visit our forum at http://forum.onlyoffice.com

各个服务的大体日志

所有服务都是up状态

[root@centos14 ~]# docker  ps -a
CONTAINER ID   IMAGE                                    COMMAND                  CREATED         STATUS         PORTS                                                                                                                                                                                          NAMES
ecc564d4038b   onlyoffice/communityserver:12.7.1.1942   "/app/run-community-…"   4 minutes ago   Up 4 minutes   0.0.0.0:443->443/tcp, :::443->443/tcp, 3306/tcp, 5280/tcp, 9865-9866/tcp, 9871/tcp, 9882/tcp, 0.0.0.0:5222->5222/tcp, :::5222->5222/tcp, 9888/tcp, 0.0.0.0:18080->80/tcp, [::]:18080->80/tcp   onlyoffice-community-server
85bafe7069ad   onlyoffice/controlpanel:3.5.4.541        "/var/www/onlyoffice…"   4 minutes ago   Up 4 minutes   80/tcp, 443/tcp                                                                                                                                                                                onlyoffice-control-panel
cfe44b02916b   onlyoffice/documentserver:9.0.3.1        "/app/ds/run-documen…"   4 minutes ago   Up 4 minutes   80/tcp, 443/tcp                                                                                                                                                                                onlyoffice-document-server
4badf9013bd4   onlyoffice/elasticsearch:7.16.3          "/bin/tini -- /usr/l…"   4 minutes ago   Up 4 minutes   9200/tcp, 9300/tcp                                                                                                                                                                             onlyoffice-elasticsearch
d35786c1e44e   mysql:8.0.29                             "docker-entrypoint.s…"   4 minutes ago   Up 4 minutes   3306/tcp, 33060/tcp    

ds的:

[  OK  ] Started ONLYOFFICE Thumb Service.
[  OK  ] Started ONLYOFFICE SsoAuth Service.
[  OK  ] Started System Logging Service.
[  OK  ] Started LSB: Mono XSP4.
[  OK  ] Started God Service.
[  OK  ] Started A high performance web server and a reverse proxy server.
[  OK  ] Started Advanced key-value store.
[  OK  ] Started MySQL Community Server.
         Starting FastCGI Mono server...
         Starting FastCGI Mono server...
         Starting Start ONLYOFFICE Backup Service...
         Starting ONLYOFFICE Feed Service...
         Starting ONLYOFFICE FilesTrashCleaner Service...
         Starting Start ONLYOFFICE Index Service...
         Starting ONLYOFFICE Jabber Service...
         Starting ONLYOFFICE MailAggregator Service...
         Starting ONLYOFFICE MailCleaner Service...
         Starting ONLYOFFICE MailImap Service...
         Starting ONLYOFFICE MailWatchdog Service...
         Starting ONLYOFFICE Notify Service...
         Starting ONLYOFFICE Radicale Service...
         Starting ONLYOFFICE SocketIO Service...
         Starting Start ONLYOFFICE StorageEncryption Service...
         Starting Start ONLYOFFICE StorageMigrate Service...
         Starting ONLYOFFICE Telegram Service...
         Starting ONLYOFFICE ThumbnailBuilder Service...
         Starting ONLYOFFICE UrlShortener Service...
         Starting ONLYOFFICE WebDav Service...
[  OK  ] Started FastCGI Mono server.
[  OK  ] Started ONLYOFFICE Radicale Service.
[  OK  ] Started ONLYOFFICE SocketIO Service.
[  OK  ] Started ONLYOFFICE UrlShortener Service.
[  OK  ] Started FastCGI Mono server.
[  OK  ] Started ONLYOFFICE WebDav Service.
[  OK  ] Started ONLYOFFICE Feed Service.
[  OK  ] Started ONLYOFFICE FilesTrashCleaner Service.
[  OK  ] Started Start ONLYOFFICE Index Service.
[  OK  ] Started Start ONLYOFFICE Backup Service.
[  OK  ] Started ONLYOFFICE Jabber Service.
[  OK  ] Started ONLYOFFICE Notify Service.
[  OK  ] Started Start ONLYOFFICE StorageEncryption Service.
[  OK  ] Started Start ONLYOFFICE StorageMigrate Service.
[  OK  ] Started ONLYOFFICE Telegram Service.
[  OK  ] Started ONLYOFFICE ThumbnailBuilder Service.
[  OK  ] Started ONLYOFFICE MailCleaner Service.
[  OK  ] Started ONLYOFFICE MailImap Service.
[  OK  ] Started ONLYOFFICE MailWatchdog Service.
[  OK  ] Started ONLYOFFICE MailAggregator Service.
[  OK  ] Reached target Multi-User System.
[  OK  ] Reached target Graphical Interface.

cp的日志:

[root@centos14 ~]# docker logs 85bafe7069ad
2025-08-06 16:04:27,015 INFO Included extra file "/etc/supervisor/conf.d/supervisord.conf" during parsing
2025-08-06 16:04:27,015 INFO Set uid to user 0 succeeded
2025-08-06 16:04:27,017 INFO RPC interface 'supervisor' initialized
2025-08-06 16:04:27,017 CRIT Server 'unix_http_server' running without any HTTP authentication checking
2025-08-06 16:04:27,018 INFO supervisord started with pid 1
2025-08-06 16:04:28,020 INFO spawned: 'www' with pid 16
2025-08-06 16:04:29,148 INFO success: www entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)

ds的日志:

[root@centos14 ~]# docker logs 85bafe7069ad
2025-08-06 16:04:27,015 INFO Included extra file "/etc/supervisor/conf.d/supervisord.conf" during parsing
2025-08-06 16:04:27,015 INFO Set uid to user 0 succeeded
2025-08-06 16:04:27,017 INFO RPC interface 'supervisor' initialized
2025-08-06 16:04:27,017 CRIT Server 'unix_http_server' running without any HTTP authentication checking
2025-08-06 16:04:27,018 INFO supervisord started with pid 1
2025-08-06 16:04:28,020 INFO spawned: 'www' with pid 16
2025-08-06 16:04:29,148 INFO success: www entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)

MySQL的日志:

[root@centos14 ~]# docker logs d35786c1e44e
2025-08-06 16:04:24+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 8.0.29-1.el8 started.
2025-08-06 16:04:24+00:00 [Note] [Entrypoint]: Switching to dedicated user 'mysql'
2025-08-06 16:04:25+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 8.0.29-1.el8 started.
'/var/lib/mysql/mysql.sock' -> '/var/run/mysqld/mysqld.sock'
2025-08-06 16:04:46+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 8.0.29-1.el8 started.
2025-08-06 16:04:46+00:00 [Note] [Entrypoint]: Switching to dedicated user 'mysql'
2025-08-06 16:04:46+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 8.0.29-1.el8 started.
'/var/lib/mysql/mysql.sock' -> '/var/run/mysqld/mysqld.sock'
2025-08-06 16:04:54+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 8.0.29-1.el8 started.
2025-08-06 16:04:55+00:00 [Note] [Entrypoint]: Switching to dedicated user 'mysql'
2025-08-06 16:04:55+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 8.0.29-1.el8 started.
'/var/lib/mysql/mysql.sock' -> '/var/run/mysqld/mysqld.sock'

elasticsearch的日志:

{"type": "server", "timestamp": "2025-08-06T16:04:37,112Z", "level": "INFO", "component": "o.e.n.Node", "cluster.name": "docker-cluster", "node.name": "4badf9013bd4", "message": "initialized" }
{"type": "server", "timestamp": "2025-08-06T16:04:37,113Z", "level": "INFO", "component": "o.e.n.Node", "cluster.name": "docker-cluster", "node.name": "4badf9013bd4", "message": "starting ..." }
{"type": "server", "timestamp": "2025-08-06T16:04:37,136Z", "level": "INFO", "component": "o.e.x.s.c.f.PersistentCache", "cluster.name": "docker-cluster", "node.name": "4badf9013bd4", "message": "persistent cache index loaded" }
{"type": "server", "timestamp": "2025-08-06T16:04:37,137Z", "level": "INFO", "component": "o.e.x.d.l.DeprecationIndexingComponent", "cluster.name": "docker-cluster", "node.name": "4badf9013bd4", "message": "deprecation component started" }
{"type": "server", "timestamp": "2025-08-06T16:04:37,210Z", "level": "INFO", "component": "o.e.t.TransportService", "cluster.name": "docker-cluster", "node.name": "4badf9013bd4", "message": "publish_address {172.18.0.3:9300}, bound_addresses {[::]:9300}" }
{"type": "server", "timestamp": "2025-08-06T16:04:37,559Z", "level": "WARN", "component": "o.e.b.BootstrapChecks", "cluster.name": "docker-cluster", "node.name": "4badf9013bd4", "message": "max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]" }
{"type": "server", "timestamp": "2025-08-06T16:04:37,561Z", "level": "INFO", "component": "o.e.c.c.Coordinator", "cluster.name": "docker-cluster", "node.name": "4badf9013bd4", "message": "cluster UUID [klSQapPZSYKDT2plZiD0PQ]" }
{"type": "server", "timestamp": "2025-08-06T16:04:37,858Z", "level": "INFO", "component": "o.e.c.s.MasterService", "cluster.name": "docker-cluster", "node.name": "4badf9013bd4", "message": "elected-as-master ([1] nodes joined)[{4badf9013bd4}{El-Y0vaIQlyQDa8pkj1Egw}{HgomzK-ARq6VtRd8ViQlYg}{172.18.0.3}{172.18.0.3:9300}{cdfhilmrstw} elect leader, _BECOME_MASTER_TASK_, _FINISH_ELECTION_], term: 10, version: 288, delta: master node changed {previous [], current [{4badf9013bd4}{El-Y0vaIQlyQDa8pkj1Egw}{HgomzK-ARq6VtRd8ViQlYg}{172.18.0.3}{172.18.0.3:9300}{cdfhilmrstw}]}" }
{"type": "server", "timestamp": "2025-08-06T16:04:37,929Z", "level": "INFO", "component": "o.e.c.s.ClusterApplierService", "cluster.name": "docker-cluster", "node.name": "4badf9013bd4", "message": "master node changed {previous [], current [{4badf9013bd4}{El-Y0vaIQlyQDa8pkj1Egw}{HgomzK-ARq6VtRd8ViQlYg}{172.18.0.3}{172.18.0.3:9300}{cdfhilmrstw}]}, term: 10, version: 288, reason: Publication{term=10, version=288}" }
{"type": "server", "timestamp": "2025-08-06T16:04:37,975Z", "level": "INFO", "component": "o.e.h.AbstractHttpServerTransport", "cluster.name": "docker-cluster", "node.name": "4badf9013bd4", "message": "publish_address {172.18.0.3:9200}, bound_addresses {[::]:9200}", "cluster.uuid": "klSQapPZSYKDT2plZiD0PQ", "node.id": "El-Y0vaIQlyQDa8pkj1Egw"  }
{"type": "server", "timestamp": "2025-08-06T16:04:37,975Z", "level": "INFO", "component": "o.e.n.Node", "cluster.name": "docker-cluster", "node.name": "4badf9013bd4", "message": "started", "cluster.uuid": "klSQapPZSYKDT2plZiD0PQ", "node.id": "El-Y0vaIQlyQDa8pkj1Egw"  }
{"type": "server", "timestamp": "2025-08-06T16:04:38,416Z", "level": "INFO", "component": "o.e.l.LicenseService", "cluster.name": "docker-cluster", "node.name": "4badf9013bd4", "message": "license [9c141f58-1d95-41e2-9d29-2e37eba460a1] mode [basic] - valid", "cluster.uuid": "klSQapPZSYKDT2plZiD0PQ", "node.id": "El-Y0vaIQlyQDa8pkj1Egw"  }
{"type": "server", "timestamp": "2025-08-06T16:04:38,418Z", "level": "INFO", "component": "o.e.x.s.s.SecurityStatusChangeListener", "cluster.name": "docker-cluster", "node.name": "4badf9013bd4", "message": "Active license is now [BASIC]; Security is disabled", "cluster.uuid": "klSQapPZSYKDT2plZiD0PQ", "node.id": "El-Y0vaIQlyQDa8pkj1Egw"  }
{"type": "server", "timestamp": "2025-08-06T16:04:38,418Z", "level": "WARN", "component": "o.e.x.s.s.SecurityStatusChangeListener", "cluster.name": "docker-cluster", "node.name": "4badf9013bd4", "message": "Elasticsearch built-in security features are not enabled. Without authentication, your cluster could be accessible to anyone. See https://www.elastic.co/guide/en/elasticsearch/reference/7.16/security-minimal-setup.html to enable security.", "cluster.uuid": "klSQapPZSYKDT2plZiD0PQ", "node.id": "El-Y0vaIQlyQDa8pkj1Egw"  }
{"type": "deprecation.elasticsearch", "timestamp": "2025-08-06T16:04:38,419Z", "level": "CRITICAL", "component": "o.e.d.x.s.s.SecurityStatusChangeListener", "cluster.name": "docker-cluster", "node.name": "4badf9013bd4", "message": "The default behavior of disabling security on basic licenses is deprecated. In a later version of Elasticsearch, the value of [xpack.security.enabled] will default to \"true\" , regardless of the license level. See https://www.elastic.co/guide/en/elasticsearch/reference/7.16/security-minimal-setup.html to enable security, or explicitly disable security by setting [xpack.security.enabled] to false in elasticsearch.yml", "key": "security_implicitly_disabled", "category": "security", "cluster.uuid": "klSQapPZSYKDT2plZiD0PQ", "node.id": "El-Y0vaIQlyQDa8pkj1Egw"  }
{"type": "server", "timestamp": "2025-08-06T16:04:38,425Z", "level": "INFO", "component": "o.e.g.GatewayService", "cluster.name": "docker-cluster", "node.name": "4badf9013bd4", "message": "recovered [27] indices into cluster_state", "cluster.uuid": "klSQapPZSYKDT2plZiD0PQ", "node.id": "El-Y0vaIQlyQDa8pkj1Egw"  }
{"type": "server", "timestamp": "2025-08-06T16:04:39,943Z", "level": "INFO", "component": "o.e.c.r.a.AllocationService", "cluster.name": "docker-cluster", "node.name": "4badf9013bd4", "message": "Cluster health status changed from [RED] to [YELLOW] (reason: [shards started [[.ds-.logs-deprecation.elasticsearch-default-2025.08.05-000001][0]]]).", "cluster.uuid": "klSQapPZSYKDT2plZiD0PQ", "node.id": "El-Y0vaIQlyQDa8pkj1Egw"  }

这些镜像的实际运行命令如下(基本比较准确,但不可直接使用):

[root@centos20 initdb]# runlike -p b5ea0b17c311
docker run --name=onlyoffice-mysql-server \
	--hostname=b5ea0b17c311 \
	--volume /app/onlyoffice/mysql/initdb:/docker-entrypoint-initdb.d \
	--volume /app/onlyoffice/mysql/conf.d:/etc/mysql/conf.d \
	--volume /app/onlyoffice/mysql/data:/var/lib/mysql \
	--volume /app/onlyoffice/mysql/logs:/var/log/mysql \
	--env=MYSQL_ROOT_PASSWORD=my-secret-pw \
	--env=MYSQL_DATABASE=onlyoffice \
	--network=onlyoffice \
	--expose=3306 \
	--expose=33060 \
	--restart=always \
	--log-opt max-size=100m \
	--runtime=runc \
	--detach=true \
	-t \
	mysql:8.0.29 \
	mysqld
[root@centos20 initdb]# runlike -p 3dc60e58f3c4
docker run --name=onlyoffice-elasticsearch \
	--hostname=3dc60e58f3c4 \
	--volume /app/onlyoffice/elasticsearch/data:/usr/share/elasticsearch/data \
	--env=indices.memory.index_buffer_size=30% \
	--env=discovery.type=single-node \
	--env=bootstrap.memory_lock=true \
	--env=ingest.geoip.downloader.enabled=false \
	--env='ES_JAVA_OPTS=-Xms1g -Xmx1g -Dlog4j2.formatMsgNoLookups=true' \
	--env=indices.fielddata.cache.size=30% \
	--network=onlyoffice \
	--workdir=/usr/share/elasticsearch \
	--expose=9200 \
	--expose=9300 \
	--restart=always \
	--log-opt max-size=100m \
	--runtime=runc \
	--detach=true \
	-t \
	onlyoffice/elasticsearch:7.16.3 \
	eswrapper
[root@centos20 initdb]# runlike -p e1d29769643d
docker run --name=onlyoffice-ds \
	--hostname=e1d29769643d \
	--volume /var/lib/postgresql \
	--volume /var/lib/rabbitmq \
	--volume /var/lib/redis \
	--volume /var/log/onlyoffice \
	--volume /app/ds/data:/var/www/onlyoffice/Data \
	--volume /app/ds/fonts:/usr/share/fonts/truetype/custom \
	--volume /var/lib/onlyoffice \
	--network=onlyoffice \
	--expose=443 \
	-p 9001:80 \
	--log-opt max-size=100m \
	--runtime=runc \
	--detach=true \
	onlyoffice/documentserver:9.0.3.1
[root@centos20 initdb]# runlike -p 6ee11342a288
docker run --name=onlyoffice-cs \
	--hostname=6ee11342a288 \
	--volume /app/onlyoffice/CommunityServer/logs:/var/log/onlyoffice \
	--volume /app/onlyoffice/CommunityServer/letsencrypt:/etc/letsencrypt \
	--volume /sys/fs/cgroup:/sys/fs/cgroup \
	--volume /var/lib/mysql \
	--volume /app/onlyoffice/CommunityServer/data:/var/www/onlyoffice/Data \
	--env=MYSQL_SERVER_ROOT_PASSWORD=my-secret-pw \
	--env=MYSQL_SERVER_DB_NAME=onlyoffice \
	--env=MYSQL_SERVER_HOST=onlyoffice-mysql-server \
	--env=MYSQL_SERVER_USER=onlyoffice_user \
	--env=MYSQL_SERVER_PASS=onlyoffice_pass \
	--network=onlyoffice \
	--privileged \
	--expose=3306 \
	-p 443:443 \
	-p 5222:5222 \
	--expose=5280 \
	-p 9100:80 \
	--expose=9865 \
	--expose=9866 \
	--expose=9871 \
	--expose=9882 \
	--expose=9888 \
	--restart=always \
	--log-opt max-size=100m \
	--runtime=runc \
	--detach=true \
	-t \
	onlyoffice/communityserver:12.7.1.1942 \
	/app/run-community-server.sh

docker run --name=onlyoffice-control-panel \
	--hostname=631ff4d76db1 \
	--volume /var/run/docker.sock:/var/run/docker.sock \
	--volume /app/onlyoffice/ControlPanel/data:/var/www/onlyoffice/Data \
	--volume /app/onlyoffice/CommunityServer/data:/app/onlyoffice/CommunityServer/data \
	--volume /app/onlyoffice/ControlPanel/logs:/var/log/onlyoffice \
	--env=ONLYOFFICE_CORE_MACHINEKEY=vwqZSf6gOzkj \
	--network=onlyoffice \
	--workdir=/var/www/onlyoffice/controlpanel \
	--expose=443 \
	--expose=80 \
	--restart=always \
	--runtime=runc \
	--detach=true \
	-t \
	onlyoffice/controlpanel:3.5.4.541

现在就可以打开浏览器进入workspace了:

密码8位以上,时区选上海,语言选中文或者英文都可以,邮箱可随意填写,但必须是邮箱格式,邮箱就是管理员账号,完成后,点击continue

第一次输入的密码和邮箱就是管理员的账号和密码了,记得妥善保存噢

离线化安装workspace基本可以做到2 3分钟内就完成,前提是docker环境是正确配置好的并导入了五个网盘内的镜像

五、

workspace业务简单介绍

创建用户

当我们使用管理员进入系统后,如果希望其它人能够也访问此系统,那么,创建添加用户是必须的,这个非常简单,找People,点击进入后,创建即可

记得把美照也上传上去,红星的必填填写完就可以了,然后保存 

创建项目

项目是最核心的功能,要记得添加成员噢

上传文档到上面创建的项目内:

点击创建好的项目,选择documents标签,可以看到多一个上传的入口:

 

当然了,随便什么word,excel也是非常简单的就可以打开了,只是注意有时候会有乱码,乱码的问题以后在说

<think>好的,用户想找如何使用Docker部署OnlyOffice Workspace的教程或指南。首先,我需要回忆一下OnlyOffice Workspace的官方文档是否有相关Docker部署的说明。通常,很多开源项目都会在官方文档里提供Docker部署方法,所以应该先检查这个部分。 接下来,用户提到的Docker部署,可能需要用到Docker Compose,因为OnlyOffice可能有多个服务需要同时运行,比如文档服务器、数据库等。这时候Docker Compose能方便地管理多个容器。 然后,用户提供的引用中有提到DockerfileDocker Compose的创建,比如引用[2]里提到创建Docker Compose yaml文件并测试应用。这可能意味着用户已经了解Docker的基本操作,但需要针对OnlyOffice的具体配置步骤。 另外,引用[3]提到使用Docker Explorer部署镜像到Azure App Service,但用户的问题是关于本地部署OnlyOffice,可能需要忽略这部分,除非用户有云部署的需求,但问题中没有提到,所以暂时不考虑。 需要确保提供的步骤正确,包括拉取镜像、编写docker-compose.yml文件、配置端口环境变量,以及持久存储。这些是Docker部署的常见步骤,但需要针对OnlyOffice的具体参数进行调整。 可能遇到的问题包括端口冲突、权限问题或者环境变量配置错误。因此,在回答中应该提醒用户检查这些部分,并参考官方文档。 最后,生成的相关问题需要围绕部署后的管理、优常见问题解决,这样用户如果有进一步的问题也能找到方向。</think>### 如何使用Docker部署OnlyOffice Workspace 以下是基于Docker部署OnlyOffice Workspace的步骤指南: --- #### 1. **安装Docker环境** - 确保已安装Docker EngineDocker Compose - 验证安装: ```bash docker --version docker-compose --version ``` --- #### 2. **创建Docker Compose文件** - 新建`docker-compose.yml`文件并添加以下内容: ```yaml version: '3' services: onlyoffice: image: onlyoffice/workspace:latest container_name: onlyoffice_workspace restart: always ports: - "80:80" - "443:443" volumes: - ./data:/var/www/onlyoffice/Data - ./logs:/var/log/onlyoffice environment: - MYSQL_HOST=db - MYSQL_DATABASE=onlyoffice - MYSQL_USER=onlyoffice_user - MYSQL_PASSWORD=your_secure_password db: image: mysql:5.7 container_name: onlyoffice_db restart: always environment: MYSQL_ROOT_PASSWORD: root_password MYSQL_DATABASE: onlyoffice MYSQL_USER: onlyoffice_user MYSQL_PASSWORD: your_secure_password volumes: - ./mysql:/var/lib/mysql ``` --- #### 3. **关键配置说明** - **端口映射**:通过`80:80``443:443`暴露HTTP/HTTPS服务 - **持久存储**:使用`volumes`将数据目录日志目录挂载到宿主机 - **数据库配置**:MySQL容器OnlyOffice容器通过环境变量联动[^2] - **安全性**:建议替换默认密码`your_secure_password` --- #### 4. **启动服务** ```bash docker-compose up -d ``` - 首次启动需要下载镜像,耗时约5-15分钟 - 检查容器状态: ```bash docker ps -a ``` --- #### 5. **访问服务** - 浏览器访问`http://localhost`或`https://your-domain` - 按照初始向导完成管理员账户配置 --- #### 6. **维护操作** - 更新版本: ```bash docker-compose pull && docker-compose up -d ``` - 查看日志: ```bash docker logs onlyoffice_workspace ``` --- ### 注意事项 1. **硬件要求**:建议4GB以上内存,SSD存储 2. **HTTPS配置**:生产环境应配置SSL证书[^3] 3. **备份策略**:定期备份`./data``./mysql`目录 官方文档参考:[OnlyOffice Workspace Docker部署指南](https://helpcenter.onlyoffice.com/installation/docs-community-install-docker.aspx)[^4] ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

晚风_END

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值